move some code around
diff --git a/planetstack/core/xoslib/static/js/xoslib/xosHelper.js b/planetstack/core/xoslib/static/js/xoslib/xosHelper.js
index 28f85fd..d9e23a6 100644
--- a/planetstack/core/xoslib/static/js/xoslib/xosHelper.js
+++ b/planetstack/core/xoslib/static/js/xoslib/xosHelper.js
@@ -28,14 +28,19 @@
     successTemplate: "#xos-success-template",
     logMessageCount: 0,
 
-    confirmDialog: function(view, event) {
+    confirmDialog: function(view, event, callback) {
         $("#xos-confirm-dialog").dialog({
            autoOpen: false,

            modal: true,

            buttons : {

                 "Confirm" : function() {

                   $(this).dialog("close");

-                  view.trigger(event);

+                  if (event) {

+                      view.trigger(event);

+                  }

+                  if (callback) {

+                      callback();

+                  }

                 },

                 "Cancel" : function() {

                   $(this).dialog("close");

@@ -45,28 +50,6 @@
         $("#xos-confirm-dialog").dialog("open");
     },
 
-    hideError: function() {
-        if (this.logWindowId) {
-        } else {
-            $(this.errorBoxId).hide();
-            $(this.successBoxId).hide();
-        }
-    },
-
-    showSuccess: function(result) {
-         result["statusclass"] = "success";
-         if (this.logTableId) {
-             this.appendLogWindow(result);
-         } else {
-             $(this.successBoxId).show();
-             $(this.successBoxId).html(_.template($(this.successTemplate).html())(result));
-             var that=this;
-             $(this.successCloseButtonId).unbind().bind('click', function() {
-                 $(that.successBoxId).hide();
-             });
-         }
-    },
-
     popupErrorDialog: function(responseText) {
         try {
             parsed_error=$.parseJSON(responseText);
@@ -77,7 +60,7 @@
             width=640;    // django stacktraces like wide width
         }
         if (parsed_error) {
-            $("#xos-error-dialog").html(templateFromId("#xos-error-response")(json));
+            $("#xos-error-dialog").html(templateFromId("#xos-error-response")(parsed_error));
         } else {
             $("#xos-error-dialog").html(templateFromId("#xos-error-rawresponse")({responseText: responseText}))
         }
@@ -91,62 +74,6 @@
         });
     },
 
-    showError: function(result) {
-         result["statusclass"] = "failure";
-         if (this.logTableId) {
-             this.appendLogWindow(result);
-             this.popupErrorDialog(result.responseText);
-         } else {
-             // this is really old stuff
-             $(this.errorBoxId).show();
-             $(this.errorBoxId).html(_.template($(this.errorTemplate).html())(result));
-             var that=this;
-             $(this.errorCloseButtonId).unbind().bind('click', function() {
-                 $(that.errorBoxId).hide();
-             });
-         }
-    },
-
-    showInformational: function(result) {
-         result["statusclass"] = "inprog";
-         if (this.logTableId) {
-             return this.appendLogWindow(result);
-         } else {
-             return undefined;
-         }
-    },
-
-    appendLogWindow: function(result) {
-        // compute a new logMessageId for this log message
-        logMessageId = "logMessage" + this.logMessageCount;
-        this.logMessageCount = this.logMessageCount + 1;
-        result["logMessageId"] = logMessageId;
-
-        logMessageTemplate=$("#xos-log-template").html();
-        assert(logMessageTemplate != undefined, "logMessageTemplate is undefined");
-        newRow = _.template(logMessageTemplate, result);
-        assert(newRow != undefined, "newRow is undefined");
-
-        if (result["infoMsgId"] != undefined) {
-            // We were passed the logMessageId of an informational message,
-            // and the caller wants us to replace that message with our own.
-            // i.e. replace an informational message with a success or an error.
-            $("#"+result["infoMsgId"]).replaceWith(newRow);
-        } else {
-            // Create a brand new log message rather than replacing one.
-            logTableBody = $(this.logTableId + " tbody");
-            logTableBody.prepend(newRow);
-        }
-
-        if (this.statusMsgId) {
-            $(this.statusMsgId).html( templateFromId("#xos-status-template")(result) );
-        }
-
-        limitTableRows(this.logTableId, 5);
-
-        return logMessageId;
-    },
-
     hideLinkedItems: function(result) {
         var index=0;
         while (index<4) {

@@ -200,8 +127,142 @@
         }

         return showModelId;

     },

-});
+

+    /* error handling callbacks */

+

+    hideError: function() {

+        if (this.logWindowId) {
+        } else {
+            $(this.errorBoxId).hide();
+            $(this.successBoxId).hide();
+        }
+    },
 
+    showSuccess: function(result) {
+         result["statusclass"] = "success";
+         if (this.logTableId) {
+             this.appendLogWindow(result);
+         } else {
+             $(this.successBoxId).show();
+             $(this.successBoxId).html(_.template($(this.successTemplate).html())(result));
+             var that=this;
+             $(this.successCloseButtonId).unbind().bind('click', function() {
+                 $(that.successBoxId).hide();
+             });
+         }
+    },

+

+    showError: function(result) {

+         result["statusclass"] = "failure";
+         if (this.logTableId) {
+             this.appendLogWindow(result);
+             this.popupErrorDialog(result.responseText);
+         } else {
+             // this is really old stuff
+             $(this.errorBoxId).show();
+             $(this.errorBoxId).html(_.template($(this.errorTemplate).html())(result));
+             var that=this;
+             $(this.errorCloseButtonId).unbind().bind('click', function() {
+                 $(that.errorBoxId).hide();
+             });
+         }
+    },

+

+    showInformational: function(result) {

+         result["statusclass"] = "inprog";
+         if (this.logTableId) {
+             return this.appendLogWindow(result);
+         } else {
+             return undefined;
+         }
+    },
+
+    appendLogWindow: function(result) {
+        // compute a new logMessageId for this log message
+        logMessageId = "logMessage" + this.logMessageCount;
+        this.logMessageCount = this.logMessageCount + 1;
+        result["logMessageId"] = logMessageId;
+
+        logMessageTemplate=$("#xos-log-template").html();
+        assert(logMessageTemplate != undefined, "logMessageTemplate is undefined");
+        newRow = _.template(logMessageTemplate, result);
+        assert(newRow != undefined, "newRow is undefined");
+
+        if (result["infoMsgId"] != undefined) {
+            // We were passed the logMessageId of an informational message,
+            // and the caller wants us to replace that message with our own.
+            // i.e. replace an informational message with a success or an error.
+            $("#"+result["infoMsgId"]).replaceWith(newRow);
+        } else {
+            // Create a brand new log message rather than replacing one.
+            logTableBody = $(this.logTableId + " tbody");
+            logTableBody.prepend(newRow);
+        }
+
+        if (this.statusMsgId) {
+            $(this.statusMsgId).html( templateFromId("#xos-status-template")(result) );
+        }
+
+        limitTableRows(this.logTableId, 5);
+
+        return logMessageId;
+    },

+

+    saveError: function(model, result, xhr, infoMsgId) {

+        console.log("saveError");

+        result["what"] = "save " + model.modelName + " " + model.attributes.humanReadableName;

+        result["infoMsgId"] = infoMsgId;

+        this.showError(result);

+    },

+

+    saveSuccess: function(model, result, xhr, infoMsgId, addToCollection) {

+        console.log("saveSuccess");

+        if (addToCollection) {

+            addToCollection.add(model);

+            addToCollection.sort();

+        }

+        result = {status: xhr.xhr.status, statusText: xhr.xhr.statusText};

+        result["what"] = "save " + model.modelName + " " + model.attributes.humanReadableName;

+        result["infoMsgId"] = infoMsgId;

+        this.showSuccess(result);

+    },
+
+    destroyError: function(model, result, xhr, infoMsgId) {
+        result["what"] = "destroy " + model.modelName + " " + model.attributes.humanReadableName;

+        result["infoMsgId"] = infoMsgId;

+        this.showError(result);

+    },

+

+    destroySuccess: function(model, result, xhr, infoMsgId) {

+        result = {status: xhr.xhr.status, statusText: xhr.xhr.statusText};

+        result["what"] = "destroy " + model.modelName + " " + model.attributes.humanReadableName;

+        result["infoMsgId"] = infoMsgId;

+        this.showSuccess(result);

+    },

+

+    /* end error handling callbacks */

+

+    destroyModel: function(model) {

+         this.hideError();
+         var infoMsgId = this.showInformational( {what: "destroy " + model.modelName + " " + model.attributes.humanReadableName, status: "", statusText: "in progress..."} );
+         var that = this;
+         model.destroy({error: function(model, result, xhr) { that.destroyError(model,result,xhr,infoMsgId);},
+                        success: function(model, result, xhr) { that.destroySuccess(model,result,xhr,infoMsgId);}});
+    },
+
+    deleteDialog: function(model, navToListAfterDelete) {
+        var that=this;
+        this.confirmDialog(this, callback=function() {
+            modelName = model.modelName;
+            that.destroyModel(model);
+            if (navToListAfterDelete) {
+                that.navigate("list", modelName);
+            }
+
+        });
+    },
+});
+

 /* XOSDetailView
       extend with:
          app - MarionetteApplication
@@ -230,39 +291,7 @@
                 this.dirty = true;

             },

 

-            saveError: function(model, result, xhr, infoMsgId) {

-                console.log("saveError");

-                result["what"] = "save " + model.modelName + " " + model.attributes.humanReadableName;

-                result["infoMsgId"] = infoMsgId;

-                this.app.showError(result);

-            },

-

-            saveSuccess: function(model, result, xhr, infoMsgId, isNew) {

-                console.log("saveSuccess");

-                if (isNew) {

-                    this.collection.add(model);

-                    this.collection.sort();

-                }

-                result = {status: xhr.xhr.status, statusText: xhr.xhr.statusText};

-                result["what"] = "save " + model.modelName + " " + model.attributes.humanReadableName;

-                result["infoMsgId"] = infoMsgId;

-                this.app.showSuccess(result);

-            },
-
-            destroyError: function(model, result, xhr, infoMsgId) {
-                result["what"] = "destroy " + model.modelName + " " + model.attributes.humanReadableName;

-                result["infoMsgId"] = infoMsgId;

-                this.app.showError(result);

-            },

-

-            destroySuccess: function(model, result, xhr, infoMsgId) {

-                result = {status: xhr.xhr.status, statusText: xhr.xhr.statusText};

-                result["what"] = "destroy " + model.modelName + " " + model.attributes.humanReadableName;

-                result["infoMsgId"] = infoMsgId;

-                this.app.showSuccess(result);

-            },
-
-            submitContinueClicked: function(e) {
+            submitContinueClicked: function(e) {

                 console.log("saveContinue");
                 e.preventDefault();
                 this.save();
@@ -302,16 +331,15 @@
 

                 if (isNew) {

                     this.model.attributes.humanReadableName = "new " + 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..."} );

 

-                this.model.save(data, {error: function(model, result, xhr) { that.saveError(model,result,xhr,infoMsgId);},

-                                       success: function(model, result, xhr) { that.saveSuccess(model,result,xhr,infoMsgId, isNew);}});

-                /*if (isNew) {

-                    this.collection.add(this.model);

-                    this.collection.sort();

-                }*/

+                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);}});

                 this.dirty = false;

             },
 
@@ -319,8 +347,8 @@
                  this.app.hideError();
                  var infoMsgId = this.app.showInformational( {what: "destroy " + model.modelName + " " + model.attributes.humanReadableName, status: "", statusText: "in progress..."} );
                  var that = this;
-                 this.model.destroy({error: function(model, result, xhr) { that.destroyError(model,result,xhr,infoMsgId);},
-                                     success: function(model, result, xhr) { that.destroySuccess(model,result,xhr,infoMsgId);}});
+                 this.model.destroy({error: function(model, result, xhr) { that.app.destroyError(model,result,xhr,infoMsgId);},
+                                     success: function(model, result, xhr) { that.app.destroySuccess(model,result,xhr,infoMsgId);}});
             },
 
              deleteClicked: function(e) {