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

Last change on this file since 32127 was 31559, checked in by ak19, 7 years ago

Clean up phase for GS3 add user comments. Removed unwanted code, but only commenting out debug statements. Will get rid of debug statements after user comments tested to work successfully on GS3 Windows.

File size: 13.6 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
22// http://stackoverflow.com/questions/6312993/javascript-seconds-to-time-with-format-hhmmss
23// Call as: alert(timestamp.printTime());
24gs.usercomments.formatTime = function(timestamp) {
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
30gs.usercomments.loadUserComments = function() {
31
32 // don't bother loading comments if we're not on a document page (in which case there's no docid)
33 var doc_id = gs.variables["d"]; ///"_cgiargdJssafe_" in GS2
34
35 if(!doc_id) {
36 return;
37 }
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.
43 // Prevent users from adding comments by disabling the submit button
44 // until existing comments have been retrieved and displayed
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
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
79 //var json_result_str = gs.functions.getMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "index");
80
81 gs.functions.getMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "index", gs.usercomments.loadedUserComments, false); // false for asynchronous
82}
83
84gs.usercomments.loadedUserComments = function(data)
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
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
100 //console.log("Got user comments to display: " + json_result_str);
101
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;
105
106 var i = 0;
107 var looping = true;
108
109
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);
117 var txt=document.createTextNode(gs.variables["textusercommentssection"]); ///"_textusercommentssection_" in GS2
118 heading.appendChild(txt);
119 usercommentdiv.appendChild(heading);
120 }
121
122
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;
129 }
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
142 gs.usercomments.displayInUserCommentList(usercommentdiv, username, timestamp, comment);
143
144 i++;
145 }
146 }
147
148 var submitButton = document.getElementById("usercommentSubmitButton");
149 // Now we've finished loading all user comments,
150 // allow the user to add a comment by enabling the submit button again
151 if(submitButton) {
152 submitButton.disabled = false;
153 }
154}
155
156
157gs.usercomments.displayInUserCommentList = function(usercommentdiv, username, timestamp, comment) {
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);
174 txt=document.createTextNode(gs.usercomments.formatTime(timestamp)); // format timestamp for date/time display
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
190gs.usercomments.addUserComment = function(_username, _comment, _docid, doc) {
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
198 if(!trimmed_comment) {
199 doc.AddUserCommentForm.comment.value = "";
200 //document.AddUserCommentForm.username.value = "";
201 document.getElementById("usercommentfeedback").innerHTML = gs.variables["textisempty"]; ///"_textisempty_" in GS2
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
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");
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
256 // Don't allow the user to submit further comments until the metadata has been updated
257 document.getElementById("usercommentSubmitButton").disabled = true;
258
259
260 //var result = gs.functions.setMetadataArray(gs.variables["c"], gs.variables["site"], docArray, "accumulate", "import|archives|index");
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,
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
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
275gs.usercomments.doneUpdatingMetatada = function(data, _username, _timestamp, _comment)
276{
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
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.
284 document.AddUserCommentForm.comment.value = "";
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;
295 document.getElementById("usercommentfeedback").innerHTML = errormessage;
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;
302 document.getElementById("usercommentfeedback").innerHTML = errormessage;
303 }
304 else { // success!
305 document.getElementById("usercommentfeedback").innerHTML = gs.variables["textcommentsubmitted"]; ///"_textcommentsubmitted_" in GS2
306
307 // update display of existing user comments to show the newly added comment
308 var usercommentdiv = document.getElementById("usercomments");
309 if(usercommentdiv != undefined) {
310 gs.usercomments.displayInUserCommentList(usercommentdiv, _username, _timestamp, _comment);
311 }
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;
317}
318
319gs.usercomments.commentAreaSetup = function() {
320 gs.usercomments.loadUserComments();
321
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
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
331$(document).ready(gs.usercomments.commentAreaSetup);
332
Note: See TracBrowser for help on using the repository browser.