complicated sliver logic implemented
[plstackapi.git] / planetstack / core / xoslib / static / js / xoslib / xosHelper.js
index 5ebc006..65ccdbd 100644 (file)
@@ -594,7 +594,66 @@ XOSDetailView = Marionette.ItemView.extend({
                                                     inputType: this.model.inputType,
                                                     model: this.model,
                                          }},
+});
+
+XOSDetailView_sliver = XOSDetailView.extend( {
+    events: $.extend(XOSDetailView.events,
+        {"change #field_deploymentNetwork": "onDeploymentNetworkChange"}
+    ),
+
+    onShow: function() {
+        // Note that this causes the selects to be updated a second time. The
+        // first time was when the template was originally invoked, and the
+        // selects will all have the full unfiltered set of candidates. Then
+        // onShow will fire, and we'll update them with the filtered values.
+        this.onDeploymentNetworkChange();
+    },
 
+    onDeploymentNetworkChange: function(e) {
+        var deploymentID = this.$el.find("#field_deploymentNetwork").val();
+
+        console.log("onDeploymentNetworkChange");
+        console.log(deploymentID);
+
+        filterFunc = function(model) { return (model.attributes.deployment==deploymentID); }
+        newSelect = idToSelect("node",
+                               this.model.attributes.node,
+                               this.model.foreignFields["node"],
+                               "humanReadableName",
+                               false,
+                               filterFunc);
+        this.$el.find("#field_node").html(newSelect);
+
+        filterFunc = function(model) { for (index in model.attributes.deployments) {
+                                          item=model.attributes.deployments[index];
+                                          if (item.toString()==deploymentID.toString()) return true;
+                                        };
+                                        return false;
+                                     }
+        newSelect = idToSelect("flavor",
+                               this.model.attributes.flavor,
+                               this.model.foreignFields["flavor"],
+                               "humanReadableName",
+                               false,
+                               filterFunc);
+        this.$el.find("#field_flavor").html(newSelect);
+
+        filterFunc = function(model) { for (index in xos.imageDeployments.models) {
+                                           imageDeployment = xos.imageDeployments.models[index];
+                                           if ((imageDeployment.attributes.deployment == deploymentID) && (imageDeployment.attributes.image == model.id)) {
+                                               return true;
+                                           }
+                                       }
+                                       return false;
+                                     };
+        newSelect = idToSelect("image",
+                               this.model.attributes.image,
+                               this.model.foreignFields["image"],
+                               "humanReadableName",
+                               false,
+                               filterFunc);
+        this.$el.find("#field_image").html(newSelect);
+    },
 });
 
 /* XOSItemView
@@ -702,6 +761,213 @@ XOSListView = FilteredCompositeView.extend({
              },
 });
 
+XOSDataTableView = Marionette.View.extend( {
+    el: '<div style="overflow: hidden">' +
+        '<h3 class="xos-list-title title_placeholder"></h3>' +
+        '<div class="header_placeholder"></div>' +
+        '<table></table>' +
+        '<div class="footer_placeholder"></div>' +
+        '</div>',
+
+    filter: undefined,
+
+     events: {"click button.btn-xos-add": "addClicked",
+              "click button.btn-xos-refresh": "refreshClicked",
+             },
+
+     _fetchStateChange: function() {
+         if (this.collection.fetching) {
+            $("#xos-list-title-spinner").show();
+         } else {
+            $("#xos-list-title-spinner").hide();
+         }
+     },
+
+     addClicked: function(e) {
+        e.preventDefault();
+        this.app.Router.navigate("add" + firstCharUpper(this.collection.modelName), {trigger: true});
+     },
+
+     refreshClicked: function(e) {
+         e.preventDefault();
+         this.collection.refresh(refreshRelated=true);
+     },
+
+
+    initialize: function() {
+        $(this.el).find(".footer_placeholder").html( xosListFooterTemplate({addChildHash: this.getAddChildHash()}) );
+        $(this.el).find(".header_placeholder").html( xosListHeaderTemplate() );
+
+        this.listenTo(this.collection, 'fetchStateChange', this._fetchStateChange);
+    },
+
+    render: function() {
+        var view = this;
+
+        view.columnsByIndex = [];
+        view.columnsByFieldName = {};
+        _.each(this.collection.listFields, function(fieldName) {
+            mRender = undefined;
+            mSearchText = undefined;
+            sTitle = fieldNameToHumanReadable(fieldName);
+            bSortable = true;
+            if (fieldName=="backend_status") {
+                mRender = function(x,y,z) { return xosBackendStatusIconTemplate(z); };
+                sTitle = "";
+                bSortable = false;
+            } else if (fieldName in view.collection.foreignFields) {
+                var foreignCollection = view.collection.foreignFields[fieldName];
+                mSearchText = function(x) { return idToName(x, foreignCollection, "humanReadableName"); };
+            }
+            if ($.inArray(fieldName, view.collection.detailLinkFields)>=0) {
+                var collectionName = view.collection.collectionName;
+                mRender = function(x,y,z) { return '<a href="#' + collectionName + '/' + z.id + '">' + x + '</a>'; };
+            }
+            thisColumn = {sTitle: sTitle, bSortable: bSortable, mData: fieldName, mRender: mRender, mSearchText: mSearchText};
+            view.columnsByIndex.push( thisColumn );
+            view.columnsByFieldName[fieldName] = thisColumn;
+        });
+
+        deleteColumn = {sTitle: "", bSortable: false, mRender: function(x,y,z) { return xosDeleteButtonTemplate({modelName: view.collection.modelName, id: z.id}); }, mData: function() { return "delete"; }};
+        view.columnsByIndex.push(deleteColumn);
+        view.columnsByFieldName["delete"] = deleteColumn;
+
+        oTable = $(this.el).find("table").dataTable( {
+            "bJQueryUI": true,
+            "bStateSave": true,
+            "bServerSide": true,
+            "aoColumns": view.columnsByIndex,
+
+            fnServerData: function(sSource, aoData, fnCallback, settings) {
+                var compareColumns = function(sortCols, sortDirs, a, b) {
+                    a = a[sortCols[0]];
+                    b = b[sortCols[0]];
+                    result = (a==b) ? 0 : ((a<b) ? -1 : 1);
+                    if (sortDirs[0] == "desc") {
+                        result = -result;
+                    }
+                    return result;
+                };
+
+                var searchMatch = function(row, sSearch) {
+                    for (fieldName in row) {
+                        if (fieldName in view.columnsByFieldName) {
+                            try {
+                                value = row[fieldName].toString();
+                            } catch(e) {
+                                continue;
+                            }
+                            if (value.indexOf(sSearch) >= 0) {
+                                return true;
+                            }
+                        }
+                    }
+                    return false;
+                };
+
+                //console.log(aoData);
+\r
+                // function used to populate the DataTable with the current\r
+                // content of the collection\r
+                var populateTable = function()\r
+                {\r
+                  console.log("populatetable!");\r
+\r
+                  // clear out old row views\r
+                  rows = [];\r
+\r
+                  sSearch = null;\r
+                  iDisplayStart = 0;\r
+                  iDisplayLength = 1000;\r
+                  sortDirs = [];\r
+                  sortCols = [];\r
+                  _.each(aoData, function(param) {\r
+                      if (param.name == "sSortDir_0") {\r
+                          sortDirs = [param.value];\r
+                      } else if (param.name == "iSortCol_0") {\r
+                          sortCols = [view.columnsByIndex[param.value].mData];\r
+                      } else if (param.name == "iDisplayStart") {\r
+                          iDisplayStart = param.value;\r
+                      } else if (param.name == "iDisplayLength") {\r
+                          iDisplayLength = param.value;\r
+                      } else if (param.name == "sSearch") {\r
+                          sSearch = param.value;\r
+                      }\r
+                  });\r
+\r
+                  aaData = view.collection.toJSON();\r
+\r
+                  // apply backbone filtering on the models\r
+                  if (view.filter) {\r
+                      aaData = aaData.filter( function(row) { model = {}; model.attributes = row; return view.filter(model); } );\r
+                  }\r
+\r
+                  var totalSize = aaData.length;\r
+\r
+                  // turn the ForeignKey fields into human readable things\r
+                  for (rowIndex in aaData) {\r
+                      row = aaData[rowIndex];\r
+                      for (fieldName in row) {\r
+                          if (fieldName in view.columnsByFieldName) {\r
+                              mSearchText = view.columnsByFieldName[fieldName].mSearchText;\r
+                              if (mSearchText) {\r
+                                  row[fieldName] = mSearchText(row[fieldName]);\r
+                              }\r
+                          }\r
+                      }\r
+                  }\r
+\r
+                  // apply datatables search\r
+                  if (sSearch) {\r
+                      aaData = aaData.filter( function(row) { return searchMatch(row, sSearch); });\r
+                  }\r
+\r
+                  var filteredSize = aaData.length;\r
+\r
+                  // apply datatables sort\r
+                  aaData.sort(function(a,b) { return compareColumns(sortCols, sortDirs, a, b); });\r
+\r
+                  // slice it for pagination\r
+                  aaData = aaData.slice(iDisplayStart, iDisplayStart+iDisplayLength);\r
+\r
+                  return fnCallback({iTotalRecords: totalSize,\r
+                         iTotalDisplayRecords: filteredSize,\r
+                         aaData: aaData});\r
+                };\r
+\r
+                aoData.shift(); // ignore sEcho
+                populateTable();
+
+                view.listenTo(view.collection, 'change', populateTable);
+                view.listenTo(view.collection, 'add', populateTable);
+                view.listenTo(view.collection, 'remove', populateTable);
+            },
+        } );
+
+        return this;
+    },
+
+     getAddChildHash: function() {
+        if (this.parentModel) {
+            parentFieldName = this.parentModel.relatedCollections[this.collection.collectionName];
+            parentFieldName = parentFieldName || "unknown";
+
+            /*parentFieldName = "unknown";
+
+            for (fieldName in this.collection.foreignFields) {
+                cname = this.collection.foreignFields[fieldName];
+                if (cname = this.collection.collectionName) {
+                    parentFieldName = fieldName;
+                }
+            }*/
+            return "#addChild" + firstCharUpper(this.collection.modelName) + "/" + this.parentModel.modelName + "/" + parentFieldName + "/" + this.parentModel.id; // modelName, fieldName, id
+        } else {
+            return null;
+        }
+     },
+
+});
+
 idToName = function(id, collectionName, fieldName) {
     return xos.idToName(id, collectionName, fieldName);
 };
