source: main/trunk/greenstone3/web/interfaces/default/js/documentedit_scripts.js@ 32853

Last change on this file since 32853 was 32853, checked in by ak19, 5 years ago

Cleanup stage one: 1. Not calling addFunctionalityToTable() on GPSmapcontainer, and no need for a cutdown addFunctionalityToGPSMap(), since the GPS map editor doesn't use any of the added functionality anyway, going out of its way to set the css to display:hide on all the added functionality (metaNameField, addRowButton and addAllButton). 2. Selecting divs that have attribute contenteditable='true' rather than all elements with .sectionText class to get a list of all the editable elements that will get converted to CKEditors. I think it's only divs that have contenteditable set to true, in which case don't need to look for any and all elements with that attribute and value. 3. Some cleanup.

File size: 17.8 KB
Line 
1/** Javascript file for editing a single document's content - metadata and text */
2/** uses other functions in documentedit_scripts_util.js */
3
4/* some vars for document editing */
5/* if true, will look through all the metadata for the document, and add each namespace into the list of metadata sets. If set to false, will only add in the ones defined in setStaticMetadataSets function (defined below) - override this function to make a custom list of sets */
6var dynamic_metadata_set_list = true;
7/* if false, will hide the metadata list selector. So the user will only get to see the default metadata set. */
8var display_metadata_set_selector = true;
9/* if true, will make the editing controls stay visible even on page scrolling */
10var keep_editing_controls_visible = true;
11/* Here you can choose which save buttons you like. Choose from 'save', 'rebuild', 'saveandrebuild' */
12var save_and_rebuild_buttons = ["saveandrebuild"];
13//var save_and_rebuild_buttons = ["save", "rebuild", "saveandrebuild"];
14
15/* What kind of metadata element selection do we provide?
16plain: just a text input box
17fixedlist: a drop down menu with a fixed list of options (provided by the availableMetadataElements list)
18autocomplete: a text input box with a list of suggestions to choose from (provided by the availableMetadataElements list). Allows additional input other than the fixed list
19 */
20var new_metadata_field_input_type = "plain";
21/* add all metadata button? only valid with fixedlist or autocomplete metadata element selection */
22var enable_add_all_metadata_button = true;
23
24/* Metadata elements to be used in the fixedlist/autocomplete options above */
25var availableMetadataElements = ["dc.Title", "dc.Subject"];
26/* metadata elements that have a list of values/suggestions */
27var autocompleteMetadata = new Array();
28/* for each metadata element specified here, one should provide an array of values. The name is the meta_name + "_values", but you must strip . and _ from the name.
29for example
30var autocompleteMetadata = ["dc.Subject"];
31var dcSubject_values = ["Kings", "Queens", "others"];
32 */
33
34/* The metadata specified in multiValuedMetadata array will be treated as a delimited list, using mvm_delimiter. On saving, the values will be separated and saved individually */
35
36var multiValuedMetadata = new Array(); // eg ["xx.Person", "xx.Location"];
37var mvm_delimiter = ";";
38
39/************************
40 * METADATA EDIT SCRIPTS *
41 ************************/
42
43function addEditMetadataLink(cell) {
44 cell = $(cell);
45 var id = cell.attr("id").substring(6);
46 var metaTable = gs.jqGet("meta" + id);
47 var row = cell.parent();
48 var newCell = $("<td>", {
49 "style": "font-size:0.7em; padding:0px 10px",
50 "class": "editMetadataButton"
51 });
52 var linkSpan = $("<span>", {
53 "class": "ui-state-default ui-corner-all",
54 "style": "padding: 2px; float:left;"
55 });
56
57 var linkLabel = $("<span>" + gs.text.de.edit_metadata + "</span>");
58 var linkIcon = $("<span>", {
59 "class": "ui-icon ui-icon-folder-collapsed"
60 });
61 newCell.linkIcon = linkIcon;
62 newCell.linkLabel = linkLabel;
63
64 var uList = $("<ul>", {
65 "style": "outline: 0 none; margin:0px; padding:0px;"
66 });
67 var labelItem = $("<li>", {
68 "style": "float:left; list-style:none outside none;"
69 });
70 var iconItem = $("<li>", {
71 "style": "float:left; list-style:none outside none;"
72 });
73
74 uList.append(iconItem);
75 uList.append(labelItem);
76 labelItem.append(linkLabel);
77 iconItem.append(linkIcon);
78
79 var newLink = $("<a>", {
80 "href": "javascript:;"
81 });
82 newLink.click(function () {
83 if (metaTable.css("display") == "none") {
84 linkLabel.html(gs.text.de.hide_metadata);
85 linkIcon.attr("class", "ui-icon ui-icon-folder-open");
86 metaTable.css("display", "block");
87 metaTable.metaNameField.css("display", "inline");
88 metaTable.addRowButton.css("display", "inline");
89 if (enable_add_all_metadata_button == true) {
90 metaTable.addAllButton.css("display", "inline");
91 }
92 } else {
93 linkLabel.html(gs.text.de.edit_metadata);
94 linkIcon.attr("class", "ui-icon ui-icon-folder-collapsed");
95 metaTable.css("display", "none");
96 metaTable.metaNameField.css("display", "none");
97 metaTable.addRowButton.css("display", "none");
98 if (enable_add_all_metadata_button == true) {
99 metaTable.addAllButton.css("display", "none");
100 }
101 }
102 });
103
104 newLink.append(uList);
105 linkSpan.append(newLink);
106 newCell.append(linkSpan);
107 row.append(newCell);
108
109 addFunctionalityToTable(metaTable);
110 metaTable.metaNameField.css("display", "none");
111 metaTable.addRowButton.css("display", "none");
112 if (enable_add_all_metadata_button == true) {
113 metaTable.addAllButton.css("display", "none");
114 }
115}
116
117var gsmap_store = {};
118var gps_metadata_name = "GPS.mapOverlay";
119
120// Called by documentedit_scripts_util.js when saving and rebuilding.
121// This function should return all the doc sections' map overlay data so that
122// setArchivesMetadata can be called for each and the entire collection rebuilt with the changes
123function getDocMapsEditDataForSaving(collName) {
124 var map_editors_array = Object.values(gsmap_store);
125 var modifiedMaps = []; // the array that is the return value: an array of only all the modified maps
126
127
128 for(var i = 0; i < map_editors_array.length; i++) {
129 var map_editor = map_editors_array[i];
130 var oldMapData = map_editor.savedOverlays; // stringified JSON shape
131 var newMapData = JSON.stringify(ShapesUtil.overlayToJSON(map_editor.overlays)); // stringified JSON shape too
132
133 // We only consider a map editor's map data to have been modified in the following cases:
134 // - if oldMapData is null, new mapData should not be empty array
135 // - OR oldMapData had some value and it's not the same as newMapData
136 if(!oldMapData && newMapData !== "[]" || oldMapData && oldMapData !== newMapData) {
137 var nodeID = map_editors_array[i].id;
138 //console.log("old vs new mapdata for nodeID " + nodeID);
139 //console.log("OLD: " + oldMapData);
140 //console.log("NEW: " + newMapData);
141
142 modifiedMaps.push({
143 collection: collName,
144 docID: nodeID,
145 name:gps_metadata_name,
146 metapos: 0,
147 value:newMapData
148 });
149
150 // Save the new overlay values as the old ones for the state after saving and rebuilding is done.
151 // Ideally this should be do after saveAndRebuild has completed successfully, since if saveAndRebuild goes wrong
152 // we'd not have saved newMapData AND because savedOverlays will contain the newMapData, we won't detect these unsaved
153 // values in future attempts to save.
154 // But for now, we're doing this here *because* this is the procedure with regular metadata (works out changes,
155 // then saves those changes as initStates BEFORE saveAndRebuild is called)
156 map_editor.savedOverlays = newMapData;
157 }
158
159 }
160
161 return modifiedMaps;
162}
163
164
165function addEditMapGPSLink(cell) {
166 cell = $(cell);
167 var id = cell.attr("id").substring(6);
168 //console.log(id);
169 var mapGPScontainer = gs.jqGet("map-and-controls-" + id);
170 var row = cell.parent();
171 var newCell = $("<td>", {
172 "style": "font-size:0.7em; padding:0px 10px",
173 "class": "editMapGPSButton"
174 });
175 var linkSpan = $("<span>", {
176 "class": "ui-state-default ui-corner-all",
177 "style": "padding: 2px; float:left;"
178 });
179
180 var linkLabel = $("<span>" + gs.text.de.edit_map_gps + "</span>");
181 var linkIcon = $("<span>", {
182 "class": "ui-icon ui-icon-folder-collapsed"
183 });
184 newCell.linkIcon = linkIcon;
185 newCell.linkLabel = linkLabel;
186
187 var uList = $("<ul>", {
188 "style": "outline: 0 none; margin:0px; padding:0px;"
189 });
190 var labelItem = $("<li>", {
191 "style": "float:left; list-style:none outside none;"
192 });
193 var iconItem = $("<li>", {
194 "style": "float:left; list-style:none outside none;"
195 });
196
197 uList.append(iconItem);
198 uList.append(labelItem);
199 labelItem.append(linkLabel);
200 iconItem.append(linkIcon);
201
202 var mapEditor = new MapEditor(id);
203 gsmap_store["map-" + id] = mapEditor;
204
205 var newLink = $("<a>", {
206 "href": "javascript:;"
207 });
208 newLink.click(function () {
209 //console.log(" Show/Hide Map Editor ");
210 var clicked_mapEditor = gsmap_store["map-" + id];
211
212 if (clicked_mapEditor.map == null) {
213 clicked_mapEditor.initMapEditorControls();
214 clicked_mapEditor.initMapEditor();
215 }
216 if (mapGPScontainer.css("display") == "none") {
217 linkLabel.html(gs.text.de.hide_map_gps);
218 linkIcon.attr("class", "ui-icon ui-icon-folder-open");
219 mapGPScontainer.css("display", "block");
220 } else {
221 linkLabel.html(gs.text.de.edit_map_gps);
222 linkIcon.attr("class", "ui-icon ui-icon-folder-collapsed");
223 mapGPScontainer.css("display", "none");
224
225 }
226 });
227
228 newLink.append(uList);
229 linkSpan.append(newLink);
230 newCell.append(linkSpan);
231 row.append(newCell);
232
233 mapGPScontainer.css("display", "none");
234
235}
236
237function setEditingFeaturesVisible(visible) {
238 if (visible) {
239 $("#editContentButton").html(gs.text.de.hide_editor);
240 $("#editContentButtonDiv").attr("class", "ui-state-default ui-corner-all");
241 } else {
242 $("#editContentButton").html(gs.text.de.edit_content);
243 $("#editContentButtonDiv").attr("class", "");
244 }
245
246 var visibility = (visible ? "" : "none");
247 if (display_metadata_set_selector == true) {
248 $("#metadataListLabel, #metadataSetList").css("display", visibility);
249 }
250
251 $(".editMetadataButton").each(function () {
252 $(this).css("display", visibility);
253 $(this.linkLabel).html(gs.text.de.edit_metadata);
254 $(this.linkIcon).attr("class", "ui-icon ui-icon-folder-collapsed");
255 });
256 /*
257 $(".editMapGPS").each(function(){
258 $(this).css("display", visibility);
259 $(this.linkLabel).html(gs.text.de.edit_map_gps);
260 $(this.linkIcon).attr("class", "ui-icon ui-icon-folder-collapsed");
261 });
262 */
263
264 $("table").each(function () {
265 if ($(this).attr("id") && $(this).attr("id").search(/^meta/) != -1) {
266 $(this).css("display", "none");
267 $(this.metaNameField).css("display", "none");
268 $(this.addRowButton).css("display", "none");
269 if (enable_add_all_metadata_button == true) {
270 $(this.addAllButton).css("display", "none");
271 }
272 }
273 });
274}
275
276/* override this function in other interface/site/collection if you want
277a different set of metadata sets
278Use in conjunction with the dynamic_metadata_set_list variable. */
279function setStaticMetadataSets(list) {
280 addOptionToList(list, "All", gs.text.de.all_metadata);
281}
282
283function readyPageForEditing() {
284
285 if ($("#metadataSetList").length) {
286 var setList = $("#metadataSetList");
287 if (!setList.css("display") || setList.css("display") == "") {
288 setEditingFeaturesVisible(false);
289 } else {
290 setEditingFeaturesVisible(true);
291 }
292 return;
293 }
294
295 $("#editContentButton").html(gs.text.de.hide_editor);
296 //wait for 0.5 sec to let ckeditor up
297
298 // Initialising editableInitStates for CKEDITOR instances now happens in the CKEDITOR.on('instanceReady') handler, which is added upon docReady, see documentedit_scripts_util::$( document ).ready(...)
299 // Attempting CKEDITOR.on('instanceReady') at the start of this method or anywhere in this method didn't work because it was probably too late in page load phase to add the event handler then
300 // (the instanceReady() event would have been triggered before this method finally got called).
301
302 var editBar = $("#editBarLeft");
303
304 var visibleMetadataList = $("<select>", {
305 "id": "metadataSetList",
306 "class": "ui-state-default"
307 });
308 setStaticMetadataSets(visibleMetadataList);
309
310 if (display_metadata_set_selector == true) {
311 var metadataListLabel = $("<span>", {
312 "id": "metadataListLabel",
313 "style": "margin-left:20px;"
314 });
315 metadataListLabel.html(gs.text.de.visible_metadata);
316 editBar.append(metadataListLabel);
317 } else {
318 visibleMetadataList.css("display", "none");
319 }
320 editBar.append(visibleMetadataList);
321 visibleMetadataList.change(onVisibleMetadataSetChange);
322 editBar.append("<br>");
323
324 for (var i = 0; i < save_and_rebuild_buttons.length; i++) {
325 var button_type = save_and_rebuild_buttons[i];
326 if (button_type == "save") {
327 var saveButton = $("<button>", {
328 "id": "saveButton",
329 "class": "ui-state-default ui-corner-all"
330 });
331 saveButton.click(save);
332 saveButton.html(gs.text.de.save);
333 editBar.append(saveButton);
334 } else if (button_type == "rebuild") {
335 var rebuildButton = $("<button>", {
336 "id": "rebuildButton",
337 "class": "ui-state-default ui-corner-all"
338 });
339 rebuildButton.click(rebuildCurrentCollection);
340 rebuildButton.html(gs.text.de.rebuild);
341 editBar.append(rebuildButton);
342 } else if (button_type == "saveandrebuild") {
343 var saveAndRebuildButton = $("<button>", {
344 "id": "saveAndRebuildButton",
345 "class": "ui-state-default ui-corner-all"
346 });
347 saveAndRebuildButton.click(saveAndRebuild);
348 saveAndRebuildButton.html(gs.text.de.saverebuild);
349 editBar.append(saveAndRebuildButton);
350
351 }
352 }
353 var statusBarDiv = $("<div>");
354 editBar.append(statusBarDiv);
355 _statusBar = new StatusBar(statusBarDiv[0]);
356
357 var titleDivs = $(".sectionTitle");
358 for (var i = 0; i < titleDivs.length; i++) {
359 addEditMetadataLink(titleDivs[i]);
360 addEditMapGPSLink(titleDivs[i]);
361 }
362
363 // We need to keep track of editableElementsInitialisationProgress: the number of editable elements that need to be initialised/need to finish initialising
364 // As CKEditors will be added, meaning more editable elements, must increment our counter editableElementsInitialisationProgress
365 //var $num_editable_textareas = $(".sectionText"); // consider searching for 'contenteditable="true"' as this is what CKEDITOR is looking for (we think!)
366 // I think for us it's always a <div> that has contenteditable="true", but to get all elements with attr contenteditable set to true,
367 // see https://stackoverflow.com/questions/4958081/find-all-elements-with-a-certain-attribute-value-in-jquery
368 // which has inefficient and slightly more efficient ways of doing that
369 var $num_editable_textareas = $('div[contenteditable="true"]');
370 editableElementsInitialisationProgress += $num_editable_textareas.length;
371
372 _baseURL = gs.xsltParams.library_name;
373 onVisibleMetadataSetChange(); // make sure that the selected item in the list is active
374
375 // If the user is attempting to leave the page, check if there are unsaved changes
376 // and if so, display an "Are you sure you want to leave" message.
377 // https://stackoverflow.com/questions/7080269/javascript-before-leaving-the-page
378 // Newer versions of Firefox/Chrome don't display custom message (security feature):
379 // https://stackoverflow.com/questions/22776544/why-is-jquery-onbeforeunload-not-working-in-chrome-and-firefox
380 // and http://jsfiddle.net/XZAWS/
381 // jquery bind() is deprecated: https://stackoverflow.com/questions/33654716/is-jquery-bind-deprecated
382 console.log("**** away to set up beforeunload handler!");
383 $(window).on("beforeunload", function(event) {
384
385 if(gs.cgiParams.docEdit == "1") { // like document.xsl, which checks the same var upon onload
386 // shouldn't check for whether changes are saved unless on Doc Editing page (DocEdit=1)
387 // else the following pop up always ends up appearing when attempting
388 // to leave a doc view page in Doc Editing Mode (when not yet actually Doc Editing)
389
390 // Because we've done extra work now in maintaining "editableElementsInitialisationProgress", which is
391 // the number of editable elements that still need to finish initialising, we can now be confident that
392 // the call to changesToUpdate() below won't return the wrong answers if a page with docEdit turned on
393 // is asked to unload (e.g. by pressing Reload) before the page has finished loading.
394 var changes = changesToUpdate();
395
396 console.log("#### CHANGES before page reload: ", changes);
397
398 if(changes.length > 0) {
399 console.log("The collection hasn't yet been saved after editing. Are you sure you want to leave?");
400 return "The collection hasn't yet been saved after editing. Are you sure you want to leave?";
401 }
402 }
403 });
404
405
406}
407
408// override the one in documentmaker_scripts_util
409// currently not used if other one is present. need to get the js include order right
410function enableSaveButtons(enabled) {
411 if (enabled) {
412 $("#saveButton, #rebuildButton, #saveAndRebuildButton").removeAttr("disabled");
413 } else {
414 $("#saveButton, #rebuildButton, #saveAndRebuildButton").attr("disabled", "disabled");
415 }
416}
417
418/* this is a cut down version of save() from documentmaker_scripts_util.js
419going back to using save, will delete this once everything working*/
420function saveMetadataChangesOld() {
421
422 console.log("Saving metadata changes");
423
424 // get collection name
425 var collection = gs.cgiParams.c;
426
427 // get document id
428 var docID = gs.cgiParams.d;
429
430 var metadataChanges = new Array();
431 if (_deletedMetadata.length > 0) {
432
433 for (var i = 0; i < _deletedMetadata.length; i++) {
434
435 var currentRow = _deletedMetadata[i];
436
437 //Get metadata name
438 var cells = currentRow.getElementsByTagName("TD");
439 var nameCell = cells[0];
440 var name = nameCell.innerHTML;
441 var valueCell = cells[1];
442 var value = valueCell.innerHTML;
443 metadataChanges.push({
444 type: 'delete',
445 docID: docID,
446 name: name,
447 value: value
448 });
449 removeFromParent(currentRow);
450 }
451 }
452
453 if (metadataChanges.length == 0) {
454 console.log(gs.text.de.no_changes);
455 return;
456 }
457
458 var processChangesLoop = function (index) {
459 var change = metadataChanges[index];
460
461 var callbackFunction;
462 if (index + 1 == metadataChanges.length) {
463 callbackFunction = function () {
464 console.log("Completed saving metadata changes. You must rebuild the collection for the changes to take effect.");
465 };
466 } else {
467 callbackFunction = function () {
468 processChangesLoop(index + 1)
469 };
470 }
471 if (change.type == "delete") {
472 gs.functions.removeArchivesMetadata(collection, gs.xsltParams.site_name, change.docID, change.name, null, change.value, function () {
473 callbackFunction();
474 });
475 } else {
476 if (change.orig) {
477 gs.functions.setArchivesMetadata(collection, gs.xsltParams.site_name, docID, change.name, null, change.value, change.orig, "override", function () {
478 callbackFunction();
479 });
480 } else {
481 gs.functions.setArchivesMetadata(collection, gs.xsltParams.site_name, docID, change.name, null, change.value, null, "accumulate", function () {
482 callbackFunction();
483 });
484 }
485 }
486 }
487 processChangesLoop(0);
488 /* need to clear the changes from the page */
489 while (_deletedMetadata.length > 0) {
490 _deletedMetadata.pop();
491 }
492
493}
Note: See TracBrowser for help on using the repository browser.