Bugfixes for browser history management. Documentation.
authorNiels Erik G. Nielsen <nielserik@indexdata.com>
Wed, 15 May 2013 16:45:14 +0000 (12:45 -0400)
committerNiels Erik G. Nielsen <nielserik@indexdata.com>
Wed, 15 May 2013 16:45:14 +0000 (12:45 -0400)
src/META-INF/resources/pz2utils/listeners.js
src/META-INF/resources/pz2utils/pz2watch.xhtml
src/main/java/com/indexdata/mkjsf/pazpar2/Pz2Bean.java
src/main/java/com/indexdata/mkjsf/pazpar2/data/RecordResponse.java
src/main/java/com/indexdata/mkjsf/pazpar2/state/StateManager.java

index 056723e..3bbfa2b 100644 (file)
@@ -46,24 +46,35 @@ function renderOnRecordTargets(doRefresh) {
   }\r
 }\r
 \r
-// Listens for browser initiated changes to 'window.location.hash' and sends the\r
-// hash\r
-// changes to the back-end (to have the back-end pull up a previous Pazpar2\r
-// state)\r
+// Listens for browser initiated changes to 'window.location.hash' and sends \r
+// the hash key changes to the back-end, to have the back-end pull up a previous \r
+// Pazpar2 state.\r
+// \r
+// See also: The field in pz2watch.xhtml, the StateListener function below,\r
+// the method Pz2Bean.handleQueryStateChanges(), and the classes \r
+// Pazpar2State and StateManager for a complete picture of browser history \r
+// handling.\r
 function windowlocationhashListener() {\r
   if (trackHistory) {\r
-    // console.log("browser hash update detected");\r
+    \r
     var stateKey = document.getElementById("pz2watch:windowlocationhash");\r
-    if (window.location.hash != stateKey.value) {\r
-      // console.log("updating stateKey with new browser hash: " +\r
-      // window.location.hash);\r
-      stateKey.value = window.location.hash;\r
-      if (!stateKey.value)\r
-        window.location.hash = '#1';\r
-      stateKey.onchange();\r
+    // console.log("browser hash update response detected.");\r
+    // console.log("pz2watch:windowlocationhash: [" + stateKey.value + "]");\r
+    // console.log("window.location.hash: [" + window.location.hash + "]");\r
+    if (window.location.hash != stateKey.value) {  \r
+      if (window.location.hash) {\r
+        //console.log("updating pz2watch:windowlocationhash with new window.location.hash [" + window.location.hash + "]");\r
+        stateKey.value = window.location.hash;\r
+        //console.log("firing pz2watch:windowlocationhash onChange");\r
+        stateKey.onchange();\r
+      } else if (stateKey.value) {\r
+        //console.log("updating window.location.hash with pz2watch:windowlocationhash  [" + stateKey.value + "]");\r
+        window.location.hash = stateKey.value;\r
+        //console.log("firing pz2watch:windowlocationhash onChange");\r
+        stateKey.onchange();\r
+      } \r
     } else {\r
-      // console.log("State hash already has the value of the new browser hash -\r
-      // not updating state hash");\r
+      //console.log("State hash already has the value of the new browser hash - not updating state hash");\r
     }\r
   }\r
 }\r
@@ -139,14 +150,12 @@ var StateListener = function() {
   this.invoke = function(field) {\r
     var stateKeyDoc = StringtoXML(field.textContent || field.text);\r
     var stateKeyValue = stateKeyDoc.childNodes[0].getAttribute("value");\r
-    // console.log('Application hash update detected. New value: ' +\r
-    // stateKeyValue);\r
+    // console.log('Received state key update from the back-end: ' + stateKeyValue);\r
     if (stateKeyValue !== window.location.hash) {\r
       window.location.hash = stateKeyValue;\r
-      // console.log("Browsers hash updated accordingly.");\r
+      // console.log("Browsers hash (window.location.hash) updated with [" + stateKeyValue + "]");\r
     } else {\r
-      // console.log("Browsers hash already has the value of the state hash. Not\r
-      // updating browser hash.");\r
+      // console.log("Browsers hash (window.location.hash) already has the value [" + stateKeyValue + "]");\r
     }\r
   };\r
 };\r
@@ -173,13 +182,12 @@ var ActiveclientsRecordListener = function() {
   this.invoke = function(field) {\r
     var updateDoc = StringtoXML(field.textContent || field.text);\r
     var activeClientsRecordValue = (updateDoc.childNodes[0].textContent || updateDoc.childNodes[0].text);\r
-    console.log('Activeclients response for record detected: '\r
-        + activeClientsRecordValue);\r
+    // console.log('Activeclients response for record detected: ' + activeClientsRecordValue);\r
     clearTimeout(renderOnRecordTargetsReqVar);\r
     if (activeClientsRecordValue > '0') {\r
       renderOnRecordTargets(true);\r
     } else {\r
-      console.log('Active clients is 0, final rendering');\r
+      // console.log('Active clients is 0, final rendering');\r
       renderOnRecordTargets(false);\r
     }\r
   };\r
index 0ca45f9..b681b98 100644 (file)
@@ -38,7 +38,7 @@
       <h:outputText id="activeClientsLabel" value="Active clients: show: " style="${cc.attrs.debug == 'true' ? '' : 'display:none;'}"/> \r
       <h:outputText id="activeclientsField" value="${pz2.update()}"  style="${cc.attrs.debug == 'true' ? '' : 'display:none;'}"/>\r
       <h:outputText id="space" value=" - record: " style="${cc.attrs.debug == 'true' ? '' : 'display:none;'}"/>\r
-      <h:outputText id="activeclientsFieldRecord" value="${pz2.update('record')}" style="${cc.attrs.debug == 'true' ? '' : 'display:none;'}"/>      \r
+      <h:outputText id="activeclientsFieldRecord" value="${pz2.doRecord()}" style="${cc.attrs.debug == 'true' ? '' : 'display:none;'}"/>      \r
     </h:form>\r
 \r
     <h:form id="stateForm" prependId="false" rendered="${cc.attrs.trackHistory == 'true'}" style="${cc.attrs.debug == 'true' ? '' : 'display:none;'}">\r
index 4c31b96..30ac455 100644 (file)
@@ -140,9 +140,12 @@ public class Pz2Bean implements Pz2Interface, StateListener, Configurable, Seria
       logger.debug("Ignoring record request due search error.");\r
       return "";\r
     } else {\r
+      logger.debug("Executing record command");\r
       ResponseDataObject responseObject = doCommand("record");\r
-      if (pzreq.getRecord().hasParameterValue("offset") ||\r
-            pzreq.getRecord().hasParameterValue("checksum")) {\r
+      if ((pzreq.getRecord().hasParameterValue("offset") ||\r
+            pzreq.getRecord().hasParameterValue("checksum")) &&\r
+            !responseObject.getType().equals("record")) {\r
+        logger.debug("Storing record offset response as 'record'");\r
         RecordResponse recordResponse = new RecordResponse();\r
         recordResponse.setType("record");\r
         recordResponse.setXml(responseObject.getXml());\r
@@ -288,7 +291,19 @@ public class Pz2Bean implements Pz2Interface, StateListener, Configurable, Seria
     pager =  new ResultsPager(pzresp,pageRange,pzreq);\r
     return pager;\r
   }\r
-    \r
+   \r
+  /**\r
+   * This methods main purpose is to support browser history.\r
+   *  \r
+   * When the browsers back or forward buttons are pressed, a  \r
+   * re-search /might/ be required - namely if the query changes.\r
+   * So, as the UI requests updates of the page (show,facets,\r
+   * etc) this method checks if a search must be executed\r
+   * before those updates are performed.\r
+   *  \r
+   * @see {@link com.indexdata.mkjsf.pazpar2.state.StateManager#setCurrentStateKey} \r
+   * @param commands\r
+   */\r
   protected void handleQueryStateChanges (String commands) {\r
     if (stateMgr.hasPendingStateChange("search") && hasQuery()) { \r
       logger.info("Triggered search: Found pending search change [" + pzreq.getCommand("search").toString() + "], doing search before updating " + commands);      \r
@@ -323,8 +338,11 @@ public class Pz2Bean implements Pz2Interface, StateListener, Configurable, Seria
     responseLogger.debug("Response was: " + commandResponse.getResponseString());\r
     responseObject = ResponseParser.getParser().getDataObject((ClientCommandResponse)commandResponse);\r
     if (ResponseParser.docTypes.contains(responseObject.getType())) {\r
+      logger.debug("Storing " + responseObject.getType() + " in pzresp. ");\r
       pzresp.put(commandName, responseObject);\r
-    }          \r
+    } else {\r
+      logger.info("Unrecognized response object type not cached in pzresp: " + responseObject.getType());\r
+    }\r
     return responseObject;\r
   }\r
     \r
index d3607c1..048b75d 100644 (file)
@@ -62,8 +62,9 @@ public class RecordResponse extends ResponseDataObject {
   }\r
   \r
   public String getActiveClients () {\r
-    logger.info("Request to get activeclients");\r
-    return getOneElementValue("activeclients");\r
+    String activeclients = getOneElementValue("activeclients");\r
+    logger.info("Request to get activeclients on record [" + getRecId() + "]. Is [" + activeclients + "]");    \r
+    return activeclients;\r
   }\r
    \r
 }\r
index d185559..04c9c3f 100644 (file)
@@ -12,7 +12,6 @@ import javax.enterprise.context.SessionScoped;
 import org.apache.log4j.Logger;\r
 \r
 import com.indexdata.mkjsf.pazpar2.commands.Pazpar2Command;\r
-import com.indexdata.mkjsf.pazpar2.commands.sp.AuthCommand;\r
 import com.indexdata.mkjsf.utils.Utils;\r
 \r
 @SessionScoped\r
@@ -90,33 +89,45 @@ public class StateManager implements Serializable {
    * Changes the current state key. Invoked from the UI to have the state \r
    * manager switch to another state than the current one. \r
    * \r
+   * @See  The state field in pz2watch.xhtml<br/> \r
+   *       The state listeners windowlocationhashListener() and StateListener()\r
+   *       in listeners.js<br/>\r
+   *       The method {@link com.indexdata.mkjsf.pazpar2.Pz2Bean#handleQueryStateChanges}<br/>\r
+   *       The class {@link com.indexdata.mkjsf.pazpar2.state.Pazpar2State}<br/> \r
+   * ... for a complete picture of browser history handling.\r
+   * \r
    * @param key\r
    */\r
   public void setCurrentStateKey(String key) {    \r
     if (currentKey.equals(key)) {\r
-      logger.debug("setCurrentStateKey: no key change detected");\r
+      logger.debug("Ignoring request from UI to set state key, already has that key [" + key + "]");\r
     } else {\r
-      logger.debug("State key change. Was: [" + currentKey + "]. Will be ["+key+"]");\r
+      logger.debug("Request from UI to change state key from: [" + currentKey + "] to ["+key+"]");\r
       if (states.get(key)==null) {\r
-        logger.error("The back-end received an unknow state key, probably UI generated: ["+ key +"].");\r
+        logger.error("Have no state registered for the key ["+ key +"].");\r
         if (key == null || key.length()==0) {\r
-          logger.info("Empty key received, treating it as identical to current key going forward.");\r
+          logger.info("Recived an empty key, retaining currentKey [" + currentKey + "]");\r
           key = currentKey;\r
         } else {\r
           if (states.get(currentKey) != null) {\r
-            logger.info("Current search state cached under both of [" + key + "] and [" + currentKey + "]");\r
-            states.put(key,states.get(currentKey));\r
+            if (key.equals("#1")) {\r
+              logger.info("Initial key created [" + key + "], but already got a state registered for the current key [" + currentKey + "]. Retaining current key.");\r
+              key = currentKey;\r
+            } else {\r
+              logger.info("Current search state cached under both new key [" + key + "] and current key [" + currentKey + "]");\r
+              states.put(key,states.get(currentKey));\r
+            }\r
           }\r
         }\r
       }\r
       \r
       if (states.get(key).getCommand("search").equals(states.get(currentKey).getCommand("search"))) {\r
-        logger.debug("No search change detected");\r
+        logger.debug("No search change detected as a consequence of processing the key ["+key+"]");\r
       } else {\r
         hasPendingStateChange("search",true);\r
       }\r
       if (states.get(key).getCommand("record").equals(states.get(currentKey).getCommand("record"))) {\r
-        logger.debug("No record change detected");\r
+        logger.debug("No record change detected as a consequence of processing the key ["+key+"]");\r
       } else {\r
         hasPendingStateChange("record",true);\r
       }\r