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

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

Added another undo feature and a bug fix

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