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

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

Implemented undo functionality

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