source: main/trunk/greenstone3/web/interfaces/default/js/debug_scripts.js@ 27010

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

Now using nicer buttons and saving will now only reload the necessary parts of the page

  • Property svn:executable set to *
File size: 17.4 KB
Line 
1function DebugWidget()
2{
3 //************************
4 //Private member variables
5 //************************
6
7 //Debugger state-keeping variables
8 var _debugOn = false;
9 var _pauseSelector = false;
10 var _elements = new Array();
11 var _itemSelected = false; //Used to prevent multiple elements from being highlighted
12 var _editModeText = false;
13 var _selectedTemplate;
14
15 //Page elements
16 var _mainDiv;
17
18 var _textEditor;
19 var _vEditor;
20
21 var _templateSelector;
22 var _editor;
23 var _editingDiv;
24 var _unpauseButton;
25 var _closeEditorButtonButton;
26 var _xmlStatusBar;
27 var _saveButton;
28 var _swapEditorButton;
29
30 //Editor state-keeping variables
31 var _currentFilepath;
32 var _currentNodename;
33 var _currentName;
34 var _currentMatch;
35 var _currentNamespace;
36 var _isVisualEditor = true;
37
38 var partialPageReload = function()
39 {
40 $.ajax(document.URL)
41 .success(function(response)
42 {
43 //Get the body text from the response
44 var bodyStartIndex = response.indexOf("<body");
45 var bodyEndIndex = response.indexOf("</body>");
46 var bodyText = response.substring(bodyStartIndex, bodyEndIndex + 7);
47
48 //Get the current top area and container
49 var topLevelTopArea = $("#topArea");
50 var topLevelContainer = $("#container");
51
52 //Create a temporary div and put the html into it
53 var tempDiv = $("<div>");
54 tempDiv.html(bodyText);
55
56 //Replace the contents of the old elements with the new elements
57 var topArea = tempDiv.find("#topArea");
58 var container = tempDiv.find("#container");
59 topLevelTopArea.html(topArea.html());
60 topLevelContainer.html(container.html());
61
62 //Update the events for the debug elements that currently don't have events associated with them
63 var debugElems = $('debug, [debug="true"]').filter(function(){return (!($.data(this, "events"))) ? true : false});
64 addMouseEventsToDebugElements(debugElems);
65 })
66 .error(function()
67 {
68 alert("There was an error reloading the page, please reload manually.");
69 });
70 }
71
72 var createDebugDiv = function()
73 {
74 _mainDiv = $("<div>", {"id":"debugDiv"});
75 _mainDiv.css(
76 {
77 "position":"fixed",
78 "font-size":"0.8em",
79 "bottom":"0px",
80 "width":"100%",
81 "background":"white",
82 "border":"1px black solid",
83 "padding":"5px",
84 "z-index":100
85 });
86
87 _editingDiv = $("<div>");
88 var toolBarDiv = $("<div>");
89 toolBarDiv.css({"height":"40px"});
90
91 var buttonDiv = $("<div>");
92 buttonDiv.css("float", "left");
93 toolBarDiv.append(buttonDiv);
94
95 _templateSelector = $("<div>", {"id":"templateSelector"});
96 _templateSelector.css({"overflow":"auto", "width":"100%"});
97
98 var pickElementButton = $("<input type=\"button\" value=\"Enable debugging\">");
99 pickElementButton.button().click(function()
100 {
101 if(!_debugOn)
102 {
103 pickElementButton.attr("value", "Disable debugging");
104 $("a").click(function(e)
105 {
106 e.preventDefault();
107 });
108 _debugOn = true;
109 }
110 else
111 {
112 pickElementButton.attr("value", "Enable debugging");
113 $("a").off("click");
114 clearAll();
115 _unpauseButton.attr("disabled", "disabled");
116 _unpauseButton.addClass("ui-state-disabled");
117 _pauseSelector = false;
118 _debugOn = false;
119 }
120 });
121
122 _unpauseButton = $("<input type=\"button\" value=\"Select new element\">");
123 _unpauseButton.button().click(function()
124 {
125 if(_pauseSelector)
126 {
127 _pauseSelector = false;
128 $(this).attr("disabled", "disabled");
129 $(this).addClass("ui-state-disabled");
130 }
131 });
132 _unpauseButton.attr("disabled", "disabled");
133 _unpauseButton.addClass("ui-state-disabled");
134
135 _closeEditorButton = $("<input type=\"button\" value=\"Close editor\">");
136 _closeEditorButton.button().click(function()
137 {
138 if($(this).val() == "Close editor")
139 {
140 $(this).val("Open editor");
141 _editingDiv.hide();
142 }
143 else
144 {
145 $(this).val("Close editor");
146 _editingDiv.show();
147 }
148 });
149 _closeEditorButton.attr("disabled", "disabled");
150 _closeEditorButton.addClass("ui-state-disabled");
151
152 _xmlStatusBar = $("<span>");
153 _xmlStatusBar.css("padding", "5px");
154 _xmlStatusBar.addClass("ui-corner-all");
155
156 //Check the XML for errors every 2 seconds
157 setInterval(function()
158 {
159 if(_editor)
160 {
161 var xmlString = _editor.getValue();
162 try
163 {
164 var 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>");
165 }
166 catch(error)
167 {
168 console.log(error);
169 _xmlStatusBar.text("XML ERROR! (Mouse over for details)");
170 _xmlStatusBar.addClass("ui-state-error");
171 _xmlStatusBar.removeClass("ui-state-active");
172 _xmlStatusBar.attr("title", error);
173 _saveButton.attr("disabled", "disabled");
174 _saveButton.addClass("ui-state-disabled");
175 _swapEditorButton.attr("disabled", "disabled");
176 _swapEditorButton.addClass("ui-state-disabled");
177 return;
178 }
179
180 _xmlStatusBar.text("XML OK!");
181 _xmlStatusBar.addClass("ui-state-active");
182 _xmlStatusBar.removeClass("ui-state-error");
183 _xmlStatusBar.removeAttr("title");
184 if(_saveButton.val() == "Save changes")
185 {
186 _saveButton.removeAttr("disabled");
187 _saveButton.removeClass("ui-state-disabled");
188 }
189 if(_swapEditorButton.val() == "Switch to Visual Editor")
190 {
191 _swapEditorButton.removeAttr("disabled");
192 _swapEditorButton.removeClass("ui-state-disabled");
193 }
194 }
195
196 }, 2000);
197
198 _saveButton = $("<input type=\"button\" value=\"Save changes\">");
199 _saveButton.button().click(function()
200 {
201 if(_editor)
202 {
203 var xmlString;
204 if(_isVisualEditor)
205 {
206 xmlString = new XMLSerializer().serializeToString(_vEditor.getXML());
207 }
208 else
209 {
210 xmlString = _editor.getValue();
211 }
212 xmlString = xmlString.replace(/&/g, "&amp;");
213
214 try
215 {
216 var 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>");
217 }
218 catch(error)
219 {
220 alert("Could not save as there is a problem with the XML.");
221 return;
222 }
223
224 var url = gs.xsltParams.library_name;
225 var parameters = {"a":"g", "rt":"r", "s":"SaveXMLTemplateToFile", "s1.filePath":_currentFilepath, "s1.namespace":_currentNamespace, "s1.nodename":_currentNodename, "s1.xml":xmlString};
226
227 if(_currentName && _currentName.length > 0){parameters["s1.name"] = _currentName;}
228 if(_currentMatch && _currentMatch.length > 0){parameters["s1.match"] = _currentMatch;}
229
230 _saveButton.val("Saving...");
231 _saveButton.attr("disabled", "disabled");
232 _saveButton.addClass("ui-state-default");
233
234 $.post(url, parameters)
235 .success(function()
236 {
237 $.ajax(gs.xsltParams.library_name + "?a=s&sa=c")
238 .success(function()
239 {
240 alert("The template has been saved successfully.");
241 })
242 .error(function()
243 {
244 alert("Error reloading collection.");
245 })
246 .complete(function()
247 {
248 _saveButton.val("Save changes");
249 _saveButton.removeAttr("disabled");
250 _saveButton.removeClass("ui-state-default");
251 partialPageReload();
252 });
253 })
254 .error(function()
255 {
256 alert("There was an error sending the request to the server, please try again.");
257 });
258 }
259 });
260 _saveButton.attr("disabled", "disabled");
261 _saveButton.addClass("ui-state-disabled");
262
263 _swapEditorButton = $("<input type=\"button\" value=\"Switch to XML Editor\">");
264 _swapEditorButton.button().click(function()
265 {
266 if(_vEditor && _textEditor)
267 {
268 if(_isVisualEditor)
269 {
270 _vEditor.getMainDiv().hide();
271 var containerNode = _vEditor.getXML().firstChild;
272 var templateNode = containerNode.firstChild;
273 while(templateNode)
274 {
275 if(templateNode.nodeType == 1)
276 {
277 break;
278 }
279 templateNode = templateNode.nextSibling;
280 }
281 var xmlText = new XMLSerializer().serializeToString(templateNode);
282 _editor.setValue(xmlText);
283 _editor.clearSelection();
284 _textEditor.show();
285 _swapEditorButton.val("Switch to Visual Editor");
286 _isVisualEditor = false;
287 }
288 else
289 {
290 _textEditor.hide();
291 var xmlText = _editor.getValue();
292 _vEditor.getMainDiv().remove();
293 _vEditor = new visualXMLEditor(xmlText);
294 _editingDiv.append(_vEditor.getMainDiv());
295 _vEditor.selectRootElement();
296 _vEditor.getMainDiv().show();
297 _swapEditorButton.val("Switch to XML Editor");
298 _isVisualEditor = true;
299 }
300 }
301 });
302
303 undoButton = $("<input type=\"button\" value=\"Undo\">");
304 undoButton.button().click(function()
305 {
306 if(_isVisualEditor)
307 {
308 _vEditor.undo();
309 }
310 else
311 {
312 _editor.undo();
313 }
314 });
315
316 var clear = $("<span>");
317 clear.css("clear", "both");
318 toolBarDiv.append(clear);
319
320 buttonDiv.append(pickElementButton);
321 buttonDiv.append(_unpauseButton);
322 buttonDiv.append(_closeEditorButton);
323 buttonDiv.append(_saveButton);
324 buttonDiv.append(_swapEditorButton);
325 buttonDiv.append(undoButton);
326 buttonDiv.append(_xmlStatusBar);
327
328 _mainDiv.append(toolBarDiv);
329 _mainDiv.append(_editingDiv);
330 _mainDiv.append("<div>Templates:</div>");
331 _mainDiv.append(_templateSelector);
332 }
333
334 var clearAll = function()
335 {
336 _itemSelected = false;
337 $(_elements).each(function()
338 {
339 $(this).remove();
340 });
341 }
342
343 var highlightElement = function(e)
344 {
345 var topBorderDiv = $("<div>");
346 var bottomBorderDiv = $("<div>");
347 var leftBorderDiv = $("<div>");
348 var rightBorderDiv = $("<div>");
349
350 topBorderDiv.css({"position":"absolute", "top":e.offset().top + "px", "left":e.offset().left + "px", "height":"0px", "width":e.width() + "px", "border":"1px solid red"});
351 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"});
352 leftBorderDiv.css({"position":"absolute", "top":e.offset().top + "px", "left":e.offset().left + "px", "height":e.height() + "px", "width":"0px", "border":"1px solid red"});
353 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"});
354
355 $("body").append(topBorderDiv, bottomBorderDiv, leftBorderDiv, rightBorderDiv);
356
357 _elements.push(topBorderDiv);
358 _elements.push(bottomBorderDiv);
359 _elements.push(leftBorderDiv);
360 _elements.push(rightBorderDiv);
361 }
362
363 var addMouseEventsToInfoContainer = function(infoContainer, filepath, nodename, namespace, name, match)
364 {
365 infoContainer.click(function()
366 {
367 if(_selectedTemplate)
368 {
369 _selectedTemplate.css("border", _selectedTemplate.prevBorder);
370 }
371 _selectedTemplate = infoContainer;
372 _selectedTemplate.prevBorder = _selectedTemplate.css("border");
373 _selectedTemplate.css("border", "red 1px solid");
374
375 _currentFilepath = filepath;
376 _currentNodename = nodename;
377 _currentNamespace = namespace;
378 _currentName = name;
379 _currentMatch = match;
380
381 var responseName = "requestedNameTemplate";
382
383 var url = gs.xsltParams.library_name + "?a=g&rt=r&s=RetrieveXMLTemplateFromFile&s1.filePath=" + _currentFilepath + "&s1.namespace=" + _currentNamespace + "&s1.nodename=" + _currentNodename;
384 if(_currentMatch && _currentMatch.length > 0){url += "&s1.match=" + _currentMatch; responseName = "requestedMatchTemplate";}
385 if(_currentName && _currentName.length > 0){url += "&s1.name=" + _currentName;}
386 $.ajax(url)
387 .success(function(response)
388 {
389 var template;
390 if(response.search(responseName) != -1)
391 {
392 var startIndex = response.indexOf("<" + responseName + ">") + responseName.length + 2;
393 var endIndex = response.indexOf("</" + responseName + ">");
394 template = response.substring(startIndex, endIndex);
395 }
396 else
397 {
398 return;
399 }
400
401 _textEditor = $("<div>", {"id":"textEditor"});
402 _textEditor.css({"width":"100%", "height":"300px"});
403 _textEditor.val(template);
404
405 if(_isVisualEditor)
406 {
407 _textEditor.hide();
408 }
409
410 _editingDiv.empty();
411 _editingDiv.append($("<p>" + filepath + "</p>"));
412 _editingDiv.append(_textEditor);
413
414 _vEditor = new visualXMLEditor(template);
415 _editingDiv.append(_vEditor.getMainDiv());
416 _vEditor.selectRootElement();
417
418 if(!_isVisualEditor)
419 {
420 _vEditor.getMainDiv().hide();
421 }
422
423 _editor = ace.edit("textEditor");
424 _editor.getSession().setMode("ace/mode/xml");
425 _editor.getSession().setUseSoftTabs(false);
426 _editor.setValue(template);
427 _editor.clearSelection();
428
429 _textEditor.css({"min-height":"200px", "border-top":"5px solid #444"});
430 _textEditor.resizable({handles: 'n', resize:function()
431 {
432 _textEditor.css({top:"0px"});
433 _editor.resize();
434 }});
435
436
437 _closeEditorButton.removeAttr("disabled");
438 _closeEditorButton.removeClass("ui-state-disabled");
439 })
440 .error(function()
441 {
442 console.log("ERROR");
443 });
444 });
445 infoContainer.mouseover(function()
446 {
447 $(this).data("background", $(this).css("background"));
448 $(this).css("background", "yellow");
449 });
450 infoContainer.mouseout(function()
451 {
452 $(this).css("background", $(this).data("background"));
453 });
454 }
455
456 var addMouseEventsToDebugElements = function(debugElems)
457 {
458 debugElems.click(function()
459 {
460 if(_debugOn)
461 {
462 _pauseSelector = true;
463 _unpauseButton.removeAttr("disabled");
464 _unpauseButton.removeClass("ui-state-disabled");
465 }
466 });
467
468 debugElems.mouseover(function()
469 {
470 if(_debugOn && !_pauseSelector)
471 {
472 var nodes = new Array();
473 if($(this).is("table, tr"))
474 {
475 var size = parseInt($(this).attr("debugSize"));
476 for(var i = 0; i < size; i++)
477 {
478 var tempNode = $("<div>");
479 tempNode.tempAttrs = new Array();
480 $(this.attributes).each(function()
481 {
482 if(this.value.charAt(0) == '[')
483 {
484 var values = eval(this.value);
485 if(values[i] == "")
486 {
487 return;
488 }
489 tempNode.attr(this.name, values[i]);
490 tempNode.tempAttrs.push({name:this.name, value:values[i]});
491 }
492 });
493 nodes.push(tempNode);
494 }
495 }
496 else
497 {
498 nodes.push(this);
499 }
500
501 $(nodes).each(function()
502 {
503 var filepath = $(this).attr("filename");
504 var fullNodename = $(this).attr("nodename");
505 var colonIndex = fullNodename.indexOf(":");
506 var namespace = fullNodename.substring(0, colonIndex);
507 var nodename = fullNodename.substring(colonIndex + 1);
508 var name = $(this).attr("name");
509 var match = $(this).attr("match");
510
511 var infoContainer = $("<div>");
512 infoContainer.addClass("gbTemplateContainer");
513
514 _elements.push(infoContainer);
515
516 addMouseEventsToInfoContainer(infoContainer, filepath, nodename, namespace, name, match);
517
518 /*
519 var attrstr = "";
520 var illegalNames = ["nodename", "filename", "style", "debug", "id", "class"];
521
522 var attributes = ((this.tempAttrs) ? this.tempAttrs : this.attributes);
523
524 $(attributes).each(function()
525 {
526 for(var i = 0; i < illegalNames.length; i++)
527 {
528 if(this.name == illegalNames[i]){return;}
529 }
530 attrstr += this.name + "=\"" + this.value + "\" ";
531 });
532
533 infoContainer.text("<" + fullNodename + " " + attrstr + ">");
534 */
535
536 if(name && name.length > 0)
537 {
538 infoContainer.text(name);
539 }
540 if(match && match.length > 0)
541 {
542 infoContainer.text(match);
543 }
544
545 if(_templateSelector.children("div").length > 0)
546 {
547 var spacer = $("<div>&gt;&gt;</div>");
548 spacer.addClass("gbSpacer");
549
550 _templateSelector.prepend(spacer);
551 _elements.push(spacer);
552 }
553
554 _templateSelector.prepend(infoContainer);
555
556 resizeContainers();
557 });
558
559 if(!_itemSelected)
560 {
561 _itemSelected = true;
562 highlightElement($(this));
563 }
564 }
565 });
566
567 debugElems.mouseout(function()
568 {
569 if(_debugOn && !_pauseSelector)
570 {
571 clearAll();
572 }
573 });
574 }
575
576 var resizeContainers = function()
577 {
578 var templates = _templateSelector.children(".gbTemplateContainer");
579 var spacers = _templateSelector.children(".gbSpacer");
580
581 var templateWidth = (79/templates.length) + "%";
582 templates.css("width", templateWidth);
583
584 if(spacers.length > 0)
585 {
586 var spacersWidth = (19/spacers.length) + "%";
587 spacers.css("width", spacersWidth);
588 }
589 }
590
591 this.init = function()
592 {
593 //We only want this on if we have debug elements in the page
594 var debugElems = $('debug, [debug="true"]');
595 if(!debugElems.length)
596 {
597 console.log("No debug tags present, debugging disabled.");
598 return;
599 }
600
601 createDebugDiv();
602 $("body").append(_mainDiv);
603
604 $(".ui-button").css({"padding":"0.2em", "margin-right":"0.5em"});
605
606 addMouseEventsToDebugElements(debugElems);
607 }
608
609}
610
611$(window).load(function()
612{
613 var debugWidget = new DebugWidget();
614 debugWidget.init();
615});
Note: See TracBrowser for help on using the repository browser.