source: main/trunk/greenstone3/web/interfaces/default/js/documentedit_scripts_util.js@ 32850

Last change on this file since 32850 was 32850, checked in by ak19, 5 years ago
  1. Zeddy introduces suppressUndo and cleaned up lots of CloneShape sectionst that were commented out. 2. Zeddy and Dr Bainbridge solved the issue whereby shapes loaded from archives_metadata were not selectable and needed a deleteAllShapes followed by Undo to make them selectable. These steps are no longer needed now, as it's solved more efficiently.
  • Property svn:executable set to *
File size: 39.5 KB
Line 
1/** Javascript file containing useful functions used by both documentedit_scripts.js and documentmaker_scripts.js */
2
3
4//Some "constants" to match the server constants
5var SUCCESS = 1;
6var ACCEPTED = 2;
7var ERROR = 3;
8var CONTINUING = 10;
9var COMPLETED = 11;
10var HALTED = 12;
11
12var _transactions = new Array();
13var _collectionsToBuild = new Array();
14var _allContents = new Array();
15var _deletedSections = new Array();
16var _deletedMetadata = new Array();
17var _undoOperations = new Array();
18var _baseURL;
19var _statusBar;
20var _metadataSetList = new Array();
21
22
23// If the user is attempting to leave the page, check if there are unsaved changes
24// and if so, display an "Are you sure you want to leave" message.
25// https://stackoverflow.com/questions/7080269/javascript-before-leaving-the-page
26// Newer versions of Firefox/Chrome don't display custom message (security feature):
27// https://stackoverflow.com/questions/22776544/why-is-jquery-onbeforeunload-not-working-in-chrome-and-firefox
28// and http://jsfiddle.net/XZAWS/
29// jquery bind() is deprecated: https://stackoverflow.com/questions/33654716/is-jquery-bind-deprecated
30$(window).on("beforeunload", function(event) {
31
32 if(gs.cgiParams.docEdit == "1") { // like document.xsl, which checks the same var upon onload
33 // shouldn't check for whether changes are saved unless on Doc Editing page (DocEdit=1)
34 // else the following pop up always ends up appearing when attempting
35 // to leave a doc view page in Doc Editing Mode (when not yet actually Doc Editing)
36
37
38 var changes = changesToUpdate();
39
40 //console.log("#### CHANGES before page reload: ", changes);
41
42 if(changes.length > 0) {
43 console.log("The collection hasn't yet been saved after editing. Are you sure you want to leave?");
44 return "The collection hasn't yet been saved after editing. Are you sure you want to leave?";
45 }
46 }
47
48});
49
50
51function encodeDelimiters(meta_value) {
52
53 var new_value = meta_value.replace(/;/g, "%253B");
54 return new_value.replace(/&/g, "%2526");
55}
56
57function getElementsByClassName(cl, parent)
58{
59 var elemArray = [];
60 var classRegEx = new RegExp("\\b" + cl + "\\b");
61 var elems;
62 if(parent)
63 {
64 elems = parent.getElementsByTagName("*");
65 }
66 else
67 {
68 elems = document.getElementsByTagName("*");
69 }
70
71 for (var i = 0; i < elems.length; i++)
72 {
73 var classeName = elems[i].className;
74 if (classRegEx.test(classeName)) elemArray.push(elems[i]);
75 }
76
77 return elemArray;
78};
79
80function getNextSiblingOfType(elem, type)
81{
82 if(elem == null)
83 {
84 return null;
85 }
86
87 var current = elem.nextSibling;
88 while(current != null)
89 {
90 if(current.nodeName.toLowerCase() == type)
91 {
92 return current;
93 }
94
95 current = current.nextSibling;
96 }
97 return null;
98}
99
100function getPrevSiblingOfType(elem, type)
101{
102 if(elem == null)
103 {
104 return null;
105 }
106
107 var current = elem.previousSibling;
108 while(current != null)
109 {
110 if(current.nodeName.toLowerCase() == type)
111 {
112 return current;
113 }
114
115 current = current.previousSibling;
116 }
117 return null;
118}
119
120function saveTransaction(transaction)
121{
122 console.log(transaction);
123 _transactions.push(transaction);
124}
125
126function undo()
127{
128 if(_undoOperations.length == 0)
129 {
130 return;
131 }
132
133 var undoOp = _undoOperations.pop();
134
135 //Create/Duplicate undo
136 if(undoOp.op == "del")
137 {
138 if(undoOp.srcElem.childList)
139 {
140 removeFromParent(undoOp.srcElem.childList);
141 }
142 if(undoOp.srcElem.parentItem)
143 {
144 undoOp.srcElem.parentItem.menu.newSectionLink.style.display = "inline";
145 undoOp.srcElem.parentItem.childList = null;
146 }
147 removeFromParent(undoOp.srcElem);
148 }
149
150 if(undoOp.op == "delMeta")
151 {
152 if(undoOp.srcElem.childList)
153 {
154 removeFromParent(undoOp.srcElem.childList);
155 }
156 if(undoOp.srcElem.parentItem)
157 {
158 undoOp.srcElem.parentItem.menu.newSectionLink.style.display = "inline";
159 undoOp.srcElem.parentItem.childList = null;
160 }
161 de.doc.unregisterEditSection(undoOp.srcElem);
162 removeFromParent(undoOp.srcElem);
163 }
164
165 //Move undo (mva is move after, mvb is move before, mvi is move into)
166 else if(undoOp.op == "mva" || undoOp.op == "mvb" || undoOp.op == "mvi")
167 {
168 if(undoOp.op == "mvb")
169 {
170 undoOp.refElem.parentNode.insertBefore(undoOp.srcElem, undoOp.refElem);
171 }
172 else if(undoOp.op == "mva")
173 {
174 insertAfter(undoOp.srcElem, undoOp.refElem);
175 }
176 else
177 {
178 undoOp.refElem.removeChild(undoOp.refElem.firstChild);
179 undoOp.refElem.appendChild(undoOp.srcElem);
180 }
181
182 if(undoOp.srcElem.textDiv)
183 {
184 insertAfter(undoOp.srcElem.textDiv, undoOp.srcElem);
185 }
186 if(undoOp.srcElem.childList)
187 {
188 insertAfter(undoOp.srcElem.childList, undoOp.srcElem.textDiv);
189 }
190
191 if(undoOp.srcElem.onmouseout)
192 {
193 //Uncolour the section if it coloured
194 undoOp.srcElem.onmouseout();
195 }
196 updateFromTop();
197 }
198 else if(undoOp.op == "display")
199 {
200 undoOp.srcElem.style.display = undoOp.subOp;
201 }
202
203 if(undoOp.removeDeletedMetadata)
204 {
205 _deletedMetadata.pop();
206 }
207
208 if(undoOp.removeTransaction)
209 {
210 _transactions.pop();
211 }
212}
213
214function enableSaveButtons(enabled) {
215 if (enabled) {
216 $("#saveButton, #quickSaveButton").html(gs.text.de.save_changes);
217 $("#saveButton, #quickSaveButton").removeAttr("disabled");
218
219 } else {
220 $("#saveButton, #quickSaveButton").html(gs.text.de.saving + "...");
221 $("#saveButton, #quickSaveButton").attr("disabled", "disabled");
222
223 }
224}
225function addCollectionToBuild(collection)
226{
227 for(var i = 0; i < _collectionsToBuild.length; i++)
228 {
229 if(collection == _collectionsToBuild[i])
230 {
231 return;
232 }
233 }
234 _collectionsToBuild.push(collection);
235}
236
237function save() {
238 saveAndRebuild(false);
239}
240
241function rebuildCurrentCollection() {
242
243 console.log(gs.text.de.rebuilding_collection);
244 enableSaveButtons(false);
245 var collection = gs.cgiParams.c;
246
247 var collectionsArray = new Array();
248 collectionsArray.push(collection);
249 buildCollections(collectionsArray, null, reloadUponRebuild); // passing in callback to reload the page after build, as requested by Kathy
250}
251
252
253function reloadUponRebuild() {
254 // finished rebuilding - reload the page after rebuild, but first
255 // clear transactions array of saved changes, now that we're done processing these changes during rebuild,
256 // since we don't want the "are you sure to leave page" popup which appears on _transactions array being non-empty
257 _transactions = null;
258 location.reload(true); // force reload, not from cache, https://www.w3schools.com/jsref/met_loc_reload.asp
259}
260
261/************************************
262* TEXT EDIT (CKEDITOR) SCRIPTS *
263**************************************/
264
265// not using this anymore as the instanceready never seems to get called
266function addCKEEditableState(evt,stateArray)
267{
268 // Event->Editor->CKE DOM Inline Element that editor was for->underlying jquery element
269 element = evt.editor.element.$;
270 nodeText = element.innerHTML;
271 stateArray.push({
272 editableNode : element,
273 initHTML : nodeText
274 });
275}
276
277function addEditableState(editable,stateArray)
278{
279
280 if(editable.tagName == 'TEXTAREA')
281 {
282 nodeText = editable.value;
283 }
284 else
285 {
286 nodeText = editable.innerHTML;
287 }
288
289 stateArray.push({
290 editableNode : editable,
291 initHTML : nodeText
292 });
293
294}
295
296function getLastEditableStates()
297{
298 editableLastStates = [];
299 $(".sectionText").each(function(){addEditableState(this,editableLastStates);});
300 $(".metaTableCellArea").each(function(){addEditableState(this,editableLastStates);});
301
302}
303
304function changesToUpdate()
305{
306 var resultArray = new Array();
307 getLastEditableStates();
308 for (var j in editableLastStates)
309 {
310 if (isNodeChanged(editableLastStates[j]))
311 {
312 resultArray.push(editableLastStates[j].editableNode);
313 }
314 }
315 return resultArray;
316}
317
318
319function isNodeChanged(StateToCheck){
320 for (var i in editableInitStates)
321 {
322 if ((StateToCheck.editableNode === editableInitStates[i].editableNode)) {
323 if ( StateToCheck.initHTML === editableInitStates[i].initHTML )
324 {
325 return false;
326 }
327 //console.log("current="+StateToCheck.initHTML);
328 //console.log("init="+editableInitStates[i].initHTML);
329 return true;
330 }
331
332 }
333 // if get here, this must be a new node, as wasn't in init states
334 // make sure its not empty - we won't add empty nodes.
335 if (StateToCheck.initHTML == "") {
336 return false;
337 }
338
339 return true;
340
341}
342
343
344function saveAndRebuild(rebuild)
345{
346//This works in most cases but will not work when taking a doc from one collection to another, will need to be fixed at some point
347 var collection;
348 if(gs.cgiParams.c && gs.cgiParams.c != "") {
349
350 collection = gs.cgiParams.c;
351 }
352 else {
353 collection = gs.cgiParams.p_c;
354 }
355
356 var sendBuildRequest = function()
357 {
358 var request = "[";
359 for(var i = 0; i < _transactions.length; i++)
360 {
361 request += _transactions[i];
362 if(i != _transactions.length - 1)
363 {
364 request += ",";
365 }
366 }
367 request += "]";
368
369 var statusID;
370 var ajax = new gs.functions.ajaxRequest();
371 ajax.open("POST", gs.xsltParams.library_name, true);
372 ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
373 ajax.onreadystatechange = function()
374 {
375 if(ajax.readyState == 4 && ajax.status == 200)
376 {
377 var text = ajax.responseText;
378 var xml = validateXML(text);
379
380 var errorElems;
381 if(!xml || checkForErrors(xml))
382 {
383 alert(gs.text.dse.error_saving);
384
385 enableSaveButtons(true);
386
387 if(_statusBar)
388 {
389 _statusBar.removeStatus(statusID);
390 }
391 return;
392 }
393
394 if(_statusBar)
395 {
396 _statusBar.removeStatus(statusID);
397 }
398 if (rebuild) {
399 buildCollections(_collectionsToBuild, null, reloadUponRebuild);
400 } else {
401 // reset the save button here
402 enableSaveButtons(true);
403 // saving to archives is now done, clear the transactions
404 // that were keeping track of the full text changes that have now
405 // been performed to archives (no member var keeps track of meta changes, only a local var)
406 _transactions = new Array();
407 }
408 }
409 }
410
411 if(_collectionsToBuild.length > 0)
412 {
413 enableSaveButtons(false);
414
415 if(_statusBar)
416 {
417 statusID = _statusBar.addStatus(gs.text.dse.modifying_archives + "...");
418 }
419 ajax.send("a=g&rt=r&s=DocumentExecuteTransaction&s1.transactions=" + request);
420 }
421 } // end sendBuildRequest definition
422
423 var metadataChanges = new Array();
424 if (_deletedMetadata.length > 0) {
425 //addCollectionToBuild(collection);
426
427 for(var i = 0; i < _deletedMetadata.length; i++) {
428
429 var currentRow = _deletedMetadata[i];
430
431 //Get document ID
432 var currentElem = currentRow;
433 while((currentElem = currentElem.parentNode).tagName != "TABLE");
434 var docID = currentElem.getAttribute("id").substring(4);
435
436 //Get metadata name
437 var cells = currentRow.getElementsByTagName("TD");
438 var nameCell = cells[0];
439 // metadata name cell might have the multivalue indicator in it, so just want the first word
440 var name = nameCell.innerHTML.split(" ")[0];
441 var valueCell = cells[1];
442 var value = valueCell.getElementsByTagName("TEXTAREA")[0].value;
443 if (value.length) {
444 // check for non empty value, in case all they have done is add a field then deleted it.
445 metadataChanges.push({type:'delete', docID:docID, name:name, value:value});
446 addCollectionToBuild(collection);
447 }
448 removeFromParent(currentRow);
449 }
450 }
451
452 var changes = changesToUpdate();
453
454 //Clean changes
455 editableInitStates = editableLastStates;
456
457 for(var i = 0; i < changes.length; i++)
458 {
459 var changedElem = changes[i];
460 //Save metadata
461
462 if(gs.functions.hasClass(changedElem, "metaTableCellArea"))
463 {
464 //Get document ID
465 var currentElem = changedElem;
466 while((currentElem = currentElem.parentNode).tagName != "TABLE");
467 var docID = currentElem.getAttribute("id").substring(4);
468
469 //Get metadata name
470 var row = changedElem.parentNode.parentNode;
471 var cells = row.getElementsByTagName("TD");
472 var nameCell = cells[0];
473 // metadata name cell might have the multivalue indicator in it, so just want the first word
474 var name = nameCell.innerHTML.split(" ")[0];
475 var value = changedElem.value;
476 value = value.replace(/&nbsp;/g, " ");
477
478 var orig = changedElem.originalValue;
479 if (orig) {
480 orig = orig.replace(/&nbsp;/g, " ");
481 }
482 if (jQuery.inArray(name, multiValuedMetadata) != -1) {
483
484 // split the values
485 var values_list = value.split(mvm_delimiter);
486 var orig_list;
487 var num_orig;
488 if (orig) {
489 orig_list = orig.split(mvm_delimiter);
490 num_orig = orig_list.length;
491 }
492
493 for(var i = 0; i < values_list.length; i++) {
494 var val = values_list[i];
495 var ori =null;
496 if (orig && i<num_orig) {
497 ori = orig_list[i];
498 }
499 metadataChanges.push({collection:collection, docID:docID, name:name, value:val, orig:ori});
500 }
501 } else {
502 metadataChanges.push({collection:collection, docID:docID, name:name, value:value, orig:orig});
503 }
504 changedElem.originalValue = changedElem.value;
505 addCollectionToBuild(collection);
506 }
507 //Save content
508 else if(gs.functions.hasClass(changedElem, "renderedText"))
509 {
510 var section = changedElem.parentDiv.parentItem;
511 saveTransaction('{"operation":"setText", "text":"' + CKEDITOR.instances[changedElem.getAttribute("id")].getData().replace(/%/g, "%25").replace(/"/g, "\\\"").replace(/&/g, "%26") + '", "collection":"' + section.collection + '", "oid":"' + section.nodeID + '"}'); //'
512 addCollectionToBuild(section.collection);
513 }
514 else if(gs.functions.hasClass(changedElem, "sectionText"))
515 {
516 var id = changedElem.getAttribute("id");
517 var sectionID = id.substring(4);
518 saveTransaction('{"operation":"setText", "text":"' + CKEDITOR.instances[changedElem.getAttribute("id")].getData().replace(/%/g, "%25").replace(/"/g, "\\\"").replace(/&/g, "%26") + '", "collection":"' + gs.cgiParams.c + '", "oid":"' + sectionID + '"}'); //'
519 addCollectionToBuild(gs.cgiParams.c);
520 }
521 }
522
523 // Check for changes to any map editors in the document
524 var modified_map_editors_data = getDocMapsEditDataForSaving(gs.cgiParams.c); // collection
525 for(var i = 0; i < modified_map_editors_data.length; i++) {
526 metadataChanges.push(modified_map_editors_data[i]); // of the form { collection: gs.cgiParams.c, docID: nodeID, name:"GSP.mapOverlay", metapos: 0, value: <stringifiedJSON> }
527 addCollectionToBuild(gs.cgiParams.c); // collection
528 }
529
530
531
532 var processChangesLoop = function(index)
533 {
534 var change = metadataChanges[index];
535
536 var callbackFunction;
537 if(index + 1 == metadataChanges.length)
538 {
539 callbackFunction = sendBuildRequest;
540 }
541 else
542 {
543 callbackFunction = function(){processChangesLoop(index + 1)};
544 }
545 if (change.type == "delete") {
546 gs.functions.removeArchivesMetadata(collection, gs.xsltParams.site_name, change.docID, change.name, null, encodeDelimiters(change.value), function(){callbackFunction();});
547 } else {
548 // Checking "if(change.metapos)" doesn't work for us as it becomes false when the property doesn't exist AND when the property is 0. But metapos IS 0 for us.
549 // https://ultimatecourses.com/blog/methods-to-determine-if-an-object-has-a-given-property
550 if('metapos' in change && change.metapos === 0) {// && change.metapos === 0) { // for maps
551
552 // collection, site, documentID, metadataName, metadataPosition, metadataValue, prevMetadataValue, metamode, responseFunction
553 //console.log("@@@ metapos! change: ", change);
554 gs.functions.setArchivesMetadata(change.collection, gs.xsltParams.site_name, change.docID, change.name, change.metapos, encodeDelimiters(change.value), null, "override", function(){callbackFunction();});
555 }
556 else if(change.orig)
557 {
558 gs.functions.setArchivesMetadata(change.collection, gs.xsltParams.site_name, change.docID, change.name, null, encodeDelimiters(change.value), encodeDelimiters(change.orig), "override", function(){callbackFunction();});
559 }
560 else
561 {
562 gs.functions.setArchivesMetadata(change.collection, gs.xsltParams.site_name, change.docID, change.name, null, encodeDelimiters(change.value), null, "accumulate", function(){callbackFunction();});
563 }
564 }
565 }
566 if (metadataChanges.length>0) {
567 // this will process each change one by one, and then send the build request
568 processChangesLoop(0);
569 }
570 else if(_collectionsToBuild.length > 0) {
571 // if there are no metadata changes, but some other changes eg text have happened, then we need to send the build request.
572 sendBuildRequest();
573 }
574
575 /* need to clear the changes from the page so that we don't process them again next time */
576 while (_deletedMetadata.length>0) {
577 _deletedMetadata.pop();
578 }
579
580}
581
582
583function buildCollections(collections, documents, callback)
584{
585 if(!collections || collections.length == 0)
586 {
587 console.log(gs.text.dse.empty_collection_list);
588 enableSaveButtons(true);
589 return;
590 }
591
592 var docs = "";
593 var buildOperation = "";
594 if(documents)
595 {
596 buildOperation = "ImportCollection";
597 docs += "&s1.documents=";
598 for(var i = 0; i < documents.length; i++)
599 {
600 docs += documents[i];
601 if(i < documents.length - 1)
602 {
603 docs += ",";
604 }
605 }
606 }
607 else
608 {
609 buildOperation = "BuildAndActivateCollection";
610 }
611
612 var counter = 0;
613 var statusID = 0;
614 var buildFunction = function()
615 {
616 var ajax = new gs.functions.ajaxRequest();
617 ajax.open("GET", gs.xsltParams.library_name + "?a=g&rt=r&ro=1&s=" + buildOperation + "&s1.incremental=true&s1.collection=" + collections[counter] + docs);
618 ajax.onreadystatechange = function()
619 {
620 if(ajax.readyState == 4 && ajax.status == 200)
621 {
622 var text = ajax.responseText;
623 var xml = validateXML(text);
624
625 if(!xml || checkForErrors(xml))
626 {
627 alert(gs.text.dse.could_not_build_p1 + " " + collections[counter] + gs.text.dse.could_not_build_p2);
628
629 if(_statusBar)
630 {
631 _statusBar.removeStatus(statusID);
632 }
633 enableSaveButtons(true);
634
635 return;
636 }
637
638 var status = xml.getElementsByTagName("status")[0];
639 var pid = status.getAttribute("pid");
640
641 startCheckLoop(pid, buildOperation, statusID, function()
642 {
643 /*
644 var localAjax = new gs.functions.ajaxRequest();
645 localAjax.open("GET", gs.xsltParams.library_name + "?a=g&rt=r&ro=1&s=ActivateCollection&s1.collection=" + collections[counter], true);
646 localAjax.onreadystatechange = function()
647 {
648 if(localAjax.readyState == 4 && localAjax.status == 200)
649 {
650 var localText = localAjax.responseText;
651 var localXML = validateXML(localText);
652
653 if(!xml || checkForErrors(xml))
654 {
655 alert(gs.text.dse.could_not_activate_p1 + " " + collections[counter] + gs.text.dse.could_not_activate_p2);
656
657 if(_statusBar)
658 {
659 _statusBar.removeStatus(statusID);
660 }
661 enableSaveButtons(true);
662
663 return;
664 }
665
666 var localStatus = localXML.getElementsByTagName("status")[0];
667 if(localStatus)
668 {
669 var localPID = localStatus.getAttribute("pid");
670 startCheckLoop(localPID, "ActivateCollection", statusID, function()
671 {
672 */
673 if(counter == collections.length - 1)
674 {
675 removeCollectionsFromBuildList(collections);
676 if(callback)
677 {
678 callback();
679 }
680 }
681 else
682 {
683 counter++;
684 buildFunction();
685 }
686
687 _transactions = new Array();
688
689 if(_statusBar)
690 {
691 _statusBar.removeStatus(statusID);
692 }
693 enableSaveButtons(true);
694 /*
695 });
696 }
697 }
698 }
699 if(_statusBar)
700 {
701 _statusBar.changeStatus(statusID, gs.text.dse.activating + " " + collections[counter] + "...");
702 }
703 localAjax.send();
704 */
705 });
706 }
707 }
708 if(_statusBar)
709 {
710 statusID = _statusBar.addStatus(gs.text.dse.building + " " + collections[counter] + "...");
711 }
712 ajax.send();
713 }
714 buildFunction();
715}
716
717function startCheckLoop(pid, serverFunction, statusID, callbackFunction)
718{
719 var ajaxFunction = function()
720 {
721 var ajax = new gs.functions.ajaxRequest();
722 ajax.open("GET", gs.xsltParams.library_name + "?a=g&rt=s&ro=1&s=" + serverFunction + "&s1.pid=" + pid, true);
723 ajax.onreadystatechange = function()
724 {
725 if(ajax.readyState == 4 && ajax.status == 200)
726 {
727 var text = ajax.responseText;
728 var xml = validateXML(text);
729
730 if(!xml || checkForErrors(xml))
731 {
732 alert(gs.text.dse.could_not_check_status_p1 + " " + serverFunction + gs.text.dse.could_not_check_status_p2a);
733
734 if(_statusBar)
735 {
736 _statusBar.removeStatus(statusID);
737 }
738 enableSaveButtons(true);
739
740 return;
741 }
742
743 var status = xml.getElementsByTagName("status")[0];
744 var code = status.getAttribute("code");
745
746 if (code == COMPLETED || code == SUCCESS)
747 {
748 callbackFunction();
749 }
750 else if (code == HALTED || code == ERROR)
751 {
752 alert(gs.text.dse.could_not_check_status_p1 + " " + serverFunction + gs.text.dse.could_not_check_status_p2b);
753
754 if(_statusBar)
755 {
756 _statusBar.removeStatus(statusID);
757 }
758 enableSaveButtons(true);
759 }
760 else
761 {
762 setTimeout(ajaxFunction, 1000);
763 }
764 }
765 }
766 ajax.send();
767 }
768 ajaxFunction();
769}
770
771function removeCollectionsFromBuildList(collections)
772{
773 var tempArray = new Array();
774 for(var i = 0; i < _collectionsToBuild.length; i++)
775 {
776 var found = false;
777 for(var j = 0; j < collections.length; j++)
778 {
779 if(collections[j] == _collectionsToBuild[i])
780 {
781 found = true;
782 break;
783 }
784 }
785
786 if(!found)
787 {
788 tempArray.push(_collectionsToBuild[i]);
789 }
790 }
791 _collectionsToBuild = tempArray;
792}
793
794function checkForErrors(xml)
795{
796 var errorElems = xml.getElementsByTagName("error");
797
798 if(errorElems && errorElems.length > 0)
799 {
800 var errorString = gs.text.dse.error_saving_changes + ": ";
801 for(var i = 0; i < errorElems.length; i++)
802 {
803 errorString += " " + errorElems.item(i).firstChild.nodeValue;
804 }
805 alert(errorString);
806 return true;
807 }
808 return false; //No errors
809}
810
811function validateXML(txt)
812{
813 // code for IE
814 if (window.ActiveXObject)
815 {
816 var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
817 xmlDoc.async = "false";
818 xmlDoc.loadXML(document.all(txt).value);
819
820 if(xmlDoc.parseError.errorCode!=0)
821 {
822 txt = dse.error_code + ": " + xmlDoc.parseError.errorCode + "\n";
823 txt = txt + dse.error_reason + ": " + xmlDoc.parseError.reason;
824 txt = txt + dse.error_line + ": " + xmlDoc.parseError.line;
825 console.log(txt);
826 return null;
827 }
828
829 return xmlDoc;
830 }
831 // code for Mozilla, Firefox, Opera, etc.
832 else if (document.implementation.createDocument)
833 {
834 var parser = new DOMParser();
835 var xmlDoc = parser.parseFromString(txt,"text/xml");
836
837 if (xmlDoc.getElementsByTagName("parsererror").length > 0)
838 {
839 console.log(gs.text.dse.xml_error);
840 return null;
841 }
842
843 return xmlDoc;
844 }
845 else
846 {
847 console.log(gs.text.dse.browse_cannot_validate_xml);
848 }
849 return null;
850}
851
852function onVisibleMetadataSetChange()
853{
854 var metadataList = document.getElementById("metadataSetList");
855 var index = metadataList.selectedIndex;
856 var options = metadataList.getElementsByTagName("OPTION");
857 var selectedOption = options[index];
858
859 var selectedSet = selectedOption.value;
860 changeVisibleMetadata(selectedSet);
861}
862
863function changeVisibleMetadata(metadataSetName)
864{
865 var metaSetList = metadataSetName.split(",");
866 var tables = document.getElementsByTagName("TABLE");
867 for(var i = 0; i < tables.length; i++)
868 {
869 var id = tables[i].getAttribute("id");
870 if(id && id.search(/^meta/) != -1)
871 {
872 var rows = tables[i].getElementsByTagName("TR");
873 for(var j = 0; j < rows.length; j++)
874 {
875 if(metadataSetName == "All")
876 {
877 rows[j].style.display = "table-row";
878 }
879 else
880 {
881 var cells = rows[j].getElementsByTagName("TD");
882 // metadata name cell might have the multivalue indicator in it, so just want the first word
883 var cellName = cells[0].innerHTML.split(" ")[0];
884
885 if(cellName.indexOf(".") == -1)
886 {
887 rows[j].style.display = "none";
888 }
889 else
890 {
891 var setName = cellName.substring(0, cellName.lastIndexOf("."));
892 if (metaSetList.indexOf(setName)!= -1)
893 {
894 rows[j].style.display = "table-row";
895 }
896 else
897 {
898 rows[j].style.display = "none";
899 }
900 }
901 }
902 }
903 }
904 }
905}
906
907function asyncRegisterEditSection(cell)
908{
909 //This registering can cause a sizeable delay so we'll thread it (effectively) so the browser is not paused
910 cell.originalValue = cell.value;
911 setTimeout(function(){addEditableState(cell, editableInitStates)}, 0);
912}
913
914function addOptionToList(list, optionvalue, optiontext, selected) {
915 var newOption = $("<option>");
916 if (optiontext) {
917 newOption.html(optiontext);
918 newOption.attr("value", optionvalue);
919 } else {
920 newOption.html(optionvalue);
921 }
922 if (selected) {
923 newOption.attr("selected", true);
924 }
925 list.append(newOption);
926}
927
928/* returns either an input or a select element. Data based on
929 availableMetadataElements var. */
930function createMetadataElementSelector() {
931 var metaNameField;
932 if (new_metadata_field_input_type == "fixedlist") {
933 metaNameField = $("<select>", {"class": "ui-state-default"});
934 for(var i=0; i<availableMetadataElements.length; i++) {
935 addOptionToList(metaNameField, availableMetadataElements[i]);
936 }
937 return metaNameField;
938 }
939 metaNameField = $("<input>", {"type": "text","style":"margin: 5px; border: 1px solid #000;"});
940 if (new_metadata_field_input_type == "autocomplete") {
941 metaNameField.autocomplete({
942 minLength: 0,
943 source: availableMetadataElements
944 });
945 metaNameField.attr("title", gs.text.de.enter_meta_dropdwon); //"Enter a metadata name, or use the down arrow to select one, then click 'Add New Metadata'");
946 } else {
947 metaNameField.attr("title", gs.text.de.enter_meta_name); //"Enter a metadata name, then click 'Add New Metadata'");
948 }
949
950 return metaNameField;
951}
952
953function addFunctionalityToMapGPS(mapGPScontainer)
954{
955
956}
957
958function addFunctionalityToTable(table)
959{
960 table.find("tr").each(function()
961 {
962 var cells = $(this).find("td");
963 var metadataName = $(cells[0]).html();
964
965 if(dynamic_metadata_set_list == true && metadataName.indexOf(".") != -1)
966 {
967 var metadataSetName = metadataName.substring(0, metadataName.lastIndexOf("."));
968
969 var found = false;
970 for(var j = 0; j < _metadataSetList.length; j++)
971 {
972 if(metadataSetName == _metadataSetList[j])
973 {
974 found = true;
975 break;
976 }
977 }
978
979 if(!found)
980 {
981 _metadataSetList.push(metadataSetName);
982 addOptionToList( $("#metadataSetList"), metadataSetName);
983 }
984 }
985
986 asyncRegisterEditSection(cells[1].getElementsByTagName("textarea")[0]);
987 addRemoveLinkToRow(this);
988
989 // add multivalued indicator if needed
990 if (jQuery.inArray(metadataName, multiValuedMetadata) != -1) {
991 //if (multiValuedMetadata.includes(metadataName)){
992 $(cells[0]).html(metadataName + " <span title='"+gs.text.de.multi_valued_tooltip + "' style='float:right;'>"+mvm_delimiter+"</span>"); //Multi-valued metadata. Separate values with semi-colon ;
993 }
994
995 });
996
997 // set up autocomplete values
998 var value_cells = $(".metaTableCellArea");
999 for (var k=0; k<autocompleteMetadata.length; k++) {
1000 var source_name = autocompleteMetadata[k].replace(/[\.-]/g, "");
1001 var source_obj = window[source_name+"_values"];
1002 if (source_obj) {
1003 value_cells.filter("."+source_name).autocomplete({
1004 minLength: 0,
1005 source: source_obj
1006 });
1007 }
1008 }
1009
1010 // add metadata field selector
1011 var metaNameField = createMetadataElementSelector();
1012 table.after(metaNameField);
1013 table.metaNameField = metaNameField;
1014
1015 /* add the buttons */
1016 // check enable_add_all_button - only valid for fixedlist and autocomplete
1017 if (enable_add_all_metadata_button == true) {
1018 if (new_metadata_field_input_type != "fixedlist" && new_metadata_field_input_type != "autocomplete") {
1019 enable_add_all_metadata_button = false;
1020 }
1021 }
1022
1023 // add single metadata button
1024 var addRowButton = $("<button>",{"class": "ui-state-default ui-corner-all", "style": "margin: 5px;"});
1025
1026 addRowButton.html(gs.text.de.add_new_metadata);
1027 addRowButton.click(function()
1028 {
1029 var name = metaNameField.val();
1030 if(!name || name == "")
1031 {
1032 console.log(gs.text.de.no_meta_name_given);
1033 return;
1034 }
1035 addNewMetadataRow(table, name);
1036
1037
1038 });
1039 table.addRowButton = addRowButton;
1040 metaNameField.after(addRowButton);
1041
1042 // add all metadata button
1043 if (enable_add_all_metadata_button == true) {
1044 var addAllButton = $("<button>",{"class": "ui-state-default ui-corner-all", "style": "margin: 5px;"});
1045 addAllButton.html(gs.text.de.add_all_metadata);
1046 addAllButton.click(function()
1047 {
1048 for(var i=0; i<availableMetadataElements.length; i++) {
1049
1050 addNewMetadataRow(table, availableMetadataElements[i])
1051 }
1052
1053 });
1054 table.addAllButton = addAllButton;
1055 addRowButton.after(addAllButton);
1056
1057 }
1058
1059}
1060
1061function addNewMetadataRow(table, name) {
1062
1063 var clean_name = name.replace(/[\.-]/g, "");
1064 var newRow = $("<tr>", {"style": "display: table-row;"});
1065 var nameCell;
1066 if (jQuery.inArray(name, multiValuedMetadata) != -1) {
1067 nameCell = $("<td>" + name + " <span title='"+gs.text.de.multi_valued_tooltip + "' style='float:right;'>"+mvm_delimiter+"</span></td>");
1068 } else {
1069 nameCell = $("<td>" + name + "</td>");
1070 }
1071 nameCell.attr("class", "metaTableCellName");
1072 var valueCell = $("<td>", {"class": "metaTableCell"});
1073 var textValue = $("<textarea>", {"class": "metaTableCellArea "+ clean_name});
1074
1075 if (jQuery.inArray(name, autocompleteMetadata) != -1) {
1076 var source_obje = window[clean_name +"_values"];
1077 if (source_obje) {
1078 textValue.autocomplete({
1079 minLength: 0,
1080 source: source_obje
1081 });
1082 }
1083 }
1084 valueCell.append(textValue);
1085 newRow.append(nameCell);
1086 newRow.append(valueCell);
1087 addRemoveLinkToRow(newRow.get(0));
1088 table.append(newRow);
1089
1090 var undo = new Array();
1091 undo.op = "delMeta";
1092 undo.srcElem = newRow;
1093 undo.removeTransaction = false;
1094 _undoOperations.push(undo);
1095 if ( hierarchyStorage && hierarchyStorage[name])
1096 {
1097 setHierarchyEventsWrappers(name);
1098 }
1099}
1100
1101function addRemoveLinkToRow(row)
1102{
1103 var newCell = $("<td>");
1104 var removeLink = $("<a>"+gs.text.de.remove+"</a>", {"href": "javascript:;"});
1105 removeLink.click(function()
1106 {
1107 var undo = new Array();
1108 undo.srcElem = row;
1109 undo.op = "display";
1110 undo.subOp = "table-row";
1111 undo.removeDeletedMetadata = true;
1112 _undoOperations.push(undo);
1113 _deletedMetadata.push(row);
1114 //row.css("display", "none");
1115 $(row).hide();
1116 });
1117 newCell.append(removeLink);
1118 newCell.attr({"class": "metaTableCellRemove", "style": "font-size:0.6em; padding-left: 3px; padding-right: 3px;"});
1119 $(row).append(newCell);
1120}
1121
1122/* This is for 'edit structure' menu bar */
1123function createTopMenuBar()
1124{
1125 //Create the top menu bar
1126 var headerTable = document.createElement("TABLE");
1127 var tableBody = document.createElement("TBODY");
1128 var row = document.createElement("TR");
1129 var newDocCell = document.createElement("TD");
1130 var newSecCell = document.createElement("TD");
1131 var saveCell = document.createElement("TD");
1132 var undoCell = document.createElement("TD");
1133 var metadataListCell = document.createElement("TD");
1134
1135 var metadataListLabel = document.createElement("SPAN");
1136 metadataListLabel.innerHTML = gs.text.de.visible_metadata;
1137 var metadataList = document.createElement("SELECT");
1138 metadataList.setAttribute("id", "metadataSetList");
1139 metadataList.onchange = onVisibleMetadataSetChange;
1140 var allMetadataOption = document.createElement("OPTION");
1141 metadataList.appendChild(allMetadataOption);
1142 allMetadataOption.innerHTML = gs.text.de.all_metadata;
1143 metadataListCell.appendChild(metadataListLabel);
1144 metadataListCell.appendChild(metadataList);
1145
1146 metadataListCell.setAttribute("class", "headerTableTD");
1147 newDocCell.setAttribute("class", "headerTableTD");
1148 newSecCell.setAttribute("class", "headerTableTD");
1149 undoCell.setAttribute("class", "headerTableTD");
1150 saveCell.setAttribute("class", "headerTableTD");
1151
1152 headerTable.appendChild(tableBody);
1153 tableBody.appendChild(row);
1154 row.appendChild(saveCell);
1155 row.appendChild(undoCell);
1156 row.appendChild(newDocCell);
1157 row.appendChild(newSecCell);
1158 row.appendChild(metadataListCell);
1159
1160 //The "Save changes" button
1161 var saveButton = document.createElement("BUTTON");
1162 saveButton.innerHTML = gs.text.de.save_changes;
1163 saveButton.setAttribute("onclick", "saveAndRebuild();");
1164 saveButton.setAttribute("id", "saveButton");
1165 saveCell.appendChild(saveButton);
1166
1167 //The "Undo" button
1168 var undoButton = document.createElement("BUTTON");
1169 undoButton.innerHTML = gs.text.dse.undo;
1170 undoButton.setAttribute("onclick", "undo();");
1171 undoCell.appendChild(undoButton);
1172
1173 //The "Create new document" button
1174 var newDocButton = document.createElement("BUTTON");
1175 newDocButton.innerHTML = gs.text.dse.create_new_document;
1176 newDocButton.setAttribute("onclick", "createNewDocumentArea();");
1177 newDocButton.setAttribute("id", "createNewDocumentButton");
1178 newDocCell.appendChild(newDocButton);
1179
1180 //The "Insert new section" LI
1181 var newSecLI = createDraggableNewSection(newSecCell);
1182
1183 return headerTable;
1184}
1185
1186function getMetadataFromNode(node, name)
1187{
1188 var currentNode = node.firstChild;
1189 while(currentNode != null)
1190 {
1191 if(currentNode.nodeName == "metadataList")
1192 {
1193 currentNode = currentNode.firstChild;
1194 break;
1195 }
1196
1197 currentNode = currentNode.nextSibling;
1198 }
1199
1200 while(currentNode != null)
1201 {
1202 if(currentNode.nodeName == "metadata" && currentNode.getAttribute("name") == name)
1203 {
1204 return currentNode.firstChild.nodeValue;
1205 }
1206
1207 currentNode = currentNode.nextSibling;
1208 }
1209 return "";
1210}
1211
1212function storeMetadata(node, listItem)
1213{
1214 listItem.metadata = new Array();
1215
1216 var currentNode = node.firstChild;
1217 while(currentNode != null)
1218 {
1219 if(currentNode.nodeName == "metadataList")
1220 {
1221 currentNode = currentNode.firstChild;
1222 break;
1223 }
1224
1225 currentNode = currentNode.nextSibling;
1226 }
1227
1228 while(currentNode != null)
1229 {
1230 if(currentNode.nodeName == "metadata")
1231 {
1232 listItem.metadata[currentNode.getAttribute("name")] = currentNode.firstChild.nodeValue;
1233 }
1234
1235 currentNode = currentNode.nextSibling;
1236 }
1237}
1238
1239function getNodeContent(node)
1240{
1241 var currentNode = node.firstChild;
1242 while(currentNode != null)
1243 {
1244 if(currentNode.nodeName == "nodeContent")
1245 {
1246 return currentNode.firstChild;
1247 }
1248
1249 currentNode = currentNode.nextSibling;
1250 }
1251 return null;
1252}
1253
1254function containsDocumentNode(node)
1255{
1256 var currentNode = node.firstChild;
1257 while(currentNode != null)
1258 {
1259 if(currentNode.nodeName == "documentNode")
1260 {
1261 return true;
1262 }
1263
1264 currentNode = currentNode.nextSibling;
1265 }
1266 return false;
1267}
1268
1269function isExpanded(textDiv)
1270{
1271 if(typeof textDiv.style == "undefined" || typeof textDiv.style.display == "undefined" || textDiv.style.display == "block")
1272 {
1273 return true;
1274 }
1275 return false;
1276}
1277
1278function toggleTextDiv(section)
1279{
1280 var textDiv = section.textDiv;
1281 if(textDiv)
1282 {
1283 if(isExpanded(textDiv))
1284 {
1285 textDiv.style.display = "none";
1286 section.menu.editTextLink.innerHTML = gs.text.dse.edit;
1287 }
1288 else
1289 {
1290 textDiv.style.display = "block";
1291 section.menu.editTextLink.innerHTML = gs.text.dse.hide;
1292 }
1293 }
1294}
1295
1296function updateFromTop()
1297{
1298 updateRecursive(document.getElementById("dbDiv"), null, null, 0);
1299}
1300
1301function insertAfter(elem, refElem)
1302{
1303 if(refElem.nextSibling)
1304 {
1305 refElem.parentNode.insertBefore(elem, refElem.nextSibling);
1306 }
1307 else
1308 {
1309 refElem.parentNode.appendChild(elem);
1310 }
1311}
1312
1313function removeFromParent(elem)
1314{
1315 elem.parentNode.removeChild(elem);
1316}
1317
1318function createSectionTitle(text)
1319{
1320 var textSpan = document.createElement("SPAN");
1321 if(text)
1322 {
1323 textSpan.appendChild(document.createTextNode(" " + text + " "));
1324 }
1325 else
1326 {
1327 textSpan.appendChild(document.createTextNode(" [" + gs.text.dse.untitled_section + "] "));
1328 }
1329 return textSpan;
1330}
1331
1332function setMouseOverAndOutFunctions(section)
1333{
1334 //Colour the list item and display the menu on mouse over
1335 section.onmouseover = function(e)
1336 {
1337 if(this.menu){this.menu.style.display = "inline";}
1338 this.style.background = "rgb(255, 200, 0)";
1339 };
1340 //Uncolour the list item and hide the menu on mouse out
1341 section.onmouseout = function(e)
1342 {
1343 if(this.menu){this.menu.style.display = "none";}
1344 this.style.background = "none";
1345 };
1346}
1347
1348function createDraggableNewSection(parent)
1349{
1350 var newSecLI = document.createElement("LI");
1351 var newSpan = document.createElement("SPAN");
1352 newSpan.innerHTML = gs.text.dse.insert_new_section + " ";
1353
1354 newSecLI.sectionTitle = newSpan;
1355 newSecLI.appendChild(newSpan);
1356 newSecLI.setAttribute("class", "dragItem newSection");
1357 newSecLI.newSection = true;
1358 newSecLI.parent = parent;
1359 newSecLI.index = -1;
1360 new YAHOO.example.DDList(newSecLI);
1361 parent.appendChild(newSecLI);
1362}
1363
1364function closeAllOpenContents()
1365{
1366 for(var i = 0; i < _allContents.length; i++)
1367 {
1368 if(isExpanded(_allContents[i].textDiv))
1369 {
1370 toggleTextDiv(_allContents[i]);
1371 }
1372 }
1373 DDM.refreshCache();
1374}
1375
1376//Status Bar class (initialised with new StatusBar(elem);)
1377function StatusBar(mainElem)
1378{
1379 var _statusMap = new Array();
1380 var _statusIDCounter = 0;
1381 var _mainElem = mainElem;
1382 var _activeMessages = 0;
1383
1384 _mainElem.style.display = "none";
1385
1386 this.addStatus = function(newStatus)
1387 {
1388 _mainElem.style.display = "block";
1389 var newStatusDiv = document.createElement("DIV");
1390 var newStatusSpan = document.createElement("SPAN");
1391
1392 var workingImage = document.createElement("IMG");
1393 workingImage.setAttribute("src", gs.imageURLs.loading);
1394 workingImage.setAttribute("height", "16px");
1395 workingImage.setAttribute("width", "16px");
1396 newStatusDiv.appendChild(workingImage);
1397
1398 newStatusDiv.appendChild(newStatusSpan);
1399 newStatusSpan.innerHTML = " " + newStatus;
1400 newStatusDiv.setAttribute("class", "statusMessage");
1401 newStatusDiv.span = newStatusSpan;
1402
1403 _mainElem.appendChild(newStatusDiv);
1404 _statusMap["status" + _statusIDCounter] = newStatusDiv;
1405 _activeMessages++;
1406 return _statusIDCounter++;
1407 }
1408
1409 this.changeStatus = function(id, newStatus)
1410 {
1411 if(_statusMap["status" + id])
1412 {
1413 _statusMap["status" + id].span.innerHTML = " " + newStatus;
1414 }
1415 }
1416
1417 this.removeStatus = function(id)
1418 {
1419 if(_statusMap["status" + id])
1420 {
1421 removeFromParent(_statusMap["status" + id]);
1422
1423 if(--_activeMessages == 0)
1424 {
1425 _mainElem.style.display = "none";
1426 }
1427 }
1428 }
1429
1430 this.clear = function()
1431 {
1432 for(var p in _statusMap)
1433 {
1434 if(_statusMap.hasOwnProperty(p))
1435 {
1436 if(_statusMap[p] && _statusMap[p].parentNode)
1437 {
1438 removeFromParent(_statusMap[p]);
1439 }
1440
1441 if(--_activeMessages == 0)
1442 {
1443 _mainElem.style.display = "none";
1444 }
1445 }
1446 }
1447 }
1448}
1449
1450/*
1451function toggleEdit(e)
1452{
1453 var mousePos = de.events.getXYInWindowFromEvent(e);
1454 var cDesc = de.cursor.getCursorDescAtXY(mousePos.x, mousePos.y, de.events.getEventTarget(e));
1455 de.cursor.setCursor(cDesc);
1456}
1457*/
Note: See TracBrowser for help on using the repository browser.