progress bar on startup, and make sure stuff is loaded before we display it
diff --git a/planetstack/core/xoslib/dashboards/xosAdminDashboard.html b/planetstack/core/xoslib/dashboards/xosAdminDashboard.html
index d8e083a..78eb8e2 100644
--- a/planetstack/core/xoslib/dashboards/xosAdminDashboard.html
+++ b/planetstack/core/xoslib/dashboards/xosAdminDashboard.html
@@ -5,6 +5,7 @@
 <script src="{{ STATIC_URL }}/js/vendor/backbone.babysitter.js"></script>
 <script src="{{ STATIC_URL }}/js/vendor/backbone.marionette.js"></script>
 
+<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
 <link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminDashboard.css' %}" media="all" >
 <link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminSite.css' %}" media="all" >
 
diff --git a/planetstack/core/xoslib/dashboards/xosAdminWholePage.html b/planetstack/core/xoslib/dashboards/xosAdminWholePage.html
index ddcd683..da9f364 100644
--- a/planetstack/core/xoslib/dashboards/xosAdminWholePage.html
+++ b/planetstack/core/xoslib/dashboards/xosAdminWholePage.html
@@ -5,6 +5,7 @@
 <script src="{{ STATIC_URL }}/js/vendor/backbone.babysitter.js"></script>
 <script src="{{ STATIC_URL }}/js/vendor/backbone.marionette.js"></script>
 
+<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
 <link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminWholePage.css' %}" media="all" >
 <link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminSite.css' %}" media="all" >
 
diff --git a/planetstack/core/xoslib/static/css/xosAdminSite.css b/planetstack/core/xoslib/static/css/xosAdminSite.css
index f5942de..5ecaa8e 100644
--- a/planetstack/core/xoslib/static/css/xosAdminSite.css
+++ b/planetstack/core/xoslib/static/css/xosAdminSite.css
@@ -65,3 +65,20 @@
     display: none;
 }
 
+/* undo what planetstack.css does to the progressbar */
+#xos-startup-progress .ui-progressbar-value {
+    background-color: rgb(204,204,204) !important;
+    background-image: url(http://code.jquery.com/ui/1.11.2/themes/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png) !important;
+    border-top: 1px !important;
+    border-right: 1px !important;
+    border-left: 1px !important;
+}
+
+#xos-detail-button-box {
+    display: none;
+}
+
+#xos-listview-button-box {
+    display: none;
+}
+
diff --git a/planetstack/core/xoslib/static/js/xosAdminSite.js b/planetstack/core/xoslib/static/js/xosAdminSite.js
index 99cf851..212c1b4 100644
--- a/planetstack/core/xoslib/static/js/xosAdminSite.js
+++ b/planetstack/core/xoslib/static/js/xosAdminSite.js
@@ -134,6 +134,24 @@
     });

 };

 

+XOSAdminApp.startNavigation = function() {

+    Backbone.history.start();

+    XOSAdminApp.navigationStarted = true;

+}

+

+XOSAdminApp.collectionLoadChange = function() {

+    stats = xos.getCollectionStatus();

+

+    if (!XOSAdminApp.navigationStarted) {

+        if (stats["isLoaded"] + stats["failedLoad"] >= stats["startedLoad"]) {

+            XOSAdminApp.startNavigation();

+        } else {

+            $("#detail").html("<h3>Loading...</h3><div id='xos-startup-progress'></div>");

+            $("#xos-startup-progress").progressbar({value: stats["completedLoad"], max: stats["startedLoad"]});

+        }

+    }

+};

