Changeset 31543

Show
Ignore:
Timestamp:
28.03.2017 17:04:10 (2 years ago)
Author:
ak19
Message:

Next incremental change to adding user comments in GS3. This time to make the get-meta-array and set-meta-array functions be called asynchronously from user_comments.js (these operations can be called synchronously by any others wishing to tuse them, and do so by default). user_comments.js chooses to call get-meta-array and even set-meta-array asynchronously by passing in the appropriate flag to make the ajax calls asynchronous. To protect against any overlapping read/write issues and mutliple submit comments (set-meta-array calls) from being fired off with overlap, the submit button gets disabled until the set-meta-array call has returned and its callback is called. Similarly, the submit button is disabled until the page has finished loading existing user comments (get-meta-array call).

Location:
main/trunk/greenstone3/web/interfaces/default
Files:
3 modified

Legend:

Unmodified
Added
Removed
  • main/trunk/greenstone3/web/interfaces/default/js/javascript-global-functions.js

    r31542 r31543  
    592592// behaviour of calling set-metadata-array. E.g. where=import|archives|index 
    593593// THIS METHOD IS SYNCHRONOUS 
    594 gs.functions.setMetadataArray = function(collection, site, docArray, metamode, where, responseFunction)  
     594gs.functions.setMetadataArray = function(collection, site, docArray, metamode, where, responseFunction, forceSync)  
    595595{ 
    596596    docArrayJSON = JSON.stringify(docArray); 
     
    610610    } 
    611611     
    612  
    613     var response = callMetadataServer("Setting metadata in "+where, "cgi-bin/metadata-server.pl?"+params, responseFunction); 
     612    // set operations are generally synchronous, but allow calling function to force ajax call  
     613    // to be synchronous or not. Default is synchronous, as it was for GS2 
     614    if(forceSync == null) { 
     615    forceSync = true; 
     616    } 
     617 
     618    var response = callMetadataServer("Setting metadata in "+where, "cgi-bin/metadata-server.pl?"+params, responseFunction, {"forceSync": forceSync}); 
    614619 
    615620    return response; 
     
    625630// See description for setMetadataArray above for information about the 'where' parameter. 
    626631// THIS METHOD IS SYNCHRONOUS BY DEFAULT. Set forceSync to false to override this default behaviour 
    627 gs.functions.getMetadataArray = function(collection, site, docArray, where, forceSync, responseFunction) 
     632gs.functions.getMetadataArray = function(collection, site, docArray, where, responseFunction, forceSync) 
    628633{ 
    629634    docArrayJSON = JSON.stringify(docArray); 
  • main/trunk/greenstone3/web/interfaces/default/js/user_comments.js

    r31540 r31543  
    44// http://stackoverflow.com/questions/256754/how-to-pass-arguments-to-addeventlistener-listener-function 
    55// http://stackoverflow.com/questions/8714472/cant-pass-event-to-addeventlistener-closure-issue 
    6  
     6// https://www.sitepoint.com/demystifying-javascript-closures-callbacks-iifes/ 
    77 
    88/*************** 
     
    1818 
    1919function loadUserComments() { 
    20     /* 
    21  
    22     if(gs.variables) { 
    23     var listing = ""; 
    24     for (prop in gs.variables) { 
    25         listing = listing + prop.toString() + ": " + gs.variables[prop] + "\n"; 
    26     } 
    27     alert ("gs variables:\n" + listing); 
    28     } else { 
    29     alert("LOADING USER COMMENTS - no gs.variables set"); 
    30     } 
    31     */ 
    32      
    33     // don't bother loading comments if we're not on a document page (in which case there's no usercommentdiv) 
     20 
     21    // don't bother loading comments if we're not on a document page (in which case there's no docid) 
     22    var doc_id = gs.variables["d"]; ///"_cgiargdJssafe_"; //escape("cgiargd"); 
     23 
     24    // stackoverflow.com/questions/36661748/what-is-the-exact-negation-of-ifvariable-in-javascript 
     25    if(!doc_id) { // vs http://stackoverflow.com/questions/784929/what-is-the-not-not-operator-in-javascript 
     26     
     27    return; 
     28    } 
     29 
     30    // Don't allow the user to add comments (which calls set-meta-array) until we've finished loading all  
     31    // user comments (which calls get-meta-array). Since get-meta-array and set-meta-array are called  
     32    // asynchronously, this is to help prevent any overlap in these functions' access of meta files in 
     33    // index|archives|import. 
     34    var submitButton = document.getElementById("usercommentSubmitButton");     
     35    if(submitButton) { // there'll be no submitButton if the comment form is not displayed (user not logged in) 
     36    submitButton.disabled = true; 
     37    } 
     38 
     39     
     40    // don't allow users to add comments (disable the submit button) 
     41    // until existing comments have been retrieved and displayed 
     42    //document.getElementById("usercommentSubmitButton").disabled = true; 
     43 
     44    // Since we have a docid, get toplevel section of the docid 
     45     
     46    var period = doc_id.indexOf("."); 
     47    if(period != -1) { 
     48    doc_id = doc_id.substring(0, period); 
     49    } 
     50     
     51    var username_rec = { 
     52    metaname: "username", 
     53    metapos: "all" 
     54    }; 
     55     
     56    var timestamp_rec = { 
     57    metaname: "usertimestamp", 
     58    metapos: "all" 
     59    }; 
     60     
     61    var comment_rec = { 
     62    metaname: "usercomment", 
     63    metapos: "all" 
     64    }; 
     65 
     66    var doc_rec = { 
     67    docid: doc_id, 
     68    metatable: [username_rec, timestamp_rec, comment_rec]        
     69    }; 
     70 
     71    var docArray = [doc_rec]; 
     72    //alert(JSON.stringify(docArray)); 
     73 
     74    //var json_result_str = gs.functions.getMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "index"); 
     75 
     76    gs.functions.getMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "index", loadedUserComments, false); // false for asynchronous 
     77} 
     78 
     79function loadedUserComments(xmlHttpObj) 
     80{ 
     81    // don't bother displaying comments if we're not on a document page 
     82    // (in which case there's no usercommentdiv). 
     83    // This shouldn't happen here, since we only call this from loadUserComments() 
     84    // and that first checks we're actually on a document page. 
    3485    var usercommentdiv = document.getElementById("usercomments"); 
    3586    if(usercommentdiv == undefined || usercommentdiv == null) { 
    3687    return; 
    3788    } 
    38      
    39     // else, if we have a usercommentdiv, we would have a docid. Get toplevel section of the docid 
    40     var doc_id = gs.variables["d"]; ///"_cgiargdJssafe_"; //escape("cgiargd"); 
    41     var period = doc_id.indexOf("."); 
    42     if(period != -1) { 
    43     doc_id = doc_id.substring(0, period); 
    44     } 
    45      
    46     var username_rec = { 
    47     metaname: "username", 
    48     metapos: "all" 
    49     }; 
    50      
    51     var timestamp_rec = { 
    52     metaname: "usertimestamp", 
    53     metapos: "all" 
    54     }; 
    55      
    56     var comment_rec = { 
    57     metaname: "usercomment", 
    58     metapos: "all" 
    59     }; 
    60  
    61     var doc_rec = { 
    62     docid: doc_id, 
    63     metatable: [username_rec, timestamp_rec, comment_rec]        
    64     }; 
    65  
    66     var docArray = [doc_rec]; 
    67     //alert(JSON.stringify(docArray)); 
    68  
    69     var json_result_str = gs.functions.getMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "index"); 
     89 
     90    var json_result_str = xmlHttpObj.responseText; 
    7091    //  alert(json_result_str); 
     92    console.log("Got to display: " + json_result_str); 
    7193    var result = JSON.parse(json_result_str); 
    7294    // result contains only one docrec (result[0]), since we asked for the usercomments of one docid 
    7395    var metatable = result[0].metatable; 
    7496    //  alert(JSON.stringify(metatable)); 
    75  
     97     
    7698    var i = 0; 
    7799    var looping = true; 
    78  
     100     
    79101     
    80102    // if there's at least one existing comment OR if the form is currently being displayed 
     
    90112    } 
    91113     
    92     
     114     
    93115    // metatable[0] = list of usernames, metatable[1] = list of timestamps, metatable[2] = list of comments  
    94116    // the 3 lists/arrays should be of even length. Assuming this, loop as long as there's another username 
     
    97119    if(metaval_rec == undefined) { 
    98120        looping = false; 
    99         }  
     121    }  
    100122    else { 
    101123         
     
    117139    }        
    118140    } 
    119  
     141     
     142    var submitButton = document.getElementById("usercommentSubmitButton"); 
     143    // Now we've finished loading all user comments, allow the user to add a comment 
     144    if(submitButton) { 
     145    submitButton.disabled = false; 
     146    } 
    120147} 
    121148 
     
    174201    if(!trimmed_comment) { // || !trimmed_username 
    175202    doc.AddUserCommentForm.comment.value = "";             
    176     //doc.AddUserCommentForm.username.value = ""; 
    177     doc.getElementById("usercommentfeedback").innerHTML = gs.variables["textisempty"]; ///"_textisempty_"; 
     203    //document.AddUserCommentForm.username.value = ""; 
     204    document.getElementById("usercommentfeedback").innerHTML = gs.variables["textisempty"]; ///"_textisempty_"; 
    178205    return; 
    179206    } 
     
    248275    //alert(JSON.stringify(docArray)); 
    249276     
    250     // GSAPI already knows the collection 
    251     var result = gs.functions.setMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "accumulate", "import|archives|index"); 
    252      
     277    // Don't allow the user to submit further comments until the metadata has been updated 
     278    document.getElementById("usercommentSubmitButton").disabled = true; 
     279 
     280     
     281    //var result = gs.functions.setMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "accumulate", "import|archives|index"); 
     282    gs.functions.setMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "accumulate", "import|archives|index", function(xmlHttpObj) { return doneUpdatingMetatada(xmlHttpObj, _username, _timestamp, _comment); }, false); // false for asynchronous,  
     283    // this is ok since we're disabling the comment submit button, so no further set-meta-array calls can be 
     284    // made until the ajax call returns and the callback is called which re-enables the submit button 
     285    // But disabling submit does not protect against concurrent access such as someone else editing the  
     286    // document (doing set-meta operations, updating archives/index/import) at the same time as someone else 
     287    // adding user comments (doing set-meta-array, updating archives|index|import). 
     288 
     289} 
     290 
     291function doneUpdatingMetatada(xmlHttpObj, _username, _timestamp, _comment) 
     292{ 
     293    var result = xmlHttpObj.responseText; 
     294    //alert("Received post response to setMeta: " + result); // just the HTML page 
     295 
    253296    // clear the comment field as it has now been submitted, but not the username field 
    254297    // as the user is logged in, so they should be able to commit again under their username. 
    255     doc.AddUserCommentForm.comment.value = "";  
     298    document.AddUserCommentForm.comment.value = "";  
    256299     
    257300    // check for locked collection error 
     
    264307    var error = result.substring(errorIndex,endIndex); 
    265308    errormessage="ERROR: Unable to add comment. " + error; 
    266     doc.getElementById("usercommentfeedback").innerHTML = errormessage; 
     309    document.getElementById("usercommentfeedback").innerHTML = errormessage; 
    267310    //alert("Result: " + result); 
    268311    }  
     
    272315    var error = result.substring(startIndex+1,endIndex); 
    273316    errormessage="ERROR: Unable to add comment. " + error; 
    274     doc.getElementById("usercommentfeedback").innerHTML = errormessage; 
     317    document.getElementById("usercommentfeedback").innerHTML = errormessage; 
    275318    //alert("Result: " + result); 
    276319    } 
    277320    else { // success! 
    278     doc.getElementById("usercommentfeedback").innerHTML = gs.variables["textcommentsubmitted"]; ///"_textcommentsubmitted_";         
     321    document.getElementById("usercommentfeedback").innerHTML = gs.variables["textcommentsubmitted"]; ///"_textcommentsubmitted_";        
    279322     
    280323    // update display of existing user comments to show the newly added comment 
     
    283326        displayInUserCommentList(usercommentdiv, _username, _timestamp, _comment); 
    284327        } 
    285     }      
     328    } 
     329 
     330    // whether there was an error or not, re-enable the submit button now 
     331    // that the set-meta-array operation has completed. 
     332    document.getElementById("usercommentSubmitButton").disabled = false; 
    286333} 
    287334 
    288335function commentAreaSetup() { 
    289336    loadUserComments(); 
     337 
    290338    //$("div#commentarea").html("<textarea required=\"required\" name=\"comment\" rows=\"10\" cols=\"64\" placeholder=\"Add your comment here...\"></textarea>"); 
    291339    $("div#commentarea").html('<textarea required="required" name="comment" rows="10" cols="64" placeholder="Add your comment here..."></textarea>'); 
     
    296344// "Handlers added via $(document).ready() don't overwrite each other, but rather execute in turn" 
    297345// as explained at http://stackoverflow.com/questions/15564029/adding-to-window-onload-event 
    298  
     346// This way we ensure we don't replace any other onLoad() functions, but append the loadUserComments()  
     347// function to the existing set of eventhandlers called onDocReady 
    299348$(document).ready(commentAreaSetup); 
    300349 
    301 /* 
    302 // http://stackoverflow.com/questions/807878/javascript-that-executes-after-page-load 
    303 // ensure we don't replace any other onLoad() functions, but append the loadUserComments()  
    304 // function to the existing onLoad handlers 
    305  
    306 if(window.onload) { 
    307     var curronload = window.onload; 
    308     var newonload = function() { 
    309         curronload(); 
    310         loadUserComments(); 
    311     }; 
    312     window.onload = newonload; 
    313 } else { 
    314     window.onload = loadUserComments; 
    315 } 
    316 */ 
  • main/trunk/greenstone3/web/interfaces/default/transform/layouts/usercomments.xsl

    r31542 r31543  
    4848      </div> 
    4949       
    50       <input type="submit" 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> 
     50      <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> 
    5151      <label id="usercommentfeedback"><xsl:comment>Text to prevent empty tags from becoming self-closing tags</xsl:comment></label> 
    5252