source: main/trunk/greenstone3/web/interfaces/default/js/visual-xml-editor.js@ 26970

Last change on this file since 26970 was 26970, checked in by sjm84, 11 years ago

Another bug fix

File size: 26.7 KB
Line 
1// ********************************************************************** //
2// Visual XML Editor //
3// This class represents an editor that allows you to modify XML visually //
4// ********************************************************************** //
5
6function visualXMLEditor(xmlString)
7{
8 var _globalID = 0;
9
10 var _xml;
11
12 var _mainDiv = $("<div>", {"id":"veMainDiv"});
13 var _toolboxDiv = $("<div>", {"id":"veToolboxDiv"});
14 var _editorContainer = $("<div>", {"id":"veEditorContainer"});
15 var _editorDiv = $("<div>", {"id":"veEditorDiv"});
16 var _infoDiv = $("<div>", {"id":"veInfoDiv"});
17 var _rootElement;
18 var _selectedElement;
19
20 var _validDropSpot = false;
21 var _validDropType;
22 var _validDropElem;
23
24 var _origDDParent;
25 var _origDDPosition;
26
27 var _overList = new Array();
28 _overList.freeSpaces = new Array();
29
30 var _transactions = new Array();
31
32 var _childRestrictions =
33 {
34 gsf:
35 {
36 "choose-metadata":["gsf:metadata", "gsf:default"]
37 }
38 };
39
40 this.getXML = function()
41 {
42 return _xml;
43 }
44
45 this.undo = function()
46 {
47 if(_transactions.length > 0)
48 {
49 var t = _transactions.pop();
50 //Undo an added element
51 if(t.type == "addElem")
52 {
53 $(t.vElem.data("parentVEElement").getXMLNode()).remove();
54 t.vElem.remove();
55 resizeAll();
56 }
57 //Undo a removed or moved element
58 else if(t.type == "remMvElem")
59 {
60 var parent = t.vElemParent;
61 var pos = t.vElemPos;
62 var elem = t.vElem;
63
64 elem.detach();
65 if(pos == 0)
66 {
67 parent.prepend(elem);
68 $(parent.parent().data("parentVEElement").getXMLNode()).prepend(elem.data("parentVEElement").getXMLNode());
69 }
70 else if(pos == parent.children(".veElement").length)
71 {
72 $(parent.children(".veElement").eq(pos - 1).data("parentVEElement").getXMLNode()).after(elem.data("parentVEElement").getXMLNode());
73 parent.children(".veElement").eq(pos - 1).after(elem);
74 }
75 else
76 {
77 $(parent.children(".veElement").eq(pos).data("parentVEElement").getXMLNode()).before(elem.data("parentVEElement").getXMLNode());
78 parent.children(".veElement").eq(pos).before(elem);
79 }
80 resizeAll();
81 }
82 //Undo an added attribute
83 else if(t.type == "addAttr")
84 {
85 if(t.row)
86 {
87 t.row.remove();
88 }
89 }
90 //Undo a removed or edited attribute
91 else if(t.type == "editAttr")
92 {
93 t.elem.removeAttribute(t.newName);
94 t.elem.setAttribute(t.name, t.value);
95 if(t.row)
96 {
97 t.row.children("td").eq(0).text(t.name);
98 t.row.children("td").eq(1).text(t.value);
99 }
100 }
101 //Undo a removed or edited attribute
102 else if(t.type == "remAttr")
103 {
104 t.elem.setAttribute(t.name, t.value);
105 if(t.rowParent)
106 {
107 t.rowParent.append(t.row);
108 }
109 }
110 //Undo edited text
111 else if(t.type == "editText")
112 {
113 t.elem.nodeValue = t.value;
114 if(t.vElem)
115 {
116 t.vElem.text(t.value);
117 }
118 }
119 }
120 }
121
122 var checkRestricted = function(child, parent)
123 {
124 var pFullNodename = parent.tagName;
125 var cFullNodename = child.tagName;
126 var pNamespace;
127 var pNodeName;
128 if(pFullNodename.indexOf(":") == -1)
129 {
130 pNamespace = "no namespace";
131 pNodeName = pFullNodename;
132 }
133 else
134 {
135 pNamespace = pFullNodename.substring(0, pFullNodename.indexOf(":"));
136 pNodeName = pFullNodename.substring(pFullNodename.indexOf(":") + 1);
137 }
138
139 var namespaceList = _childRestrictions[pNamespace];
140 if(namespaceList)
141 {
142 var childList = namespaceList[pNodeName];
143 if(childList)
144 {
145 for(var i = 0; i < childList.length; i++)
146 {
147 if(childList[i] == cFullNodename)
148 {
149 return true;
150 }
151 }
152 return false;
153 }
154 }
155
156 return true;
157 }
158
159 var populateToolbar = function()
160 {
161 var elemList =
162 {
163 html:["a", "div", "li", "script", "span", "table", "td", "tr", "ul"],
164 xsl:
165 [
166 "apply-imports", "apply-templates", "attribute", "attribute-set", "call-template",
167 "choose", "copy", "copy-of", "decimal-format", "element",
168 "fallback", "for-each", "if", "import", "include",
169 "key", "message", "namespace-alias", "number", "otherwise",
170 "output", "param", "preserve-space", "processing-instruction", "sort",
171 "strip-space", "stylesheet", "template", "text", "transform",
172 "value-of", "variable", "when", "with-param"
173 ],
174 gsf:
175 [
176 "cgi-param", "choose-metadata", "collectionText", "displayItem", "displayText",
177 "equivlinkgs3", "foreach-metadata", "icon", "if-metadata-exists", "image",
178 "interfaceText", "link", "meta-value", "metadata", "script",
179 "style", "switch", "template", "text", "variable"
180 ]
181 };
182
183 var tabHolder = $("<ul>");
184 _toolboxDiv.append(tabHolder);
185
186 for(var key in elemList)
187 {
188 var currentList = elemList[key];
189
190 var tab = $("<li>");
191 var tabLink = $("<a>", {"href":"#ve" + key});
192 tabLink.css({"font-size":"0.9em", "padding":"5px"});
193 tabLink.text(key);
194 tab.append(tabLink);
195 tabHolder.append(tab);
196
197 var tabDiv = $("<div>", {"id":"ve" + key});
198 for(var j = 0; j < currentList.length; j++)
199 {
200 var elemName = currentList[j];
201
202 var ns = (key == "html") ? "" : (key + ":");
203
204 var newElem = _xml.createElement(ns + elemName);
205 var veElement = new VEElement(newElem);
206 var veDiv = veElement.getDiv();
207 veDiv.css("float", "none");
208 veDiv.data("toolbar", true);
209 tabDiv.append(veDiv);
210 }
211
212 _toolboxDiv.append(tabDiv);
213 }
214
215 var otherTab = $("<li>");
216 var otherTabLink = $("<a>", {"href":"#veother"});
217 otherTabLink.css({"font-size":"0.9em", "padding":"5px"});
218 otherTabLink.text("other");
219 otherTab.append(otherTabLink);
220 tabHolder.append(otherTab);
221
222 var otherTabDiv = $("<div>", {"id":"veother"});
223 var textNode = _xml.createTextNode("text");
224 var textVEElement = new VEElement(textNode);
225 var textDiv = textVEElement.getDiv();
226 textDiv.css("float", "none");
227 textDiv.data("toolbar", true);
228 otherTabDiv.append(textDiv);
229
230 var customInput = $("<input type=\"text\">");
231 var customElemHolder = $("<div>");
232 var customCreateButton = $("<button>Create element</button>");
233 customCreateButton.click(function()
234 {
235 var elemName = customInput.val();
236 if(elemName.length)
237 {
238 var elem = _xml.createElement(elemName);
239 var veElement = new VEElement(elem);
240 var customElemDiv = veElement.getDiv();
241 customElemDiv.css("float", "none");
242 customElemDiv.data("toolbar", true);
243 customElemHolder.empty();
244 customElemHolder.append(customElemDiv);
245 }
246 });
247 otherTabDiv.append(customInput);
248 otherTabDiv.append(customCreateButton);
249 otherTabDiv.append(customElemHolder);
250
251 _toolboxDiv.append(otherTabDiv);
252
253 _toolboxDiv.tabs();
254 }
255
256 var constructDivsRecursive = function(currentDiv, currentParent, level)
257 {
258 if(!level)
259 {
260 level = 1;
261 }
262
263 var container = $("<div>");
264 container.addClass("veContainerElement");
265 currentDiv.append(container);
266
267 var allowedList = new Array();
268 var counter = currentParent.firstChild;
269 while(counter)
270 {
271 if(counter.nodeType == 1)
272 {
273 allowedList.push(counter)
274 }
275 else if(counter.nodeType == 3 && counter.nodeValue.search(/\S/) != -1)
276 {
277 allowedList.push(counter)
278 }
279 counter = counter.nextSibling;
280 }
281
282 var width = 100 / allowedList.length;
283 for(var i = 0; i < allowedList.length; i++)
284 {
285 var currentElement = allowedList[i];
286
287 var veElement = new VEElement(currentElement);
288 var elementDiv = veElement.getDiv();
289 veElement.setWidth(width);
290
291 if(!_rootElement)
292 {
293 _rootElement = elementDiv;
294 }
295
296 container.append(elementDiv);
297 if(currentElement.firstChild)
298 {
299 constructDivsRecursive(elementDiv, currentElement, level + 1);
300 }
301
302 currentElement = currentElement.nextSibling;
303 }
304
305 container.append($("<div>", {"style":"clear:both;"}));
306 }
307
308 this.selectRootElement = function()
309 {
310 var height = _editorDiv.height() + 10;
311 if(height < 300){height = 300;}
312
313 _editorContainer.css("height", height + "px");
314 _infoDiv.css("height", height + "px");
315 _rootElement.trigger("click");
316 }
317
318 this.getMainDiv = function()
319 {
320 return _mainDiv;
321 }
322
323 var addToOverList = function(veElement)
324 {
325 for(var i = 0; i < _overList.length; i++)
326 {
327 if(!_overList[i])
328 {
329 continue;
330 }
331
332 if(_overList[i].getID() == veElement.getID())
333 {
334 return false;
335 }
336 }
337
338 if(_overList.freeSpaces.length > 0)
339 {
340 _overList[_overList.freeSpaces.pop()] = veElement;
341 }
342 else
343 {
344 _overList.push(veElement);
345 }
346 }
347
348 var removeFromOverList = function(veElement)
349 {
350 for(var i = 0; i < _overList.length; i++)
351 {
352 if(!_overList[i])
353 {
354 continue;
355 }
356
357 if(_overList[i].getID() == veElement.getID())
358 {
359 delete _overList[i];
360 _overList.freeSpaces.push(i);
361 }
362 }
363 }
364
365 var getDeepestOverElement = function()
366 {
367 if(_overList.length == 0)
368 {
369 return null;
370 }
371
372 var deepestVal = 0;
373 var deepestElem = _overList[0];
374
375 for(var i = 0; i < _overList.length; i++)
376 {
377 if(!_overList[i])
378 {
379 continue;
380 }
381
382 var depth = _overList[i].getDiv().parents(".veElement").length;
383 depth = (depth) ? depth : 0;
384
385 if (depth > deepestVal)
386 {
387 deepestVal = depth;
388 deepestElem = _overList[i];
389 }
390 }
391
392 return deepestElem;
393 }
394
395 var resizeAll = function()
396 {
397 var filterFunction = function()
398 {
399 var toolbarStatus = $(this).data("toolbar");
400 var beingDraggedStatus = $(this).data("dragging");
401
402 if(beingDraggedStatus || !toolbarStatus)
403 {
404 return true;
405 }
406
407 return false;
408 }
409
410 var allElems = $(".veElement").filter(filterFunction).each(function()
411 {
412 if($(this).data("helper")){return;}
413
414 var size = $(this).data("expanded");
415 if(size == "small")
416 {
417 var width = (10 / ($(this).siblings(".veElement").filter(function(){return !($(this).data("helper"))}).length - 1));
418 $(this).css("width", width + "%");
419 }
420 else if(size == "normal")
421 {
422 var width = (100 / ($(this).siblings(".veElement").filter(function(){return !($(this).data("helper"))}).length + 1));
423 $(this).css("width", width + "%");
424 }
425 else if(size == "expanded")
426 {
427 $(this).css("width", "90%");
428 }
429 });
430 }
431
432 var initVXE = function()
433 {
434 try
435 {
436 _xml = $.parseXML('<testContainer xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:java="http://xml.apache.org/xslt/java" xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil" xmlns:gslib="http://www.greenstone.org/skinning" xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat">' + xmlString + "</testContainer>");
437 constructDivsRecursive(_editorDiv, _xml.firstChild);
438 }
439 catch(error)
440 {
441 console.log(error);
442 return null;
443 }
444
445 populateToolbar();
446
447 _editorContainer.append(_editorDiv);
448 _mainDiv.append(_toolboxDiv);
449 _mainDiv.append(_editorContainer);
450 _mainDiv.append($("<div>", {"id":"veSpacerDiv"}));
451 _mainDiv.append(_infoDiv);
452 _mainDiv.append($("<div>", {"style":"clear:both;"}));
453 }
454
455 // *********************************************************************** //
456 // Visual Editor Attribute //
457 // This inner class represents a single xml attribute in the visual editor //
458 // *********************************************************************** //
459
460 var VEAttribute = function(attrElem, xmlElem, name, value)
461 {
462 var _name;
463 if(name)
464 {
465 _name = name;
466 }
467 else if(attrElem && attrElem.name)
468 {
469 _name = attrElem.name;
470 }
471
472 var _value;
473 if(value)
474 {
475 _value = value;
476 }
477 else if(attrElem && attrElem.value)
478 {
479 _value = attrElem.value;
480 }
481
482 var _xmlElem = xmlElem;
483 var _row;
484
485 this.getName = function()
486 {
487 return _name;
488 }
489
490 this.getValue = function()
491 {
492 return _value;
493 }
494
495 var createNameCell = function()
496 {
497 var cell = $("<td>", {"class":"veNameCell"});
498 cell.text(_name);
499 return cell;
500 }
501
502 var createValueCell = function()
503 {
504 var cell = $("<td>", {"class":"veValueCell"});
505 cell.text(_value);
506 return cell;
507 }
508
509 var createEditCell = function()
510 {
511 var cell = $("<td>", {"class":"veEditCell"});
512 var link = $("<a href=\"javascript:;\">edit</a>");
513 link.click(function()
514 {
515 var nameCell = _row.children("td").eq(0);
516 var valueCell = _row.children("td").eq(1);
517 if(link.text() == "edit")
518 {
519 link.text("save edit");
520
521 var nameInput = $("<input type=\"text\">");
522 nameInput.width(nameCell.width() - 5);
523 nameInput.val(_name);
524
525 var valueInput = $("<input type=\"text\">");
526 valueInput.width(valueCell.width() - 5);
527 valueInput.val(_value);
528
529 nameCell.text("");
530 valueCell.text("");
531
532 nameCell.append(nameInput);
533 valueCell.append(valueInput);
534 }
535 else
536 {
537 link.text("edit");
538
539 var nameInput = nameCell.children("input");
540 var valueInput = valueCell.children("input");
541
542 var name = nameInput.val();
543 var value = valueInput.val();
544
545 nameCell.empty();
546 nameCell.text(name);
547
548 valueCell.empty();
549 valueCell.text(value);
550
551 if(nameCell.data("prevName") != "")
552 {
553 _xmlElem.removeAttribute(_name);
554 }
555 _xmlElem.setAttribute(name, value);
556
557 _transactions.push({type:"editAttr", elem:_xmlElem, row:_row, newName:name, name:_name, value:_value});
558
559 _name = name;
560 _value = value;
561 }
562 });
563 cell.append(link);
564 return cell;
565 }
566
567 var createDeleteCell = function()
568 {
569 var cell = $("<td>", {"class":"veDeleteCell"});
570 var link = $("<a href=\"javascript:;\">delete</a>");
571 link.click(function()
572 {
573 _transactions.push({type:"remAttr", elem:_xmlElem, row:_row, rowParent:_row.parent(), name:_name, value:_value});
574 _xmlElem.removeAttribute(_name);
575 _row.detach();
576 });
577 cell.append(link);
578 return cell;
579 }
580
581 this.getAsTableRow = function()
582 {
583 var tableRow = $("<tr>");
584
585 var attributeName = createNameCell();
586 tableRow.append(attributeName);
587
588 var attributeValue = createValueCell();
589 tableRow.append(attributeValue);
590
591 var editCell = createEditCell()
592 tableRow.append(editCell);
593
594 var deleteCell = createDeleteCell();
595 tableRow.append(deleteCell);
596
597 _row = tableRow;
598
599 return tableRow;
600 }
601 }
602
603 // ********************************************************************************** //
604 // Visual Editor Element //
605 // This inner class represents a single xml element or text node in the visual editor //
606 // ********************************************************************************** //
607 var VEElement = function(xml)
608 {
609 var _div = $("<div>");
610 var _xmlNode = xml;
611 var _id = _globalID++;
612
613 _div.data("parentVEElement", this);
614 _div.data("expanded", "normal");
615
616 var makeDraggable = function()
617 {
618 _div.draggable(
619 {
620 "revert":"true",
621 "helper":function()
622 {
623 //Make sure the cursor is put in the centre of the div
624 var height = _div.children(".veTitleElement").height();
625 _div.draggable("option", "cursorAt", {top:(height / 2), left:(_div.width() / 2)});
626
627 var tempVEE = new VEElement(_xmlNode);
628 var tempDiv = tempVEE.getDiv();
629 tempDiv.css("border", "1px solid orangered");
630 tempDiv.css("background", "orange");
631 tempDiv.width(_div.width());
632 tempDiv.data("helper", true);
633 return tempDiv;
634 },
635 "cursor":"move",
636 "appendTo":_mainDiv,
637 "start":function(event, ui)
638 {
639 _origDDParent = _div.parent();
640 _origDDPosition = _div.index();
641
642 _div.siblings(".veElement").filter(function(){return !($(this).data("helper"))}).data("expanded", "normal");
643 _div.css("border", "1px solid orangered");
644 _div.data("prevBackground", _div.css("background"));
645 _div.css("background", "orange");
646 _div.css("float", "left");
647
648 _div.data("dragging", true);
649 if(_div.data("toolbar"))
650 {
651 var cloneElem = new VEElement(_xmlNode.cloneNode(true));
652 var cloneDiv = cloneElem.getDiv();
653 cloneDiv.css("float", "none");
654 cloneDiv.data("toolbar", true);
655 _div.before(cloneDiv);
656 }
657 _div.detach();
658
659 resizeAll();
660 },
661 "drag":function(event, ui)
662 {
663 var foundDefined = false;
664 for(var i = 0; i < _overList.length; i++)
665 {
666 if(!(_overList[i] === "undefined"))
667 {
668 foundDefined = true;
669 }
670 }
671
672 _validDropSpot = false;
673 if(foundDefined)
674 {
675 var overElement = getDeepestOverElement();
676 if(overElement && overElement.getXMLNode().nodeType != 3 && checkRestricted(_xmlNode, overElement.getXMLNode()))
677 {
678 _validDropSpot = true;
679 var overDiv = overElement.getDiv();
680
681 var overLeft = overDiv.offset().left;
682 var helperLeft = ui.helper.offset().left;
683 var helperMiddle = helperLeft + (ui.helper.width() / 2);
684
685 var overContainers = overDiv.children(".veContainerElement");
686 if(!overContainers.length)
687 {
688 overDiv.append($("<div>", {"class":"veContainerElement"}));
689 overContainers = overDiv.children(".veContainerElement");
690 }
691 var overChildren = overContainers.children(".veElement").filter(function(){return !($(this).data("helper")) && !(_div.data("parentVEElement").getID() == $(this).data("parentVEElement").getID())});
692 var overChildrenLength = overChildren.length + 1;
693
694 if(!overChildren.length)
695 {
696 _validDropElem = overDiv;
697 _validDropType = "into";
698 overContainers.append(_div);
699 }
700 else
701 {
702 var posPercent = (helperMiddle - overLeft) / overDiv.width();
703 if(posPercent < 0)
704 {
705 posPercent = 0;
706 }
707 else if(posPercent > 1)
708 {
709 posPercent = 1;
710 }
711 var pos = Math.floor(overChildrenLength * posPercent);
712
713 if(pos < overChildrenLength - 1)
714 {
715 _validDropElem = overChildren.eq(pos);
716 _validDropType = "before";
717 overChildren.eq(pos).before(_div);
718 }
719 else
720 {
721 _validDropElem = overChildren.eq(pos - 1);
722 //Necessary to fix a rare bug that causes pos to be off by one
723 if(!_validDropElem.length)
724 {
725 _validDropElem = overChildren.eq(pos - 2);
726 }
727 _validDropType = "after";
728 overChildren.eq(pos - 1).after(_div);
729 }
730 }
731
732 overChildren.data("expanded", "normal");
733 _div.data("expanded", "normal");
734
735 resizeAll();
736 }
737 }
738 },
739 "stop":function(event)
740 {
741 var transactionType = (_div.data("toolbar")) ? "addElem" : "remMvElem";
742 _div.data("dragging", false);
743 _div.data("toolbar", false);
744
745 _div.css("border", "1px dashed black");
746 _div.css("background", _div.data("prevBackground"));
747
748 //If the element was not dropped in a valid place then put it back
749 if(!_validDropSpot)
750 {
751 _div.detach();
752 if(_origDDPosition == 0)
753 {
754 _origDDParent.prepend(_div);
755 }
756 else if(_origDDPosition == _origDDParent.children(".veElement").length)
757 {
758 _origDDParent.children(".veElement").eq(_origDDPosition - 1).after(_div);
759 }
760 else
761 {
762 _origDDParent.children(".veElement").eq(_origDDPosition).before(_div);
763 }
764
765 resizeAll();
766 }
767 //Otherwise modify the XML
768 else
769 {
770 var xmlNode = _validDropElem.data("parentVEElement").getXMLNode();
771 if(_validDropType == "before")
772 {
773 $(xmlNode).before(_xmlNode);
774 }
775 else if (_validDropType == "after")
776 {
777 $(xmlNode).after(_xmlNode);
778 }
779 else if (_validDropType == "into")
780 {
781 $(xmlNode).append(_xmlNode);
782 }
783 _transactions.push({type:transactionType, vElemParent:_origDDParent, vElemPos:_origDDPosition, vElem:_div});
784 }
785
786 _overList = new Array();
787 _overList.freeSpaces = new Array();
788 }
789 });
790
791 _div.droppable(
792 {
793 "over":function(event, ui)
794 {
795 addToOverList($(this).data("parentVEElement"));
796 event.stopPropagation();
797 },
798 "out":function(event)
799 {
800 removeFromOverList($(this).data("parentVEElement"));
801 event.stopPropagation();
802 }
803 });
804 }
805
806 this.getDiv = function()
807 {
808 return _div;
809 }
810
811 this.getXMLNode = function()
812 {
813 return _xmlNode;
814 }
815
816 this.getID = function()
817 {
818 return _id;
819 }
820
821 var createTableHeader = function()
822 {
823 var tableHeader = $("<tr>");
824 tableHeader.html("<td class=\"veNameCell\">Name</td><td class=\"veValueCell\">Value</td>");
825 return tableHeader;
826 }
827
828 this.populateInformationDiv = function()
829 {
830 _infoDiv.empty();
831
832 var nameElement = $("<p>");
833 if(_xmlNode.nodeType == 1)
834 {
835 nameElement.text("Name: " + _xmlNode.nodeName);
836 }
837 else
838 {
839 nameElement.text("[text node]");
840 }
841 _infoDiv.append(nameElement);
842
843 if(_xmlNode.nodeType == 1)
844 {
845 var attributeTableTitle = $("<p>Attributes:<p/>");
846 var attributeTable = $("<table>");
847 attributeTable.addClass("veAttributeTableContainer");
848
849 attributeTable.append(createTableHeader());
850
851 $(_xmlNode.attributes).each(function()
852 {
853 var veAttribute = new VEAttribute(this, _xmlNode);
854 attributeTable.append(veAttribute.getAsTableRow());
855 });
856
857 _infoDiv.append(attributeTableTitle);
858 _infoDiv.append(attributeTable);
859
860 var addButton = $("<button>Add attribute</button>");
861 addButton.click(function()
862 {
863 var newAtt = new VEAttribute(null, _xmlNode, "", "");
864 var row = newAtt.getAsTableRow();
865 attributeTable.append(row);
866 _transactions.push({type:"addAttr", row:row})
867 });
868 _infoDiv.append(addButton);
869 }
870
871 if(_xmlNode.nodeType == 3)
872 {
873 var textEditor = $("<div>");
874 var textTitle = $("<div>Text:</div>");
875 var nodeText = $("<div>");
876 nodeText.text(_xmlNode.nodeValue);
877
878 textEditor.append(textTitle);
879 textEditor.append(nodeText);
880
881 _infoDiv.append(textEditor);
882
883 var editButton = $("<button>edit text</button>");
884 editButton.click(function()
885 {
886 if(editButton.text() == "edit text")
887 {
888 nodeText.data("prevTextValue", nodeText.text());
889 var textArea = $("<textarea>");
890 textArea.val(nodeText.text());
891 nodeText.text("");
892 nodeText.append(textArea);
893 editButton.text("save edit");
894 }
895 else
896 {
897 _transactions.push({type:"editText", elem:_xmlNode, vElem: nodeText, value:nodeText.data("prevTextValue")});
898 var textArea = nodeText.find("textarea");
899 var newValue = textArea.val();
900 _xmlNode.nodeValue = newValue;
901 nodeText.empty();
902 nodeText.text(newValue);
903 editButton.text("edit text");
904 }
905 });
906
907 textEditor.append(editButton);
908 }
909
910 _infoDiv.append($("<br>"));
911 _infoDiv.append($("<br>"));
912
913 var removeButton = $("<button>Delete this element</button>");
914 _infoDiv.append(removeButton);
915 removeButton.click(function()
916 {
917 var divParent = _div.parents(".veElement");
918 _transactions.push({type:"remMvElem", vElemParent:_div.parent(), vElemPos:_div.index(), vElem:_div});
919 _div.data("expanded", "normal");
920 $(_xmlNode).remove();
921 _div.detach();
922 _infoDiv.empty();
923
924 if(divParent.length)
925 {
926 divParent.first().trigger("click");
927 }
928 });
929 }
930
931 var addMouseEvents = function()
932 {
933 _div.mouseover(function(event)
934 {
935 event.stopPropagation();
936 _div.css("border", "1px solid orange");
937 var titleString = " ";
938 if(_xmlNode.nodeType == 1)
939 {
940 for(var i = 0; i < _xmlNode.attributes.length; i++)
941 {
942 var current = _xmlNode.attributes[i];
943 var name = current.name;
944 var value = current.value;
945
946 titleString += name + "=\"" + value + "\" ";
947 }
948 }
949 else if(_xmlNode.nodeType == 3)
950 {
951 titleString = _xmlNode.nodeValue;
952 }
953 _div.attr("title", titleString);
954 });
955 _div.mouseout(function(event)
956 {
957 _div.css("border", "1px dashed black");
958 event.stopPropagation();
959 });
960 _div.click(function(event)
961 {
962 if(_selectedElement)
963 {
964 _selectedElement.css("border", _selectedElement.prevBorder);
965 }
966 _selectedElement = _div;
967 _div.prevBorder = _div.css("border");
968 _div.css("border", "red solid 1px");
969
970 _div.data("parentVEElement").focus();
971 _div.data("parentVEElement").populateInformationDiv();
972
973 event.stopPropagation();
974 });
975 }
976
977 this.expand = function()
978 {
979 var siblings = _div.siblings(".veElement");
980 if(!(_div.data("expanded") == "expanded") && siblings.length && siblings.length > 0)
981 {
982 var sibWidth = 10 / siblings.length;
983 siblings.each(function()
984 {
985 $(this).animate({width:sibWidth + "%"}, 900);
986 $(this).data("expanded", "small");
987 });
988
989 _div.animate({width:"90%"}, 1000);
990 _div.data("expanded", "expanded");
991 }
992 }
993
994 this.evenlyDistributeChildren = function()
995 {
996 var children = _div.find(".veElement")
997 .each(function()
998 {
999 $(this).data("expanded", "normal");
1000 var length = $(this).siblings(".veElement").filter(function(){return !($(this).data("helper"))}).length + 1;
1001 $(this).css("width", (100 / length) + "%");//$(this).animate({"width":(100 / length) + "%"}, 900);
1002 });
1003 }
1004
1005 this.focus = function()
1006 {
1007 _div.data("parentVEElement").expand();
1008
1009 var parents = _div.parents(".veElement");
1010 parents.each(function()
1011 {
1012 $(this).data("parentVEElement").expand();
1013 });
1014
1015 _div.data("parentVEElement").evenlyDistributeChildren();
1016 }
1017
1018 this.setWidth = function(width)
1019 {
1020 _div.css("width", width + "%");
1021 }
1022
1023 //Visual Editor Element constructor
1024 var initVEE = function()
1025 {
1026 _div.addClass("veElement");
1027 makeDraggable();
1028
1029 var titleText;
1030 if(_xmlNode.nodeType == 3 && _xmlNode.nodeValue.search(/\S/) != -1)
1031 {
1032 _div.addClass("veTextElement");
1033 titleText = "[text]";
1034 }
1035 else if (_xmlNode.nodeType == 1)
1036 {
1037 if(_xmlNode.tagName.search(/^xsl/) != -1)
1038 {
1039 _div.addClass("veXSLElement");
1040 }
1041 else if(_xmlNode.tagName.search(/^gsf/) != -1)
1042 {
1043 _div.addClass("veGSFElement");
1044 }
1045 else if(_xmlNode.tagName.search(/^gslib/) != -1)
1046 {
1047 _div.addClass("veGSLIBElement");
1048 }
1049 else
1050 {
1051 _div.addClass("veHTMLElement");
1052 }
1053 titleText = _xmlNode.tagName;
1054 }
1055
1056 addMouseEvents();
1057
1058 _div.append("<div class=\"veTitleElement\">" + titleText + "</div>");
1059 }
1060
1061 initVEE();
1062 }
1063
1064 //Call the constructor
1065 initVXE();
1066}
Note: See TracBrowser for help on using the repository browser.