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

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

Implemented the ability to restrict the types of elements are allowed inside another element as well as more bug fixing

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 if(pos == 0)
65 {
66 parent.prepend(elem);
67 $(parent.parent().data("parentVEElement").getXMLNode()).prepend(elem.data("parentVEElement").getXMLNode());
68 }
69 else if(pos == parent.children(".veElement").length)
70 {
71 $(parent.children(".veElement").eq(pos - 1).data("parentVEElement").getXMLNode()).after(elem.data("parentVEElement").getXMLNode());
72 parent.children(".veElement").eq(pos - 1).after(elem);
73 }
74 else
75 {
76 $(parent.children(".veElement").eq(pos).data("parentVEElement").getXMLNode()).before(elem.data("parentVEElement").getXMLNode());
77 parent.children(".veElement").eq(pos).before(elem);
78 }
79 resizeAll();
80 }
81 //Undo an added attribute
82 else if(t.type == "addAttr")
83 {
84 if(t.row)
85 {
86 t.row.remove();
87 }
88 }
89 //Undo a removed or edited attribute
90 else if(t.type == "editAttr")
91 {
92 t.elem.removeAttribute(t.newName);
93 t.elem.setAttribute(t.name, t.value);
94 if(t.row)
95 {
96 t.row.children("td").eq(0).text(t.name);
97 t.row.children("td").eq(1).text(t.value);
98 }
99 }
100 //Undo a removed or edited attribute
101 else if(t.type == "remAttr")
102 {
103 t.elem.setAttribute(t.name, t.value);
104 if(t.rowParent)
105 {
106 t.rowParent.append(t.row);
107 }
108 }
109 //Undo edited text
110 else if(t.type == "editText")
111 {
112 t.elem.nodeValue = t.value;
113 if(t.vElem)
114 {
115 t.vElem.text(t.value);
116 }
117 }
118 }
119 }
120
121 var checkRestricted = function(child, parent)
122 {
123 var pFullNodename = parent.tagName;
124 var cFullNodename = child.tagName;
125 var pNamespace;
126 var pNodeName;
127 if(pFullNodename.indexOf(":") == -1)
128 {
129 pNamespace = "no namespace";
130 pNodeName = pFullNodename;
131 }
132 else
133 {
134 pNamespace = pFullNodename.substring(0, pFullNodename.indexOf(":"));
135 pNodeName = pFullNodename.substring(pFullNodename.indexOf(":") + 1);
136 }
137
138 var namespaceList = _childRestrictions[pNamespace];
139 if(namespaceList)
140 {
141 var childList = namespaceList[pNodeName];
142 if(childList)
143 {
144 for(var i = 0; i < childList.length; i++)
145 {
146 if(childList[i] == cFullNodename)
147 {
148 return true;
149 }
150 }
151 return false;
152 }
153 }
154
155 return true;
156 }
157
158 var populateToolbar = function()
159 {
160 var elemList =
161 {
162 html:["a", "div", "li", "script", "span", "table", "td", "tr", "ul"],
163 xsl:
164 [
165 "apply-imports", "apply-templates", "attribute", "attribute-set", "call-template",
166 "choose", "copy", "copy-of", "decimal-format", "element",
167 "fallback", "for-each", "if", "import", "include",
168 "key", "message", "namespace-alias", "number", "otherwise",
169 "output", "param", "preserve-space", "processing-instruction", "sort",
170 "strip-space", "stylesheet", "template", "text", "transform",
171 "value-of", "variable", "when", "with-param"
172 ],
173 gsf:
174 [
175 "cgi-param", "choose-metadata", "collectionText", "displayItem", "displayText",
176 "equivlinkgs3", "foreach-metadata", "icon", "if-metadata-exists", "image",
177 "interfaceText", "link", "meta-value", "metadata", "script",
178 "style", "switch", "template", "text", "variable"
179 ]
180 };
181
182 var tabHolder = $("<ul>");
183 _toolboxDiv.append(tabHolder);
184
185 for(var key in elemList)
186 {
187 var currentList = elemList[key];
188
189 var tab = $("<li>");
190 var tabLink = $("<a>", {"href":"#ve" + key});
191 tabLink.css({"font-size":"0.9em", "padding":"5px"});
192 tabLink.text(key);
193 tab.append(tabLink);
194 tabHolder.append(tab);
195
196 var tabDiv = $("<div>", {"id":"ve" + key});
197 for(var j = 0; j < currentList.length; j++)
198 {
199 var elemName = currentList[j];
200
201 var ns = (key == "html") ? "" : (key + ":");
202
203 var newElem = _xml.createElement(ns + elemName);
204 var veElement = new VEElement(newElem);
205 var veDiv = veElement.getDiv();
206 veDiv.css("float", "none");
207 veDiv.data("toolbar", true);
208 tabDiv.append(veDiv);
209 }
210
211 _toolboxDiv.append(tabDiv);
212 }
213
214 var otherTab = $("<li>");
215 var otherTabLink = $("<a>", {"href":"#veother"});
216 otherTabLink.css({"font-size":"0.9em", "padding":"5px"});
217 otherTabLink.text("other");
218 otherTab.append(otherTabLink);
219 tabHolder.append(otherTab);
220
221 var otherTabDiv = $("<div>", {"id":"veother"});
222 var textNode = _xml.createTextNode("text");
223 var textVEElement = new VEElement(textNode);
224 var textDiv = textVEElement.getDiv();
225 textDiv.css("float", "none");
226 textDiv.data("toolbar", true);
227 otherTabDiv.append(textDiv);
228
229 var customInput = $("<input type=\"text\">");
230 var customElemHolder = $("<div>");
231 var customCreateButton = $("<button>Create element</button>");
232 customCreateButton.click(function()
233 {
234 var elemName = customInput.val();
235 if(elemName.length)
236 {
237 var elem = _xml.createElement(elemName);
238 var veElement = new VEElement(elem);
239 var customElemDiv = veElement.getDiv();
240 customElemDiv.css("float", "none");
241 customElemDiv.data("toolbar", true);
242 customElemHolder.empty();
243 customElemHolder.append(customElemDiv);
244 }
245 });
246 otherTabDiv.append(customInput);
247 otherTabDiv.append(customCreateButton);
248 otherTabDiv.append(customElemHolder);
249
250 _toolboxDiv.append(otherTabDiv);
251
252 _toolboxDiv.tabs();
253 }
254
255 var constructDivsRecursive = function(currentDiv, currentParent, level)
256 {
257 if(!level)
258 {
259 level = 1;
260 }
261
262 var container = $("<div>");
263 container.addClass("veContainerElement");
264 currentDiv.append(container);
265
266 var allowedList = new Array();
267 var counter = currentParent.firstChild;
268 while(counter)
269 {
270 if(counter.nodeType == 1)
271 {
272 allowedList.push(counter)
273 }
274 else if(counter.nodeType == 3 && counter.nodeValue.search(/\S/) != -1)
275 {
276 allowedList.push(counter)
277 }
278 counter = counter.nextSibling;
279 }
280
281 var width = 100 / allowedList.length;
282 for(var i = 0; i < allowedList.length; i++)
283 {
284 var currentElement = allowedList[i];
285
286 var veElement = new VEElement(currentElement);
287 var elementDiv = veElement.getDiv();
288 veElement.setWidth(width);
289
290 if(!_rootElement)
291 {
292 _rootElement = elementDiv;
293 }
294
295 container.append(elementDiv);
296 if(currentElement.firstChild)
297 {
298 constructDivsRecursive(elementDiv, currentElement, level + 1);
299 }
300
301 currentElement = currentElement.nextSibling;
302 }
303
304 container.append($("<div>", {"style":"clear:both;"}));
305 }
306
307 this.selectRootElement = function()
308 {
309 var height = _editorDiv.height() + 10;
310 if(height < 300){height = 300;}
311
312 _editorContainer.css("height", height + "px");
313 _infoDiv.css("height", height + "px");
314 _rootElement.trigger("click");
315 }
316
317 this.getMainDiv = function()
318 {
319 return _mainDiv;
320 }
321
322 var addToOverList = function(veElement)
323 {
324 for(var i = 0; i < _overList.length; i++)
325 {
326 if(!_overList[i])
327 {
328 continue;
329 }
330
331 if(_overList[i].getID() == veElement.getID())
332 {
333 return false;
334 }
335 }
336
337 if(_overList.freeSpaces.length > 0)
338 {
339 _overList[_overList.freeSpaces.pop()] = veElement;
340 }
341 else
342 {
343 _overList.push(veElement);
344 }
345 }
346
347 var removeFromOverList = function(veElement)
348 {
349 for(var i = 0; i < _overList.length; i++)
350 {
351 if(!_overList[i])
352 {
353 continue;
354 }
355
356 if(_overList[i].getID() == veElement.getID())
357 {
358 delete _overList[i];
359 _overList.freeSpaces.push(i);
360 }
361 }
362 }
363
364 var getDeepestOverElement = function()
365 {
366 if(_overList.length == 0)
367 {
368 return null;
369 }
370
371 var deepestVal = 0;
372 var deepestElem = _overList[0];
373
374 for(var i = 0; i < _overList.length; i++)
375 {
376 if(!_overList[i])
377 {
378 continue;
379 }
380
381 var depth = _overList[i].getDiv().parents(".veElement").length;
382 depth = (depth) ? depth : 0;
383
384 if (depth > deepestVal)
385 {
386 deepestVal = depth;
387 deepestElem = _overList[i];
388 }
389 }
390
391 return deepestElem;
392 }
393
394 var resizeAll = function()
395 {
396 var filterFunction = function()
397 {
398 var toolbarStatus = $(this).data("toolbar");
399 var beingDraggedStatus = $(this).data("dragging");
400
401 if(beingDraggedStatus || !toolbarStatus)
402 {
403 return true;
404 }
405
406 return false;
407 }
408
409 var allElems = $(".veElement").filter(filterFunction).each(function()
410 {
411 if($(this).data("helper")){return;}
412
413 var size = $(this).data("expanded");
414 if(size == "small")
415 {
416 var width = (10 / ($(this).siblings(".veElement").filter(function(){return !($(this).data("helper"))}).length - 1));
417 $(this).css("width", width + "%");
418 }
419 else if(size == "normal")
420 {
421 var width = (100 / ($(this).siblings(".veElement").filter(function(){return !($(this).data("helper"))}).length + 1));
422 $(this).css("width", width + "%");
423 }
424 else if(size == "expanded")
425 {
426 $(this).css("width", "90%");
427 }
428 });
429 }
430
431 var initVXE = function()
432 {
433 try
434 {
435 _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>");
436 constructDivsRecursive(_editorDiv, _xml.firstChild);
437 }
438 catch(error)
439 {
440 console.log(error);
441 return null;
442 }
443
444 populateToolbar();
445
446 _editorContainer.append(_editorDiv);
447 _mainDiv.append(_toolboxDiv);
448 _mainDiv.append(_editorContainer);
449 _mainDiv.append($("<div>", {"id":"veSpacerDiv"}));
450 _mainDiv.append(_infoDiv);
451 _mainDiv.append($("<div>", {"style":"clear:both;"}));
452 }
453
454 // *********************************************************************** //
455 // Visual Editor Attribute //
456 // This inner class represents a single xml attribute in the visual editor //
457 // *********************************************************************** //
458
459 var VEAttribute = function(attrElem, xmlElem, name, value)
460 {
461 var _name;
462 if(name)
463 {
464 _name = name;
465 }
466 else if(attrElem && attrElem.name)
467 {
468 _name = attrElem.name;
469 }
470
471 var _value;
472 if(value)
473 {
474 _value = value;
475 }
476 else if(attrElem && attrElem.value)
477 {
478 _value = attrElem.value;
479 }
480
481 var _xmlElem = xmlElem;
482 var _row;
483
484 this.getName = function()
485 {
486 return _name;
487 }
488
489 this.getValue = function()
490 {
491 return _value;
492 }
493
494 var createNameCell = function()
495 {
496 var cell = $("<td>", {"class":"veNameCell"});
497 cell.text(_name);
498 return cell;
499 }
500
501 var createValueCell = function()
502 {
503 var cell = $("<td>", {"class":"veValueCell"});
504 cell.text(_value);
505 return cell;
506 }
507
508 var createEditCell = function()
509 {
510 var cell = $("<td>", {"class":"veEditCell"});
511 var link = $("<a href=\"javascript:;\">edit</a>");
512 link.click(function()
513 {
514 var nameCell = _row.children("td").eq(0);
515 var valueCell = _row.children("td").eq(1);
516 if(link.text() == "edit")
517 {
518 link.text("save edit");
519
520 var nameInput = $("<input type=\"text\">");
521 nameInput.width(nameCell.width() - 5);
522 nameInput.val(_name);
523
524 var valueInput = $("<input type=\"text\">");
525 valueInput.width(valueCell.width() - 5);
526 valueInput.val(_value);
527
528 nameCell.text("");
529 valueCell.text("");
530
531 nameCell.append(nameInput);
532 valueCell.append(valueInput);
533 }
534 else
535 {
536 link.text("edit");
537
538 var nameInput = nameCell.children("input");
539 var valueInput = valueCell.children("input");
540
541 var name = nameInput.val();
542 var value = valueInput.val();
543
544 nameCell.empty();
545 nameCell.text(name);
546
547 valueCell.empty();
548 valueCell.text(value);
549
550 if(nameCell.data("prevName") != "")
551 {
552 _xmlElem.removeAttribute(_name);
553 }
554 _xmlElem.setAttribute(name, value);
555
556 _transactions.push({type:"editAttr", elem:_xmlElem, row:_row, newName:name, name:_name, value:_value});
557
558 _name = name;
559 _value = value;
560 }
561 });
562 cell.append(link);
563 return cell;
564 }
565
566 var createDeleteCell = function()
567 {
568 var cell = $("<td>", {"class":"veDeleteCell"});
569 var link = $("<a href=\"javascript:;\">delete</a>");
570 link.click(function()
571 {
572 _transactions.push({type:"remAttr", elem:_xmlElem, row:_row, rowParent:_row.parent(), name:_name, value:_value});
573 _xmlElem.removeAttribute(_name);
574 _row.detach();
575 });
576 cell.append(link);
577 return cell;
578 }
579
580 this.getAsTableRow = function()
581 {
582 var tableRow = $("<tr>");
583
584 var attributeName = createNameCell();
585 tableRow.append(attributeName);
586
587 var attributeValue = createValueCell();
588 tableRow.append(attributeValue);
589
590 var editCell = createEditCell()
591 tableRow.append(editCell);
592
593 var deleteCell = createDeleteCell();
594 tableRow.append(deleteCell);
595
596 _row = tableRow;
597
598 return tableRow;
599 }
600 }
601
602 // ********************************************************************************** //
603 // Visual Editor Element //
604 // This inner class represents a single xml element or text node in the visual editor //
605 // ********************************************************************************** //
606 var VEElement = function(xml)
607 {
608 var _div = $("<div>");
609 var _xmlNode = xml;
610 var _id = _globalID++;
611
612 _div.data("parentVEElement", this);
613 _div.data("expanded", "normal");
614
615 var makeDraggable = function()
616 {
617 _div.draggable(
618 {
619 "revert":"true",
620 "helper":function()
621 {
622 //Make sure the cursor is put in the centre of the div
623 var height = _div.children(".veTitleElement").height();
624 _div.draggable("option", "cursorAt", {top:(height / 2), left:(_div.width() / 2)});
625
626 var tempVEE = new VEElement(_xmlNode);
627 var tempDiv = tempVEE.getDiv();
628 tempDiv.css("border", "1px solid orangered");
629 tempDiv.css("background", "orange");
630 tempDiv.width(_div.width());
631 tempDiv.data("helper", true);
632 return tempDiv;
633 },
634 "cursor":"move",
635 "appendTo":_mainDiv,
636 "start":function(event, ui)
637 {
638 _origDDParent = _div.parent();
639 _origDDPosition = _div.index();
640
641 _div.siblings(".veElement").filter(function(){return !($(this).data("helper"))}).data("expanded", "normal");
642 _div.css("border", "1px solid orangered");
643 _div.data("prevBackground", _div.css("background"));
644 _div.css("background", "orange");
645 _div.css("float", "left");
646
647 _div.data("dragging", true);
648 if(_div.data("toolbar"))
649 {
650 var cloneElem = new VEElement(_xmlNode.cloneNode(true));
651 var cloneDiv = cloneElem.getDiv();
652 cloneDiv.css("float", "none");
653 cloneDiv.data("toolbar", true);
654 _div.before(cloneDiv);
655 }
656 _div.detach();
657
658 resizeAll();
659 },
660 "drag":function(event, ui)
661 {
662 var foundDefined = false;
663 for(var i = 0; i < _overList.length; i++)
664 {
665 if(!(_overList[i] === "undefined"))
666 {
667 foundDefined = true;
668 }
669 }
670
671 _validDropSpot = false;
672 if(foundDefined)
673 {
674 var overElement = getDeepestOverElement();
675 if(overElement)
676 {
677 if(overElement.getXMLNode().nodeType == 3 || !checkRestricted(_xmlNode, overElement.getXMLNode()))
678 {
679 return;
680 }
681
682 _validDropSpot = true;
683 var overDiv = overElement.getDiv();
684
685 var overLeft = overDiv.offset().left;
686 var helperLeft = ui.helper.offset().left;
687 var helperMiddle = helperLeft + (ui.helper.width() / 2);
688
689 var overContainers = overDiv.children(".veContainerElement");
690 if(!overContainers.length)
691 {
692 overDiv.append($("<div>", {"class":"veContainerElement"}));
693 overContainers = overDiv.children(".veContainerElement");
694 }
695 var overChildren = overContainers.children(".veElement").filter(function(){return !($(this).data("helper")) && !(_div.data("parentVEElement").getID() == $(this).data("parentVEElement").getID())});
696 var overChildrenLength = overChildren.length + 1;
697
698 if(!overChildren.length)
699 {
700 _validDropElem = overDiv;
701 _validDropType = "into";
702 overContainers.append(_div);
703 }
704 else
705 {
706 var posPercent = (helperMiddle - overLeft) / overDiv.width();
707 if(posPercent < 0)
708 {
709 posPercent = 0;
710 }
711 else if(posPercent > 1)
712 {
713 posPercent = 1;
714 }
715 var pos = Math.floor(overChildrenLength * posPercent);
716
717 if(pos < overChildrenLength - 1)
718 {
719 _validDropElem = overChildren.eq(pos);
720 _validDropType = "before";
721 overChildren.eq(pos).before(_div);
722 }
723 else
724 {
725 _validDropElem = overChildren.eq(pos - 1);
726 //Necessary to fix a rare bug that causes pos to be off by one
727 if(!_validDropElem.length)
728 {
729 _validDropElem = overChildren.eq(pos - 2);
730 }
731 _validDropType = "after";
732 overChildren.eq(pos - 1).after(_div);
733 }
734 }
735
736 overChildren.data("expanded", "normal");
737 _div.data("expanded", "normal");
738
739 resizeAll();
740 }
741 }
742 },
743 "stop":function(event, ui)
744 {
745 var transactionType = (_div.data("toolbar")) ? "addElem" : "remMvElem";
746 _div.data("dragging", false);
747 _div.data("toolbar", false);
748
749 _div.css("border", "1px dashed black");
750 _div.css("background", _div.data("prevBackground"));
751
752 //If the element was not dropped in a valid place then put it back
753 if(!_validDropSpot)
754 {
755 if(_origDDPosition == 0)
756 {
757 _origDDParent.prepend(_div);
758 }
759 else if(_origDDPosition == _origDDParent.children(".veElement").length - 1)
760 {
761 _origDDParent.children(".veElement").eq(_origDDPosition - 1).after(_div);
762 }
763 else
764 {
765 _origDDParent.children(".veElement").eq(_origDDPosition).before(_div);
766 }
767
768 resizeAll();
769 }
770 //Otherwise modify the XML
771 else
772 {
773 var xmlNode = _validDropElem.data("parentVEElement").getXMLNode();
774 if(_validDropType == "before")
775 {
776 $(xmlNode).before(_xmlNode);
777 }
778 else if (_validDropType == "after")
779 {
780 $(xmlNode).after(_xmlNode);
781 }
782 else if (_validDropType == "into")
783 {
784 $(xmlNode).append(_xmlNode);
785 }
786 _transactions.push({type:transactionType, vElemParent:_origDDParent, vElemPos:_origDDPosition, vElem:_div});
787 }
788 }
789 });
790
791 _div.droppable(
792 {
793 "over":function(event)
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.