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

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

Renamed the trash to be recycle bit and updating the css file

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