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

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

Implemented a "drag to trash" feature

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\">Trash</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.