Ignore:
Timestamp:
2017-03-28T17:04:10+13:00 (7 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/js
Files:
2 edited

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 */
Note: See TracChangeset for help on using the changeset viewer.