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

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