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

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