source: gs3-extensions/seaweed-debug/trunk/src/Core.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: 13.4 KB
Line 
1/*
2 * file: Core.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// Short-hands which can be munged
21var
22 // Notes:
23 // Not in core notation ($...) or internal notation (_...) since not ready for all scripts until library initialized.
24 /**
25 * The document.body reference. Available when library initialized.
26 * @type Node
27 */
28 docBody,
29
30 /**
31 * @type undefined
32 */
33 $undefined;
34
35/**
36 * @namespace The main namespace for the whole system
37 * @author Brook Jesse Novak
38 */
39de = {
40
41 version : "0.0.1",
42
43 /**
44 * @private
45 * Module register
46 */
47 m : [],
48
49 /**
50 * @namespace Contains useful collections like listed lists and hashsets.
51 * @author Brook Jesse Novak
52 */
53 collections: {},
54
55 /**
56 * @namespace The DOM events subsystem.
57 * @author Brook Jesse Novak
58 */
59 events: {},
60
61
62 /**
63 * Adds a callback function to be invoked once the DOM is ready.
64 * Allows multiple registrations of handlers.
65 * <br/>
66 * NOTE: In the debug release, the window "onload" events are used instead of "domready"
67 * events and therefore take longer to be raised than expected. This is to ensure that all
68 * scripts are downloaded by the bootstrapper.
69 *
70 * @type Function
71 * @param {Function} handler A call back function to be invoked when the document is loaded and direct edit can be initialized.
72 */
73 onready : (function() {
74
75 var handlers = []; // zeroed when dom ready occurs
76
77 function onReadyHandler() {
78
79 if (handlers) { // First onload event?
80
81 // Fire event to handlers
82 for (var i in handlers) {
83 handlers[i]();
84 }
85
86 // Mark that onload event has occured
87 handlers = 0;
88 }
89 };
90
91 // @DEBUG ON
92 (function() {
93 // @DEBUG OFF
94
95 // @DEBUG ON
96 // Use window onload in debug release since some broswers can invoke onready
97 // events before the bootstrapper download all scripts in the seaweed api.
98
99 // Register to onload event
100 if (window.addEventListener)
101 window.addEventListener("load", onReadyHandler, false);
102 else if (window.attachEvent)
103 window.attachEvent("onload", onReadyHandler);
104 else {
105 // Save exisiting handlers
106 if (window.onload)
107 handlers.push(window.onload);
108 window.onload = onloadFunc;
109 }
110 return;
111
112 // @DEBUG OFF
113
114 // For the release use DOMReady event - nice and quick.
115 // This code is based from JQuerry 1.3.2 bindReady event (MIT licensed code)
116
117 if (document.addEventListener) { // W3C Compliant
118 // Use the handy event callback
119 document.addEventListener("DOMContentLoaded", function(){
120 document.removeEventListener("DOMContentLoaded", arguments.callee, false);
121 onReadyHandler();
122
123 }, false);
124
125 } else if (document.attachEvent) { // IE
126 // Ensure firing before onload.
127 // maybe late but safe also for iframes
128 document.attachEvent("onreadystatechange", function(){
129 if (document.readyState === "complete") {
130 document.detachEvent("onreadystatechange", arguments.callee);
131 onReadyHandler();
132 }
133 });
134
135 // If IE and not an iframe continually check to see if the document is ready
136 if (document.documentElement.doScroll && window == window.top) (function(){
137 if (!handlers)
138 return;
139
140 try {
141 // If IE is used, use the trick by Diego Perini
142 // http://javascript.nwbox.com/IEContentLoaded/
143 document.documentElement.doScroll("left");
144 } catch (error) {
145 setTimeout(arguments.callee, 0);
146 return;
147 }
148
149 // and execute any waiting functions
150 onReadyHandler();
151 })();
152
153 // Fallback: use window onload. NOTE: In release mode this will be present
154 // in this very script so it is safe to use it.
155 _addHandler(window, "load", function(){
156 onReadyHandler();
157 _removeHandler(window, "load", arguments.callee);
158 });
159
160 }
161
162 // @DEBUG ON
163 })();
164 // @DEBUG OFF
165
166
167 // The function
168 return function(handler) {
169 // Pending onload?
170 if (handlers)
171 handlers.push(handler);
172 else handler(); // Immedite exec since onload occured
173 };
174
175 })(),
176
177 /**
178 * Prepares DEdit for usage
179 */
180 init: function() {
181
182 // Already initialized?
183 if (!de.m)
184 return;
185
186 docBody = document.body;
187
188 var modules = de.m;
189
190 // @DEBUG ON
191
192 // Check integrity of init queue
193 for (var i in modules) {
194
195 // Esnure no module depends on self
196 if (modules[i].depends) {
197 for (var j in modules[i].depends) {
198 debug.assert(modules[i].depends[j] != modules[i].name, "Bad dependancy: Module " + modules[i].name + " depends on self");
199 var found = false;
200 for (var k in bootstrap.loadedModules) {
201 if (bootstrap.loadedModules[k] == modules[i].depends[j]) {
202 found = true;
203 break;
204 }
205 }
206
207 debug.assert(found, "Bad dependancy: Module " + modules[i].name + " depends on unknown dependancy \"" + modules[i].depends[j] + "\"");
208 }
209 }
210 }
211
212 // @DEBUG OFF
213
214 // Initialize modules
215 var orderChanged;
216
217 do { // sort dependancies in a bubble sort manner
218 // NOTE: This does not detect cyclic dependancies... thus can inifitely loop
219 // in such cases.
220
221 //TODO: Faster/elegant way of building dependency tree
222
223 orderChanged = false;
224 for (var i = 0; i < modules.length; i++) {
225
226 var currentMod = modules[i];
227
228 // If this has no dependancies then leave as is
229 if (!currentMod.depends) continue;
230
231 // Check that dependancies occur before this
232 for (var j = 0; j < currentMod.depends.length; j++) {
233
234 for (var k = i + 1; k < modules.length; k++) {
235 if (currentMod.depends[j] == modules[k].name) {
236 // Move this (modules[i]) to after the dependancy (modules[k])
237 var old = modules;
238 modules = old.slice(0, i).concat(old.slice(i + 1, k + 1).concat([currentMod].concat(old.slice(k + 1))));
239 orderChanged = true;
240 break;
241 }
242 }
243
244 if (orderChanged) break;
245 }
246
247 if (orderChanged) break;
248
249 } // Next module
250 } while (orderChanged); // Continue bubble sorting the dependancy list
251
252 // Execute initialization code
253 for (i in modules) {
254 if (modules[i].init) modules[i].init();
255 }
256
257 // cleanup initialization breadcrumbs
258 delete de["m"];
259 }
260};
261
262/*
263 * Declare core internals inline .. this is a special setup since Core is the first script declared
264 */
265
266/**
267 * <p>
268 * Enqueue's an intialization function to be invoked during the DEdit API initialization phase (after DOM is ready).
269 * </p>
270 * <p>
271 * If a module (script) needs to be initialized before usage and depends on the document DOM state to be ready -
272 * or should only be initialized when the API is explicitely been asked to be initialized, or initialization code
273 * depends on a public API interface then use this function (at most once per module).
274 * </p>
275 * NOTE: All internals will be loaded upon execution of the initialization code, therefore there is no need to
276 * delcare dependancies (@DEPENDS or via this method) for usage of internals within initialization code.
277 *
278 * @param {String} moduleName The name of the module (script file name without extension).
279 *
280 * @param {Function} init An optional initialization method. If the initialization code depends on
281 * other modules' public interfaces, then specify the module names as additional arguments to this call.
282 */
283function $enqueueInit(moduleName, init){
284
285 // @DEBUG ON
286
287 debug.assert(de.m ? true : false, "Attempted to enqueue initializor function after API has initialized");
288
289 for (var i in de.m) { // Integrity check
290 debug.assert(de.m[i].name != moduleName, 'An initializor is already registered under the name "' + moduleName + '"');
291 }
292
293 // @DEBUG OFF
294
295 // Discover dependancies (declared as extra arguments)
296 var dependancies = Array.prototype.slice.call(arguments);
297 dependancies.splice(0, 2);
298
299 // Store the initializor for the module
300 de.m.push({
301 name: moduleName,
302 init: init,
303 depends: dependancies
304 });
305
306};
307
308/**
309 * Adds/suppliments all members to a target object from a source object.
310 * If the target object has a member that is also contained in source, it will
311 * be overridden with the source member.
312 *
313 * Leaves the source object in tact.
314 *
315 * @param {Object} target The destination object
316 *
317 * @param {Object} source The source object
318 *
319 * @param {Boolean} override (Optional) True to override existing members on conflicts,
320 * false skip conflicts. Defaults to true
321 *
322 * @return {Object} The target object
323 */
324function $extend(target, source, override) {
325
326 if (override !== false)
327 override = true;
328
329 for (var mem in source) {
330 if (override || typeof target[mem] == "undefined")
331 target[mem] = source[mem];
332 }
333
334 return target;
335}
336
337/**
338 * Create a hash map of booleans from a comma separated set of keys.
339 * @param {String} str A comma separated set of keys. White spaces are not truncated
340 * @return {Object} A lookup map
341 */
342function $createLookupMap(str){
343 var arr = str.split(",");
344 var map = {};
345 for (var i in arr) {
346 map[arr[i]] = true;
347 }
348 return map;
349}
350
351/**
352 * Shorthand for document.createElement
353 * @param {String} tag The element name
354 * @return {Element} A new element
355 */
356function $createElement(tag) {
357 return document.createElement(tag);
358}
359
360// @DEBUG ON
361
362// MSHTML Does not provide Node type constants.
363// Therefore declare them explicitely. This is only needed in the debug version
364// since the release version replaces them with actual values
365// NOTE: This may cause other scripts confusion!! If they test for the presence of
366// the node object and assume it is an actual node class!
367if (typeof Node == "undefined") {
368 Node = {_DE_DEBUG_CREATED : true};
369}
370
371if (typeof Node.ELEMENT_NODE == "undefined") {
372
373
374 $extend(Node, {
375 // @REPLACE Node.ELEMENT_NODE 1
376 ELEMENT_NODE : 1,
377
378 // @REPLACE Node.ATTRIBUTE_NODE 2
379 ATTRIBUTE_NODE : 2,
380
381 // @REPLACE Node.TEXT_NODE 3
382 TEXT_NODE : 3,
383
384 // @REPLACE Node.CDATA_SECTION_NODE 4
385 CDATA_SECTION_NODE : 4,
386
387 // @REPLACE Node.ENTITY_REFERENCE_NODE 5
388 ENTITY_REFERENCE_NODE : 5,
389
390 // @REPLACE Node.ENTITY_NODE 6
391 ENTITY_NODE : 6,
392
393 // @REPLACE Node.PROCESSING_INSTRUCTION_NODE 7
394 PROCESSING_INSTRUCTION_NODE : 7,
395
396 // @REPLACE Node.COMMENT_NODE 8
397 COMMENT_NODE : 8,
398
399 // @REPLACE Node.DOCUMENT_NODE 9
400 DOCUMENT_NODE : 9,
401
402 // @REPLACE Node.DOCUMENT_TYPE_NODE 10
403 DOCUMENT_TYPE_NODE : 10,
404
405 // @REPLACE Node.DOCUMENT_FRAGMENT_NODE 11
406 DOCUMENT_FRAGMENT_NODE : 11,
407
408 // @REPLACE Node.NOTATION_NODE 12
409 NOTATION_NODE : 12
410 });
411
412}
413// @DEBUG OFF
Note: See TracBrowser for help on using the repository browser.