function DebugWidget() { //************************ //Private member variables //************************ //The this variable var _greenbug = this; //Template tracker class var TemplateTracker = function() { var templates = new Array(); var currentIndex = -1; this.push = function(object) { if(currentIndex < templates.length - 1 && templates.length > 0) { templates.splice(currentIndex + 1, templates.length - 1 - currentIndex); } templates[++currentIndex] = object; _forwardButton.button("option", "disabled", true); if(templates.length > 1) { _backButton.button("option", "disabled", false); } } this.next = function() { if(currentIndex == templates.length - 1) { return; } if(currentIndex + 1 == templates.length - 1) { _forwardButton.button("option", "disabled", true); } _backButton.button("option", "disabled", false); return templates[++currentIndex]; } this.previous = function() { if(currentIndex == 0) { return; } if(currentIndex - 1 == 0) { _backButton.button("option", "disabled", true); } _forwardButton.button("option", "disabled", false); return templates[--currentIndex]; } this.peekPrevious = function() { if(currentIndex == 0) { return; } return templates[currentIndex - 1]; } this.peekNext = function() { if(currentIndex == templates.length - 1) { return; } return templates[currentIndex + 1]; } } var _templateTracker = new TemplateTracker(); //Debugger state-keeping variables var _debugOn = false; var _pauseSelector = false; var _elements = new Array(); var _itemSelected = false; //Used to prevent multiple elements from being highlighted var _editModeText = false; var _fromSelection = false; var _selectedInfoContainers = new Array(); //Page elements var _mainDiv; var _textEditor; var _vEditor; var _navArea; var _fileSelector; var _templateSelector; var _editor; var _editingDiv; var _xmlStatusBar; //Buttons var _backButton; var _forwardButton; var _currentSelectionButton; var _enableSelectorButton; var _closeEditorButton; var _saveButton; var _swapEditorButton; //Editor state-keeping variables var _currentFileName; var _currentLocation; var _currentNodename; var _currentName; var _currentMatch; var _currentNamespace; var _currentXPath; var _isVisualEditor = true; var _styleFunctions = new Array(); //Used to reload the page while keeping the state of the editor var partialPageReload = function(callback) { $.ajax(document.URL) .success(function(response) { //Get the body text from the response var bodyStartIndex = response.indexOf(""); var bodyText = response.substring(bodyStartIndex, bodyEndIndex + 7); //Get the current top area and container var topLevelTopArea = $("#topArea"); var topLevelContainer = $("#container"); //Create a temporary div and put the html into it var tempDiv = $("
"); tempDiv.html(bodyText); //Replace the contents of the old elements with the new elements var topArea = tempDiv.find("#topArea"); var container = tempDiv.find("#container"); topLevelTopArea.html(topArea.html()); topLevelContainer.html(container.html()); //Update the events for the debug elements that currently don't have events associated with them var debugElems = $('debug, [debug="true"]').filter(function(){return (!($.data(this, "events"))) ? true : false}); addMouseEventsToDebugElements(debugElems); }) .error(function() { alert("There was an error reloading the page, please reload manually."); }); if(callback) { callback(); } } //Some functions need to be called after an element is added to the page. So we store them and call them later. var callStyleFunctions = function() { for(var i = 0; i < _styleFunctions.length; i++) { var sFunction = _styleFunctions[i]; sFunction(); } } var changeToSelectedElement = function(templateIndex, templateList) { _templateSelector.children("select").empty(); for(var i = 0; i < templateList.length; i++) { _templateSelector.children("select").append($(templateList[i]).clone(true)); } if(templateIndex === undefined) { _templateSelector.find("option").first().trigger("change", [true]); } else { _templateSelector.find("option").filter(function(){return $(this).data("index") == templateIndex}).first().trigger("change", [true]); } return; } var createNavButtons = function(buttonDiv) { var navButtonHolder = $("
").css("float", "left"); var backForwardFunction = function(e) { var template; if($(e.target).attr("id") == "veBack") { template = _templateTracker.previous(); } else { template = _templateTracker.next(); } if(!template) { return; } _fileSelector.find("option").filter(function(){return $(this).data("index") == template.fileIndex}).prop("selected", true); changeToSelectedElement(template.templateIndex, template.list); } _backButton = $("").attr("id", "veBack"); _backButton.click(backForwardFunction); _styleFunctions.push(function(){_backButton.button({icons:{primary:"ui-icon-triangle-1-w"}, text:false, disabled:true})}); _forwardButton = $("").attr("id", "veForwards"); _forwardButton.click(backForwardFunction); _styleFunctions.push(function(){_forwardButton.button({icons:{primary:"ui-icon-triangle-1-e"}, text:false, disabled:true})}); //Changes the template list to what is currently selected _currentSelectionButton = $(""); _currentSelectionButton.click(function() { _fileSelector.find("option").eq(0).prop("selected", true); changeToSelectedElement(undefined, _selectedInfoContainers); var selectedCopy = new Array(); for(var i = 0; i < _selectedInfoContainers.length; i++) { selectedCopy[i] = _selectedInfoContainers[i]; } _templateTracker.push({fileIndex:-1, templateIndex:0, list:selectedCopy}); }); _styleFunctions.push(function(){_currentSelectionButton.button({icons:{primary:"ui-icon-pencil"}, text:false, disabled:true})}); navButtonHolder.append(_backButton); navButtonHolder.append(_forwardButton); navButtonHolder.append(_currentSelectionButton); buttonDiv.append(navButtonHolder); } //Create the area where the buttons are stored var createControlButtons = function(buttonDiv) { //Used to enable the selector to get the templates of a particular area of the page _enableSelectorButton = $(""); _enableSelectorButton.click(function() { _enableSelectorButton.button("option", "label", "Select new element"); $("a").click(function(e) { e.preventDefault(); }); _debugOn = true; _pauseSelector = false; _enableSelectorButton.button("option", "disabled", true); }); _styleFunctions.push(function(){_enableSelectorButton.button({icons:{primary:"ui-icon-pencil"}})}); //Used to minimise/restore the editor _closeEditorButton = $(""); _closeEditorButton.click(function() { if(_closeEditorButton.button("option", "label") == "Close editor") { _closeEditorButton.button("option", "label", "Open editor"); _editingDiv.hide(); } else { _closeEditorButton.button("option", "label", "Close editor"); _editingDiv.show(); } }); _closeEditorButton.css("float", "right"); _styleFunctions.push(function(){_closeEditorButton.button({icons:{secondary:"ui-icon-newwin"}, disabled:true})}); //Used to save any changes that have been made to this template _saveButton = $(""); _saveButton.click(function() { if(_editor) { var xmlString; if(_isVisualEditor) { _vEditor.savePendingEdits(); xmlString = new XMLSerializer().serializeToString(_vEditor.getXML()); } else { xmlString = _editor.getValue(); } xmlString = xmlString.replace(/&/g, "&"); try { var xml = $.parseXML('' + xmlString + ""); } catch(error) { alert("Could not save as there is a problem with the XML."); return; } var url = gs.xsltParams.library_name; var parameters = {"a":"g", "rt":"r", "s":"SaveXMLTemplateToFile", "s1.locationName":_currentLocation, "s1.fileName":_currentFileName, "s1.interfaceName":gs.xsltParams.interface_name, "s1.siteName":gs.xsltParams.site_name, "s1.collectionName":gs.cgiParams.c, "s1.namespace":_currentNamespace, "s1.nodename":_currentNodename, "s1.xml":xmlString}; if(_currentName && _currentName.length > 0){parameters["s1.name"] = _currentName;} if(_currentMatch && _currentMatch.length > 0){parameters["s1.match"] = _currentMatch;} if(_currentXPath && _currentXPath.length > 0){parameters["s1.xpath"] = _currentXPath} _saveButton.button("option", "disabled", true); $.blockUI({message:'
Saving, please wait...
'}); $.post(url, parameters) .success(function() { $.ajax(gs.xsltParams.library_name + "?a=s&sa=c") .success(function() { partialPageReload(function(){$.unblockUI();}); }) .error(function() { $.unblockUI(); alert("Error reloading collection."); }) .complete(function() { _saveButton.button("option", "disabled", false); }); }) .error(function() { alert("There was an error sending the request to the server, please try again."); }); } }); _styleFunctions.push(function(){_saveButton.button({icons:{primary:"ui-icon-disk"}, disabled:true})}); //Used to switch between the XML and Visual editors _swapEditorButton = $(""); _swapEditorButton.button().click(function() { if(_vEditor && _textEditor) { if(_isVisualEditor) { _vEditor.savePendingEdits(); _vEditor.getMainDiv().hide(); var containerNode = _vEditor.getXML().firstChild; var templateNode = containerNode.firstChild; while(templateNode) { if(templateNode.nodeType == 1) { break; } templateNode = templateNode.nextSibling; } var xmlText = new XMLSerializer().serializeToString(templateNode); _editor.setValue(xmlText); _editor.clearSelection(); var UndoManager = require("ace/undomanager").UndoManager; _editor.getSession().setUndoManager(new UndoManager()); _textEditor.show(); _swapEditorButton.button("option", "label", "Switch to visual editor"); _isVisualEditor = false; _xmlStatusBar.show(); } else { _textEditor.hide(); var xmlText = _editor.getValue(); _vEditor.getMainDiv().remove(); _vEditor = new visualXMLEditor(xmlText); _editingDiv.append(_vEditor.getMainDiv()); _vEditor.selectRootElement(); _vEditor.getMainDiv().show(); _swapEditorButton.button("option", "label", "Switch to XML editor"); _isVisualEditor = true; _xmlStatusBar.hide(); } } }); _styleFunctions.push(function(){_swapEditorButton.button({icons:{primary:"ui-icon-refresh"}})}); undoButton = $(""); undoButton.click(function() { if(_isVisualEditor) { _vEditor.undo(); } else { _editor.undo(); } }); _styleFunctions.push(function(){undoButton.button({icons:{primary:"ui-icon-arrowreturnthick-1-w"}})}); buttonDiv.append(_enableSelectorButton); buttonDiv.append(_closeEditorButton); buttonDiv.append(_saveButton); buttonDiv.append(_swapEditorButton); buttonDiv.append(undoButton); } //Used to monitor the state of the XML in the XML editor and will notify the user if there is an error var createXMLStatusBar = function(buttonDiv) { _xmlStatusBar = $(""); _xmlStatusBar.css("padding", "5px"); _xmlStatusBar.addClass("ui-corner-all"); _styleFunctions.push(function(){_xmlStatusBar.hide();}); //Check the XML for errors every 2 seconds setInterval(function() { if(_editor) { var xmlString = _editor.getValue(); try { var xml = $.parseXML('' + xmlString + ""); } catch(error) { console.log(error); _xmlStatusBar.text("XML ERROR! (Mouse over for details)"); _xmlStatusBar.addClass("ui-state-error"); _xmlStatusBar.removeClass("ui-state-active"); _xmlStatusBar.attr("title", error); _saveButton.button("option", "disabled", true); _swapEditorButton.button("option", "disabled", true); return; } _xmlStatusBar.text("XML OK!"); _xmlStatusBar.addClass("ui-state-active"); _xmlStatusBar.removeClass("ui-state-error"); _xmlStatusBar.removeAttr("title"); if(_saveButton.button("option", "label") == "Save changes") { _saveButton.button("option", "disabled", false); } if(_swapEditorButton.button("option", "label") == "Switch to visual editor") { _swapEditorButton.button("option", "disabled", false); } } }, 2000); buttonDiv.append(_xmlStatusBar); } //Create the elements that allow var createFileAndTemplateSelectors = function(buttonDiv) { _templateSelector = $("
", {"id":"veTemplateSelector", "class":"ui-state-default ui-corner-all"}); _templateSelector.append($("Templates: ")); var templateSelectBox = $(""); fileSelectBox.append($("").data("index", -1)); _fileSelector.addClass("ui-state-default"); _fileSelector.addClass("ui-corner-all"); _fileSelector.append("Files: "); _fileSelector.append(fileSelectBox); for(var i = 0; i < list.length; i++) { var item = list[i]; var option = $("").data("index", i); option.data("fileItem", item); fileSelectBox.append(option); } fileSelectBox.change(function() { var selectedItem = fileSelectBox.find(":selected"); if(!selectedItem.data("fileItem")) { return; } _greenbug.populateTemplateSelectorFromFile(selectedItem.data("fileItem").path, selectedItem.data("fileItem").location, function(){_templateSelector.children("select").trigger("change")}); }); }) .error(function() { console.log("Error retrieving XSLT files"); }); } //The function that creates all the necessary elements for Greenbug var createDebugDiv = function() { _mainDiv = $("
", {"id":"debugDiv"}); _mainDiv.css( { "position":"fixed", "font-size":"0.8em", "bottom":"0px", "width":"100%", "background":"white", "border":"1px black solid", "padding":"5px", "z-index":100 }); _editingDiv = $("
"); var toolBarDiv = $("
"); toolBarDiv.css({"height":"40px"}); toolBarDiv.append("
", {style:"clear:both;"}); var buttonDiv = $("
"); toolBarDiv.append(buttonDiv); createNavButtons(buttonDiv); createControlButtons(buttonDiv); createFileAndTemplateSelectors(buttonDiv); createXMLStatusBar(buttonDiv); _styleFunctions.push(function(){$(".ui-button").css({"margin-right":"0.5em"});}); _mainDiv.append(toolBarDiv); _mainDiv.append(_editingDiv); _mainDiv.append(_navArea); } //Clear all selected elements on the page var clearAll = function() { _itemSelected = false; $(_elements).each(function() { $(this).remove(); }); } //Put a border around the given element var highlightElement = function(e) { var topBorderDiv = $("
"); var bottomBorderDiv = $("
"); var leftBorderDiv = $("
"); var rightBorderDiv = $("
"); topBorderDiv.css({"position":"absolute", "top":e.offset().top + "px", "left":e.offset().left + "px", "height":"0px", "width":e.width() + "px", "border":"1px solid red"}); bottomBorderDiv.css({"position":"absolute", "top":(e.offset().top + e.height()) + "px", "left":e.offset().left + "px", "height":"0px", "width":e.width() + "px", "border":"1px solid red"}); leftBorderDiv.css({"position":"absolute", "top":e.offset().top + "px", "left":e.offset().left + "px", "height":e.height() + "px", "width":"0px", "border":"1px solid red"}); rightBorderDiv.css({"position":"absolute", "top":e.offset().top + "px", "left":(e.offset().left + e.width()) + "px", "height":e.height() + "px", "width":"0px", "border":"1px solid red"}); $("body").append(topBorderDiv, bottomBorderDiv, leftBorderDiv, rightBorderDiv); _elements.push(topBorderDiv); _elements.push(bottomBorderDiv); _elements.push(leftBorderDiv); _elements.push(rightBorderDiv); } this.populateTemplateSelectorFromFile = function(filename, location, callback) { var getURL = gs.xsltParams.library_name + "?a=g&rt=r&s=GetTemplateListFromFile&s1.fileName=" + filename + "&s1.locationName=" + location + "&s1.interfaceName=" + gs.xsltParams.interface_name + "&s1.siteName=" + gs.xsltParams.site_name + "&s1.collectionName=" + gs.cgiParams.c; $.ajax(getURL) .success(function(templateResponse) { var templateListStart = templateResponse.indexOf("") + "".length; var templateListEnd = templateResponse.indexOf(""); if(templateListStart == "".length - 1) { return; } var templateListString = templateResponse.substring(templateListStart, templateListEnd).replace(/"/g, "\""); var templateList = eval(templateListString); _templateSelector.children("select").empty(); if(templateList.length == 0) { _templateSelector.children("select").append($("").data("index", -1)); } for(var i = 0; i < templateList.length; i++) { var namespace = templateList[i].namespace; var nodename = "template"; var name = templateList[i].name; var match = templateList[i].match; var xpath = templateList[i].xpath; if(name) { name = templateList[i].name.replace(/'/g, "'").replace(/"/g, "\"").replace(/&/g, "&"); } if(match) { match = templateList[i].match.replace(/'/g, "'").replace(/"/g, "\"").replace(/&/g, "&"); } var infoContainer = $("