source: main/trunk/greenstone3/web/interfaces/default/js/user_comments.js@ 38928

Last change on this file since 38928 was 38326, checked in by anupama, 8 months ago
  1. Confirmation dialog when deleting selected user comments. 2. The Delete Selected button should be unavailable if no user comments are checked.
File size: 28.7 KB
Line 
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
6// https://www.sitepoint.com/demystifying-javascript-closures-callbacks-iifes/
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/
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
14
15/***************
16* USER COMMENTS
17****************/
18
19// avoid making usercomments js functions global (which attaches them as properties to the window object)
20gs.usercomments = {};
21
22gs.usercomments.defaults = {
23 "metaname_username" : "username",
24 "metaname_usertimestamp": "usertimestamp",
25 "metaname_usercomment" : "usercomment"
26}
27
28// http://stackoverflow.com/questions/6312993/javascript-seconds-to-time-with-format-hhmmss
29// Call as: alert(timestamp.printTime());
30gs.usercomments.formatTime = function(timestamp) {
31 var int_timestamp = parseInt(timestamp, 10); // don't forget the second param
32 var date = new Date(int_timestamp);
33 return date.toLocaleDateString() + " " + date.toLocaleTimeString();
34}
35
36gs.usercomments.loadUserComments = function(opt_metaname_username, opt_metaname_usertimestamp, opt_metaname_usercomment) {
37
38 // don't bother loading comments if we're not on a document page (in which case there's no docid)
39 var doc_id = gs.variables["d"]; ///"_cgiargdJssafe_" in GS2
40
41 if(!doc_id) {
42 return;
43 }
44
45 // Don't allow the user to add comments (which calls set-meta-array) until we've finished loading all
46 // user comments (which calls get-meta-array). Since get-meta-array and set-meta-array are called
47 // asynchronously, this is to help prevent any overlap in these functions' access of meta files in
48 // index|archives|import.
49 // Prevent users from adding comments by disabling the submit button
50 // until existing comments have been retrieved and displayed
51 var submitButton = document.getElementById("usercommentSubmitButton");
52 if(submitButton) { // there'll be no submitButton if the comment form is not displayed (user not logged in)
53 submitButton.disabled = true;
54 }
55
56 // Since we have a docid, get toplevel section of the docid
57
58 var period = doc_id.indexOf(".");
59 if(period != -1) {
60 doc_id = doc_id.substring(0, period);
61 }
62
63 /* The current pattern of use (from usercomments.xsl) is to globally override/redefine
64 the metadata names in gs.usercomments.defaults{ values }. However, anticipating
65 future, more general use, loadUserComments() and addUserComment() have been written
66 with the ability to have optional parameters passed in the supersede the values in
67 gs.usercomments.defaults{} */
68
69 var username_rec = {
70 metaname: opt_metaname_username || gs.usercomments.defaults.metaname_username, // e.g. "username"
71 metapos: "all"
72 };
73
74 var timestamp_rec = {
75 metaname: opt_metaname_usertimestamp || gs.usercomments.defaults.metaname_usertimestamp, // e.g. "usertimestamp"
76 metapos: "all"
77 };
78
79 var comment_rec = {
80 metaname: opt_metaname_usercomment || gs.usercomments.defaults.metaname_usercomment, // e.g. "usercomment"
81 metapos: "all"
82 };
83
84 var doc_rec = {
85 docid: doc_id,
86 metatable: [username_rec, timestamp_rec, comment_rec]
87 };
88
89 var docArray = [doc_rec];
90
91 //var json_result_str = gs.functions.getMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "index");
92
93 gs.functions.getMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "index",
94 gs.usercomments.loadedUserComments, false); // false for asynchronous
95}
96
97
98gs.usercomments.loadedUserComments = function(data)
99{
100 // don't bother displaying comments if we're not on a document page
101 // (in which case there's no usercommentdiv).
102 // This shouldn't happen here, since we only call this from loadUserComments()
103 // and that first checks we're actually on a document page.
104 var usercommentdiv = document.getElementById("usercomments");
105 if(usercommentdiv == undefined || usercommentdiv == null) {
106 return;
107 }
108
109 // data is xmlHttpRequest Object if gsajaxapi is used for the ajax call.
110 // And data is a string if jQuery AJAX was used.
111 // Using JavaScript's feature sensing to detect which of the two we're dealing with:
112 var json_result_str = (data.responseText) ? data.responseText : data;
113
114 var result = JSON.parse(json_result_str);
115 // result contains only one docrec (result[0]), since we asked for the usercomments of one docid
116 var metatable = result[0].metatable;
117
118 var i = 0;
119 var looping = true;
120
121 var canDeleteComments = gs.variables["userCanDeleteComments"];
122
123 // if there's at least one existing comment OR if the form is currently being displayed
124 // (regardless of whether previous comments exist), display a heading for the comments section
125 if(metatable[0].metavals[0] != undefined || document.getElementById("usercommentform") != undefined) {
126 var heading=document.createElement("div");
127 var attr=document.createAttribute("class");
128 attr.nodeValue="usercommentheading";
129 heading.setAttributeNode(attr);
130 var txt=document.createTextNode(gs.variables["textusercommentssection"]); ///"_textusercommentssection_" in GS2
131 heading.appendChild(txt);
132 usercommentdiv.appendChild(heading);
133 }
134
135
136 // metatable[0] = list of usernames, metatable[1] = list of timestamps, metatable[2] = list of comments
137 // the 3 lists/arrays should be of even length. Assuming this, loop as long as there's another username
138 while(looping) {
139 var metaval_rec = metatable[0].metavals[i];
140 if(metaval_rec == undefined) {
141 looping = false;
142 }
143 else {
144
145 var username = metaval_rec.metavalue;
146 var timestamp = metatable[1].metavals[i].metavalue;
147 var comment = metatable[2].metavals[i].metavalue;
148
149 // No need to sort by time, as the meta are already stored sorted
150 // and hence retrieved in the right order by using the i (metapos) counter
151 // If sorting the array of comment records, which would be by timestamp, see
152 // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort
153
154 // for each usercomment, create a child div with the username, timestamp and comment
155 gs.usercomments.displayInUserCommentList(usercommentdiv, username, timestamp, comment, canDeleteComments, i);
156
157 i++;
158 }
159 }
160
161 if(canDeleteComments != 0) {
162 var delButtonDiv = document.createElement("div");
163 delButtonDiv.setAttribute("id", "del-button-div");
164 var delCommentsButton = document.createElement("button");
165 delCommentsButton.innerHTML = "Delete selected";
166 delCommentsButton.setAttribute("id", "del-selected-comments-button");
167 //delCommentsButton.setAttribute("onclick", gs.usercomments.deleteSelectedComments);
168 // alternatively: https://www.w3schools.com/jsref/met_element_addeventlistener.asp
169
170 delCommentsButton.addEventListener("click", gs.usercomments.removeSelectedComments);
171 // Arduous way: deletes each metadata individually
172 //delCommentsButton.addEventListener("click", gs.usercomments.deleteSelectedComments);
173 delCommentsButton.disabled = true;
174 delButtonDiv.appendChild(delCommentsButton);
175
176 var prevNode = document.getElementById("usercomments");
177 gs.usercomments.insertAfter(delButtonDiv, prevNode);
178 }
179
180 var submitButton = document.getElementById("usercommentSubmitButton");
181 // Now we've finished loading all user comments,
182 // allow the user to add a comment by enabling the submit button again
183 if(submitButton) {
184 submitButton.disabled = false;
185 }
186}
187
188
189// https://www.javascripttutorial.net/javascript-dom/javascript-insertafter/
190gs.usercomments.insertAfter = function(newNode, existingNode) {
191 existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling);
192}
193
194gs.usercomments.displayInUserCommentList = function(usercommentdiv, username, timestamp, comment, canDeleteComments, metapos) {
195
196 if(metapos == undefined) {
197 metapos = document.querySelectorAll('div[class=usercomment]').length;
198 }
199
200 var divgroup=document.createElement("div");
201 var attr=document.createAttribute("class");
202 attr.nodeValue="usercomment";
203 divgroup.setAttributeNode(attr);
204
205 var divuser=document.createElement("div");
206 var divtime=document.createElement("div");
207 var divcomment=document.createElement("div");
208
209 if(canDeleteComments != 0) {
210 var deleteCheckBox = document.createElement("input");
211 deleteCheckBox.style.cssFloat = "left";
212 deleteCheckBox.setAttribute("type", "checkbox");
213 deleteCheckBox.setAttribute("class", "del-me-comment");
214 deleteCheckBox.setAttribute("data-metapos", metapos);
215 //deleteCheckBox.setAttribute("data-username", username);
216 //deleteCheckBox.setAttribute("data-timestamp", timestamp);
217 //deleteCheckBox.setAttribute("data-comment", comment);
218 divgroup.appendChild(deleteCheckBox);
219
220 //deleteCheckBox.setAttribute("checked", false); // why does this check the box?
221 deleteCheckBox.addEventListener('change', function() {
222 var delCommentsButton = document.getElementById("del-selected-comments-button");
223 if(delCommentsButton.disabled && this.checked) {
224 delCommentsButton.disabled = false;
225 } else if(!this.checked) { //if we just unchecked current checkbox
226 // only disable DeleteSelected button if all other checkboxes are all unchecked
227 var selectedComments = document.querySelectorAll('input[class=del-me-comment][type=checkbox]:checked');
228 if(selectedComments.length <= 0) {
229 delCommentsButton.disabled = true;
230 }
231 }
232 });
233 }
234
235 divgroup.appendChild(divuser);
236 var txt=document.createTextNode(username);
237
238 divuser.appendChild(txt);
239
240 divgroup.appendChild(divtime);
241 txt=document.createTextNode(gs.usercomments.formatTime(timestamp)); // format timestamp for date/time display
242 divtime.appendChild(txt);
243
244 // any quotes and colons in the fields would have been protected for transmitting as JSON
245 // so decode their entity values
246 comment = comment.replace(/&quot;/gmi, '"');
247 comment = comment.replace(/&58;/gmi, ':');
248
249 divgroup.appendChild(divcomment);
250 txt=document.createTextNode(comment);
251 divcomment.appendChild(txt);
252
253 usercommentdiv.appendChild(divgroup);
254
255}
256
257// Uses remove array to remove multiple metadata in one ajax call
258gs.usercomments.removeSelectedComments = function(eventObject, opt_metaname_username, opt_metaname_usertimestamp, opt_metaname_usercomment)
259{
260 // https://sabe.io/blog/javascript-yes-no-confirmation-box
261 var confirmResponse = confirm("Are you sure you want to delete the selected user comment(s)?");
262 if (!confirmResponse) { // user cancelled
263 return;
264 }
265
266
267 // https://stackoverflow.com/questions/590018/getting-all-selected-checkboxes-in-an-array
268 // https://stackoverflow.com/questions/6166763/jquery-multiple-checkboxes-array
269
270 var selectedComments = document.querySelectorAll('input[class=del-me-comment][type=checkbox]:checked');
271
272 if(selectedComments.length > 0) {
273
274 // Don't allow the user to submit further comments or delete comments
275 // until the metadata has been updated
276 document.getElementById("usercommentSubmitButton").disabled = true;
277 var delCommentsButton = document.getElementById("del-selected-comments-button");
278 if(delCommentsButton != undefined) {// should be defined when in this function
279 delCommentsButton.disabled = true;
280 }
281
282 // User comment meta are at topmost section of the document.
283 // So only get the docId up to any period mark:
284 var _docid = document.AddUserCommentForm.d.value;
285 var period = _docid.indexOf(".");
286 if(period != -1) {
287 _docid = _docid.substring(0, period);
288 }
289
290 //document.querySelectorAll('input[class=del-me-comment][type=checkbox]:checked').forEach(elem => console.log(elem.getAttribute('data-metapos')));
291
292 var metadataPositions = [];
293 var failure = false;
294
295 // remove-metadata-array perl functions now ensure metapos array
296 // is sorted in descending order
297 for (var i = 0; i < selectedComments.length; i++) {
298 var metapos = selectedComments[i].getAttribute("data-metapos");
299 metadataPositions.push(metapos);
300 //metadataPositions.unshift(metapos); // add metapos to start of array
301 }
302
303 /*
304 for (var i = selectedComments.length - 1; i >= 0; i--) {
305 var metapos = selectedComments[i].getAttribute("data-metapos");
306 metadataPositions.push(metapos); // add next lowest metapos to end of array
307 }
308 */
309 }
310
311 // now we have all the metapositions we need to delete
312 // create a JSON of indicating the username, timestamp and comment metadata need to be deleted
313 // at all those metapositions
314
315 // removeMetadataArray escapes the entire JSON, so we don't individually escape the fields here
316
317 // For creating the JSON object that gets turned into a string, see
318 // http://msdn.microsoft.com/en-us/library/ie/cc836459%28v=vs.94%29.aspx
319 // http://jsfiddle.net/qmacro/W54hy/
320
321 var username_rec = {
322 metaname: opt_metaname_username || gs.usercomments.defaults.metaname_username, // e.g. "username"
323 metapositions: metadataPositions
324 };
325
326 var timestamp_rec = {
327 metaname: opt_metaname_usertimestamp || gs.usercomments.defaults.metaname_usertimestamp, // e.g. "usertimestamp"
328 metapositions: metadataPositions
329 };
330
331 var comment_rec = {
332 metaname: opt_metaname_usercomment || gs.usercomments.defaults.metaname_usercomment, // e.g. "usercomment"
333 metapositions: metadataPositions
334 };
335
336 var doc_rec = {
337 docid: _docid,
338 metatable: [username_rec, timestamp_rec, comment_rec],
339 //metamode: "accumulate"
340 };
341
342 var docArray = [doc_rec];
343
344 // Don't allow the user to submit further comments or delete any
345 // until the metadata has been updated
346 document.getElementById("usercommentSubmitButton").disabled = true;
347 var delCommentsButton = document.getElementById("del-selected-comments-button");
348 if(delCommentsButton != undefined) {
349 delCommentsButton.disabled = true;
350 }
351
352 console.log("About to remove usercomments at metapositions: " + metadataPositions);
353
354 gs.functions.removeMetadataArray(
355 gs.variables["c"],
356 gs.variables["site"],
357 docArray,
358 null, //metamode
359 "import|archives|index",
360 function(ajaxResult) { return gs.usercomments.doneRemovingMetadata(ajaxResult, metadataPositions); },
361 false, // false for asynchronous, see comment in gs.usercomments.addUserComment()
362 function(ajaxError) { return gs.usercomments.removeMultipleCommentsFailed(ajaxError); }
363 );
364
365 //console.log("metapositions to remove: " + metadataPositions);
366 //console.log("docArray:\n" + JSON.stringify(docArray));
367}
368
369gs.usercomments.removeMultipleCommentsFailed = function(data) {
370 var result = (data.responseText) ? data.responseText : data;
371 alert("Remove failed. Got: " + result);
372 failure = true;
373
374 // TODO, force a page reload so that the usercomments' state somewhat better reflects what's in DBs
375 location.reload();
376}
377
378
379// Removes single metadata at a time
380gs.usercomments.deleteSelectedComments = function() {
381 // https://stackoverflow.com/questions/590018/getting-all-selected-checkboxes-in-an-array
382 // https://stackoverflow.com/questions/6166763/jquery-multiple-checkboxes-array
383
384 var selectedComments = document.querySelectorAll('input[class=del-me-comment][type=checkbox]:checked');
385
386 if(selectedComments.length > 0) {
387
388 // Don't allow the user to submit further comments or delete comments
389 // until the metadata has been updated
390 document.getElementById("usercommentSubmitButton").disabled = true;
391 var delCommentsButton = document.getElementById("del-selected-comments-button");
392 if(delCommentsButton != undefined) {// should be defined when in this function
393 delCommentsButton.disabled = true;
394 }
395
396 // User comment meta are at topmost section of the document.
397 // So only get the docId up to any period mark:
398 var _docid = document.AddUserCommentForm.d.value;
399 var period = _docid.indexOf(".");
400 if(period != -1) {
401 _docid = _docid.substring(0, period);
402 }
403
404 //document.querySelectorAll('input[class=del-me-comment][type=checkbox]:checked').forEach(elem => console.log(elem.getAttribute('data-username')));
405
406 var modifiedMetapos = [];
407 var failure = false;
408
409 // start deleting from end of metadata list, so we don't have to recalculate metapos each time
410 for (var i = selectedComments.length-1; i >= 0; i--) {
411
412 var metapos = selectedComments[i].getAttribute("data-metapos");
413 //var username = selectedComments[i].getAttribute("data-username");
414 //var timestamp = selectedComments[i].getAttribute("data-timestamp");
415 //var comment = selectedComments[i].getAttribute("data-comment");
416 //console.log("metapos: " + metapos);
417
418 // There is no remove array version yet!!!
419
420 //var result = gs.functions.removeMetadataAtPos(gs.variables["c"], gs.variables["site"], docArray, "accumulate", "import|archives|index");
421 gs.functions.removeMetadataAtPos(gs.variables["c"],
422 gs.variables["site"],
423 _docid,
424 gs.usercomments.defaults.metaname_username,
425 metapos,
426 //"import|archives|index",
427 null, //function(ajaxResult) { alert(ajaxResult); },
428 function(ajaxError) { return gs.usercomments.removeFailed(ajaxError, metapos); },
429 true); // true for synchronous, meaning is opposite to explanation for addUserComment() function below
430
431 if(failure) {
432 continue;
433 }
434 gs.functions.removeMetadataAtPos(gs.variables["c"],
435 gs.variables["site"],
436 _docid,
437 gs.usercomments.defaults.metaname_usertimestamp,
438 metapos,
439 //"import|archives|index",
440 null, //function(ajaxResult) { alert(ajaxResult); },
441 function(ajaxError) { return gs.usercomments.removeFailed(ajaxError, metapos); },
442 true); // true for synchronous, meaning is opposite to explanation for addUserComment() function below
443
444 if(failure) {
445 continue;
446 }
447 gs.functions.removeMetadataAtPos(gs.variables["c"],
448 gs.variables["site"],
449 _docid,
450 gs.usercomments.defaults.metaname_usercomment,
451 metapos,
452 //"import|archives|index",
453 null, //function(ajaxResult) { alert(ajaxResult); },
454 function(ajaxError) { return gs.usercomments.removeFailed(ajaxError, metapos); },
455 true); // true for synchronous, meaning is opposite to explanation for addUserComment() function below
456
457
458 gs.usercomments.removedMetadata(metapos, modifiedMetapos);
459 failure = false; // reinitialise
460 }
461
462 //console.log("modifiedMetapos: " + modifiedMetapos);
463
464 gs.usercomments.doneRemovingMetadata(null, modifiedMetapos);
465 }
466}
467
468
469gs.usercomments.removedMetadata = function(metapos, modifiedMetapos) {
470 modifiedMetapos.unshift(metapos); // add metapos to start of array
471}
472
473gs.usercomments.removeFailed = function(data, metapos) {
474 var result = (data.responseText) ? data.responseText : data;
475 alert("Remove failed. Got: " + result);
476 failure = true;
477}
478
479gs.usercomments.doneRemovingMetadata = function(data, modifiedMetapos) {
480
481 // data is xmlHttpRequest Object if gsajaxapi is used for the ajax call.
482 // And data is a string if jQuery AJAX was used.
483 // Using JavaScript's feature sensing to detect which of the two we're dealing with:
484 var result = (data.responseText) ? data.responseText : data;
485
486 /*
487 // check for gsdl_cgi->generate_error() result, which ends up in a silent die statement
488 // unless we look for it in the "success" result, in the form of a message starting
489 // with "ERROR:"
490 if(result.indexOf("ERROR: ") !== -1 || result.indexOf("<Error>") !== -1) {
491 gs.usercomments.removeMultipleCommentsFailed(data);
492 return;
493 }
494 */
495
496 //console.log("@@@ Done removing metadata:\n" + result);
497
498 var userCommentsDiv = document.getElementById("usercomments");
499
500 // modifiedMetaPos has all the positions for usercomments metadata that need to be removed, in normal (ascending) order
501 // So start at end, removing usercomments with highest metapos
502 for (var i = modifiedMetapos.length-1; i >= 0; i--) {
503 var metapos = modifiedMetapos[i];
504
505 //console.log("About to remove usercomment at metapos " + metapos);
506
507 // find the checkbox with data-metapos=metapos and delete its username, timestamp, comment
508 var removeUserCommentForCheckbox = document.querySelector("input[data-metapos=\""+metapos+"\"]");
509 var usercommentDivToRemove = removeUserCommentForCheckbox.parentElement; // get the <div class="usercomment"/> above this checkbox
510 userCommentsDiv.removeChild(usercommentDivToRemove);
511 }
512
513 // Now re-number the metapos for all the input class=del-me-comment
514 var usercommentCheckboxes = document.querySelectorAll('input[class=del-me-comment][type=checkbox]');
515 for (var i = 0; i < usercommentCheckboxes.length; i++) {
516 usercommentCheckboxes[i].setAttribute("data-metapos", i);
517 }
518
519 // whether there was an error or not, re-enable the submit button now
520 // that the removeMetadata ajax operations have completed.
521 document.getElementById("usercommentSubmitButton").disabled = false;
522
523 var delCommentsButton = document.getElementById("del-selected-comments-button");
524 if(delCommentsButton != undefined) {
525 var delCheckboxes = document.querySelectorAll('input[class=del-me-comment][type=checkbox]');
526 if(delCheckboxes.length <= 0) {
527 delCommentsButton.disabled = true;
528 }
529 }
530}
531
532
533gs.usercomments.addUserComment = function(_username, _comment, _docid, doc,
534 opt_metaname_username, opt_metaname_usertimestamp, opt_metaname_usercomment) {
535
536 // don't add empty strings for name/comment
537
538 // http://stackoverflow.com/questions/498970/how-do-i-trim-a-string-in-javascript
539 //var trimmed_username=_username.replace(/^\s+|\s+$/g, '');
540 var trimmed_comment = _comment.replace(/^\s+|\s+$/g, '');
541
542 if(!trimmed_comment) {
543 doc.AddUserCommentForm.comment.value = "";
544 //document.AddUserCommentForm.username.value = "";
545 document.getElementById("usercommentfeedback").innerHTML = gs.variables["textisempty"]; ///"_textisempty_" in GS2
546 return;
547 }
548
549 // Need to the add user comment meta of username, timestamp and comment to the
550 // topmost section of the document. So only get the docId up to any period mark:
551 var period = _docid.indexOf(".");
552 if(period != -1) {
553 _docid = _docid.substring(0, period);
554 }
555
556
557 // Want to store username, timestamp and comment in import/metadata.xml, archives/doc.xml
558 // and index/col.gdb.
559
560 // For getting the current time, see
561 // http://stackoverflow.com/questions/3830244/get-current-date-time-in-seconds
562 var _timestamp = new Date().getTime(); // div by 1000 to get seconds. valueOf() may return string
563
564 // setMetadataArray escapes the entire JSON, so we don't individually escape the fields here
565 // If we did, and called gsapi.setMetadata or gs.functions (in javascript-global-functions.js) instead,
566 // then resort to escaping first, e.g.
567 // _comment = escape(_comment);
568 // gsapi.setMetadata(_docid, "usercomment", null, _comment, "accumulate", "import|archives|index");
569
570
571 // Use the new JSON metatable format to set username, timestamp and comment meta for docid in one go
572
573 // For creating the JSON object that gets turned into a string, see
574 // http://msdn.microsoft.com/en-us/library/ie/cc836459%28v=vs.94%29.aspx
575 // http://jsfiddle.net/qmacro/W54hy/
576
577 var username_rec = {
578 metaname: opt_metaname_username || gs.usercomments.defaults.metaname_username, // e.g. "username"
579 metavals: [_username]
580 };
581
582 var timestamp_rec = {
583 metaname: opt_metaname_usertimestamp || gs.usercomments.defaults.metaname_usertimestamp, // e.g. "usertimestamp"
584 metavals: [_timestamp]
585 };
586
587 var comment_rec = {
588 metaname: opt_metaname_usercomment || gs.usercomments.defaults.metaname_usercomment, // e.g. "usercomment"
589 metavals: [_comment]
590 };
591
592 var doc_rec = {
593 docid: _docid,
594 metatable: [username_rec, timestamp_rec, comment_rec],
595 metamode: "accumulate"
596 };
597
598 var docArray = [doc_rec];
599
600 // Don't allow the user to submit further comments or delete any
601 // until the metadata has been updated
602 document.getElementById("usercommentSubmitButton").disabled = true;
603 var delCommentsButton = document.getElementById("del-selected-comments-button");
604 if(delCommentsButton != undefined) {
605 delCommentsButton.disabled = true;
606 }
607
608 //var result = gs.functions.setMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "accumulate", "import|archives|index");
609 gs.functions.setMetadataArray(gs.variables["c"],
610 gs.variables["site"],
611 docArray, "accumulate",
612 "import|archives|index",
613 function(ajaxResult) { return gs.usercomments.doneUpdatingMetatada(ajaxResult, _username, _timestamp, _comment); },
614 false); // false for asynchronous,
615 // async here is ok since we're disabling the comment submit button, so no further set-meta-array calls
616 // can be made until the ajax call returns and the callback is called which re-enables the submit button
617 // But disabling submit does not protect against concurrent access such as someone else editing the
618 // document (doing set-meta operations, updating archives/index/import) at the same time as someone else
619 // adding user comments (doing set-meta-array, updating archives|index|import).
620
621}
622
623gs.usercomments.doneUpdatingMetatada = function(data, _username, _timestamp, _comment)
624{
625 // data is xmlHttpRequest Object if gsajaxapi is used for the ajax call.
626 // And data is a string if jQuery AJAX was used.
627 // Using JavaScript's feature sensing to detect which of the two we're dealing with:
628 var result = (data.responseText) ? data.responseText : data;
629
630 // clear the comment field as it has now been submitted, but not the username field
631 // as the user is logged in, so they should be able to commit again under their username.
632 document.AddUserCommentForm.comment.value = "";
633
634 // check for locked collection error
635 var errorIndex = result.indexOf("ERROR");
636 // check for any error discovered on the server side
637 var responseErrorIndex = result.indexOf("<error");
638
639 if(errorIndex != -1) {
640 var endIndex = result.indexOf("\\n");
641 var error = result.substring(errorIndex,endIndex);
642 errormessage="ERROR: Unable to add comment. " + error;
643 document.getElementById("usercommentfeedback").innerHTML = errormessage;
644 }
645 else if (responseErrorIndex != -1) {
646 var endIndex = result.indexOf("</error>");
647 var startIndex = result.indexOf(">", responseErrorIndex+1);
648 var error = result.substring(startIndex+1,endIndex);
649 errormessage="ERROR: Unable to add comment. " + error;
650 document.getElementById("usercommentfeedback").innerHTML = errormessage;
651 }
652 else { // success!
653 document.getElementById("usercommentfeedback").innerHTML = gs.variables["textcommentsubmitted"]; ///"_textcommentsubmitted_" in GS2
654
655 // update display of existing user comments to show the newly added comment
656 var usercommentdiv = document.getElementById("usercomments");
657 if(usercommentdiv != undefined) {
658 gs.usercomments.displayInUserCommentList(usercommentdiv, _username, _timestamp, _comment);
659 }
660 }
661
662 // whether there was an error or not, re-enable the submit button now
663 // that the set-meta-array operation has completed.
664 document.getElementById("usercommentSubmitButton").disabled = false;
665 var delCommentsButton = document.getElementById("del-selected-comments-button");
666 if(delCommentsButton != undefined) {
667 var selectedComments = document.querySelectorAll('input[class=del-me-comment][type=checkbox]:checked');
668 if(selectedComments.length <= 0) {
669 delCommentsButton.disabled = true;
670 } else {
671 delCommentsButton.disabled = false;
672 }
673 }
674}
675
676gs.usercomments.commentAreaSetup = function() {
677 gs.usercomments.loadUserComments();
678
679 $("div#commentarea").html('<textarea required="required" name="comment" rows="10" cols="64" placeholder="Add your comment here..."></textarea>');
680
681}
682
683
684// "Handlers added via $(document).ready() don't overwrite each other, but rather execute in turn"
685// as explained at http://stackoverflow.com/questions/15564029/adding-to-window-onload-event
686// This way we ensure we don't replace any other onLoad() functions, but append the loadUserComments()
687// function to the existing set of eventhandlers called onDocReady
688$(document).ready(gs.usercomments.commentAreaSetup);
689
Note: See TracBrowser for help on using the repository browser.