// ********************************************************************** //
// Visual XML Editor //
// This class represents an editor that allows you to modify XML visually //
// ********************************************************************** //
function visualXMLEditor(xmlString)
{
//Variables that store the visual editor and a link to the DebugWidget
var _thisEditor = this;
var _greenbug;
//Store this file's location and name
var _fileLocation;
var _fileName;
//Stores what id we are up to (used to compare VEElements)
var _globalID = 0;
//Stores the current state of the XML
var _xml;
//Elements of the editor
var _mainDiv = $("
", {"id":"veMainDiv"});
var _toolboxDiv = $("
", {"id":"veToolboxDiv"});
var _editorContainer = $("
", {"id":"veEditorContainer"});
var _editorDiv = $("
", {"id":"veEditorDiv"});
var _infoDiv = $("
", {"id":"veInfoDiv"});
//State-keeping variables
var _rootElement;
var _selectedElement;
var _overTrash = false;
var _validDropSpot = false;
var _validDropType;
var _validDropElem;
var _origDDParent;
var _origDDPosition;
//Keep track of what is currently being edited
var _editingNodes = new Array();
//Stores what elements we are currently over while dragging (necessary to find the deepest element)
var _overList = new Array();
_overList.freeSpaces = new Array();
//Keep a list of what has been changed so that it can be undone
var _transactions = new Array();
//A list of "ready-made" attributes for certain elements
var _validAttrList =
{
gsf:
{
"cgi-param":["name"],
"collectionText":["args", "name"],
"displayItem":["name"],
"displayText":["name"],
"equivlinkgs3":["name"],
"foreach-metadata":["name", "separator"],
"icon":["type"],
"if-metadata-exists":["name"],
"image":["type"],
"interfaceText":["name"],
"link":["OID", "OIDmetadata", "name", "nodeID", "target", "title", "titlekey", "type"],
"metadata":["format", "hidden", "name", "pos", "prefix", "separator", "suffix", "type"],
"script":["src"],
"style":["src"],
"switch":["preprocess", "test", "test-value"]
}
}
//The list of elements that show up in the toolbox (gslib is added dynamically later)
var _elemList =
{
html:["a", "br", "div", "li", "link", "p", "script", "span", "table", "td", "tr", "ul"],
xsl:
[
"apply-imports", "apply-templates", "attribute", "attribute-set", "call-template",
"choose", "copy", "copy-of", "decimal-format", "element",
"fallback", "for-each", "if", "import", "include",
"key", "message", "namespace-alias", "number", "otherwise",
"output", "param", "preserve-space", "processing-instruction", "sort",
"strip-space", "stylesheet", "template", "text", "transform",
"value-of", "variable", "when", "with-param"
],
gsf:
[
"cgi-param", "choose-metadata", "collectionText", "displayItem", "displayText",
"equivlinkgs3", "foreach-metadata", "icon", "if-metadata-exists", "image",
"interfaceText", "link", "meta-value", "metadata", "script",
"style", "switch", "template", "text", "variable"
]
};
//Restricts what elements can be added to a given element
var _childRestrictions =
{
gsf:
{
"choose-metadata":["gsf:metadata", "gsf:default"],
"metadata":[]
}
};
this.setFileLocation = function(fileLocation)
{
_fileLocation = fileLocation;
}
this.setFileName = function(fileName)
{
_fileName = fileName;
}
//Get a connection to the DebugWidget
this.setGreenbug = function(gb)
{
_greenbug = gb;
}
//Get the XML in its current state
this.getXML = function()
{
return _xml;
}
//Undo a transation
this.undo = function()
{
if(_transactions.length > 0)
{
var t = _transactions.pop();
//Undo an added element
if(t.type == "addElem")
{
$(t.vElem.data("parentVEElement").getXMLNode()).remove();
t.vElem.remove();
resizeAll();
}
//Undo a removed or moved element
else if(t.type == "remMvElem")
{
var parent = t.vElemParent;
var pos = t.vElemPos;
var elem = t.vElem;
elem.detach();
if(pos == 0)
{
parent.prepend(elem);
$(parent.parent().data("parentVEElement").getXMLNode()).prepend(elem.data("parentVEElement").getXMLNode());
}
else if(pos == parent.children(".veElement").length)
{
$(parent.children(".veElement").eq(pos - 1).data("parentVEElement").getXMLNode()).after(elem.data("parentVEElement").getXMLNode());
parent.children(".veElement").eq(pos - 1).after(elem);
}
else
{
$(parent.children(".veElement").eq(pos).data("parentVEElement").getXMLNode()).before(elem.data("parentVEElement").getXMLNode());
parent.children(".veElement").eq(pos).before(elem);
}
resizeAll();
//Check if we need to change the recycle bin icon
var found = false;
for(var i = 0; i < _transactions.length; i++)
{
if(_transactions[i].type == "remMvElem"){found = true; break;}
}
if(!found)
{
$("#veTrash").children("img").attr("src", gs.imageURLs.trashEmpty);
}
}
//Undo an added attribute
else if(t.type == "addAttr")
{
if(t.row)
{
t.row.remove();
}
}
//Undo a removed or edited attribute
else if(t.type == "editAttr")
{
t.elem.removeAttribute(t.newName);
t.elem.setAttribute(t.name, t.value);
if(t.row)
{
t.row.children("td").eq(0).text(t.name);
t.row.children("td").eq(1).text(t.value);
}
}
//Undo a removed or edited attribute
else if(t.type == "remAttr")
{
t.elem.setAttribute(t.name, t.value);
if(t.rowParent)
{
t.rowParent.append(t.row);
}
}
//Undo edited text
else if(t.type == "editText")
{
t.elem.nodeValue = t.value;
if(t.vElem)
{
t.vElem.text(t.value);
}
}
}
}
//Check if an element is allowed as a child to another element
var checkRestricted = function(child, parent)
{
var pFullNodename = parent.tagName;
var cFullNodename = child.tagName;
var pNamespace;
var pNodeName;
if(pFullNodename.indexOf(":") == -1)
{
pNamespace = "no namespace";
pNodeName = pFullNodename;
}
else
{
pNamespace = pFullNodename.substring(0, pFullNodename.indexOf(":"));
pNodeName = pFullNodename.substring(pFullNodename.indexOf(":") + 1);
}
var namespaceList = _childRestrictions[pNamespace];
if(namespaceList)
{
var childList = namespaceList[pNodeName];
if(childList)
{
for(var i = 0; i < childList.length; i++)
{
if(childList[i] == cFullNodename)
{
return true;
}
}
return false;
}
}
return true;
}
//Add the trash bin to the editor
var placeTrashBin = function()
{
var binImage = $("");
var bin = $("
");
bin.append(binImage);
bin.addClass("ui-state-default");
bin.addClass("ui-corner-all");
bin.droppable(
{
"over":function()
{
_overTrash = true;
},
"out":function()
{
_overTrash = false;
}
});
_editorContainer.append(bin);
}
//Dynamically retrieve the gslib elements from the gslib.xsl file to put into the toolbox
var retrieveGSLIBTemplates = function(callback)
{
if($(document).data("gslibList"))
{
_elemList["gslib"] = $(document).data("gslibList");
if(callback)
{
callback();
}
}
else
{
var url = gs.xsltParams.library_name + "?a=g&rt=r&s=GetTemplateListFromFile&s1.locationName=interface&s1.interfaceName=" + gs.xsltParams.interface_name + "&s1.fileName=gslib.xsl";
$.ajax(url)
.success(function(response)
{
startIndex = response.search("") + "".length;
endIndex = response.search("");
if(startIndex == "".length - 1)
{
console.log("Error retrieving GSLIB templates");
return;
}
var listString = response.substring(startIndex, endIndex);
var list = eval(listString.replace(/"/g, "\""));
var modifiedList = new Array();
for(var i = 0; i < list.length; i++)
{
var current = list[i];
if(current.name)
{
modifiedList.push(current.name);
}
}
_elemList["gslib"] = modifiedList;
$(document).data("gslibList", modifiedList);
if(callback)
{
callback();
}
})
.error(function()
{
console.log("Error retrieving GSLIB templates");
});
}
}
//Create the toolbar
var populateToolbar = function()
{
var tabHolder = $("
");
_toolboxDiv.append(tabHolder);
for(var key in _elemList)
{
var currentList = _elemList[key];
var tab = $("