- Timestamp:
- 2013-03-27T12:04:48+13:00 (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/greenstone3/web/interfaces/default/js/visual-xml-editor.js
r27110 r27130 3 3 // This class represents an editor that allows you to modify XML visually // 4 4 // ********************************************************************** // 5 6 5 function visualXMLEditor(xmlString) 7 6 { 7 //Variables that store the visual editor and a link to the DebugWidget 8 8 var _thisEditor = this; 9 9 var _greenbug; 10 10 11 //Stores what id we are up to (used to compare VEElements) 11 12 var _globalID = 0; 12 13 14 //Stores the current state of the XML 13 15 var _xml; 14 16 17 //Elements of the editor 15 18 var _mainDiv = $("<div>", {"id":"veMainDiv"}); 16 19 var _toolboxDiv = $("<div>", {"id":"veToolboxDiv"}); … … 18 21 var _editorDiv = $("<div>", {"id":"veEditorDiv"}); 19 22 var _infoDiv = $("<div>", {"id":"veInfoDiv"}); 23 24 //State-keeping variables 20 25 var _rootElement; 21 26 var _selectedElement; 22 23 27 var _overTrash = false; 24 25 28 var _validDropSpot = false; 26 29 var _validDropType; 27 30 var _validDropElem; 28 29 31 var _origDDParent; 30 32 var _origDDPosition; 31 33 34 //Keep track of what is currently being edited 32 35 var _editingNodes = new Array(); 33 36 37 //Stores what elements we are currently over while dragging (necessary to find the deepest element) 34 38 var _overList = new Array(); 35 39 _overList.freeSpaces = new Array(); 36 40 41 //Keep a list of what has been changed so that it can be undone 37 42 var _transactions = new Array(); 38 43 44 //A list of "ready-made" attributes for certain elements 39 45 var _validAttrList = 40 46 { … … 58 64 } 59 65 } 60 66 67 //The list of elements that show up in the toolbox (gslib is added dynamically later) 61 68 var _elemList = 62 69 { … … 80 87 ] 81 88 }; 82 89 90 //Restricts what elements can be added to a given element 83 91 var _childRestrictions = 84 92 { … … 89 97 } 90 98 }; 91 99 100 //Get a connection to the DebugWidget 92 101 this.setGreenbug = function(gb) 93 102 { 94 103 _greenbug = gb; 95 104 } 96 105 106 //Get the XML in its current state 97 107 this.getXML = function() 98 108 { 99 109 return _xml; 100 110 } 101 111 112 //Undo a transation 102 113 this.undo = function() 103 114 { … … 118 129 var pos = t.vElemPos; 119 130 var elem = t.vElem; 120 131 121 132 elem.detach(); 122 133 if(pos == 0) … … 188 199 } 189 200 } 190 201 202 //Check if an element is allowed as a child to another element 191 203 var checkRestricted = function(child, parent) 192 204 { … … 205 217 pNodeName = pFullNodename.substring(pFullNodename.indexOf(":") + 1); 206 218 } 207 219 208 220 var namespaceList = _childRestrictions[pNamespace]; 209 221 if(namespaceList) … … 222 234 } 223 235 } 224 236 225 237 return true; 226 238 } 227 239 240 //Add the trash bin to the editor 228 241 var placeTrashBin = function() 229 242 { … … 246 259 _editorContainer.append(bin); 247 260 } 248 261 262 //Dynamically retrieve the gslib elements from the gslib.xsl file to put into the toolbox 249 263 var retrieveGSLIBTemplates = function(callback) 250 264 { … … 256 270 startIndex = response.search("<templateList>") + "<templateList>".length; 257 271 endIndex = response.search("</templateList>"); 258 272 259 273 var listString = response.substring(startIndex, endIndex); 260 274 var list = eval(listString.replace(/"/g, "\"")); 261 275 var modifiedList = new Array(); 262 276 263 277 for(var i = 0; i < list.length; i++) 264 278 { … … 269 283 } 270 284 } 271 285 272 286 _elemList["gslib"] = modifiedList; 273 287 274 288 if(callback) 275 289 { … … 282 296 }); 283 297 } 284 298 299 //Create the toolbar 285 300 var populateToolbar = function() 286 301 { … … 316 331 _toolboxDiv.append(tabDiv); 317 332 } 318 333 319 334 var otherTab = $("<li>"); 320 335 var otherTabLink = $("<a>", {"href":"#veother"}); … … 323 338 otherTab.append(otherTabLink); 324 339 tabHolder.append(otherTab); 325 340 326 341 var otherTabDiv = $("<div>", {"id":"veother"}); 327 342 var textNode = _xml.createTextNode("text"); … … 331 346 textDiv.data("toolbar", true); 332 347 otherTabDiv.append(textDiv); 333 348 334 349 var customInput = $("<input type=\"text\">"); 335 350 var customElemHolder = $("<div>"); … … 352 367 otherTabDiv.append(customCreateButton); 353 368 otherTabDiv.append(customElemHolder); 354 369 355 370 _toolboxDiv.append(otherTabDiv); 356 371 357 372 _toolboxDiv.tabs(); 358 373 359 374 customCreateButton.button(); 360 375 } 361 376 377 //Turns the given XML into the nice visual structure recursively 362 378 var constructDivsRecursive = function(currentDiv, currentParent, level) 363 379 { … … 370 386 container.addClass("veContainerElement"); 371 387 currentDiv.append(container); 372 388 373 389 var allowedList = new Array(); 374 390 var counter = currentParent.firstChild; … … 394 410 var elementDiv = veElement.getDiv(); 395 411 veElement.setWidth(width); 396 412 397 413 if(!_rootElement) 398 414 { … … 411 427 container.append($("<div>", {"style":"clear:both;"})); 412 428 } 413 429 430 //Fake a click on the root element 414 431 this.selectRootElement = function() 415 432 { 416 433 var height = _editorDiv.height() + 10; 417 434 if(height < 300){height = 300;} 418 435 419 436 _editorContainer.css("height", height + "px"); 420 437 _infoDiv.css("height", height + "px"); 421 438 _rootElement.trigger("click"); 422 439 } 423 440 441 //Return the main visual editor div 424 442 this.getMainDiv = function() 425 443 { 426 444 return _mainDiv; 427 445 } 428 446 447 //Save any unfinished edits 429 448 this.savePendingEdits = function() 430 449 { … … 435 454 } 436 455 } 437 456 457 //Add the given VEElement to the list of VEElements we are currently dragging over 438 458 var addToOverList = function(veElement) 439 459 { … … 442 462 return; 443 463 } 444 464 445 465 for(var i = 0; i < _overList.length; i++) 446 466 { … … 449 469 continue; 450 470 } 451 471 452 472 if(_overList[i].getID() == veElement.getID()) 453 473 { … … 455 475 } 456 476 } 457 477 458 478 if(_overList.freeSpaces.length > 0) 459 479 { … … 465 485 } 466 486 } 467 487 488 //Remove the given VEElement from the list of VElements we are currently dragging over 468 489 var removeFromOverList = function(veElement) 469 490 { … … 474 495 continue; 475 496 } 476 497 477 498 if(_overList[i].getID() == veElement.getID()) 478 499 { … … 482 503 } 483 504 } 484 505 506 //Get the deepest VEElement we are currently dragging over 485 507 var getDeepestOverElement = function() 486 508 { … … 512 534 return deepestElem; 513 535 } 514 536 537 //Resize all the VEElements 515 538 var resizeAll = function() 516 539 { … … 519 542 var toolbarStatus = $(this).data("toolbar"); 520 543 var beingDraggedStatus = $(this).data("dragging"); 521 544 522 545 if(beingDraggedStatus || !toolbarStatus) 523 546 { 524 547 return true; 525 548 } 526 549 527 550 return false; 528 551 } 529 552 530 553 var allElems = $(".veElement").filter(filterFunction).each(function() 531 554 { … … 550 573 } 551 574 575 //Initialise the visual editor 552 576 var initVXE = function() 553 577 { … … 573 597 _mainDiv.append($("<div>", {"style":"clear:both;"})); 574 598 } 575 599 576 600 // *********************************************************************** // 577 601 // Visual Editor Text // 578 602 // This inner class represents a single xml text node in the visual editor // 579 603 // *********************************************************************** // 580 581 604 var VEText = function(node) 582 605 { 606 //Constructor code 583 607 var _thisNode = this; 584 608 var _xmlNode = node; 585 609 586 610 var _textEditor = $("<div>"); 587 611 var _nodeText = $("<div>"); … … 589 613 590 614 _textEditor.append(_nodeText); 591 615 592 616 var _editButton = $("<button>Edit text</button>"); 593 617 _editButton.click(function() … … 603 627 }); 604 628 _textEditor.append(_editButton); 605 629 630 //Enable editing of this text node 606 631 this.editMode = function() 607 632 { … … 615 640 } 616 641 642 //Save edits to this text node 617 643 this.saveEdits = function() 618 644 { … … 625 651 } 626 652 } 627 653 628 654 _transactions.push({type:"editText", elem:_xmlNode, vElem: _nodeText, value:_nodeText.data("prevTextValue")}); 629 655 var textArea = _nodeText.find("textarea"); … … 635 661 } 636 662 663 //Create a text node editor 637 664 this.getDiv = function() 638 665 { … … 642 669 } 643 670 } 644 671 645 672 // *********************************************************************** // 646 673 // Visual Editor Attribute // 647 674 // This inner class represents a single xml attribute in the visual editor // 648 675 // *********************************************************************** // 649 650 676 var VEAttribute = function(attrElem, xmlElem, name, value) 651 677 { 678 //Constructor code 652 679 var _name; 653 680 if(name) … … 659 686 _name = attrElem.name; 660 687 } 661 688 662 689 var _value; 663 690 if(value) … … 673 700 674 701 var _thisAttr = this; 675 702 703 //Get the attribute name 676 704 this.getName = function() 677 705 { … … 679 707 } 680 708 709 //Get the attribute value 681 710 this.getValue = function() 682 711 { … … 684 713 } 685 714 715 //Get the name cell of the attribute table 686 716 var createNameCell = function() 687 717 { … … 691 721 } 692 722 723 //Get the value cell of the attribute table 693 724 var createValueCell = function() 694 725 { … … 698 729 } 699 730 731 //Get the edit cell of the attribute table 700 732 var createEditCell = function() 701 733 { 702 734 var cell = $("<td>", {"class":"veEditCell"}); 703 735 var link = $("<a href=\"javascript:;\">edit</a>"); 704 736 705 737 link.click(function() 706 738 { … … 711 743 } 712 744 745 //Get the delete cell of the attribute table 713 746 var createDeleteCell = function() 714 747 { … … 725 758 } 726 759 760 //Create a table row from this attribute 727 761 this.getAsTableRow = function() 728 762 { … … 745 779 return tableRow; 746 780 } 747 781 782 //Enable editing of this attribute 748 783 this.editMode = function(editValue) 749 784 { 750 785 _editingNodes.push(_thisAttr); 751 786 752 787 var nameCell = _row.children("td").eq(0); 753 788 var valueCell = _row.children("td").eq(1); … … 784 819 } 785 820 } 786 821 822 //Save edits to this attribute 787 823 this.saveEdits = function() 788 824 { … … 799 835 var valueCell = _row.children("td").eq(1); 800 836 var editLink = _row.children("td").eq(2).find("a"); 801 837 802 838 editLink.text("edit"); 803 839 editLink.off("click"); … … 809 845 var nameInput = nameCell.children("input"); 810 846 var valueInput = valueCell.children("input"); 811 847 812 848 nameInput.blur(); 813 849 valueInput.blur(); … … 815 851 var name = nameInput.val(); 816 852 var value = valueInput.val(); 817 853 818 854 if(name.length == 0 || name.search(/\w/g) == -1) 819 855 { … … 821 857 return; 822 858 } 823 859 824 860 nameCell.empty(); 825 861 nameCell.text(name); … … 827 863 valueCell.empty(); 828 864 valueCell.text(value); 829 865 830 866 if(nameCell.data("prevName") != "") 831 867 { … … 833 869 } 834 870 _xmlElem.setAttribute(name, value); 835 871 836 872 _transactions.push({type:"editAttr", elem:_xmlElem, row:_row, newName:name, name:_name, value:_value}); 837 873 838 874 _name = name; 839 875 _value = value; … … 853 889 _div.data("parentVEElement", this); 854 890 _div.data("expanded", "normal"); 855 891 892 //Add the necessary functions to make this VEElement draggable 856 893 var makeDraggable = function() 857 894 { 858 895 _div.draggable( 859 896 { 897 "distance":"20", 860 898 "revert":"true", 861 899 "helper":function() … … 864 902 var height = _div.children(".veTitleElement").height(); 865 903 _div.draggable("option", "cursorAt", {top:(height / 2), left:(_div.width() / 2)}); 866 904 867 905 var tempVEE = new VEElement(_xmlNode); 868 906 var tempDiv = tempVEE.getDiv(); … … 952 990 } 953 991 var pos = Math.floor(overChildrenLength * posPercent); 954 992 955 993 if(pos < overChildrenLength - 1) 956 994 { … … 982 1020 { 983 1021 var transactionType = (_div.data("toolbar")) ? "addElem" : "remMvElem"; 984 1022 985 1023 if(_div.data("toolbar")) 986 1024 { … … 990 1028 _div.css("border", "1px solid black"); 991 1029 _div.css("background", _div.data("prevBackground")); 992 1030 993 1031 //If the element was not dropped in a valid place then put it back 994 1032 if(!_validDropSpot && !_div.data("toolbar")) … … 1007 1045 _origDDParent.children(".veElement").eq(_origDDPosition).before(_div); 1008 1046 } 1009 1047 1010 1048 if(_overTrash) 1011 1049 { … … 1034 1072 _transactions.push({type:transactionType, vElemParent:_origDDParent, vElemPos:_origDDPosition, vElem:_div}); 1035 1073 } 1036 1074 1037 1075 _div.data("dragging", false); 1038 1076 _div.data("toolbar", false); 1039 1077 1040 1078 _overList = new Array(); 1041 1079 _overList.freeSpaces = new Array(); … … 1043 1081 }); 1044 1082 1083 //Also make this element a drop-zone for other elements 1045 1084 _div.droppable( 1046 1085 { … … 1057 1096 }); 1058 1097 } 1059 1098 1099 //Get the underlying div 1060 1100 this.getDiv = function() 1061 1101 { 1062 1102 return _div; 1063 1103 } 1064 1104 1105 //Get the XML for this element 1065 1106 this.getXMLNode = function() 1066 1107 { 1067 1108 return _xmlNode; 1068 1109 } 1069 1110 1111 //Get the unique ID of this VEElement 1070 1112 this.getID = function() 1071 1113 { … … 1073 1115 } 1074 1116 1075 var createTableHeader = function() 1076 { 1077 var tableHeader = $("<tr>"); 1078 tableHeader.html("<td class=\"veNameCell\">Name</td><td class=\"veValueCell\">Value</td>"); 1079 return tableHeader; 1080 } 1081 1117 //Fill the information area with details about this element 1082 1118 this.populateInformationDiv = function() 1083 1119 { … … 1104 1140 attributeTable.addClass("veAttributeTableContainer"); 1105 1141 1106 attributeTable.append( createTableHeader());1142 attributeTable.append($("<tr>").html("<td class=\"veNameCell\">Name</td><td class=\"veValueCell\">Value</td>")); 1107 1143 1108 1144 $(_xmlNode.attributes).each(function() … … 1114 1150 _infoDiv.append(attributeTableTitle); 1115 1151 _infoDiv.append(attributeTable); 1116 1152 1117 1153 var addDiv = $("<div>", {"class":"veInfoDivTitle"}); 1118 1154 var addSelect = $("<select>"); … … 1144 1180 } 1145 1181 } 1146 1182 1147 1183 var addButton = $("<button>Add attribute</button>"); 1148 1184 addButton.click(function() … … 1170 1206 _infoDiv.append(addDiv); 1171 1207 addButton.button(); 1172 1208 1173 1209 /* 1174 1210 if(_xmlNode.tagName == "xsl:call-template" && _xmlNode.getAttribute("name").length > 0) … … 1246 1282 } 1247 1283 1284 //Add mouseover/out and click events to this element 1248 1285 var addMouseEvents = function() 1249 1286 { … … 1291 1328 }); 1292 1329 } 1293 1330 1331 //Check if we need to expand an element before we do 1294 1332 var checkResizeNecessary = function() 1295 1333 { … … 1315 1353 return false; 1316 1354 } 1317 1355 1356 //Remove this from the editor 1318 1357 this.remove = function() 1319 1358 { … … 1324 1363 _div.detach(); 1325 1364 _infoDiv.empty(); 1326 1365 1327 1366 if(divParent.length) 1328 1367 { 1329 1368 divParent.first().trigger("click"); 1330 1369 } 1331 1370 1332 1371 $("#veTrash").children("img").attr("src", gs.imageURLs.trashFull); 1333 1372 } 1334 1373 1374 //Expend this element horizontally 1335 1375 this.expand = function() 1336 1376 { … … 1344 1384 $(this).data("expanded", "small"); 1345 1385 }); 1346 1386 1347 1387 _div.animate({width:"80%"}, 1000); 1348 1388 _div.data("expanded", "expanded"); … … 1350 1390 } 1351 1391 1392 //Evenly distribute the children of this node evenly 1352 1393 this.evenlyDistributeChildren = function() 1353 1394 { … … 1361 1402 } 1362 1403 1404 //Expand this node and any parents and evenly distribute its children 1363 1405 this.focus = function() 1364 1406 { … … 1366 1408 { 1367 1409 _div.data("parentVEElement").expand(); 1368 1410 1369 1411 var parents = _div.parents(".veElement"); 1370 1412 parents.each(function() … … 1376 1418 _div.data("parentVEElement").evenlyDistributeChildren(); 1377 1419 } 1378 1420 1421 //Set whether to use the short name for this element (i.e. without the namespace) 1379 1422 this.setShortName = function(short) 1380 1423 { … … 1389 1432 } 1390 1433 1434 //Set the width of this element 1391 1435 this.setWidth = function(width) 1392 1436 { 1393 1437 _div.css("width", width + "%"); 1394 1438 } 1395 1439 1396 1440 //Visual Editor Element constructor 1397 1441 var initVEE = function() … … 1400 1444 _div.addClass("ui-corner-all"); 1401 1445 makeDraggable(); 1402 1446 1403 1447 var titleText; 1404 1448 if(_xmlNode.nodeType == 3 && _xmlNode.nodeValue.search(/\S/) != -1) … … 1427 1471 titleText = _xmlNode.tagName; 1428 1472 } 1429 1473 1430 1474 addMouseEvents(); 1431 1475 1432 1476 _div.append("<div class=\"veTitleElement\">" + titleText + "</div>"); 1433 1477 } … … 1435 1479 initVEE(); 1436 1480 } 1437 1481 1438 1482 //Call the constructor 1439 1483 initVXE();
Note:
See TracChangeset
for help on using the changeset viewer.