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

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

Clean up

File size: 17.5 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 //map_editor.savedOverlays = newMapData;
151 // Saving the new overlay values as the old ones, for the state after saving and rebuilding is done,
152 // now happens after all setArchivesMeta)_ calls have succeeded,
153 // which is just at the start of sendBuildRequest() in documentedit_scripts_util.js::saveAndRebuild()
154 }
155
156 }
157
158 return modifiedMaps;
159}
160
161
162function addEditMapGPSLink(cell) {
163 cell = $(cell);
164 var id = cell.attr("id").substring(6);
165 //console.log(id);
166 var mapGPScontainer = gs.jqGet("map-and-controls-" + id);
167 var row = cell.parent();
168 var newCell = $("<td>", {
169 "style": "font-size:0.7em; padding:0px 10px",
170 "class": "editMapGPSButton"
171 });
172 var linkSpan = $("<span>", {
173 "class": "ui-state-default ui-corner-all",
174 "style": "padding: 2px; float:left;"
175 });
176
177 var linkLabel = $("<span>" + gs.text.de.edit_map_gps + "</span>");
178 var linkIcon = $("<span>", {
179 "class": "ui-icon ui-icon-folder-collapsed"
180 });
181 newCell.linkIcon = linkIcon;
182 newCell.linkLabel = linkLabel;
183
184 var uList = $("<ul>", {
185 "style": "outline: 0 none; margin:0px; padding:0px;"
186 });
187 var labelItem = $("<li>", {
188 "style": "float:left; list-style:none outside none;"
189 });
190 var iconItem = $("<li>", {
191 "style": "float:left; list-style:none outside none;"
192 });
193
194 uList.append(iconItem);
195 uList.append(labelItem);
196 labelItem.append(linkLabel);
197 iconItem.append(linkIcon);
198
199 var mapEditor = new MapEditor(id);
200 gsmap_store["map-" + id] = mapEditor;
201
202 var newLink = $("<a>", {
203 "href": "javascript:;"
204 });
205 newLink.click(function () {
206 //console.log(" Show/Hide Map Editor ");
207 var clicked_mapEditor = gsmap_store["map-" + id];
208
209 if (clicked_mapEditor.map == null) {
210 clicked_mapEditor.initMapEditorControls();
211 clicked_mapEditor.initMapEditor();
212 }
213 if (mapGPScontainer.css("display") == "none") {
214 linkLabel.html(gs.text.de.hide_map_gps);
215 linkIcon.attr("class", "ui-icon ui-icon-folder-open");
216 mapGPScontainer.css("display", "block");
217 } else {
218 linkLabel.html(gs.text.de.edit_map_gps);
219 linkIcon.attr("class", "ui-icon ui-icon-folder-collapsed");
220 mapGPScontainer.css("display", "none");
221
222 }
223 });
224
225 newLink.append(uList);
226 linkSpan.append(newLink);
227 newCell.append(linkSpan);
228 row.append(newCell);
229
230 mapGPScontainer.css("display", "none");
231
232}
233
234function setEditingFeaturesVisible(visible) {
235 if (visible) {
236 $("#editContentButton").html(gs.text.de.hide_editor);
237 $("#editContentButtonDiv").attr("class", "ui-state-default ui-corner-all");
238 } else {
239 $("#editContentButton").html(gs.text.de.edit_content);
240 $("#editContentButtonDiv").attr("class", "");
241 }
242
243 var visibility = (visible ? "" : "none");
244 if (display_metadata_set_selector == true) {
245 $("#metadataListLabel, #metadataSetList").css("display", visibility);
246 }
247
248 $(".editMetadataButton").each(function () {
249 $(this).css("display", visibility);
250 $(this.linkLabel).html(gs.text.de.edit_metadata);
251 $(this.linkIcon).attr("class", "ui-icon ui-icon-folder-collapsed");
252 });
253 /*
254 $(".editMapGPS").each(function(){
255 $(this).css("display", visibility);
256 $(this.linkLabel).html(gs.text.de.edit_map_gps);
257 $(this.linkIcon).attr("class", "ui-icon ui-icon-folder-collapsed");
258 });
259 */
260
261 $("table").each(function () {
262 if ($(this).attr("id") && $(this).attr("id").search(/^meta/) != -1) {
263 $(this).css("display", "none");
264 $(this.metaNameField).css("display", "none");
265 $(this.addRowButton).css("display", "none");
266 if (enable_add_all_metadata_button == true) {
267 $(this.addAllButton).css("display", "none");
268 }
269 }
270 });
271}
272
273/* override this function in other interface/site/collection if you want
274a different set of metadata sets
275Use in conjunction with the dynamic_metadata_set_list variable. */
276function setStaticMetadataSets(list) {
277 addOptionToList(list, "All", gs.text.de.all_metadata);
278}
279
280function readyPageForEditing() {
281
282 if ($("#metadataSetList").length) {
283 var setList = $("#metadataSetList");
284 if (!setList.css("display") || setList.css("display") == "") {
285 setEditingFeaturesVisible(false);
286 } else {
287 setEditingFeaturesVisible(true);
288 }
289 return;
290 }
291
292 $("#editContentButton").html(gs.text.de.hide_editor);
293 //wait for 0.5 sec to let ckeditor up
294
295 // Initialising editableInitStates for CKEDITOR instances now happens in the CKEDITOR.on('instanceReady') handler, which is added upon docReady, see documentedit_scripts_util::$( document ).ready(...)
296 // 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
297 // (the instanceReady() event would have been triggered before this method finally got called).
298
299 var editBar = $("#editBarLeft");
300
301 var visibleMetadataList = $("<select>", {
302 "id": "metadataSetList",
303 "class": "ui-state-default"
304 });
305 setStaticMetadataSets(visibleMetadataList);
306
307 if (display_metadata_set_selector == true) {
308 var metadataListLabel = $("<span>", {
309 "id": "metadataListLabel",
310 "style": "margin-left:20px;"
311 });
312 metadataListLabel.html(gs.text.de.visible_metadata);
313 editBar.append(metadataListLabel);
314 } else {
315 visibleMetadataList.css("display", "none");
316 }
317 editBar.append(visibleMetadataList);
318 visibleMetadataList.change(onVisibleMetadataSetChange);
319 editBar.append("<br>");
320
321 for (var i = 0; i < save_and_rebuild_buttons.length; i++) {
322 var button_type = save_and_rebuild_buttons[i];
323 if (button_type == "save") {
324 var saveButton = $("<button>", {
325 "id": "saveButton",
326 "class": "ui-state-default ui-corner-all"
327 });
328 saveButton.click(save);
329 saveButton.html(gs.text.de.save);
330 editBar.append(saveButton);
331 } else if (button_type == "rebuild") {
332 var rebuildButton = $("<button>", {
333 "id": "rebuildButton",
334 "class": "ui-state-default ui-corner-all"
335 });
336 rebuildButton.click(rebuildCurrentCollection);
337 rebuildButton.html(gs.text.de.rebuild);
338 editBar.append(rebuildButton);
339 } else if (button_type == "saveandrebuild") {
340 var saveAndRebuildButton = $("<button>", {
341 "id": "saveAndRebuildButton",
342 "class": "ui-state-default ui-corner-all"
343 });
344 saveAndRebuildButton.click(saveAndRebuild);
345 saveAndRebuildButton.html(gs.text.de.saverebuild);
346 editBar.append(saveAndRebuildButton);
347
348 }
349 }
350 var statusBarDiv = $("<div>");
351 editBar.append(statusBarDiv);
352 _statusBar = new StatusBar(statusBarDiv[0]);
353
354 var titleDivs = $(".sectionTitle");
355 for (var i = 0; i < titleDivs.length; i++) {
356 addEditMetadataLink(titleDivs[i]);
357 addEditMapGPSLink(titleDivs[i]);
358 }
359
360 // We need to keep track of editableElementsInitialisationProgress: the number of editable elements that need to be initialised/need to finish initialising
361 // As CKEditors will be added, meaning more editable elements, must increment our counter editableElementsInitialisationProgress
362 //var $num_editable_textareas = $(".sectionText"); // consider searching for 'contenteditable="true"' as this is what CKEDITOR is looking for (we think!)
363 // I think for us it's always a <div> that has contenteditable="true", but to get all elements with attr contenteditable set to true,
364 // see https://stackoverflow.com/questions/4958081/find-all-elements-with-a-certain-attribute-value-in-jquery
365 // which has inefficient and slightly more efficient ways of doing that
366 var $num_editable_textareas = $('div[contenteditable="true"]');
367 editableElementsInitialisationProgress += $num_editable_textareas.length;
368
369 _baseURL = gs.xsltParams.library_name;
370 onVisibleMetadataSetChange(); // make sure that the selected item in the list is active
371
372 // If the user is attempting to leave the page, check if there are unsaved changes
373 // and if so, display an "Are you sure you want to leave" message.
374 // https://stackoverflow.com/questions/7080269/javascript-before-leaving-the-page
375 // Newer versions of Firefox/Chrome don't display custom message (security feature):
376 // https://stackoverflow.com/questions/22776544/why-is-jquery-onbeforeunload-not-working-in-chrome-and-firefox
377 // and http://jsfiddle.net/XZAWS/
378 // jquery bind() is deprecated: https://stackoverflow.com/questions/33654716/is-jquery-bind-deprecated
379
380 $(window).on("beforeunload", function(event) {
381
382 if(gs.cgiParams.docEdit == "1") { // like document.xsl, which checks the same var upon onload
383 // shouldn't check for whether changes are saved unless on Doc Editing page (DocEdit=1)
384 // else the following pop up always ends up appearing when attempting
385 // to leave a doc view page in Doc Editing Mode (when not yet actually Doc Editing)
386
387 // Because we've done extra work now in maintaining "editableElementsInitialisationProgress", which is
388 // the number of editable elements that still need to finish initialising, we can now be confident that
389 // the call to changesToUpdate() below won't return the wrong answers if a page with docEdit turned on
390 // is asked to unload (e.g. by pressing Reload) before the page has finished loading.
391 var changes = changesToUpdate();
392
393 //console.log("#### CHANGES before page reload: ", changes);
394
395 if(changes.length > 0) {
396 console.log("The collection hasn't yet been saved after editing. Are you sure you want to leave?");
397 return "The collection hasn't yet been saved after editing. Are you sure you want to leave?";
398 }
399 }
400 });
401
402
403}
404
405// override the one in documentmaker_scripts_util
406// currently not used if other one is present. need to get the js include order right
407function enableSaveButtons(enabled) {
408 if (enabled) {
409 $("#saveButton, #rebuildButton, #saveAndRebuildButton").removeAttr("disabled");
410 } else {
411 $("#saveButton, #rebuildButton, #saveAndRebuildButton").attr("disabled", "disabled");
412 }
413}
414
415/* this is a cut down version of save() from documentmaker_scripts_util.js
416going back to using save, will delete this once everything working*/
417function saveMetadataChangesOld() {
418
419 console.log("Saving metadata changes");
420
421 // get collection name
422 var collection = gs.cgiParams.c;
423
424 // get document id
425 var docID = gs.cgiParams.d;
426
427 var metadataChanges = new Array();
428 if (_deletedMetadata.length > 0) {
429
430 for (var i = 0; i < _deletedMetadata.length; i++) {
431
432 var currentRow = _deletedMetadata[i];
433
434 //Get metadata name
435 var cells = currentRow.getElementsByTagName("TD");
436 var nameCell = cells[0];
437 var name = nameCell.innerHTML;
438 var valueCell = cells[1];
439 var value = valueCell.innerHTML;
440 metadataChanges.push({
441 type: 'delete',
442 docID: docID,
443 name: name,
444 value: value
445 });
446 removeFromParent(currentRow);
447 }
448 }
449
450 if (metadataChanges.length == 0) {
451 console.log(gs.text.de.no_changes);
452 return;
453 }
454
455 var processChangesLoop = function (index) {
456 var change = metadataChanges[index];
457
458 var callbackFunction;
459 if (index + 1 == metadataChanges.length) {
460 callbackFunction = function () {
461 console.log("Completed saving metadata changes. You must rebuild the collection for the changes to take effect.");
462 };
463 } else {
464 callbackFunction = function () {
465 processChangesLoop(index + 1)
466 };
467 }
468 if (change.type == "delete") {
469 gs.functions.removeArchivesMetadata(collection, gs.xsltParams.site_name, change.docID, change.name, null, change.value, function () {
470 callbackFunction();
471 });
472 } else {
473 if (change.orig) {
474 gs.functions.setArchivesMetadata(collection, gs.xsltParams.site_name, docID, change.name, null, change.value, change.orig, "override", function () {
475 callbackFunction();
476 });
477 } else {
478 gs.functions.setArchivesMetadata(collection, gs.xsltParams.site_name, docID, change.name, null, change.value, null, "accumulate", function () {
479 callbackFunction();
480 });
481 }
482 }
483 }
484 processChangesLoop(0);
485 /* need to clear the changes from the page */
486 while (_deletedMetadata.length > 0) {
487 _deletedMetadata.pop();
488 }
489
490}
Note: See TracBrowser for help on using the repository browser.