X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=planetstack%2Fcore%2Fxoslib%2Fstatic%2Fjs%2Fxoslib%2FxosHelper.js;h=6b6419c884d8a503653569ed8d03cc875e246d4a;hb=a1298a8aec652145ba249b6f8ccea96dcbb96b75;hp=2a1e94f89955f4dd9c1d74a0f09f1df7c27502e6;hpb=a6a4f91317a695011e17b6d2b22c189f02631ff9;p=plstackapi.git
diff --git a/planetstack/core/xoslib/static/js/xoslib/xosHelper.js b/planetstack/core/xoslib/static/js/xoslib/xosHelper.js
index 2a1e94f..6b6419c 100644
--- a/planetstack/core/xoslib/static/js/xoslib/xosHelper.js
+++ b/planetstack/core/xoslib/static/js/xoslib/xosHelper.js
@@ -4,6 +4,41 @@ HTMLView = Marionette.ItemView.extend({
},
});
+SliceSelectorOption = Marionette.ItemView.extend({
+ template: "#xos-sliceselector-option",
+ tagName: "option",
+ attributes: function() {
+ if (this.options.selectedID == this.model.get("id")) {
+ return { value: this.model.get("id"), selected: 1 };
+ } else {
+ return { value: this.model.get("id") };
+ }
+ },
+});
+
+SliceSelectorView = Marionette.CompositeView.extend({
+ template: "#xos-sliceselector-select",
+ childViewContainer: "select",
+ childView: SliceSelectorOption,
+ caption: "Slice",
+
+ events: {"change select": "onSliceChanged"},
+
+ childViewOptions: function() {
+ return { selectedID: this.options.selectedID || this.selectedID || null };
+ },
+
+ onSliceChanged: function() {
+ this.sliceChanged(this.$el.find("select").val());
+ },
+
+ sliceChanged: function(id) {
+ console.log("sliceChanged " + id);
+ },
+
+ templateHelpers: function() { return {caption: this.options.caption || this.caption }; },
+});
+
FilteredCompositeView = Marionette.CompositeView.extend( {
showCollection: function() {
var ChildView;
@@ -25,6 +60,7 @@ XOSRouter = Marionette.AppRouter.extend({
onRoute: function(x,y,z) {
this.routeStack.push(Backbone.history.fragment);
+ this.routeStack = this.routeStack.slice(-32); // limit the size of routeStack to something reasonable
},
prevPage: function() {
@@ -33,8 +69,8 @@ XOSRouter = Marionette.AppRouter.extend({
showPreviousURL: function() {
prevPage = this.prevPage();
- console.log("showPreviousURL");
- console.log(this.routeStack);
+ //console.log("showPreviousURL");
+ //console.log(this.routeStack);
if (prevPage) {
this.navigate("#"+prevPage, {trigger: false, replace: true} );
}
@@ -47,8 +83,25 @@ XOSRouter = Marionette.AppRouter.extend({
Marionette.AppRouter.prototype.navigate.call(this, href, options);
},
});
-
-
+
+// XXX - We import backbone multiple times (BAD!) since the import happens
+// inside of the view's html. The second time it's imported (developer
+// view), it wipes out Backbone.Syphon. So, save it as Backbone_Syphon for
+// now.
+Backbone_Syphon = Backbone.Syphon
+Backbone_Syphon.InputReaders.register('select', function(el) {
+ // Modify syphon so that if a select has "syphonall" in the class, then
+ // the value of every option will be returned, regardless of whether of
+ // not it is selected.
+ if (el.hasClass("syphonall")) {
+ result = [];
+ _.each(el.find("option"), function(option) {
+ result.push($(option).val());
+ });
+ return result;
+ }
+ return el.val();
+});
XOSApplication = Marionette.Application.extend({
detailBoxId: "#detailBox",
@@ -91,6 +144,8 @@ XOSApplication = Marionette.Application.extend({
parsed_error=undefined;
width=640; // django stacktraces like wide width
}
+ console.log(responseText);
+ console.log(parsed_error);
if (parsed_error) {
$("#xos-error-dialog").html(templateFromId("#xos-error-response")(parsed_error));
} else {
@@ -353,6 +408,8 @@ XOSApplication = Marionette.Application.extend({
that.destroyModel(model);
if (afterDelete=="list") {
that.navigate("list", modelName);
+ } else if (afterDelete) {
+ afterDelete();
}
});
},
@@ -380,7 +437,7 @@ XOSButtonView = Marionette.ItemView.extend({
},
submitDeleteClicked: function(e) {
- this.options.linkedView.submitDeleteClicked.call(this.options.linkedView, e);
+ this.options.linkedView.deleteClicked.call(this.options.linkedView, e);
},
addClicked: function(e) {
@@ -404,6 +461,8 @@ XOSListButtonView = XOSButtonView.extend({ template: "#xos-listbuttons-template"
XOSDetailView = Marionette.ItemView.extend({
tagName: "div",
+ viewInitializers: [],
+
events: {"click button.btn-xos-save-continue": "submitContinueClicked",
"click button.btn-xos-save-leave": "submitLeaveClicked",
"click button.btn-xos-save-another": "submitAddAnotherClicked",
@@ -416,15 +475,30 @@ XOSDetailView = Marionette.ItemView.extend({
*/
initialize: function() {
- this.on("saveSuccess", this.onAfterSave);
+ this.on("saveSuccess", this.onSaveSuccess);
this.synchronous = false;
},
+ onShow: function() {
+ _.each(this.viewInitializers, function(initializer) {
+ initializer();
+ });
+ },
+
+ saveSuccess: function(e) {
+ // always called after a save succeeds
+ },
+
afterSave: function(e) {
+ // if this.synchronous, then called after the save succeeds
+ // if !this.synchronous, then called after save is initiated
},
- onAfterSave: function(e) {
- this.afterSave(e);
+ onSaveSuccess: function(e) {
+ this.saveSuccess(e);
+ if (this.synchronous) {
+ this.afterSave(e);
+ }
},
inputChanged: function(e) {
@@ -441,6 +515,9 @@ XOSDetailView = Marionette.ItemView.extend({
submitLeaveClicked: function(e) {
console.log("saveLeave");
e.preventDefault();
+ if (this.options.noSubmitButton || this.noSubmitButton) {
+ return;
+ }
var that=this;
this.afterSave = function() {
that.app.navigate("list", that.model.modelName);
@@ -462,10 +539,12 @@ XOSDetailView = Marionette.ItemView.extend({
save: function() {
this.app.hideError();
- var data = Backbone.Syphon.serialize(this);
+ var data = Backbone_Syphon.serialize(this);
var that = this;
var isNew = !this.model.id;
+ console.log(data);
+
this.$el.find(".help-inline").remove();
/* although model.validate() is called automatically by
@@ -479,19 +558,17 @@ XOSDetailView = Marionette.ItemView.extend({
}
if (isNew) {
- this.model.attributes.humanReadableName = "new " + model.modelName;
+ this.model.attributes.humanReadableName = "new " + this.model.modelName;
this.model.addToCollection = this.collection;
} else {
this.model.addToCollection = undefined;
}
- var infoMsgId = this.app.showInformational( {what: "save " + model.modelName + " " + model.attributes.humanReadableName, status: "", statusText: "in progress..."} );
+ var infoMsgId = this.app.showInformational( {what: "save " + this.model.modelName + " " + this.model.attributes.humanReadableName, status: "", statusText: "in progress..."} );
this.model.save(data, {error: function(model, result, xhr) { that.app.saveError(model,result,xhr,infoMsgId);},
success: function(model, result, xhr) { that.app.saveSuccess(model,result,xhr,infoMsgId);
- if (that.synchronous) {
- that.trigger("saveSuccess");
- }
+ that.trigger("saveSuccess");
}});
this.dirty = false;
@@ -574,7 +651,6 @@ XOSDetailView = Marionette.ItemView.extend({
onFormDataInvalid: function(errors) {
var self=this;
var markErrors = function(value, key) {
- console.log("name='" + key + "'");
var $inputElement = self.$el.find("[name='" + key + "']");
var $inputContainer = $inputElement.parent();
//$inputContainer.find(".help-inline").remove();
@@ -588,13 +664,75 @@ XOSDetailView = Marionette.ItemView.extend({
collectionName: this.model.collectionName,
addFields: this.model.addFields,
listFields: this.model.listFields,
- detailFields: this.model.detailFields,
+ detailFields: this.options.detailFields || this.detailFields || this.model.detailFields,
+ fieldDisplayNames: this.options.fieldDisplayNames || this.fieldDisplayNames || this.model.fieldDisplayNames || {},
foreignFields: this.model.foreignFields,
detailLinkFields: this.model.detailLinkFields,
inputType: this.model.inputType,
model: this.model,
+ detailView: this,
+ choices: this.options.choices || this.choices || this.model.choices || {},
}},
+});
+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
@@ -744,33 +882,47 @@ XOSDataTableView = Marionette.View.extend( {
render: function() {
var view = this;
+ var fieldDisplayNames = view.options.fieldDisplayNames || view.fieldDisplayNames || {};
view.columnsByIndex = [];
view.columnsByFieldName = {};
_.each(this.collection.listFields, function(fieldName) {
+ inputType = view.options.inputType || view.inputType || {};
mRender = undefined;
mSearchText = undefined;
- if (fieldName in view.collection.foreignFields) {
+ sTitle = fieldName in fieldDisplayNames ? fieldDisplayNames[fieldName] : 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"); };
+ } else if (inputType[fieldName] == "spinner") {
+ mRender = function(x,y,z) { return xosDataTableSpinnerTemplate( {value: x, collectionName: view.collection.collectionName, fieldName: fieldName, id: z.id, app: view.app} ); };
}
if ($.inArray(fieldName, view.collection.detailLinkFields)>=0) {
var collectionName = view.collection.collectionName;
mRender = function(x,y,z) { return '' + x + ''; };
}
- thisColumn = {sTitle: fieldNameToHumanReadable(fieldName), mData: fieldName, mRender: mRender, mSearchText: mSearchText};
+ thisColumn = {sTitle: sTitle, bSortable: bSortable, mData: fieldName, mRender: mRender, mSearchText: mSearchText};
view.columnsByIndex.push( thisColumn );
view.columnsByFieldName[fieldName] = thisColumn;
});
- deleteColumn = {sTitle: "delete", 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;
+ if (!view.noDeleteColumn) {
+ 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,
+ "bFilter": ! (view.options.disableFilter || view.disableFilter),
+ "bPaginate": ! (view.options.disablePaginate || view.disablePaginate),
"aoColumns": view.columnsByIndex,
fnServerData: function(sSource, aoData, fnCallback, settings) {
@@ -806,7 +958,7 @@ XOSDataTableView = Marionette.View.extend( {
// content of the collection
var populateTable = function()
{
- console.log("populatetable!");
+ //console.log("populatetable!");
// clear out old row views
rows = [];
@@ -863,7 +1015,9 @@ XOSDataTableView = Marionette.View.extend( {
aaData.sort(function(a,b) { return compareColumns(sortCols, sortDirs, a, b); });
// slice it for pagination
- aaData = aaData.slice(iDisplayStart, iDisplayStart+iDisplayLength);
+ if (iDisplayLength >= 0) {
+ aaData = aaData.slice(iDisplayStart, iDisplayStart+iDisplayLength);
+ }
return fnCallback({iTotalRecords: totalSize,
iTotalDisplayRecords: filteredSize,
@@ -907,6 +1061,10 @@ idToName = function(id, collectionName, fieldName) {
return xos.idToName(id, collectionName, fieldName);
};
+makeIdToName = function(collectionName, fieldName) {
+ return function(id) { return idToName(id, collectionName, fieldName); }
+};
+
/* Constructs lists of ';
}
return result;
@@ -938,15 +1099,37 @@ 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 = '