Index: /main/trunk/greenstone3/web/interfaces/default/js/javascript-global-functions.js
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default/js/javascript-global-functions.js	(revision 31557)
+++ /main/trunk/greenstone3/web/interfaces/default/js/javascript-global-functions.js	(revision 31558)
@@ -6,5 +6,5 @@
 var HALTED = 12;
 
-gs.functions = new Array();
+gs.functions = {};
 
 gs.jqGet = function(id)
@@ -436,5 +436,5 @@
 // - opts param: No function overloading in JavaScript. Can pass a custom object, however can pass opts,
 // see http://stackoverflow.com/questions/456177/function-overloading-in-javascript-best-practices
-function callMetadataServer(callingFunction, payload, responseFunction, opts)
+gs.functions.callMetadataServer = function(callingFunction, payload, responseFunction, opts)
 {
 
@@ -443,5 +443,5 @@
     // Set/remove operations will switch to synchronous AJAX, unless opt["forceSync"] is set otherwise
     var async_setting = true; 
-    var method = "GET"; // GET was the default before
+    var method = "POST"; // GET was the default before
     
     // Set to false if you wish to use the regular JavaScript AJAX way in gsajaxapi.js (will use payload.url)
@@ -457,5 +457,5 @@
     // set method = "GET" (above, but also in calling functions that specify this optional parameter!)
     // and set the default here below for _use_payload_in_data_not_url_form to false.
-    var _use_payload_in_data_not_url_form = false;
+    var _use_payload_in_data_not_url_form = true; // code will anyway set this to true for jQuery $.ajax() with POST
 
     var _modifyingMeta  = false;
@@ -481,6 +481,4 @@
 	async_setting = false; // for 'write' operations (set/remove meta), we force sequential processing of the internal operation.
 
-	// for meta modification operatons, should we make the method=POST??????
-	// method = "POST";
     }
     // check for any overrides by calling code that knows what it's doing
@@ -580,7 +578,9 @@
 // of the payload. Then calling functions, and the callMetadataServer() function they call, will control
 // and determine which of the two forms ultimately gets used.
