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

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

Implemented undo functionality

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