@@ -713,7 +979,7 @@ idToName = function(id, collectionName, fieldName) {
    fieldName = name of field within models of collection that will be displayed
 */
 
-idToOptions = function(selectedId, collectionName, fieldName) {
+idToOptions = function(selectedId, collectionName, fieldName, filterFunc) {
     result=""
     for (index in xos[collectionName].models) {
         linkedObject = xos[collectionName].models[index];
@@ -724,6 +990,9 @@ idToOptions = function(selectedId, collectionName, fieldName) {
         } else {
             selected = "";
         }
+        if ((filterFunc) && (!filterFunc(linkedObject))) {
+            continue;
+        }
         result = result + '<option value="' + linkedId + '"' + selected + '>' + linkedName + '</option>';
     }
     return result;
@@ -737,14 +1006,14 @@ idToOptions = function(selectedId, collectionName, fieldName) {
    fieldName = name of field within models of collection that will be displayed
 */
 
-idToSelect = function(variable, selectedId, collectionName, fieldName, readOnly) {
+idToSelect = function(variable, selectedId, collectionName, fieldName, readOnly, filterFunc) {
     if (readOnly) {
         readOnly = " readonly";
     } else {
         readOnly = "";
     }
-    result = '<select name="' + variable + '"' + readOnly + '>' +
-             idToOptions(selectedId, collectionName, fieldName) +
+    result = '<select name="' + variable + '" id="field_' + variable + '"' + readOnly + '>' +
+             idToOptions(selectedId, collectionName, fieldName, filterFunc) +
              '</select>';
     return result;
 }