source: gs3-extensions/seaweed-debug/trunk/src/DEdit.js@ 25160

Last change on this file since 25160 was 25160, checked in by sjm84, 12 years ago

Initial cut at a version of seaweed for debugging purposes. Check it out live into the web/ext folder

File size: 24.3 KB
Line 
1/*
2 * file: DEdit.js
3 *
4 * @BEGINLICENSE
5 * Copyright 2010 Brook Novak (email : [email protected])
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 * @ENDLICENSE
18 */
19/**
20 * @namespace The debug namespace will be removed in release builds.
21 */
22debug = {};
23
24/**
25 * Asserts a condition. If a condition fails a alert box shows and an exception is thrown.
26 *
27 * @param {Boolean} cond A condition
28 *
29 * @param {String} msg An optional message
30 *
31 * @throws {Error} if a condition fails
32 */
33debug.assert = function(cond, msg) {
34
35 try {
36 if (!cond) throw new Error("Assertion failed" + (msg ? ": " + msg : ""));
37 } catch (e) {
38
39 var fullMsg = e.message + (e.stack ? "\nstack:\n" + e.stack : "");
40
41 alert(fullMsg);
42
43 throw e;
44 }
45}
46
47debug.close = function(){
48
49 debug.stop = true;
50
51 if (typeof _debugConsole != "undefined" && _debugConsole) {
52
53 _debugConsole.parentNode.removeChild(_debugConsole);
54
55 _debugConsole = null;
56
57 }
58}
59
60debug.stop = false;
61
62/**
63 * Prints a message to a debug console.
64 *
65 * @param {String} msg A message to print.
66 */
67debug.print = function(msg){
68
69 if (debug.stop)
70 return;
71
72 if (window.console && console.log) {
73 console.log(msg);
74 } else if (window.opera && window.opera.postError){
75 window.opera.postError(msg);
76 } else {
77
78 // Setup debug console
79 if (typeof _debugConsole == "undefined" || !_debugConsole) {
80
81 _debugConsole = document.createElement("div");
82 _debugConsole.style.backgroundColor = "#444444";
83 _debugConsole.style.position = "fixed";
84 _debugConsole.style.border = "2px solid #000000";
85 _debugConsole.style.width = "320px";
86 _debugConsole.style.height = "174px";
87 _debugConsole.style.zIndex = "9999";
88 _debugConsole.style.top = "0";
89 _debugConsole.style.left = "0";
90
91 _debugConsole.innerHTML = '<div style="width:320px; color:white; font-weight:bold; font-family:arial,sans; text-align:center; font-size:14px;"><div style="float:right;border: 1px dashed black; color:black; background-color:#66D390; padding:4px; cursor:pointer;" onclick="debug.close();">close</div>~Seaweed~ Debug Console</div>';
92
93 _debugOutput = document.createElement("div");
94 _debugOutput.style.backgroundColor = "white";
95 _debugOutput.style.overflow = "scroll";
96 _debugOutput.style.width = _debugConsole.style.width;
97 _debugOutput.style.height = "140px";
98
99 _debugConsole.appendChild(_debugOutput);
100
101 }
102
103 if (document.body && _debugConsole && _debugConsole.parentNode != document.body)
104 document.body.appendChild(_debugConsole);
105
106 _debugOutput.innerHTML += msg.replace(/\n/g,"<br/>");
107 var st = _debugOutput.scrollHeight - _debugOutput.clientHeight;
108 if (st < 0) st = 0;
109 _debugOutput.scrollTop = st;
110
111 }
112}
113
114/**
115 * Prints a message to a debug console with a new line
116 *
117 * @param {String} msg A message to print.
118 */
119debug.println = function(msg){
120 debug.print(msg + "\n");
121};
122
123/**
124 * Prints out a TODO message and it's stack location
125 * @param {String} msg An optional todo message
126 */
127debug.todo = function(msg) {
128 try {
129 throw new Error();
130 } catch (e) {
131 var fullMsg = "TODO: " + (msg ? msg : "") + (e.stack ? "\nAt" + e.stack : + "");
132 debug.println(fullMsg);
133 }
134};
135
136
137/*
138 * file: Core.js
139 *
140 * @BEGINLICENSE
141 * Copyright 2010, Brook Jesse Novak, All rights reserved
142 * @ENDLICENSE
143 */
144
145// Short-hands which can be munged
146var
147 // Notes:
148 // Not in core notation ($...) or internal notation (_...) since not ready for all scripts until library initialized.
149 /**
150 * The document.body reference. Available when library initialized.
151 * @type Node
152 */
153 docBody,
154
155 /**
156 * @type undefined
157 */
158 $undefined;
159
160/**
161 * @namespace The main namespace for the whole system
162 * @author Brook Jesse Novak
163 */
164de = {
165
166 version : "0.0.1",
167
168 /**
169 * @private
170 * Module register
171 */
172 m : [],
173
174 /**
175 * @namespace Contains useful collections like listed lists and hashsets.
176 * @author Brook Jesse Novak
177 */
178 collections: {},
179
180 /**
181 * @namespace The DOM events subsystem.
182 * @author Brook Jesse Novak
183 */
184 events: {},
185
186
187 /**
188 * Adds a callback function to be invoked once the DOM is ready.
189 * Allows multiple registrations of handlers.
190 * <br/>
191 * NOTE: In the debug release, the window "onload" events are used instead of "domready"
192 * events and therefore take longer to be raised than expected. This is to ensure that all
193 * scripts are downloaded by the bootstrapper.
194 *
195 * @type Function
196 * @param {Function} handler A call back function to be invoked when the document is loaded and direct edit can be initialized.
197 */
198 onready : (function() {
199
200 var handlers = []; // zeroed when dom ready occurs
201
202 function onReadyHandler() {
203
204 if (handlers) { // First onload event?
205
206 // Fire event to handlers
207 for (var i in handlers) {
208 handlers[i]();
209 }
210
211 // Mark that onload event has occured
212 handlers = 0;
213 }
214 };
215
216 // @DEBUG ON
217 (function() {
218 // @DEBUG OFF
219
220 // @DEBUG ON
221 // Use window onload in debug release since some broswers can invoke onready
222 // events before the bootstrapper download all scripts in the seaweed api.
223
224 // Register to onload event
225 if (window.addEventListener)
226 window.addEventListener("load", onReadyHandler, false);
227 else if (window.attachEvent)
228 window.attachEvent("onload", onReadyHandler);
229 else {
230 // Save exisiting handlers
231 if (window.onload)
232 handlers.push(window.onload);
233 window.onload = onloadFunc;
234 }
235 return;
236
237 // @DEBUG OFF
238
239 // For the release use DOMReady event - nice and quick.
240 // This code is based from JQuerry 1.3.2 bindReady event (MIT licensed code)
241
242 if (document.addEventListener) { // W3C Compliant
243 // Use the handy event callback
244 document.addEventListener("DOMContentLoaded", function(){
245 document.removeEventListener("DOMContentLoaded", arguments.callee, false);
246 onReadyHandler();
247
248 }, false);
249
250 } else if (document.attachEvent) { // IE
251 // Ensure firing before onload.
252 // maybe late but safe also for iframes
253 document.attachEvent("onreadystatechange", function(){
254 if (document.readyState === "complete") {
255 document.detachEvent("onreadystatechange", arguments.callee);
256 onReadyHandler();
257 }
258 });
259
260 // If IE and not an iframe continually check to see if the document is ready
261 if (document.documentElement.doScroll && window == window.top) (function(){
262 if (!handlers)
263 return;
264
265 try {
266 // If IE is used, use the trick by Diego Perini
267 // http://javascript.nwbox.com/IEContentLoaded/
268 document.documentElement.doScroll("left");
269 } catch (error) {
270 setTimeout(arguments.callee, 0);
271 return;
272 }
273
274 // and execute any waiting functions
275 onReadyHandler();
276 })();
277
278 // Fallback: use window onload. NOTE: In release mode this will be present
279 // in this very script so it is safe to use it.
280 _addHandler(window, "load", function(){
281 onReadyHandler();
282 _removeHandler(window, "load", arguments.callee);
283 });
284
285 }
286
287 // @DEBUG ON
288 })();
289 // @DEBUG OFF
290
291
292 // The function
293 return function(handler) {
294 // Pending onload?
295 if (handlers)
296 handlers.push(handler);
297 else handler(); // Immedite exec since onload occured
298 };
299
300 })(),
301
302 /**
303 * Prepares DEdit for usage
304 */
305 init: function() {
306
307 // Already initialized?
308 if (!de.m)
309 return;
310
311 docBody = document.body;
312
313 var modules = de.m;
314
315 // @DEBUG ON
316
317 // Check integrity of init queue
318 for (var i in modules) {
319
320 // Esnure no module depends on self
321 if (modules[i].depends) {
322 for (var j in modules[i].depends) {
323 debug.assert(modules[i].depends[j] != modules[i].name, "Bad dependancy: Module " + modules[i].name + " depends on self");
324 var found = false;
325 for (var k in bootstrap.loadedModules) {
326 if (bootstrap.loadedModules[k] == modules[i].depends[j]) {
327 found = true;
328 break;
329 }
330 }
331
332 debug.assert(found, "Bad dependancy: Module " + modules[i].name + " depends on unknown dependancy \"" + modules[i].depends[j] + "\"");
333 }
334 }
335 }
336
337 // @DEBUG OFF
338
339 // Initialize modules
340 var orderChanged;
341
342 do { // sort dependancies in a bubble sort manner
343 // NOTE: This does not detect cyclic dependancies... thus can inifitely loop
344 // in such cases.
345
346 //TODO: Faster/elegant way of building dependency tree
347
348 orderChanged = false;
349 for (var i = 0; i < modules.length; i++) {
350
351 var currentMod = modules[i];
352
353 // If this has no dependancies then leave as is
354 if (!currentMod.depends) continue;
355
356 // Check that dependancies occur before this
357 for (var j = 0; j < currentMod.depends.length; j++) {
358
359 for (var k = i + 1; k < modules.length; k++) {
360 if (currentMod.depends[j] == modules[k].name) {
361 // Move this (modules[i]) to after the dependancy (modules[k])
362 var old = modules;
363 modules = old.slice(0, i).concat(old.slice(i + 1, k + 1).concat([currentMod].concat(old.slice(k + 1))));
364 orderChanged = true;
365 break;
366 }
367 }
368
369 if (orderChanged) break;
370 }
371
372 if (orderChanged) break;
373
374 } // Next module
375 } while (orderChanged); // Continue bubble sorting the dependancy list
376
377 // Execute initialization code
378 for (i in modules) {
379 if (modules[i].init) modules[i].init();
380 }
381
382 // cleanup initialization breadcrumbs
383 delete de["m"];
384 }
385};
386
387/*
388 * Declare core internals inline .. this is a special setup since Core is the first script declared
389 */
390
391/**
392 * <p>
393 * Enqueue's an intialization function to be invoked during the DEdit API initialization phase (after DOM is ready).
394 * </p>
395 * <p>
396 * If a module (script) needs to be initialized before usage and depends on the document DOM state to be ready -
397 * or should only be initialized when the API is explicitely been asked to be initialized, or initialization code
398 * depends on a public API interface then use this function (at most once per module).
399 * </p>
400 * NOTE: All internals will be loaded upon execution of the initialization code, therefore there is no need to
401 * delcare dependancies (@DEPENDS or via this method) for usage of internals within initialization code.
402 *
403 * @param {String} moduleName The name of the module (script file name without extension).
404 *
405 * @param {Function} init An optional initialization method. If the initialization code depends on
406 * other modules' public interfaces, then specify the module names as additional arguments to this call.
407 */
408function $enqueueInit(moduleName, init){
409
410 // @DEBUG ON
411
412 debug.assert(de.m ? true : false, "Attempted to enqueue initializor function after API has initialized");
413
414 for (var i in de.m) { // Integrity check
415 debug.assert(de.m[i].name != moduleName, 'An initializor is already registered under the name "' + moduleName + '"');
416 }
417
418 // @DEBUG OFF
419
420 // Discover dependancies (declared as extra arguments)
421 var dependancies = Array.prototype.slice.call(arguments);
422 dependancies.splice(0, 2);
423
424 // Store the initializor for the module
425 de.m.push({
426 name: moduleName,
427 init: init,
428 depends: dependancies
429 });
430
431};
432
433/**
434 * Adds/suppliments all members to a target object from a source object.
435 * If the target object has a member that is also contained in source, it will
436 * be overridden with the source member.
437 *
438 * Leaves the source object in tact.
439 *
440 * @param {Object} target The destination object
441 *
442 * @param {Object} source The source object
443 *
444 * @param {Boolean} override (Optional) True to override existing members on conflicts,
445 * false skip conflicts. Defaults to true
446 *
447 * @return {Object} The target object
448 */
449function $extend(target, source, override) {
450
451 if (override !== false)
452 override = true;
453
454 for (var mem in source) {
455 if (override || typeof target[mem] == "undefined")
456 target[mem] = source[mem];
457 }
458
459 return target;
460}
461
462/**
463 * Create a hash map of booleans from a comma separated set of keys.
464 * @param {String} str A comma separated set of keys. White spaces are not truncated
465 * @return {Object} A lookup map
466 */
467function $createLookupMap(str){
468 var arr = str.split(",");
469 var map = {};
470 for (var i in arr) {
471 map[arr[i]] = true;
472 }
473 return map;
474}
475
476/**
477 * Shorthand for document.createElement
478 * @param {String} tag The element name
479 * @return {Element} A new element
480 */
481function $createElement(tag) {
482 return document.createElement(tag);
483}
484
485// @DEBUG ON
486
487// MSHTML Does not provide Node type constants.
488// Therefore declare them explicitely. This is only needed in the debug version
489// since the release version replaces them with actual values
490// NOTE: This may cause other scripts confusion!! If they test for the presence of
491// the node object and assume it is an actual node class!
492if (typeof Node == "undefined") {
493 Node = {_DE_DEBUG_CREATED : true};
494}
495
496if (typeof Node.ELEMENT_NODE == "undefined") {
497
498
499 $extend(Node, {
500 // @REPLACE Node.ELEMENT_NODE 1
501 ELEMENT_NODE : 1,
502
503 // @REPLACE Node.ATTRIBUTE_NODE 2
504 ATTRIBUTE_NODE : 2,
505
506 // @REPLACE Node.TEXT_NODE 3
507 TEXT_NODE : 3,
508
509 // @REPLACE Node.CDATA_SECTION_NODE 4
510 CDATA_SECTION_NODE : 4,
511
512 // @REPLACE Node.ENTITY_REFERENCE_NODE 5
513 ENTITY_REFERENCE_NODE : 5,
514
515 // @REPLACE Node.ENTITY_NODE 6
516 ENTITY_NODE : 6,
517
518 // @REPLACE Node.PROCESSING_INSTRUCTION_NODE 7
519 PROCESSING_INSTRUCTION_NODE : 7,
520
521 // @REPLACE Node.COMMENT_NODE 8
522 COMMENT_NODE : 8,
523
524 // @REPLACE Node.DOCUMENT_NODE 9
525 DOCUMENT_NODE : 9,
526
527 // @REPLACE Node.DOCUMENT_TYPE_NODE 10
528 DOCUMENT_TYPE_NODE : 10,
529
530 // @REPLACE Node.DOCUMENT_FRAGMENT_NODE 11
531 DOCUMENT_FRAGMENT_NODE : 11,
532
533 // @REPLACE Node.NOTATION_NODE 12
534 NOTATION_NODE : 12
535 });
536
537}
538// @DEBUG OFF
539/*
540 * This Bootloader was auto-generated on 27/02/2010 14:18:11
541 * @author Brook Novak
542Copyright 2010 Brook Novak (email : [email protected])
543
544This program is free software; you can redistribute it and/or modify
545it under the terms of the GNU General Public License as published by
546the Free Software Foundation; either version 2 of the License, or
547(at your option) any later version.
548
549This program is distributed in the hope that it will be useful,
550but WITHOUT ANY WARRANTY; without even the implied warranty of
551MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
552GNU General Public License for more details.
553
554You should have received a copy of the GNU General Public License
555along with this program; if not, write to the Free Software
556Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
557
558(function() {
559
560var baseScripts=["collections/DoublyLinkedList.js","MVC.js","Platform.js","UndoMan.js","Util.js"];
561var dependantScripts=["Changes.js","Clipboard.js","ContainerNormalization.js","Cursor.js","Doc.js","Error.js","events/Events.js","events/Mouse.js","FormatEnvironment.js","Fragment.js","OperationManager.js","events/Keyboard.js","Selection.js","Spell.js","Typing.js","actions/TextAlignAction.js","actions/SplitContainerAction.js","actions/RemoveTextAction.js","actions/RemoveDOMAction.js","actions/PromoteItemAction.js","actions/ModifyTableAction.js","actions/ItemizeAction.js","actions/InsertTextAction.js","actions/InsertHTMLAction.js","actions/IndentAction.js","actions/FormatAction.js","actions/DemoteItemAction.js","actions/CreateTableAction.js","actions/ChangeContainerAction.js","actions/BlockQuoteAction.js","DTDUtil.js","Viewport.js","WhitespaceUtil.js"];
562
563var thisFilename="DEdit.js";
564
565/*
566 * file: Bootstrapper.js
567 *
568 * @BEGINLICENSE
569 * Copyright 2010, Brook Jesse Novak, All rights reserved
570 * @ENDLICENSE
571 */
572/**********************************************************************************************************************
573 * @author Brook Novak
574 *
575 * Assumes:
576 * - Core.js is prepended(or loaded).
577 * - An array named "baseScripts" exists with all relative paths of scripts to load first in the given order.
578 * - An array named "dependantScripts" exists with all relative paths of scripts to load after the base scripts.
579 * - A string named "thisFilename" exists, set to the filename of this file, which is contained in the libraries TDL.
580 * - That this script is encapsulated in an anonymous function (To avoid polluting global scope)
581 **********************************************************************************************************************/
582
583// Mimic the addHandler method in the events module to make available before the events module script is even available
584var eventHandlers = [];
585de.events.addHandler = function(eventSource, eventName, handler) { // will be overridden
586 eventHandlers.push(arguments);
587}
588
589// Override the onready function (declared in Core)- so that all callbacks are invoked once
590// the window.onload occurs AND all scripts are loaded
591var onReadyCallbacks = [],
592 origReady = de.onready;
593de.onready = function(handler) {
594 onReadyCallbacks.push(handler);
595}
596
597/**
598 * @namespace
599 * The bootstrap namespace.
600 */
601bootstrap = {
602
603 /**
604 * A list of all laoded module names
605 * @type [String]
606 */
607 loadedModules : [],
608
609 /**
610 * For all scripts in the API you must invoke this function to register the script when the script is first executed.
611 *
612 * @param {String} name The name of module that is loaded.
613 * The Module name is the relative path without the file extension (.js),
614 * and directory separators are replaced with period-symbols.
615 */
616 provides : function(name) {
617
618 // debug.println("Loaded: " + name);
619
620 this.loadedModules.push(name);
621
622 // First Phase: base-script loading
623 if (baseScripts.length > 0) {
624
625 // A base script is loaded - remove it
626 baseScripts.shift();
627
628 if (baseScripts.length > 0) { // More base scripts to load
629
630 // Load the next base script
631 loadScript(baseURL + baseScripts[0]);
632
633 } else { // Finished download base scripts
634
635 // Pull in remaining API source files asynchronously
636 for (var i in dependantScripts) {
637 loadScript(baseURL + dependantScripts[i]);
638 }
639 }
640
641 } else { // Second phase: dependant-script loading
642
643 // A dependant script is loaded.
644
645 // Get relative path for registered module
646 var registeredPath = name.replace(/\./g,"/").toLowerCase() + ".js";
647
648 // Remove include path for the registered module
649 for (var i = 0; i < dependantScripts.length; i++) {
650 if (dependantScripts[i].toLowerCase() == registeredPath) {
651 dependantScripts.splice(i, 1);
652 break;
653 }
654 }
655
656 if (dependantScripts.length == 0) { // All scripts loaded?
657
658 // Schedule finishing-up code on another event to let the last script load
659 setTimeout(function() {
660
661 // Add all registered events...
662 for (var i in eventHandlers) {
663 var args = eventHandlers[i];
664
665 var eventSource = (args.length > 0) ? args[0] : null,
666 eventName = (args.length > 1) ? args[1] : null,
667 handler = (args.length > 2) ? args[2] : null;
668
669 _addHandler(eventSource, eventName, handler);
670 }
671
672 // Add all on-ready funcs
673 for (var i in onReadyCallbacks) {
674 origReady(onReadyCallbacks[i]); // Fires instantly is onload already occured
675 }
676
677 de.onready = origReady;
678
679 }, 1);
680
681 }
682 }
683
684 }
685
686};
687
688// Determine the base URL of the library.
689var baseURL;
690var libcoreRegExp = new RegExp("(^|[\\/\\\\])" + thisFilename.replace(/\./g,"\\.") + "(\\?|$)");
691var scriptElements = document.getElementsByTagName("script");
692
693for (var i in scriptElements) {
694 var src = scriptElements[i].src;
695 if (src && src.match(libcoreRegExp)) {
696
697 baseURL = src;
698 i = src.lastIndexOf("/");
699 if (i == -1) i = src.lastIndexOf("\\");
700 baseURL = (i == -1) ? "" : src.substring(0, i + 1);
701
702 break;
703 }
704
705}
706
707if (!baseURL) throw new Error("Unable to import library: could not discover DEdit libhome");
708
709// Pull in API base source files first, once this is done the rest of the api source will be pulled in
710loadScript(baseURL + baseScripts[0]);
711
712function loadScript(scriptSrc){
713
714 // gets document head element
715 var docHead = document.getElementsByTagName('head')[0];
716
717 if (docHead) {
718 // creates a new script tag
719 var scriptEl = document.createElement('script');
720
721 // adds src and type attribute to script tag
722 scriptEl.setAttribute('src', scriptSrc);
723 scriptEl.setAttribute('type', 'text/javascript');
724
725 // append the script tag to document head element
726 docHead.appendChild(scriptEl);
727 }
728}
729
730
731})();
Note: See TracBrowser for help on using the repository browser.