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