-// UNUSED: http://stackoverflow.com/questions/8648892/convert-url-parameters-to-a-javascript-object
-function getBasicDataForMetadataServer(metaServerCommand, collection, site, documentID, metadataName, metamode, metadataValue, prevMetadataValue, metadataPosition) {
-
+// (Constructing both URL and data structure, as I could not successfully convert old URL way to data structure
+// http://stackoverflow.com/questions/8648892/convert-url-parameters-to-a-javascript-object)
+gs.functions.getBasicDataForMetadataServer = function(metaServerCommand, collection, site, documentID, metadataName,
+						       metamode, metadataValue, prevMetadataValue, metadataPosition)
+{
     // if we're doing set- or remove- metadata operations,
     // then we need change the data params that will make up the query string
@@ -665,6 +665,6 @@
 
 // See description for getBasicDataForMetadataServer()
-function getComplexDataForMetadataServer(metaServerCommand, collection, site, docArray, metamode, where) {
-
+gs.functions.getComplexDataForMetadataServer = function(metaServerCommand, collection, site, docArray, metamode, where)
+{
     var docArrayJSON = JSON.stringify(docArray);
     
@@ -746,12 +746,10 @@
 *************************/
 
-// callMetadataServerURLMode("setImportMetadata", "cgi-bin/metadata-server.pl?a=set-import-metadata&c=" + collection + "&site=" + site + "&d=" + documentID + "&metaname=" + metadataName + "&metavalue=" + metadataValue + "&prevmetavalue=" + prevMetadataValue + "&metamode=" + metamode, responseFunction);
-
 gs.functions.setImportMetadata = function(collection, site, documentID, metadataName, metadataValue, prevMetadataValue, metamode, responseFunction)
 {    
 
-    callMetadataServer(
+    gs.functions.callMetadataServer(
 	"setImportMetadata", 
-	getBasicDataForMetadataServer("set-import-metadata", collection, site, documentID, metadataName, metamode, metadataValue, prevMetadataValue, null /*metapos*/), 
+	gs.functions.getBasicDataForMetadataServer("set-import-metadata", collection, site, documentID, metadataName, metamode, metadataValue, prevMetadataValue, null /*metapos*/), 
 	responseFunction);
     
@@ -764,7 +762,7 @@
     }
 
-    callMetadataServer(
+    gs.functions.callMetadataServer(
 	"setArchivesMetadata",
-	getBasicDataForMetadataServer("set-archives-metadata", collection, site, documentID, metadataName, metamode, metadataValue, prevMetadataValue, metadataPosition),
+	gs.functions.getBasicDataForMetadataServer("set-archives-metadata", collection, site, documentID, metadataName, metamode, metadataValue, prevMetadataValue, metadataPosition),
 	responseFunction);
 
@@ -781,7 +779,7 @@
     if(metadataPosition != null || prevMetadataValue != null) { 
     
-	callMetadataServer(
+	gs.functions.callMetadataServer(
 	    "setIndexMetadata",
-	    getBasicDataForMetadataServer("set-metadata", collection, site, documentID, metadataName, metamode, metadataValue, prevMetadataValue, metadataPosition),
+	    gs.functions.getBasicDataForMetadataServer("set-metadata", collection, site, documentID, metadataName, metamode, metadataValue, prevMetadataValue, metadataPosition),
 	    responseFunction);
     }
@@ -797,7 +795,7 @@
 	    // previous version of this function did not allow setting metapos or prevMetavalue
 	    // so leaving the behaviour the same along with function signature.
-	    callMetadataServer(
+	    gs.functions.callMetadataServer(
 		nameArray[i],
-		getBasicDataForMetadataServer(functionArray[i], collection, site, documentID, metadataName, metamode, metadataValue, null /*prevMetadataValue*/, null /*metadataPosition*/),
+		gs.functions.getBasicDataForMetadataServer(functionArray[i], collection, site, documentID, metadataName, metamode, metadataValue, null /*prevMetadataValue*/, null /*metadataPosition*/),
 		responseFunction);
 	}
@@ -812,5 +810,5 @@
 {  
 
-    var payload = getComplexDataForMetadataServer("set-metadata-array", collection, site, docArray, metamode, where);
+    var payload = gs.functions.getComplexDataForMetadataServer("set-metadata-array", collection, site, docArray, metamode, where);
     
     // set operations are generally synchronous, but allow calling function to force ajax call 
@@ -822,5 +820,5 @@
     //console.log("cgi-bin/metadata-server.pl?"+params);
     
-    var response = callMetadataServer("Setting metadata in "+where, payload, responseFunction, {"forceSync": forceSync, "requestMethod": "POST"});
+    var response = gs.functions.callMetadataServer("Setting metadata in "+where, payload, responseFunction, {"forceSync": forceSync, "requestMethod": "POST"});
 	
     return response;
@@ -837,5 +835,5 @@
 gs.functions.getMetadataArray = function(collection, site, docArray, where, responseFunction, forceSync)
 {
-    var payload = getComplexDataForMetadataServer("get-metadata-array", collection, site, docArray, null /*metamode*/, where);    
+    var payload = gs.functions.getComplexDataForMetadataServer("get-metadata-array", collection, site, docArray, null /*metamode*/, where);    
 
     // get operations are generally asynchronous, but allow calling function to force ajax call 
@@ -847,5 +845,5 @@
     // http://stackoverflow.com/questions/456177/function-overloading-in-javascript-best-practices
     // https://www.w3schools.com/js/js_objects.asp
-    var response = callMetadataServer("Getting metadata from "+where, payload, responseFunction, {"forceSync":forceSync, "requestMethod": "POST"});
+    var response = gs.functions.callMetadataServer("Getting metadata from "+where, payload, responseFunction, {"forceSync":forceSync, "requestMethod": "POST"});
 
     return response;
@@ -855,6 +853,6 @@
 gs.functions.getImportMetadata = function(collection, site, documentID, metadataName, responseFunction)
 {
-    var payload = getBasicDataForMetadataServer("get-import-metadata", collection, site, documentID, metadataName);
-    callMetadataServer("getImportMetadata", payload, function(responseText) {
+    var payload = gs.functions.getBasicDataForMetadataServer("get-import-metadata", collection, site, documentID, metadataName);
+    gs.functions.callMetadataServer("getImportMetadata", payload, function(responseText) {
 	    var metadata = new GSMetadata(collection, site, documentID, metadataName, null, null, responseText);
 		if(responseFunction != null)
@@ -867,7 +865,7 @@
 gs.functions.getArchivesMetadata = function(collection, site, documentID, metadataName, metadataPosition, responseFunction)
 {
-    var payload = getBasicDataForMetadataServer("get-archives-metadata", collection, site, documentID, metadataName, null /*metamode*/, null /*metavalue*/, null /*prevmetavalue*/, metadataPosition);
-
-    callMetadataServer("getArchivesMetadata", payload, function(responseText) {
+    var payload = gs.functions.getBasicDataForMetadataServer("get-archives-metadata", collection, site, documentID, metadataName, null /*metamode*/, null /*metavalue*/, null /*prevmetavalue*/, metadataPosition);
+
+    gs.functions.callMetadataServer("getArchivesMetadata", payload, function(responseText) {
 	var metadata = new GSMetadata(collection, site, documentID, metadataName, null, metadataPosition, responseText); // indexPos, archivesPos, metaval (responseText)
 	if(responseFunction != null)
@@ -880,7 +878,7 @@
 gs.functions.getIndexMetadata = function(collection, site, documentID, metadataName, metadataPosition, responseFunction)
 {
-    var payload = getBasicDataForMetadataServer("get-metadata", collection, site, documentID, metadataName, null /*metamode*/, null /*metavalue*/, null /*prevmetavalue*/, metadataPosition);
-
-    callMetadataServer("getIndexMetadata", payload, function(responseText) {
+    var payload = gs.functions.getBasicDataForMetadataServer("get-metadata", collection, site, documentID, metadataName, null /*metamode*/, null /*metavalue*/, null /*prevmetavalue*/, metadataPosition);
+
+    gs.functions.callMetadataServer("getIndexMetadata", payload, function(responseText) {
 	var metadata = new GSMetadata(collection, site, documentID, metadataName, metadataPosition, null, responseText); // indexPos, archivesPos, metaval (responseText)
 	
@@ -898,7 +896,7 @@
 gs.functions.removeImportMetadata = function(collection, site, documentID, metadataName, metadataValue, responseFunction)
 {
-    callMetadataServer(
+    gs.functions.callMetadataServer(
 	"removeImportMetadata", 
-	getBasicDataForMetadataServer("remove-import-metadata", collection, site, documentID, metadataName, null /*metamode*/, metadataValue, null /*prevmetavalue*/, null /*metapos*/), 
+	gs.functions.getBasicDataForMetadataServer("remove-import-metadata", collection, site, documentID, metadataName, null /*metamode*/, metadataValue, null /*prevmetavalue*/, null /*metapos*/), 
 	responseFunction);
 }
@@ -910,7 +908,7 @@
     }
 
-    callMetadataServer(
+    gs.functions.callMetadataServer(
 	"removeArchiveMetadata", 
-	getBasicDataForMetadataServer("remove-archives-metadata", collection, site, documentID, metadataName, null /*metamode*/, metadataValue, null /*prevmetavalue*/, metadataPosition), 
+	gs.functions.getBasicDataForMetadataServer("remove-archives-metadata", collection, site, documentID, metadataName, null /*metamode*/, metadataValue, null /*prevmetavalue*/, metadataPosition), 
 	responseFunction);
 }
@@ -922,7 +920,7 @@
     }
 
-    callMetadataServer(
+    gs.functions.callMetadataServer(
 	"removeIndexMetadata", 
-	getBasicDataForMetadataServer("remove-metadata", collection, site, documentID, metadataName, null /*metamode*/, metadataValue, null /*prevmetavalue*/, metadataPosition), 
+	gs.functions.getBasicDataForMetadataServer("remove-metadata", collection, site, documentID, metadataName, null /*metamode*/, metadataValue, null /*prevmetavalue*/, metadataPosition), 
 	responseFunction);
 }
@@ -935,8 +933,9 @@
 	for(var i = 0; i < nameArray.length; i++)
 	{
-	    callMetadataServer(
+	    gs.functions.callMetadataServer(
 		nameArray[i],
-		getBasicDataForMetadataServer(functionArray[i], collection, site, documentID, metadataName, null /*metamode*/, metadataValue, null /*prevmetavalue*/, null /*metapos*/),
+		gs.functions.getBasicDataForMetadataServer(functionArray[i], collection, site, documentID, metadataName, null /*metamode*/, metadataValue, null /*prevmetavalue*/, null /*metapos*/),
 		responseFunction);
 	}
 }
+
Index: /main/trunk/greenstone3/web/interfaces/default/js/user_comments.js
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default/js/user_comments.js	(revision 31557)
+++ /main/trunk/greenstone3/web/interfaces/default/js/user_comments.js	(revision 31558)
@@ -5,11 +5,19 @@
 // http://stackoverflow.com/questions/8714472/cant-pass-event-to-addeventlistener-closure-issue
 // https://www.sitepoint.com/demystifying-javascript-closures-callbacks-iifes/
+// http://stackoverflow.com/questions/4869712/new-without-delete-on-same-variable-in-javascript
+// http://stackoverflow.com/questions/7375120/why-is-arr-faster-than-arr-new-array
+// http://stackoverflow.com/questions/874205/what-is-the-difference-between-an-array-and-an-object
+// http://stackoverflow.com/questions/33514915/what-s-the-difference-between-and-while-declaring-a-javascript-array
+// http://www.nfriedly.com/techblog/2009/06/advanced-javascript-objects-arrays-and-array-like-objects/
 
 /***************
 * USER COMMENTS
 ****************/
+
+gs.usercomments = {};
+
 // http://stackoverflow.com/questions/6312993/javascript-seconds-to-time-with-format-hhmmss
 // Call as: alert(timestamp.printTime());
-function formatTime(timestamp) {
+gs.usercomments.formatTime = function(timestamp) {
     var int_timestamp    = parseInt(timestamp, 10); // don't forget the second param
     var date = new Date(int_timestamp);
@@ -17,5 +25,5 @@
 }
 
-function loadUserComments() {
+gs.usercomments.loadUserComments = function() {
 
     // don't bother loading comments if we're not on a document page (in which case there's no docid)
@@ -74,8 +82,8 @@
     //var json_result_str = gs.functions.getMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "index");
 
-    gs.functions.getMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "index", loadedUserComments, false); // false for asynchronous
-}
-
-function loadedUserComments(data)
+    gs.functions.getMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "index", gs.usercomments.loadedUserComments, false); // false for asynchronous
+}
+
+gs.usercomments.loadedUserComments = function(data)
 {
     // don't bother displaying comments if we're not on a document page
@@ -141,5 +149,5 @@
 	    
 	    // for each usercomment, create a child div with the username, timestamp and comment
-	    displayInUserCommentList(usercommentdiv, username, timestamp, comment);
+	    gs.usercomments.displayInUserCommentList(usercommentdiv, username, timestamp, comment);
 	    
 	    i++;
@@ -155,5 +163,5 @@
 
 
-function displayInUserCommentList(usercommentdiv, username, timestamp, comment) {
+gs.usercomments.displayInUserCommentList = function(usercommentdiv, username, timestamp, comment) {
     
     //alert("Comment: " + username + " " + timestamp + " " + comment);
@@ -174,5 +182,5 @@
     
     divgroup.appendChild(divtime);
-    txt=document.createTextNode(formatTime(timestamp)); // format timestamp for date/time display
+    txt=document.createTextNode(gs.usercomments.formatTime(timestamp)); // format timestamp for date/time display
     divtime.appendChild(txt);
     
@@ -193,10 +201,10 @@
 // Unused. Replaced in favour of call to escape() in setMetaArray function that calls urlPostSync
 // http://stackoverflow.com/questions/6020714/escape-html-using-jquery
-function safeHTML(str) {
+gs.usercomments.safeHTML = function(str) {
     return str.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace('"',"&quot;").replace("'","&#x27;").replace("/", "&#x2F;"); //"\\""
-} 
-
-
-function addUserComment(_username, _comment, _docid, doc) {
+}
+
+
+gs.usercomments.addUserComment = function(_username, _comment, _docid, doc) {
     
     // don't add empty strings for name/comment		
@@ -287,5 +295,10 @@
     
     //var result = gs.functions.setMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "accumulate", "import|archives|index");
-    gs.functions.setMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "accumulate", "import|archives|index", function(ajaxResult) { return doneUpdatingMetatada(ajaxResult, _username, _timestamp, _comment); }, false); // false for asynchronous, 
+    gs.functions.setMetadataArray(gs.variables["c"],
+	gs.variables["site"],
+	docArray, "accumulate",
+	"import|archives|index",
+	function(ajaxResult) { return gs.usercomments.doneUpdatingMetatada(ajaxResult, _username, _timestamp, _comment); },
+	false); // false for asynchronous, 
     // this is ok since we're disabling the comment submit button, so no further set-meta-array calls can be
     // made until the ajax call returns and the callback is called which re-enables the submit button
@@ -296,5 +309,5 @@
 }
 
-function doneUpdatingMetatada(data, _username, _timestamp, _comment)
+gs.usercomments.doneUpdatingMetatada = function(data, _username, _timestamp, _comment)
 {
 
@@ -339,5 +352,5 @@
 	var usercommentdiv = document.getElementById("usercomments");
 	if(usercommentdiv != undefined) {
-	    displayInUserCommentList(usercommentdiv, _username, _timestamp, _comment);
+	    gs.usercomments.displayInUserCommentList(usercommentdiv, _username, _timestamp, _comment);
      	}
     }
@@ -348,6 +361,6 @@
 }
 
-function commentAreaSetup() {
-    loadUserComments();
+gs.usercomments.commentAreaSetup = function() {
+    gs.usercomments.loadUserComments();
 
     //$("div#commentarea").html("<textarea required=\"required\" name=\"comment\" rows=\"10\" cols=\"64\" placeholder=\"Add your comment here...\"></textarea>");
@@ -361,4 +374,4 @@
 // This way we ensure we don't replace any other onLoad() functions, but append the loadUserComments() 
 // function to the existing set of eventhandlers called onDocReady
-$(document).ready(commentAreaSetup);
-
+$(document).ready(gs.usercomments.commentAreaSetup);
+
Index: /main/trunk/greenstone3/web/interfaces/default/transform/layouts/usercomments.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default/transform/layouts/usercomments.xsl	(revision 31557)
+++ /main/trunk/greenstone3/web/interfaces/default/transform/layouts/usercomments.xsl	(revision 31558)
@@ -48,5 +48,5 @@
 	  </div>
 	  
-	  <input type="submit" id="usercommentSubmitButton" onclick="addUserComment(document.AddUserCommentForm.username.value, document.AddUserCommentForm.comment.value, document.AddUserCommentForm.d.value, document); return false;"><xsl:attribute name="value"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'usercomments.submit')"/></xsl:attribute></input>
+	  <input type="submit" id="usercommentSubmitButton" onclick="gs.usercomments.addUserComment(document.AddUserCommentForm.username.value, document.AddUserCommentForm.comment.value, document.AddUserCommentForm.d.value, document); return false;"><xsl:attribute name="value"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'usercomments.submit')"/></xsl:attribute></input>
 	  <label id="usercommentfeedback"><xsl:comment>Text to prevent empty tags from becoming self-closing tags</xsl:comment></label>
 