+

 XOSAdminApp.on("start", function() {

      XOSAdminApp.buildViews();
 
@@ -143,10 +161,11 @@
 
      XOSAdminApp.rewriteLinks();
 
-     if (Backbone.history) {
-         console.log("history start");
-         Backbone.history.start();
-     }
+     // fire it once to initially show the progress bar
+     XOSAdminApp.collectionLoadChange();
+
+     // fire it each time the collection load status is updated
+     Backbone.on("xoslib:collectionLoadChange", XOSAdminApp.collectionLoadChange);
 });
 
 $(document).ready(function(){
diff --git a/planetstack/core/xoslib/static/js/xoslib/xos-backbone.js b/planetstack/core/xoslib/static/js/xoslib/xos-backbone.js
index 75a3e45..36df6eb 100644
--- a/planetstack/core/xoslib/static/js/xoslib/xos-backbone.js
+++ b/planetstack/core/xoslib/static/js/xoslib/xos-backbone.js
@@ -78,6 +78,8 @@
 
         initialize: function(){
           this.isLoaded = false;
+          this.failedLoad = false;
+          this.startedLoad = false;
           this.sortVar = 'name';

           this.sortOrder = 'asc';

           this.on( "sort", this.sorted );

@@ -87,7 +89,7 @@
         foreignCollections: [],

 

         sorted: function() {

-            this.isLoaded = true;

+            //console.log("sorted " + this.modelName);

         },

 

         simpleComparator: function( model ){

@@ -113,6 +115,43 @@
             }

         },

 

+        fetchSuccess: function(collection, response, options) {

+            this.failedLoad = false;

+            if (!this.isLoaded) {

+                this.isLoaded = true;

+                Backbone.trigger("xoslib:collectionLoadChange", this);

+            }

+            if (options["orig_success"]) {

+                options["orig_success"](collection, response, options);

+            }

+        },

+

+        fetchFailure: function(collection, response, options) {

+            if ((!this.isLoaded) && (!this.failedLoad)) {

+                this.failedLoad=true;

+                Backbone.trigger("xoslib:collectionLoadChange", this);

+            }

+            if (options["orig_failure"]) {

+                options["orig_failure"](collection, response, options);

+            }

+        },

+

+        fetch: function(options) {

+            var self=this;

+            if (!this.startedLoad) {

+                this.startedLoad=true;

+                Backbone.trigger("xoslib:collectionLoadChange", this);

+            }

+            if (options == undefined) {

+                options = {};

+            }

+            options["orig_success"] = options["success"];

+            options["orig_failure"] = options["failure"];

+            options["success"] = function(collection, response, options) { self.fetchSuccess.call(self, collection, response, options); };

+            options["failure"] = this.fetchFailure;

+            Backbone.Collection.prototype.fetch.call(this, options);

+        },

+

         startPolling: function() {

             if (!this._polling) {

                 var collection=this;
@@ -229,10 +268,12 @@
         lib[collectionName] = new lib[collectionClassName]();
 
         lib.allCollectionNames.push(collectionName);
+        lib.allCollections.push(lib[collectionName]);
     };
 
     function xoslib() {
         this.allCollectionNames = [];
+        this.allCollections = [];
 
         define_model(this, {urlRoot: SLIVER_API,
                             relatedCollections: {"networkSlivers": "sliver"},
@@ -303,6 +344,24 @@
                             modelName: "slicePlus"});
 
         this.listObjects = function() { return this.allCollectionNames; };
+
+        this.getCollectionStatus = function() {
+            stats = {isLoaded: 0, failedLoad: 0, startedLoad: 0};
+            for (index in this.allCollections) {
+                collection = this.allCollections[index];
+                if (collection.isLoaded) {
+                    stats["isLoaded"] = stats["isLoaded"] + 1;
+                }
+                if (collection.failedLoad) {
+                    stats["failedLoad"] = stats["failedLoad"] + 1;
+                }
+                if (collection.startedLoad) {
+                    stats["startedLoad"] = stats["startedLoad"] + 1;
+                }
+            }
+            stats["completedLoad"] = stats["failedLoad"] + stats["isLoaded"];
+            return stats;
+        };
     };
 
     xos = new xoslib();
diff --git a/planetstack/core/xoslib/static/js/xoslib/xosHelper.js b/planetstack/core/xoslib/static/js/xoslib/xosHelper.js
index 0fc9496..b8e0347 100644
--- a/planetstack/core/xoslib/static/js/xoslib/xosHelper.js
+++ b/planetstack/core/xoslib/static/js/xoslib/xosHelper.js
@@ -138,7 +138,13 @@
     detailShower: function(detailName, collection_name, regionName, title) {

         var app=this;

         showModelId = function(model_id) {

-            showModel = function(model) {

+            $("#contentTitle").html(templateFromId("#xos-title-detail")({"title": title}));

+

+            collection = xos[collection_name];

+            model = collection.get(model_id);

+            if (model == undefined) {

+                app[regionName].show(new HTMLView({html: "failed to load object " + model_id + " from collection " + collection_name}));

+            } else {

                 detailViewClass = app[detailName];

                 detailView = new detailViewClass({model: model});

                 app[regionName].show(detailView);

@@ -146,33 +152,6 @@
                 $("#xos-detail-button-box").show();

                 $("#xos-listview-button-box").hide();

             }

-

-            $("#contentTitle").html(templateFromId("#xos-title-detail")({"title": title}));

-

-            collection = xos[collection_name];

-            model = collection.get(model_id);

-            if (model == undefined) {

-                if (!collection.isLoaded) {

-                    // If the model cannot be found, then maybe it's because

-                    // we haven't finished loading the collection yet. So wait for

-                    // the sort event to complete, then try again.

-                    collection.once("sort", function() {

-                        collection = xos[collection_name];

-                        model = collection.get(model_id);

-                        if (model == undefined) {

-                            // We tried. It's not here. Complain to the user.

-                            app[regionName].show(new HTMLView({html: "failed to load object " + model_id + " from collection " + collection_name}));

-                        } else {

-                            showModel(model);

-                        }

-                    });

-                } else {

-                    // The collection was loaded, the user must just be asking for something we don't have.

-                    app[regionName].show(new HTMLView({html: "failed to load object " + model_id + " from collection " + collection_name}));

-                }

-            } else {

-                showModel(model);

-            }

         }

         return showModelId;

     },