browser staff: more printing and storage
authorBill Erickson <berick@esilibrary.com>
Wed, 16 Apr 2014 18:57:47 +0000 (14:57 -0400)
committerBill Erickson <berick@esilibrary.com>
Wed, 16 Apr 2014 18:57:47 +0000 (14:57 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/web/js/ui/default/staff/services/printstore.js

index 034c39e..2b2ede6 100644 (file)
@@ -1,11 +1,24 @@
 /**
- * Core Service - egPrint
+ * Core Service - egPrintStore
+ *
+ * Dispatches print and data storage requests to the appropriate handler.
+ *
+ * With each request, if a connection to Hatch is established, the
+ * request is relayed.  If a connection has not been attempted, an
+ * attempt is made then the request is handled.  If Hatch is known to be
+ * inaccessible, requests are routed to local handlers.
+ *
+ * Printing is handled locally with an egPrintContainer whose contents
+ * are made visible during printing using CSS print media.
+ *
+ * Storage requests are handled by $window.localStorage.
+ *
+ * Note that all requests return promises, since any request may be
+ * subject to aschronous processing by Hatch.
  *
  */
-
 angular.module('egCoreMod')
 
-
 .factory('egPrintStore', 
            ['$q','$window','$timeout', 
     function($q , $window , $timeout) {
@@ -17,6 +30,8 @@ angular.module('egCoreMod')
     service.socket = null;
     service.hatchAvailable = null;
     service.hatchURL = 'wss://localhost:8443/hatch'; 
+    service.hatchRequired = false;
+    // TODO: would be nice to support local fall-through for specific actions
 
     // write a message to the Hatch websocket
     service.sendToHatch = function(msg) {
@@ -59,25 +74,18 @@ angular.module('egCoreMod')
     // it from our tracked requests.
     service.resolveRequest = function(msg) {
 
-        var srcMsg = service.messages[msg.msgid];
-        if (!srcMsg) {
-            console.log(
-                "egPrintStore found no source message for response " + 
-                msg.msgid
-            );
-            return;
-        }
-
-        // remove the source message
-        delete service.messages[msg.msgid];
+        // for requests sent through Hatch, only the cached 
+        // request will have the original promise attached
+        msg.deferred = service.messages[msg.msgid].deferred;
+        delete service.messages[msg.msgid]; // un-cache
 
         // resolve / reject
         if (msg.success) {
             console.debug("command succeeded : " + msg.success);
-            srcMsg.deferred.resolve(msg.success);
+            msg.deferred.resolve(msg.success);
         } else {
             console.error("command failed : " + msg.error);
-            srcMsg.deferred.reject(msg.error);
+            msg.deferred.reject(msg.error);
         }
     }
 
@@ -85,19 +93,31 @@ angular.module('egCoreMod')
     service.handleRequestsLocally = function() {
         service.socket = null;
         service.hatchAvailable = false;
-        angular.forEach(service.pending, function(msg) {
+
+        while ( (msg = service.pending.shift()) ) {
+
+            if (service.hatchRequired) {
+                throw new Error(
+                    "egPrintStore : attempt to perform '" + msg.action + 
+                    "' operation failed because no connection to Hatch could be " +
+                    "established and egPrintStore.hatchRequired is set to TRUE"
+                );
+            }
+
             switch(msg.action) {
                 case 'print':
-                    return service.browserPrint(msg);
+                    service.browserPrint(msg);
+                    break;
                 case 'keys':
                 case 'get':
                 case 'set':
                 case 'append':
                 case 'remove':
-                    return service.handleLocalStorageRequest(msg);
+                    service.handleLocalStorageRequest(msg);
+                    break;
             }
             service.resolveRequest(msg); 
-        });
+        }
     }
 
     service.hatchConnect = function() {
@@ -136,6 +156,7 @@ angular.module('egCoreMod')
         }
 
         service.socket.onerror = function() {
+            if (service.hatchAvailable === false) return; // already registered
             console.debug(
                 "unable to connect to Hatch server at " + service.hatchURL);
             service.handleRequestsLocally();
@@ -157,12 +178,15 @@ angular.module('egCoreMod')
         }
     }
 
+    // print locally via the browser
     service.browserPrint = function(msg) {
         // let our local print container handle printing
         service.onBrowserPrint(msg.contentType, msg.content);
         msg.success = true; // assume browser print succeeded
     }
 
+    // print the provided content
+    // supported values for contentType are 'text/html' and 'text/plain'
     service.print = function(contentType, content) {
         if (service.hatchAvailable === false) {
             service.browserPrint(contentType, content);
@@ -178,52 +202,71 @@ angular.module('egCoreMod')
         });
     }
 
+    // get the value for a stored item
     service.getItem = function(key) {
+        return service.dispatchRequest({key : key, action : 'get'});
     }
 
+    // set the value for a stored or new item
     service.setItem = function(key, value) {
-        if (key === null || value === null) {
-            logger.warn("invalid key or value in egPrintStore.setItem()");
-            return $q.reject();
-        }
-        return service.dispatchRequest({
-            key : key,
-            value : value,
-            action : 'set',
-        });
+        return service.dispatchRequest(
+            {key : key, value : value, action : 'set'});
+    }
+
+    // appends the value to the existing item stored at key.
+    // If not item is found at key, this behaves just like setItem()
+    service.appendItem = function(key, value) {
+        return service.dispatchRequest(
+            {key : key, value : value, action : 'append'});
     }
 
-    service.removeItem = function() {
+    // remove a stored item
+    service.removeItem = function(key) {
+        return service.dispatchRequest({key : key, action : 'remove'});
     }
 
     // if set, prefix limits the return set to keys starting with 'prefix'
     service.getKeys = function(prefix) {
-        return service.dispatchRequest({
-            key : prefix,
-            action : 'keys',
-        });
+        return service.dispatchRequest({key : prefix, action : 'keys'});
     }
 
     // get, set, remove, append, keys : via $window.localStorage
     service.handleLocalStorageRequest = function(msg) {
+        console.log('service.handleLocalStorageRequest() ' + msg.action);
+        var key = msg.key;
+        var value = msg.value;
         switch(msg.action) {
             case 'keys':
                 var keys = [];
                 var idx = 0;
-                while (true) {
-                    var key = $window.localStorage.keys(idx);
-                    if (key === null) break;
-                    keys.push(key);
+                while ( (k = $window.localStorage.key(idx++)) !== null) {
+                    // key prefix match test
+                    if (key && k.substr(0, key.length) != key) continue; 
+                    keys.push(k);
                 }
                 msg.success = keys;
                 break;
 
             case 'set':
-                $window.localStorage.setItem(msg.key, msg.value);
+                $window.localStorage.setItem(key, value);
                 msg.success = true;
                 break;
 
-            // ...
+            case 'get':
+                msg.success = $window.localStorage.getItem(msg.key);
+                break;
+
+            case 'remove':
+                $window.localStorage.removeItem(msg.key);
+                msg.success = true;
+                break;
+
+            case 'append':
+                var item = $window.localStorage.getItem(key);
+                if (item) value = item + value;
+                $window.localStorage.setItem(key, value);
+                msg.success = value;
+                break;
         }
     }