1 function assert(outcome, description) {
3 console.log(description);
7 HTMLView = Marionette.ItemView.extend({
9 this.$el.append(this.options.html);
13 XOSApplication = Marionette.Application.extend({
14 detailBoxId: "#detailBox",
15 errorBoxId: "#errorBox",
16 errorCloseButtonId: "#close-error-box",
17 successBoxId: "#successBox",
18 successCloseButtonId: "#close-success-box",
19 errorTemplate: "#xos-error-template",
20 successTemplate: "#xos-success-template",
23 hideError: function() {
24 if (this.logWindowId) {
26 $(this.errorBoxId).hide();
27 $(this.successBoxId).hide();
31 showSuccess: function(result) {
32 if (this.logTableId) {
33 result["success"] = "success";
34 this.appendLogWindow(result);
36 $(this.successBoxId).show();
37 $(this.successBoxId).html(_.template($(this.successTemplate).html())(result));
38 $(this.successCloseButtonId).unbind().bind('click', function() {
39 $(this.successBoxId).hide();
44 showError: function(result) {
45 if (this.logTableId) {
46 result["success"] = "failure";
47 this.appendLogWindow(result);
49 $(this.errorBoxId).show();
50 $(this.errorBoxId).html(_.template($(this.errorTemplate).html())(result));
51 $(this.errorCloseButtonId).unbind().bind('click', function() {
52 $(this.errorBoxId).hide();
57 showInformational: function(result) {
58 if (this.logTableId) {
59 result["success"] = "information";
60 return this.appendLogWindow(result);
66 appendLogWindow: function(result) {
67 // compute a new logMessageId for this log message
68 logMessageId = "logMessage" + this.logMessageCount;
69 this.logMessageCount = this.logMessageCount + 1;
70 result["logMessageId"] = logMessageId;
72 logMessageTemplate=$("#xos-log-template").html();
73 assert(logMessageTemplate != undefined, "logMessageTemplate is undefined");
74 newRow = _.template(logMessageTemplate, result);
75 assert(newRow != undefined, "newRow is undefined");
77 if (result["infoMsgId"] != undefined) {
78 // We were passed the logMessageId of an informational message,
79 // and the caller wants us to replace that message with our own.
80 // i.e. replace an informational message with a success or an error.
81 console.log(result["infoMsgId"]);
82 console.log($("."+result["infoMsgId"]));
83 $("#"+result["infoMsgId"]).replaceWith(newRow);
85 // Create a brand new log message rather than replacing one.
86 logTableBody = $(this.logTableId + " tbody");
87 logTableBody.prepend(newRow);
92 hideLinkedItems: function(result) {
95 this["linkedObjs" + (index+1)].empty();
\r
100 listViewShower: function(listViewName, regionName) {
\r
102 return function() {
\r
103 app[regionName].show(new app[listViewName]);
\r
104 app.hideLinkedItems();
\r
108 detailShower: function(detailName, collection_name, regionName) {
\r
110 showModelId = function(model_id) {
\r
111 showModel = function(model) {
\r
113 detailViewClass = app[detailName];
\r
114 detailView = new detailViewClass({model: model});
\r
115 app[regionName].show(detailView);
\r
116 detailView.showLinkedItems();
\r
119 collection = xos[collection_name];
\r
120 model = collection.get(model_id);
\r
121 if (model == undefined) {
\r
122 if (!collection.isLoaded) {
\r
123 // If the model cannot be found, then maybe it's because
\r
124 // we haven't finished loading the collection yet. So wait for
\r
125 // the sort event to complete, then try again.
\r
126 collection.once("sort", function() {
\r
127 collection = xos[collection_name];
\r
128 model = collection.get(model_id);
\r
129 if (model == undefined) {
\r
130 // We tried. It's not here. Complain to the user.
\r
131 app[regionName].show(new HTMLView({html: "failed to load object " + model_id + " from collection " + collection_name}));
\r
137 // The collection was loaded, the user must just be asking for something we don't have.
\r
138 app[regionName].show(new HTMLView({html: "failed to load object " + model_id + " from collection " + collection_name}));
\r
144 return showModelId;
\r
150 app - MarionetteApplication
151 template - template (See XOSHelper.html)
154 XOSDetailView = Marionette.ItemView.extend({
157 events: {"click button.js-submit": "submitClicked",
158 "change input": "inputChanged"},
160 events: {"click button.js-submit": "submitClicked",
161 "change input": "inputChanged"},
163 /* inputChanged is watching the onChange events of the input controls. We
164 do this to track when this view is 'dirty', so we can throw up a warning
\r
165 if the user tries to change his slices without saving first.
\r
168 inputChanged: function(e) {
\r
172 saveError: function(model, result, xhr, infoMsgId) {
\r
173 result["what"] = "save " + model.__proto__.modelName;
\r
174 result["infoMsgId"] = infoMsgId;
\r
175 this.app.showError(result);
\r
178 saveSuccess: function(model, result, xhr, infoMsgId) {
\r
179 result = {status: xhr.xhr.status, statusText: xhr.xhr.statusText};
\r
180 result["what"] = "save " + model.__proto__.modelName;
\r
181 result["infoMsgId"] = infoMsgId;
\r
182 this.app.showSuccess(result);
\r
185 submitClicked: function(e) {
186 this.app.hideError();
\r
187 e.preventDefault();
\r
188 var infoMsgId = this.app.showInformational( {what: "save " + this.model.__proto__.modelName, status: "", statusText: "in progress..."} );
\r
189 var data = Backbone.Syphon.serialize(this);
\r
191 this.model.save(data, {error: function(model, result, xhr) { that.saveError(model,result,xhr,infoMsgId);},
\r
192 success: function(model, result, xhr) { that.saveSuccess(model,result,xhr,infoMsgId);}});
\r
193 this.dirty = false;
\r
196 showLinkedItems: function() {
198 for (relatedName in this.model.collection.relatedCollections) {
\r
199 relatedField = this.model.collection.relatedCollections[relatedName];
\r
201 relatedListViewClassName = relatedName + "ListView";
\r
202 if (this.app[relatedListViewClassName] == undefined) {
\r
203 console.log("warning: " + relatedListViewClassName + " not found");
\r
205 relatedListViewClass = this.app[relatedListViewClassName].extend({collection: xos[relatedName].filterBy(relatedField,this.model.id)});
\r
206 this.app["linkedObjs" + (index+1)].show(new relatedListViewClass());
\r
211 this.app["linkedObjs" + (index+1)].empty();
\r
218 This is for items that will be displayed as table rows.
220 app - MarionetteApplication
221 template - template (See XOSHelper.html)
222 detailClass - class of detail view, probably an XOSDetailView
225 XOSItemView = Marionette.ItemView.extend({
227 className: 'test-tablerow',
229 events: {"click": "changeItem"},
231 changeItem: function(e) {
\r
232 this.app.hideError();
\r
233 e.preventDefault();
\r
234 e.stopPropagation();
\r
236 this.app.navigateToModel(this.app, this.detailClass, this.detailNavLink, this.model);
\r
242 app - MarionetteApplication
243 childView - class of ItemView, probably an XOSItemView
244 template - template (see xosHelper.html)
245 collection - collection that holds these objects
246 title - title to display in template
249 XOSListView = Marionette.CompositeView.extend({
250 childViewContainer: 'tbody',
\r
252 initialize: function() {
\r
253 this.listenTo(this.collection, 'change', this._renderChildren)
255 // Because many of the templates use idToName(), we need to
256 // listen to the collections that hold the names for the ids
257 // that we want to display.
258 for (i in this.collection.foreignCollections) {
259 foreignName = this.collection.foreignCollections[i];
260 if (xos[foreignName] == undefined) {
261 console.log("Failed to find xos class " + foreignName);
263 this.listenTo(xos[foreignName], 'change', this._renderChildren);
264 this.listenTo(xos[foreignName], 'sort', this._renderChildren);
268 templateHelpers: function() {
269 return { title: this.title };
273 /* Give an id, the name of a collection, and the name of a field for models
274 within that collection, lookup the id and return the value of the field.
277 idToName = function(id, collectionName, fieldName) {
278 linkedObject = xos[collectionName].get(id);
279 if (linkedObject == undefined) {
282 return linkedObject.attributes[fieldName];
286 /* Constructs lists of <option> html blocks for items in a collection.
288 selectedId = the id of an object that should be selected, if any
289 collectionName = name of collection
290 fieldName = name of field within models of collection that will be displayed
293 idToOptions = function(selectedId, collectionName, fieldName) {
295 for (index in xos[collectionName].models) {
296 linkedObject = xos[collectionName].models[index];
297 linkedId = linkedObject["id"];
298 linkedName = linkedObject.attributes[fieldName];
299 if (linkedId == selectedId) {
300 selected = " selected";
304 result = result + '<option value="' + linkedId + '"' + selected + '>' + linkedName + '</option>';
309 /* Constructs an html <select> and the <option>s to go with it.
311 variable = variable name to return to form
312 selectedId = the id of an object that should be selected, if any
313 collectionName = name of collection
314 fieldName = name of field within models of collection that will be displayed
317 idToSelect = function(variable, selectedId, collectionName, fieldName) {
318 result = '<select name="' + variable + '">' +
319 idToOptions(selectedId, collectionName, fieldName) +