[31537] | 1 | // http://toddmotto.com/avoiding-anonymous-javascript-functions
|
---|
| 2 | // https://toddmotto.com/everything-you-wanted-to-know-about-javascript-scope/
|
---|
| 3 | // pass event to addEventListener onmouseover
|
---|
| 4 | // http://stackoverflow.com/questions/256754/how-to-pass-arguments-to-addeventlistener-listener-function
|
---|
| 5 | // http://stackoverflow.com/questions/8714472/cant-pass-event-to-addeventlistener-closure-issue
|
---|
[31543] | 6 | // https://www.sitepoint.com/demystifying-javascript-closures-callbacks-iifes/
|
---|
[31558] | 7 | // http://stackoverflow.com/questions/4869712/new-without-delete-on-same-variable-in-javascript
|
---|
| 8 | // http://stackoverflow.com/questions/7375120/why-is-arr-faster-than-arr-new-array
|
---|
| 9 | // http://stackoverflow.com/questions/874205/what-is-the-difference-between-an-array-and-an-object
|
---|
| 10 | // http://stackoverflow.com/questions/33514915/what-s-the-difference-between-and-while-declaring-a-javascript-array
|
---|
| 11 | // http://www.nfriedly.com/techblog/2009/06/advanced-javascript-objects-arrays-and-array-like-objects/
|
---|
[31559] | 12 | // stackoverflow.com/questions/36661748/what-is-the-exact-negation-of-ifvariable-in-javascript
|
---|
| 13 | // http://stackoverflow.com/questions/784929/what-is-the-not-not-operator-in-javascript
|
---|
[31537] | 14 |
|
---|
| 15 | /***************
|
---|
| 16 | * USER COMMENTS
|
---|
| 17 | ****************/
|
---|
[31558] | 18 |
|
---|
[31559] | 19 | // avoid making usercomments js functions global (which attaches them as properties to the window object)
|
---|
[31558] | 20 | gs.usercomments = {};
|
---|
| 21 |
|
---|
[31537] | 22 | // http://stackoverflow.com/questions/6312993/javascript-seconds-to-time-with-format-hhmmss
|
---|
| 23 | // Call as: alert(timestamp.printTime());
|
---|
[31558] | 24 | gs.usercomments.formatTime = function(timestamp) {
|
---|
[31537] | 25 | var int_timestamp = parseInt(timestamp, 10); // don't forget the second param
|
---|
| 26 | var date = new Date(int_timestamp);
|
---|
| 27 | return date.toLocaleDateString() + " " + date.toLocaleTimeString();
|
---|
| 28 | }
|
---|
| 29 |
|
---|
[31558] | 30 | gs.usercomments.loadUserComments = function() {
|
---|
[31537] | 31 |
|
---|
[31543] | 32 | // don't bother loading comments if we're not on a document page (in which case there's no docid)
|
---|
[31559] | 33 | var doc_id = gs.variables["d"]; ///"_cgiargdJssafe_" in GS2
|
---|
[31543] | 34 |
|
---|
[31559] | 35 | if(!doc_id) {
|
---|
[31537] | 36 | return;
|
---|
| 37 | }
|
---|
[31543] | 38 |
|
---|
| 39 | // Don't allow the user to add comments (which calls set-meta-array) until we've finished loading all
|
---|
| 40 | // user comments (which calls get-meta-array). Since get-meta-array and set-meta-array are called
|
---|
| 41 | // asynchronously, this is to help prevent any overlap in these functions' access of meta files in
|
---|
| 42 | // index|archives|import.
|
---|
[31559] | 43 | // Prevent users from adding comments by disabling the submit button
|
---|
| 44 | // until existing comments have been retrieved and displayed
|
---|
[31543] | 45 | var submitButton = document.getElementById("usercommentSubmitButton");
|
---|
| 46 | if(submitButton) { // there'll be no submitButton if the comment form is not displayed (user not logged in)
|
---|
| 47 | submitButton.disabled = true;
|
---|
| 48 | }
|
---|
| 49 |
|
---|
| 50 | // Since we have a docid, get toplevel section of the docid
|
---|
| 51 |
|
---|
[31537] | 52 | var period = doc_id.indexOf(".");
|
---|
| 53 | if(period != -1) {
|
---|
| 54 | doc_id = doc_id.substring(0, period);
|
---|
| 55 | }
|
---|
| 56 |
|
---|
| 57 | var username_rec = {
|
---|
| 58 | metaname: "username",
|
---|
| 59 | metapos: "all"
|
---|
| 60 | };
|
---|
| 61 |
|
---|
| 62 | var timestamp_rec = {
|
---|
| 63 | metaname: "usertimestamp",
|
---|
| 64 | metapos: "all"
|
---|
| 65 | };
|
---|
| 66 |
|
---|
| 67 | var comment_rec = {
|
---|
| 68 | metaname: "usercomment",
|
---|
| 69 | metapos: "all"
|
---|
| 70 | };
|
---|
| 71 |
|
---|
| 72 | var doc_rec = {
|
---|
| 73 | docid: doc_id,
|
---|
| 74 | metatable: [username_rec, timestamp_rec, comment_rec]
|
---|
| 75 | };
|
---|
| 76 |
|
---|
| 77 | var docArray = [doc_rec];
|
---|
| 78 |
|
---|
[31543] | 79 | //var json_result_str = gs.functions.getMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "index");
|
---|
| 80 |
|
---|
[31558] | 81 | gs.functions.getMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "index", gs.usercomments.loadedUserComments, false); // false for asynchronous
|
---|
[31543] | 82 | }
|
---|
| 83 |
|
---|
[31558] | 84 | gs.usercomments.loadedUserComments = function(data)
|
---|
[31543] | 85 | {
|
---|
| 86 | // don't bother displaying comments if we're not on a document page
|
---|
| 87 | // (in which case there's no usercommentdiv).
|
---|
| 88 | // This shouldn't happen here, since we only call this from loadUserComments()
|
---|
| 89 | // and that first checks we're actually on a document page.
|
---|
| 90 | var usercommentdiv = document.getElementById("usercomments");
|
---|
| 91 | if(usercommentdiv == undefined || usercommentdiv == null) {
|
---|
| 92 | return;
|
---|
| 93 | }
|
---|
| 94 |
|
---|
[31547] | 95 | // data is xmlHttpRequest Object if gsajaxapi is used for the ajax call.
|
---|
| 96 | // And data is a string if jQuery AJAX was used.
|
---|
| 97 | // Using JavaScript's feature sensing to detect which of the two we're dealing with:
|
---|
| 98 | var json_result_str = (data.responseText) ? data.responseText : data;
|
---|
| 99 |
|
---|
[31559] | 100 | //console.log("Got user comments to display: " + json_result_str);
|
---|
| 101 |
|
---|
[31537] | 102 | var result = JSON.parse(json_result_str);
|
---|
| 103 | // result contains only one docrec (result[0]), since we asked for the usercomments of one docid
|
---|
| 104 | var metatable = result[0].metatable;
|
---|
[31543] | 105 |
|
---|
[31537] | 106 | var i = 0;
|
---|
| 107 | var looping = true;
|
---|
| 108 |
|
---|
[31543] | 109 |
|
---|
[31540] | 110 | // if there's at least one existing comment OR if the form is currently being displayed
|
---|
| 111 | // (regardless of whether previous comments exist), display a heading for the comments section
|
---|
| 112 | if(metatable[0].metavals[0] != undefined || document.getElementById("usercommentform") != undefined) {
|
---|
| 113 | var heading=document.createElement("div");
|
---|
| 114 | var attr=document.createAttribute("class");
|
---|
| 115 | attr.nodeValue="usercommentheading";
|
---|
| 116 | heading.setAttributeNode(attr);
|
---|
[31559] | 117 | var txt=document.createTextNode(gs.variables["textusercommentssection"]); ///"_textusercommentssection_" in GS2
|
---|
[31540] | 118 | heading.appendChild(txt);
|
---|
| 119 | usercommentdiv.appendChild(heading);
|
---|
| 120 | }
|
---|
| 121 |
|
---|
[31543] | 122 |
|
---|
[31537] | 123 | // metatable[0] = list of usernames, metatable[1] = list of timestamps, metatable[2] = list of comments
|
---|
| 124 | // the 3 lists/arrays should be of even length. Assuming this, loop as long as there's another username
|
---|
| 125 | while(looping) {
|
---|
| 126 | var metaval_rec = metatable[0].metavals[i];
|
---|
| 127 | if(metaval_rec == undefined) {
|
---|
| 128 | looping = false;
|
---|
[31543] | 129 | }
|
---|
[31537] | 130 | else {
|
---|
| 131 |
|
---|
| 132 | var username = metaval_rec.metavalue;
|
---|
| 133 | var timestamp = metatable[1].metavals[i].metavalue;
|
---|
| 134 | var comment = metatable[2].metavals[i].metavalue;
|
---|
| 135 |
|
---|
| 136 | // No need to sort by time, as the meta are already stored sorted
|
---|
| 137 | // and hence retrieved in the right order by using the i (metapos) counter
|
---|
| 138 | // If sorting the array of comment records, which would be by timestamp, see
|
---|
| 139 | // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort
|
---|
| 140 |
|
---|
| 141 | // for each usercomment, create a child div with the username, timestamp and comment
|
---|
[31558] | 142 | gs.usercomments.displayInUserCommentList(usercommentdiv, username, timestamp, comment);
|
---|
[31537] | 143 |
|
---|
| 144 | i++;
|
---|
| 145 | }
|
---|
| 146 | }
|
---|
[31543] | 147 |
|
---|
| 148 | var submitButton = document.getElementById("usercommentSubmitButton");
|
---|
[31559] | 149 | // Now we've finished loading all user comments,
|
---|
| 150 | // allow the user to add a comment by enabling the submit button again
|
---|
[31543] | 151 | if(submitButton) {
|
---|
| 152 | submitButton.disabled = false;
|
---|
| 153 | }
|
---|
[31537] | 154 | }
|
---|
| 155 |
|
---|
| 156 |
|
---|
[31558] | 157 | gs.usercomments.displayInUserCommentList = function(usercommentdiv, username, timestamp, comment) {
|
---|
[31537] | 158 |
|
---|
| 159 | var divgroup=document.createElement("div");
|
---|
| 160 | var attr=document.createAttribute("class");
|
---|
| 161 | attr.nodeValue="usercomment";
|
---|
| 162 | divgroup.setAttributeNode(attr);
|
---|
| 163 |
|
---|
| 164 | var divuser=document.createElement("div");
|
---|
| 165 | var divtime=document.createElement("div");
|
---|
| 166 | var divcomment=document.createElement("div");
|
---|
| 167 |
|
---|
| 168 |
|
---|
| 169 | divgroup.appendChild(divuser);
|
---|
| 170 | var txt=document.createTextNode(username);
|
---|
| 171 | divuser.appendChild(txt);
|
---|
| 172 |
|
---|
| 173 | divgroup.appendChild(divtime);
|
---|
[31558] | 174 | txt=document.createTextNode(gs.usercomments.formatTime(timestamp)); // format timestamp for date/time display
|
---|
[31537] | 175 | divtime.appendChild(txt);
|
---|
| 176 |
|
---|
| 177 | // any quotes and colons in the fields would have been protected for transmitting as JSON
|
---|
| 178 | // so decode their entity values
|
---|
| 179 | comment = comment.replace(/"/gmi, '"');
|
---|
| 180 | comment = comment.replace(/&58;/gmi, ':');
|
---|
| 181 |
|
---|
| 182 | divgroup.appendChild(divcomment);
|
---|
| 183 | txt=document.createTextNode(comment);
|
---|
| 184 | divcomment.appendChild(txt);
|
---|
| 185 |
|
---|
| 186 | usercommentdiv.appendChild(divgroup);
|
---|
| 187 |
|
---|
| 188 | }
|
---|
| 189 |
|
---|
[31558] | 190 | gs.usercomments.addUserComment = function(_username, _comment, _docid, doc) {
|
---|
[31537] | 191 |
|
---|
| 192 | // don't add empty strings for name/comment
|
---|
| 193 |
|
---|
| 194 | // http://stackoverflow.com/questions/498970/how-do-i-trim-a-string-in-javascript
|
---|
| 195 | //var trimmed_username=_username.replace(/^\s+|\s+$/g, '');
|
---|
| 196 | var trimmed_comment = _comment.replace(/^\s+|\s+$/g, '');
|
---|
| 197 |
|
---|
[31559] | 198 | if(!trimmed_comment) {
|
---|
[31537] | 199 | doc.AddUserCommentForm.comment.value = "";
|
---|
[31543] | 200 | //document.AddUserCommentForm.username.value = "";
|
---|
[31559] | 201 | document.getElementById("usercommentfeedback").innerHTML = gs.variables["textisempty"]; ///"_textisempty_" in GS2
|
---|
[31537] | 202 | return;
|
---|
| 203 | }
|
---|
| 204 |
|
---|
| 205 | // Need to the add user comment meta of username, timestamp and comment to the
|
---|
| 206 | // topmost section of the document. So only get the docId up to any period mark:
|
---|
| 207 | var period = _docid.indexOf(".");
|
---|
| 208 | if(period != -1) {
|
---|
| 209 | _docid = _docid.substring(0, period);
|
---|
| 210 | }
|
---|
| 211 |
|
---|
| 212 |
|
---|
| 213 | // Want to store username, timestamp and comment in import/metadata.xml, archives/doc.xml
|
---|
| 214 | // and index/col.gdb.
|
---|
| 215 |
|
---|
| 216 | // For getting the current time, see
|
---|
| 217 | // http://stackoverflow.com/questions/3830244/get-current-date-time-in-seconds
|
---|
| 218 | var _timestamp = new Date().getTime(); // div by 1000 to get seconds. valueOf() may return string
|
---|
| 219 |
|
---|
[31559] | 220 | // setMetadataArray escapes the entire JSON, so we don't individually escape the fields here
|
---|
| 221 | // If we did, and called gsapi.setMetadata or gs.functions (in javascript-global-functions.js) instead,
|
---|
| 222 | // then resort to escaping first, e.g.
|
---|
| 223 | // _comment = escape(_comment);
|
---|
| 224 | // gsapi.setMetadata(_docid, "usercomment", null, _comment, "accumulate", "import|archives|index");
|
---|
[31537] | 225 |
|
---|
| 226 |
|
---|
| 227 | // Use the new JSON metatable format to set username, timestamp and comment meta for docid in one go
|
---|
| 228 |
|
---|
| 229 | // For creating the JSON object that gets turned into a string, see
|
---|
| 230 | // http://msdn.microsoft.com/en-us/library/ie/cc836459%28v=vs.94%29.aspx
|
---|
| 231 | // http://jsfiddle.net/qmacro/W54hy/
|
---|
| 232 |
|
---|
| 233 | var username_rec = {
|
---|
| 234 | metaname: "username",
|
---|
| 235 | metavals: [_username]
|
---|
| 236 | };
|
---|
| 237 |
|
---|
| 238 | var timestamp_rec = {
|
---|
| 239 | metaname: "usertimestamp",
|
---|
| 240 | metavals: [_timestamp]
|
---|
| 241 | };
|
---|
| 242 |
|
---|
| 243 | var comment_rec = {
|
---|
| 244 | metaname: "usercomment",
|
---|
| 245 | metavals: [_comment]
|
---|
| 246 | };
|
---|
| 247 |
|
---|
| 248 | var doc_rec = {
|
---|
| 249 | docid: _docid,
|
---|
| 250 | metatable: [username_rec, timestamp_rec, comment_rec],
|
---|
| 251 | metamode: "accumulate"
|
---|
| 252 | };
|
---|
| 253 |
|
---|
| 254 | var docArray = [doc_rec];
|
---|
| 255 |
|
---|
[31543] | 256 | // Don't allow the user to submit further comments until the metadata has been updated
|
---|
| 257 | document.getElementById("usercommentSubmitButton").disabled = true;
|
---|
| 258 |
|
---|
[31537] | 259 |
|
---|
[31543] | 260 | //var result = gs.functions.setMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "accumulate", "import|archives|index");
|
---|
[31558] | 261 | gs.functions.setMetadataArray(gs.variables["c"],
|
---|
| 262 | gs.variables["site"],
|
---|
| 263 | docArray, "accumulate",
|
---|
| 264 | "import|archives|index",
|
---|
| 265 | function(ajaxResult) { return gs.usercomments.doneUpdatingMetatada(ajaxResult, _username, _timestamp, _comment); },
|
---|
| 266 | false); // false for asynchronous,
|
---|
[31559] | 267 | // async here is ok since we're disabling the comment submit button, so no further set-meta-array calls
|
---|
| 268 | // can be made until the ajax call returns and the callback is called which re-enables the submit button
|
---|
[31543] | 269 | // But disabling submit does not protect against concurrent access such as someone else editing the
|
---|
| 270 | // document (doing set-meta operations, updating archives/index/import) at the same time as someone else
|
---|
| 271 | // adding user comments (doing set-meta-array, updating archives|index|import).
|
---|
| 272 |
|
---|
| 273 | }
|
---|
| 274 |
|
---|
[31558] | 275 | gs.usercomments.doneUpdatingMetatada = function(data, _username, _timestamp, _comment)
|
---|
[31543] | 276 | {
|
---|
[31547] | 277 | // data is xmlHttpRequest Object if gsajaxapi is used for the ajax call.
|
---|
| 278 | // And data is a string if jQuery AJAX was used.
|
---|
| 279 | // Using JavaScript's feature sensing to detect which of the two we're dealing with:
|
---|
| 280 | var result = (data.responseText) ? data.responseText : data;
|
---|
| 281 |
|
---|
[31537] | 282 | // clear the comment field as it has now been submitted, but not the username field
|
---|
| 283 | // as the user is logged in, so they should be able to commit again under their username.
|
---|
[31543] | 284 | document.AddUserCommentForm.comment.value = "";
|
---|
[31537] | 285 |
|
---|
| 286 | // check for locked collection error
|
---|
| 287 | var errorIndex = result.indexOf("ERROR");
|
---|
| 288 | // check for any error discovered on the server side
|
---|
| 289 | var responseErrorIndex = result.indexOf("<error");
|
---|
| 290 |
|
---|
| 291 | if(errorIndex != -1) {
|
---|
| 292 | var endIndex = result.indexOf("\\n");
|
---|
| 293 | var error = result.substring(errorIndex,endIndex);
|
---|
| 294 | errormessage="ERROR: Unable to add comment. " + error;
|
---|
[31543] | 295 | document.getElementById("usercommentfeedback").innerHTML = errormessage;
|
---|
[31537] | 296 | }
|
---|
| 297 | else if (responseErrorIndex != -1) {
|
---|
| 298 | var endIndex = result.indexOf("</error>");
|
---|
| 299 | var startIndex = result.indexOf(">", responseErrorIndex+1);
|
---|
| 300 | var error = result.substring(startIndex+1,endIndex);
|
---|
| 301 | errormessage="ERROR: Unable to add comment. " + error;
|
---|
[31543] | 302 | document.getElementById("usercommentfeedback").innerHTML = errormessage;
|
---|
[31537] | 303 | }
|
---|
| 304 | else { // success!
|
---|
[31559] | 305 | document.getElementById("usercommentfeedback").innerHTML = gs.variables["textcommentsubmitted"]; ///"_textcommentsubmitted_" in GS2
|
---|
[31537] | 306 |
|
---|
| 307 | // update display of existing user comments to show the newly added comment
|
---|
| 308 | var usercommentdiv = document.getElementById("usercomments");
|
---|
| 309 | if(usercommentdiv != undefined) {
|
---|
[31558] | 310 | gs.usercomments.displayInUserCommentList(usercommentdiv, _username, _timestamp, _comment);
|
---|
[31537] | 311 | }
|
---|
[31543] | 312 | }
|
---|
| 313 |
|
---|
| 314 | // whether there was an error or not, re-enable the submit button now
|
---|
| 315 | // that the set-meta-array operation has completed.
|
---|
| 316 | document.getElementById("usercommentSubmitButton").disabled = false;
|
---|
[31537] | 317 | }
|
---|
| 318 |
|
---|
[31558] | 319 | gs.usercomments.commentAreaSetup = function() {
|
---|
| 320 | gs.usercomments.loadUserComments();
|
---|
[31543] | 321 |
|
---|
[31537] | 322 | $("div#commentarea").html('<textarea required="required" name="comment" rows="10" cols="64" placeholder="Add your comment here..."></textarea>');
|
---|
| 323 |
|
---|
| 324 | }
|
---|
| 325 |
|
---|
| 326 |
|
---|
| 327 | // "Handlers added via $(document).ready() don't overwrite each other, but rather execute in turn"
|
---|
| 328 | // as explained at http://stackoverflow.com/questions/15564029/adding-to-window-onload-event
|
---|
[31543] | 329 | // This way we ensure we don't replace any other onLoad() functions, but append the loadUserComments()
|
---|
| 330 | // function to the existing set of eventhandlers called onDocReady
|
---|
[31558] | 331 | $(document).ready(gs.usercomments.commentAreaSetup);
|
---|
[31537] | 332 |
|
---|