UNPKG

52.6 kBJavaScriptView Raw
1// CrossBrowdy by Joan Alba Maldonado (workindalian@gmail.com).
2
3/**
4 * @file Main CrossBrowdy file.
5 * @author Joan Alba Maldonado <workindalian@gmail.com>
6 * @license Creative Commons Attribution 4.0 International. See more at {@link https://crossbrowdy.com/about#what_is_the_crossbrowdy_copyright_and_license}.
7 * @todo Clear all timeouts before creating them (just in case).
8 */
9
10
11//CrossBrowdy constants and variables:
12/**
13 * Keeps the name of the script (the main script will use this name with the ".js" extension). Case sensitive.
14 * @constant
15 * @type {string}
16 * @default
17 */
18var CB_NAME = "CrossBrowdy";
19
20/**
21 * CrossBrowdy version.
22 * @constant
23 * @type {string}
24 */
25var CB_VERSION = "0.99.96.31";
26
27/**
28 * Keeps the CrossBrowdy "this" context.
29 * @constant
30 * @type {Object}
31 */
32var CB_this = this;
33
34/**
35 * Two-dimensional object defined by the user with the desired options for CrossBrowdy and its modules. The options supported are the ones used by the {@link CB_Configuration} object.
36 <br>
37 First-level indexes should belong to the module name (or to "CrossBrowdy", for general options) and second-level indexes should belong to the option name.
38 <br>
39 Example:
40 <br>
41 {
42 CrossBrowdy:
43 {
44 CB_console_ALLOW_ALERTS: false
45 },
46 CrossBase:
47 {
48 SLCANVAS_LOAD : true,
49 FLASHCANVAS_LOAD : true
50 }
51 }
52
53 * @constant CB_OPTIONS
54 * @type {Object}
55 * @default undefined
56 */
57
58/**
59 * Static class to manage the configuration. It will be overwritten with the values defined in {@link CB_OPTIONS} (if any).
60 <br>
61 First-level indexes should belong to the module name and second-level indexes should belong to the option name.
62 <br>
63 Follows the same format as {@link CB_OPTIONS}.
64 * @namespace
65*/
66var CB_Configuration = {};
67
68/**
69 Property that contains an object with the options for the main script.
70 * @namespace CB_Configuration.CrossBrowdy
71 */
72CB_Configuration[CB_NAME] =
73{
74 /**
75 * Default path of the script (path can be changed when {@link CB_init} is called)
76 * @memberof CB_Configuration.CrossBrowdy
77 * @constant
78 * @type {string}
79 * @default {@link CB_NAME} + "/"
80 */
81 SCRIPT_PATH_DEFAULT: "../" + CB_NAME + "/",
82
83
84 /**
85 * Defines whether to show the splash screen in the beginning by default or not.
86 * @memberof CB_Configuration.CrossBrowdy
87 * @constant
88 * @type {boolean}
89 * @default
90 */
91 SHOW_SPLASH_SCREEN_DEFAULT: true,
92
93
94 /**
95 * Defines whether to register statistics or not. If it is enabled, the URL defined in {@link CB_Configuration.CrossBrowdy.STATS_URL} will be called (by including it as a JavaScript file) as soon as CrossBrowdy gets called (might not be ready yet).
96 * This parameter do not do anything else, just includes your desired URL (defined in {@link CB_Configuration.CrossBrowdy.STATS_URL}) as a JavaScript file when CrossBrowdy is called.
97 * @memberof CB_Configuration.CrossBrowdy
98 * @constant
99 * @type {boolean}
100 * @default false
101 */
102 STATS: false,
103
104
105 /**
106 * URL to register the statistics if {@link CB_Configuration.CrossBrowdy.STATS} is enabled. When {@link CB_Configuration.CrossBrowdy.STATS} is enabled, this URL will be included as a JavaScript file as soon as CrossBrowdy gets called (might not be ready yet).
107 * The URL will be called (included in the document as a JavaScript file) adding three parameters: "cb" parameter with the CrossBrowdy version as the value, "time" with a timestamp which belongs to the current time of the client and "url" parameter with the current URL visited by the user as the value.
108 * @memberof CB_Configuration.CrossBrowdy
109 * @constant
110 * @type {string}
111 * @default
112 */
113 STATS_URL: "https://crossbrowdy.com/_stats/CB_stats.php",
114
115
116 /**
117 * Defines whether to allow the use of alert()'s as a fallback when using {@link CB_console} and neither the [console]{@link https://developer.mozilla.org/en-US/docs/Web/API/Console} object nor a DOM element with "CB_console" ID are found.
118 * @memberof CB_Configuration.CrossBrowdy
119 * @constant
120 * @type {boolean}
121 * @default
122 */
123 CB_console_ALLOW_ALERTS: true,
124
125
126 /**
127 * Default milliseconds before firing the timeout callback for the {@link CB_includeJSFile} function.
128 * @memberof CB_Configuration.CrossBrowdy
129 * @constant
130 * @type {int}
131 * @default
132 */
133 CB_includeJSFile_TIMEOUT_MS_DEFAULT: 90000
134};
135
136
137
138/**
139 * It will contain the CrossBrowdy path when it finally loads.
140 * @var
141 * @readonly
142 * @type {string}
143 * @default {@link CB_scriptPathCalculate}();
144 */
145var CB_scriptPath = CB_scriptPathCalculate(); //Can be modified later.
146
147
148//Applies the options set by the user (if any):
149CB_applyOptions(CB_NAME, CB_this);
150
151
152//Needed modules:
153/**
154 * Static class that contains all the modules and the tools to manage them.
155 * @namespace
156 */
157var CB_Modules = {};
158CB_Modules.modules = {};
159
160/**
161 * Enum which defines possible module statuses.
162 * @memberof CB_Modules
163 * @readonly
164 * @enum {integer} CB_Modules.STATUSES
165 */
166CB_Modules.STATUSES =
167{
168 /** The module has failed to load. */
169 FAILED: -1,
170 /** The module has an unkwnown status. */
171 UNKNOWN : 0,
172 /** The module is not loaded yet. Default status. */
173 UNLOADED : 1,
174 /** The module is being loading. */
175 LOADING : 2,
176 /** The module has loaded successfully (coudl be not ready yet). */
177 LOADED : 3,
178 /** The module has loaded successfully and it is ready to be used. */
179 READY : 4
180};
181
182/**
183 * Callback that is called before loading a file and should return true if we want to load the file or false otherwise.
184 * @memberof CB_Modules
185 * @callback CB_Modules.neededFile_LOAD_CHECKER
186 * @param {string} filepath - Filepath of the needed file (including the filename).
187 * @param {CB_Modules.NEEDED_FILE} neededFile - Object that contains the needed file.
188 * @returns {boolean} - Returns true if we want to load the file or false otherwise.
189 */
190
191/**
192 * Object that contains a needed file for a module.
193 * @memberof CB_Modules
194 * @typedef {Object} CB_Modules.NEEDED_FILE
195 * @property {boolean} [load=false] - Defines whether to load the file or not.
196 * @property {boolean} [mandatory=false] - Defines whether the file is mandatory. If the file is not mandatory, its module could be declared as loaded successfully before the file is loaded (and maybe never will).
197 * @property {boolean} [absolutePath=false] - Defines whether the path of the file is relative to the path of the main script or absolute.
198 * @property {CB_Modules.neededFile_LOAD_CHECKER} [loadChecker] - Callback that will be called when the file tries to be loaded and should return true if the file needs to be loaded.
199 * @property {string} [id] - Desired string to identify the file.
200 * @property {array} [requires] - Array of strings with the IDs of the files that must be loaded before loading this file. The file will not be loaded until the required files are loaded first.
201 */
202
203 /**
204 * Object that contains the needed files for a module. Each property will represent a needed file.
205 * @memberof CB_Modules
206 * @typedef {Object} CB_Modules.NEEDED_FILES
207 * @property {CB_Modules.NEEDED_FILE} path_to_the_file - Object that contains a needed file for a module. The property name must be either the path to the file or a variable containing it. Tto use a variable, the name of the property must start with "VALUEOF_" and continue with the name of the variable. In the case that the variable is an object, each property must be separated by a dot (".").
208 */
209
210
211 /**
212 * Object that contains a needed module for a parent module.
213 * @memberof CB_Modules
214 * @typedef {Object} CB_Modules.NEEDED_MODULE
215 * @property {string} name - Name of the module.
216 * @property {CB_Modules.NEEDED_FILES} neededFiles - Object containing the needed files.
217 */
218
219 /**
220 * Callback for the different events of a module.
221 * @memberof CB_Modules
222 * @callback CB_Modules.CALLBACK
223 * @param {string} scriptPath - The value for the "scriptPath" parameter used by {@link CB_init} when it was called.
224 */
225
226/**
227 * Object that contains a module.
228 * @memberof CB_Modules
229 * @typedef {Object} CB_Modules.MODULE
230 * @property {string} name - Name of the module.
231 * @property {CB_Modules.STATUSES} status - Module status.
232 * @property {CB_Modules.CALLBACK} onCall - Callback for when the module is called to be loaded. Being "this" the {@link CB_Modules.MODULE} object itself.
233 * @property {CB_Modules.CALLBACK} onLoad - Callback for when the module loads successfully. Being "this" the {@link CB_Modules.MODULE} object itself.
234 * @property {CB_Modules.CALLBACK} onReady - Callback for when the module is totally ready. Being "this" the {@link CB_Modules.MODULE} object itself.
235 * @property {CB_Modules.CALLBACK} onFail - Callback for when the module fails to load. Being "this" the {@link CB_Modules.MODULE} object itself. NOT IMPLEMENTED YET.
236 * @property {CB_Modules.NEEDED_FILES} neededFiles - Object containing the needed files.
237 * @property {array} neededModules - Array of {@link CB_Modules.NEEDED_MODULE} objects, containing the needed modules.
238 * @property {string} credits - Credits of the module.
239 */
240
241//Main module basic configuration:
242/**
243 * Contains all the modules, one per property.
244 * @var CB_Modules.modules
245 * @type {Object}
246 * @property {CB_Modules.MODULE} name_of_the_module - Object that contains the module data. The property name must be the name of the module.
247 */
248CB_Modules.modules[CB_NAME] =
249{
250 //Name of the module:
251 "name" : CB_NAME,
252 //Status (UNKNOWN, UNLOADED, LOADING, LOADED, READY or FAILED):
253 "status" : CB_Modules.STATUSES.UNLOADED,
254 //Function to call as soon as the module is called (before loading its scripts):
255 "onCall" :
256 function(scriptPathGiven)
257 {
258 if (CB_Configuration[CB_NAME].STATS) { CB_sendStats(); } //If we want, includes the file for statistics purposes.
259 CB_Modules.setStatus(CB_NAME, CB_Modules.STATUSES.LOADED);
260 },
261 //Callback function to call when the module has been loaded successfully:
262 "onLoad" :
263 function(scriptPathGiven)
264 {
265 CB_Modules.setStatus(CB_NAME, CB_Modules.STATUSES.READY);
266 },
267 //Callback function to call when the module is ready:
268 "onReady" :
269 function(scriptPathGiven)
270 {
271 CB_scriptPath = scriptPathGiven; //The path given was correct so we set it.
272 CB_ready = true; //Set as it's ready.
273 },
274 //Callback function to call when module has not been loaded successfully:
275 //"onFail" => null,
276 //Needed files:
277 "neededFiles" : null, //Format: "needed_file" : { load: needs_to_be_loaded, [mandatory: needed_to_begin_CrossBrowdy], [absolutePath: relative_to_CrossBrowdy_path_or_absolute], [loadChecker: function that will be called and return true if the file needs to be loaded], [id: file_identifier_string], [requires: array_with_required_ids_of_files_required] }
278 //Needed modules:
279 "neededModules" :
280 [
281 {
282 "name" : "CrossBase",
283 //Format: "needed_file" : { load: needs_to_be_loaded, [mandatory: needed_to_begin_CrossBrowdy], [absolutePath: relative_to_CrossBrowdy_path_or_absolute], [loadChecker: function that will be called and return true if the file needs to be loaded], [id: file_identifier_string], [requires: array_with_required_ids_of_files_required] }
284 "neededFiles" : { "CrossBase/CrossBase.js" : { load: true, mandatory: true } }
285 }
286 ],
287 //Credits:
288 "credits" : "[CB] " + CB_NAME + " " + CB_VERSION + " by Joan Alba Maldonado<br />"
289};
290
291//Sets default credits:
292/**
293 * Default credits.
294 * @var
295 * @readonly
296 * @type {string}
297 * @default
298 */
299var CB_CREDITS_DEFAULT = "";
300CB_addCredits(CB_Modules.modules[CB_NAME]["credits"]);
301
302
303//If now() static function not available, uses getTime() method:
304if (!Date.now) { Date.now = function() { return new Date().getTime(); }; }
305
306
307/**
308 * Attaches the given credits to the default ones (to {@link CB_CREDITS_DEFAULT}).
309 * @function
310 * @param {string} credits - Path to the JS file.
311 * @returns {string} Returns the default credits after attaching the given ones.
312 */
313 function CB_addCredits(credits)
314 {
315 return CB_CREDITS_DEFAULT += credits;
316 }
317
318
319/**
320 * Alias for the "console" function which fallbacks to a DOM element with "CB_console" id (its CSS "style" attribute will be modified if needed, which means that its "display" property will be set to "block" if it is "none" and its "visibility" property to "visible" regardless its previous value) or even to an alert when it is not available ("alert" will only be used as a fallback in the case that the {@link CB_console_ALLOW_ALERTS} parameter is set to true).
321 * @function
322 * @param {string} message - Message to display
323 * @todo When "console" is not available and it gets polyfilled, allow more parameters (use "arguments").
324 */
325var CB_console;
326if (typeof(console) !== "undefined" && typeof(console.log) !== "undefined")
327{
328 if (typeof(console.log.apply) !== "undefined")
329 {
330 CB_console = function() { console.log.apply(console, arguments); };
331 }
332 else
333 {
334 CB_console = console.log;
335 }
336}
337else
338{
339 CB_console =
340 function(message) //TODO: allow more parameters (use "arguments").
341 {
342 message += "";
343 var CB_consoleElement = document.getElementById("CB_console");
344 if (CB_consoleElement !== null)
345 {
346 CB_consoleElement.style.visibility = "visible";
347 if (CB_consoleElement.style.display === "none") { CB_consoleElement.style.display = "block"; }
348 CB_consoleElement.innerHTML += message.replace(/\n/gi, "<br />") + "<br />";
349 CB_consoleElement.scrollTop = CB_consoleElement.scrollHeight;
350 }
351 else if (CB_Configuration[CB_NAME].CB_console_ALLOW_ALERTS) { alert(message); }
352 };
353 console = { log : CB_console };
354}
355
356
357var CB_filesRequested = {};
358var CB_filesLoaded = [];
359var CB_filesLoadedIds = {};
360/**
361 * Callback for when the file is included successfully or fails to load.
362 * @callback CB_includeJSFile_CALLBACK
363 * @param {string} filepath - The 'filepath' parameter when {@link CB_includeJSFile} was called (if any).
364 * @param {CB_includeJSFile_CALLBACK} callbackOk - The 'callbackOk' parameter when {@link CB_includeJSFile} was called (if any).
365 * @param {CB_includeJSFile_CALLBACK} callbackError - The 'callbackError' parameter when {@link CB_includeJSFile} was called (if any).
366 * @param {integer} timeoutMs - The 'timeoutMs' parameter when {@link CB_includeJSFile} was called (if any).
367 * @param {boolean} asynchronously - The 'asynchronously' parameter when {@link CB_includeJSFile} was called (if any).
368 */
369
370/**
371 * Includes a JavaScript file to the current document.
372 * @function
373 * @param {string} filepath - Path to the JS file.
374 * @param {CB_includeJSFile_CALLBACK} [callbackOk] - Callback for when the file is included successfully.
375 * @param {CB_includeJSFile_CALLBACK} [callbackError] - Callback for when there is any error including the file or it cannot be included after the defined timeout.
376 * @param {integer} [timeoutMs={@link CB_Configuration.CrossBrowdy.CB_includeJSFile_TIMEOUT_MS_DEFAULT}] - Timeout in milliseconds to consider that the inclusion of the file has failed.
377 * @param {boolean} [asynchronously=true] - Defines whether to load the file asynchronously or not.
378 * @param {string} [fileId] - Internal usage recommended only.
379 * @param {array} [fileRequires] - Internal usage recommended only.
380 * @param {boolean} [notMandatory=false] - Internal usage recommended only.
381 * @returns {Object|null|false} Returns null when the script file cannot be loaded yet as some required file has still not been loaded. Returns false when neither the 'HEAD' tag nor the document body can be found. Otherwise, returns an object whose two properties are 'scriptElement' (with the [SCRIPT]{@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script} element just created) and 'timeoutFailure' (with the [setTimeout]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout} ID created to check whether the file cannot be loaded after the given time).
382 */
383function CB_includeJSFile(filepath, callbackOk, callbackError, timeoutMs, asynchronously, fileId, fileRequires, notMandatory)
384{
385 //If the file requires another one and it has still not loaded, calls the function again after a while:
386 if (fileRequires && typeof(fileRequires.length) !== "undefined" && fileRequires.length > 0)
387 {
388 for (var x = 0; x < fileRequires.length; x++)
389 {
390 if (!CB_filesLoadedIds[fileRequires[x]])
391 {
392 setTimeout(function() { CB_includeJSFile(filepath, callbackOk, callbackError, timeoutMs, asynchronously, fileId, fileRequires, notMandatory); }, 10);
393 return null;
394 }
395 }
396 }
397
398 //If not given, uses the default timeout:
399 timeoutMs = timeoutMs || CB_Configuration[CB_NAME].CB_includeJSFile_TIMEOUT_MS_DEFAULT
400
401 //If not given, uses the default value for the 'asynchronously' parameter:
402 if (asynchronously !== false) { asynchronously = true; }
403
404 //Stores the file as not loaded in the array:
405 if (!notMandatory) { CB_filesRequested[filepath] = true; }
406
407 //var parentElement = document.getElementsByTagName("head") || document.head || document.getElementsByTagName("body") || document.body || document.documentElement;
408 var parentElement = CB_getElementsByTagName("head");
409 if (parentElement.length === 0) { parentElement = document.head || CB_getElementsByTagName("body"); }
410 if (parentElement.length === 0) { parentElement = document.body || document.documentElement || null; }
411 if (parentElement && typeof(parentElement[0]) === "undefined") { parentElement = [parentElement]; }
412 if (typeof(parentElement) === "undefined" || parentElement === null || typeof(parentElement[0]) === "undefined" || parentElement[0] === null)
413 {
414 CB_console("[ERROR] Neither <HEAD> tag nor document body could be found! (CB_includeJSFile)");
415 if (typeof(callbackError) === "function") { callbackError(filepath, callbackOk, callbackError, timeoutMs, asynchronously); }
416 return false;
417 }
418
419 parentElement = parentElement[0];
420
421 var scriptTag = document.createElement("script");
422 scriptTag.src = filepath;
423 scriptTag.language = "javascript";
424 scriptTag.type = "text/javascript";
425 scriptTag.async = asynchronously;
426
427 parentElement.appendChild(scriptTag);
428
429 var onLoadExecuted = false;
430 var onLoad =
431 function()
432 {
433 this.onreadystatechange = this.onload = null;
434 setTimeout
435 (
436 function()
437 {
438 if (onErrorExecuted || onLoadExecuted) { return; } //Exists if the timeout has already been executed.
439 onLoadExecuted = true;
440
441 //Stores the file as already loaded in the array:
442 CB_filesRequested[filepath] = false;
443 CB_filesLoaded[CB_filesLoaded.length] = filepath;
444 if (fileId) { CB_filesLoadedIds[fileId] = true; }
445
446 //If defined, calls the OK function:
447 if (typeof(callbackOk) === "function") { callbackOk(filepath, callbackOk, callbackError, timeoutMs, asynchronously); }
448 },
449 10
450 );
451 };
452
453 if (scriptTag.readyState)
454 {
455 scriptTag.onreadystatechange =
456 function()
457 {
458 if (this.readyState === "loaded" || this.readyState === "complete") { onLoad(); }
459 };
460 }
461 else { scriptTag.onload = onLoad; }
462
463 var onErrorExecuted = false;
464 var onError =
465 function()
466 {
467 if (onErrorExecuted || onLoadExecuted) { return; } //Exists if the onLoad has been already executed.
468 onErrorExecuted = true;
469
470 //Stores the file as failed to load in the array:
471 CB_filesRequested[filepath] = null;
472
473 if (typeof(callbackError) === "function") { callbackError(filepath, callbackOk, callbackError, timeoutMs, asynchronously); }
474 };
475 scriptTag.onerror = onError;
476
477 //Starts counting for the timeout:
478 var callbackErrorTimeout = setTimeout(onError, timeoutMs);
479
480 return { scriptElement: scriptTag, timeoutFailure: callbackErrorTimeout };
481}
482
483
484
485/**
486 * Callback for when the script is loaded successfully. Without parameters.
487 * @callback CB_includeRequiredFileErrorCallback
488 * @param {string} filepath - The 'filepath' parameter when {@link CB_includeJSFile} was called internally (if any).
489 * @param {CB_includeJSFile_CALLBACK} callbackOk - The 'callbackOk' parameter when {@link CB_includeJSFile} was called internally (if any).
490 * @param {CB_includeJSFile_CALLBACK} callbackError - The 'callbackError' parameter when {@link CB_includeJSFile} was called internally (if any).
491 * @param {integer} timeoutMs - The 'timeoutMs' parameter when {@link CB_includeJSFile} was called internally (if any).
492 * @param {boolean} asynchronously - The 'asynchronously' parameter when {@link CB_includeJSFile} was called (if any).
493 * @param {object} filesRequested - Object whose indexes are all the filepaths of the script files requested so far and the value is true when the file is still loading (or to be loaded in the future), false if it was loaded successfully (the most likely) or null if it failed to load.
494 * @param {array} filesLoaded - Numeric array whose values are the filepaths of the script files loaded successfully so far.
495 */
496
497//Function executed when a required file cannot be loaded (because of an error or timeout):
498CB_Modules._includeRequiredFileError = function(filepath, callbackOk, callbackError, timeoutMs, asynchronously)
499{
500 CB_console("[CB] [ERROR] Script file failed to load: " + filepath);
501 if (typeof(CB_initOnErrorLoadingFile) === "function") { CB_initOnErrorLoadingFile(filepath, callbackOk, callbackError, timeoutMs, asynchronously, CB_filesRequested, CB_filesLoaded); }
502}
503
504
505//Function that includes all required files:
506CB_Modules._includeAllRequiredFiles = function(CB_scriptPathGiven, neededFiles, callbackOk)
507{
508 //Parses the neededFiles object to turn variable keys into the real value of those variables:
509 var currentValue = null;
510 var allIndexes = null;
511 var allIndexesLength = 0;
512 var x = 0;
513 for (var currentFile in neededFiles)
514 {
515 if (currentFile.substring(0, 8) === "VALUEOF_")
516 {
517 allIndexes = currentFile.substring(8).split(".");
518 allIndexesLength = allIndexes.length;
519 currentValue = CB_this;//window;
520 for (var x = 0; x < allIndexesLength; x++)
521 {
522 if (typeof(currentValue[allIndexes[x]]) !== "undefined" && currentValue[allIndexes[x]] !== null) { currentValue = currentValue[allIndexes[x]]; }
523 else { break; }
524 }
525 if (typeof(currentValue) !== "string" && !(currentValue instanceof String)) { currentValue = ""; }
526
527 if (currentValue !== "") { neededFiles[currentValue] = { load: neededFiles[currentFile].load, loadChecker: neededFiles[currentFile].loadChecker, mandatory: neededFiles[currentFile].mandatory, id: neededFiles[currentFile].id, requires: neededFiles[currentFile].requires }; }
528
529 neededFiles[currentFile].load = false; //It contains the key without parsing, so we set as we don't need it to load it to ignore it.
530 neededFiles[currentFile].disabled = true; //Disables it.
531 }
532 }
533
534 //Includes all files needed:
535 var neededFilesPending = 0;
536 for (currentFile in neededFiles)
537 {
538 if (neededFiles[currentFile].disabled) { continue; }
539
540 //Performs the load checker that can change the load property (if any):
541 if (typeof(neededFiles[currentFile].loadChecker) === "function" && neededFiles[currentFile].load) { neededFiles[currentFile].load = neededFiles[currentFile].loadChecker(currentFile, neededFiles[currentFile]); }
542
543 //If the file needs to be loaded, we load it:
544 if (neededFiles[currentFile].load)
545 {
546 new function(currentFile) //Creates a new scope because we are in a loop.
547 {
548 var functionWhenLoad = null;
549 if (neededFiles[currentFile].mandatory) //Only increases and decreases counter for mandatory files.
550 {
551 neededFilesPending++;
552 functionWhenLoad =
553 function(filepath, callbackOk, callbackError, timeoutMs)
554 {
555 neededFilesPending--;
556 if (typeof(neededFiles) !== "undefined" && neededFiles !== null && typeof(neededFiles[currentFile]) !== "undefined" && neededFiles[currentFile] !== null)
557 {
558 neededFiles[currentFile].load = false; //We have loaded it and don't need to load it more.
559 }
560 };
561 }
562 var scriptPath = CB_scriptPathGiven;
563 if (neededFiles[currentFile].absolutePath) { scriptPath = ""; }
564 CB_includeJSFile(scriptPath + currentFile, functionWhenLoad, CB_Modules._includeRequiredFileError, undefined, undefined, neededFiles[currentFile].id, neededFiles[currentFile].requires);
565 }(currentFile);
566 }
567 }
568
569 //Interval that will check when all the modules has been loaded:
570 var allRequiredFilesLoaded =
571 function()
572 {
573 if (neededFilesPending <= 0 && typeof(callbackOk) === "function")
574 {
575 callbackOk();
576 }
577 else if (typeof(callbackOk) === "function")
578 {
579 setTimeout(allRequiredFilesLoaded, 1);
580 }
581 };
582 allRequiredFilesLoaded();
583}
584
585
586
587//Function that includes all required modules:
588CB_Modules._includeAllRequiredModules = function(CB_scriptPathGiven, modules, callbackOk)
589{
590 if (typeof(modules) === "undefined" || modules === null) { return; }
591
592 var modulesLength = modules.length;
593 var neededModulesPending = 0;
594 for (var x = 0; x < modulesLength; x++)
595 {
596 if (typeof(modules[x].name) !== "undefined" && typeof(modules[x].neededFiles) !== "undefined" && modules[x].neededFiles)
597 {
598 neededModulesPending++;
599 new function(moduleName) //Closure to keep moduleName value for every loop.
600 {
601 CB_Modules._includeAllRequiredFiles
602 (
603 CB_scriptPathGiven,
604 modules[x]["neededFiles"],
605 function()
606 {
607 setTimeout
608 (
609 function()
610 {
611 CB_Modules._initializeModule(CB_scriptPathGiven, moduleName);
612 neededModulesPending--;
613 },
614 10
615 );
616 }
617 );
618 }(modules[x].name);
619 }
620 }
621
622 //Interval that will check when all the modules has been loaded:
623 var allRequiredModulesLoaded =
624 function()
625 {
626 if (neededModulesPending <= 0 && typeof(callbackOk) === "function")
627 {
628 callbackOk();
629 }
630 else if (typeof(callbackOk) === "function")
631 {
632 setTimeout(allRequiredModulesLoaded, 1);
633 }
634 };
635 allRequiredModulesLoaded();
636}
637
638
639
640//Tells the number of required files loaded:
641CB_Modules._numberFilesLoaded = function(neededFiles, onlyMandatory)
642{
643 //Checks all files needed:
644 var numberNeededFilesLoaded = 0;
645 for (var currentFile in neededFiles)
646 {
647 //Checks whether the needed file has been loaded:
648 if (neededFiles[currentFile].load)
649 {
650 if (!onlyMandatory || neededFiles[currentFile].mandatory)
651 {
652 numberNeededFilesLoaded++;
653 }
654 }
655 }
656 return numberNeededFilesLoaded;
657}
658
659
660//Checks whether all required files have been loaded:
661CB_Modules._allFilesLoaded = function(neededFiles, onlyMandatory)
662{
663 //Checks all files needed:
664 var allFilesNeededIncluded = true;
665 for (var currentFile in neededFiles)
666 {
667 //If the file has not been included yet, exits the bucle:
668 if (neededFiles[currentFile].load)
669 {
670 if (!onlyMandatory || neededFiles[currentFile].mandatory)
671 {
672 allFilesNeededIncluded = false; break;
673 }
674 }
675 }
676 return allFilesNeededIncluded;
677}
678
679
680//Checks whether all required modules have been loaded:
681CB_Modules._allModulesLoaded = function(neededModules, onlyMandatory)
682{
683 if (typeof(neededModules) === "undefined" || neededModules === null) { return true; }
684 var allModulesNeededIncluded = true;
685 var neededModulesLength = neededModules.length;
686 for (var x = 0; x < neededModulesLength; x++)
687 {
688 if (typeof(neededModules[x].name) !== "undefined" && typeof(neededModules[x].neededFiles) !== "undefined" && neededModules[x].neededFiles)
689 {
690 if (!CB_Modules._allFilesLoaded(neededModules[x].neededFiles, onlyMandatory)) { allModulesNeededIncluded = false; break; }
691 }
692 }
693 return allModulesNeededIncluded;
694}
695
696
697//Checks whether a given module is ready or not:
698CB_Modules._moduleReady = function(moduleName)
699{
700 return (CB_Modules._getModuleStatus(moduleName) === CB_Modules.STATUSES.READY);
701}
702
703
704//Checks whether all required modules are ready:
705CB_Modules._allModulesReady = function(neededModules)
706{
707 if (typeof(neededModules) === "undefined" || neededModules === null) { return true; }
708 var allModulesNeededReady = true;
709 var neededModulesLength = neededModules.length;
710 for (var x = 0; x < neededModulesLength; x++)
711 {
712 if (typeof(neededModules[x].name) !== "undefined" && typeof(neededModules[x].neededFiles) !== "undefined" && neededModules[x].neededFiles)
713 {
714 if (!CB_Modules._moduleReady(neededModules[x].name)) { allModulesNeededReady = false; break; }
715 }
716 }
717 return allModulesNeededReady;
718}
719
720
721//Returns the status of a given module:
722CB_Modules._getModuleStatus = function(moduleName)
723{
724 if (typeof(CB_Modules.modules[moduleName]) !== "undefined" && typeof(CB_Modules.modules[moduleName].status) !== "undefined")
725 {
726 return CB_Modules.modules[moduleName].status;
727 }
728 else { return CB_Modules.STATUSES.UNKNOWN; }
729}
730
731
732/**
733 * Sets a status for a given module.
734 * @memberof CB_Modules
735 * @function
736 * @param {string} moduleName - Name of the module.
737 * @param {integer} status - The desired status. Must be a value that exists in the {@link CB_Modules.STATUSES} enum.
738 * @returns {boolean} It will return true if succeeded or false otherwise.
739 */
740CB_Modules.setStatus = function(moduleName, status)
741{
742 if (typeof(CB_Modules.modules[moduleName]) !== "undefined")
743 {
744 CB_Modules.modules[moduleName].status = status;
745 }
746}
747
748
749//Function that initializes a module:
750//var CB_allFilesLoadedInterval; //Interval that checks if CrossBrowdy is ready or not.
751CB_Modules._initializeModule = function(CB_scriptPathGiven, moduleName)
752{
753 //It the module still does not exist (status is unknown), tries to load it again after some time:
754 if (CB_Modules._getModuleStatus(moduleName) === CB_Modules.STATUSES.UNKNOWN) { setTimeout(function() { CB_Modules._initializeModule(CB_scriptPathGiven, moduleName); }, 1); return; }
755
756 CB_Modules.setStatus(moduleName, CB_Modules.STATUSES.LOADING);
757
758 if (typeof(CB_Modules.modules[moduleName]["onCall"]) === "function")
759 {
760 CB_Modules.modules[moduleName]["onCall"].call(CB_Modules.modules[moduleName], CB_scriptPathGiven);
761 }
762
763 //Applies default path if it was not sent:
764 if (typeof(CB_scriptPathGiven) === "undefined" || CB_scriptPathGiven === null)
765 {
766 CB_scriptPathGiven = CB_scriptPathCalculate();
767 }
768
769 //Includes required files:
770 CB_Modules._includeAllRequiredFiles(CB_scriptPathGiven, CB_Modules.modules[moduleName]["neededFiles"]);
771
772 //Includes required modules:
773 CB_Modules._includeAllRequiredModules(CB_scriptPathGiven, CB_Modules.modules[moduleName]["neededModules"]);
774
775 //Show credits in console:
776 CB_console(CB_credits(CB_Modules.modules[moduleName]["credits"], false));
777
778 //Interval that checks if CrossBrowdy is ready (and initializes the static objects):
779 var onLoadProcessed = false;
780 var onReadyProcessed = false;
781 var CB_allFilesLoadedCheck =
782 function()
783 {
784 var loopAgain = true;
785 //If all files needed are loaded (mandatory files only):
786 if (CB_Modules._allFilesLoaded(CB_Modules.modules[moduleName]["neededFiles"], true))
787 {
788 //If all needed modules are loaded (mandatory module files only):
789 if (CB_Modules._allModulesLoaded(CB_Modules.modules[moduleName]["neededModules"], true))
790 {
791 //If defined, executes the onLoad function of the module:
792 if (!onLoadProcessed && typeof(CB_Modules.modules[moduleName]["onLoad"]) === "function")
793 {
794 onLoadProcessed = true;
795 CB_Modules.modules[moduleName]["onLoad"].call(CB_Modules.modules[moduleName], CB_scriptPathGiven);
796 }
797
798 //If all needed modules are ready:
799 if (CB_Modules._allModulesReady(CB_Modules.modules[moduleName]["neededModules"]))
800 {
801 //If the module itself is ready:
802 if (CB_Modules._moduleReady(moduleName))
803 {
804 //If defined, executes the onReady function of the module:
805 if (!onReadyProcessed && typeof(CB_Modules.modules[moduleName]["onReady"]) === "function")
806 {
807 onReadyProcessed = true;
808 CB_Modules.modules[moduleName]["onReady"].call(CB_Modules.modules[moduleName], CB_scriptPathGiven);
809 }
810 loopAgain = false;
811 }
812 }
813 }
814 }
815 if (loopAgain) { setTimeout(CB_allFilesLoadedCheck, 1); }
816 };
817 CB_allFilesLoadedCheck();
818}
819
820
821/**
822 * Returns a {@link CB_Modules.MODULE} object for module management.
823 * @memberof CB_Modules
824 * @function
825 * @param {string} moduleName - Name of the desired module.
826 * @returns {CB_Modules.MODULE|null} If found, it will return the {@link CB_Modules.MODULE} object desired. Otherwise, it will return null.
827 */
828CB_Modules.get = function(moduleName)
829{
830 if (typeof(CB_Modules.modules[moduleName]) !== "undefined")
831 {
832 return CB_Modules.modules[moduleName];
833 }
834 return null;
835}
836
837
838/**
839 * Gets the value of a desired module property (or returns null).
840 * @memberof CB_Modules
841 * @function
842 * @param {string} moduleName - Name of the desired module.
843 * @param {string} property - Name of the desired property.
844 * @returns {*|null} If found, it will return the value of the desired module property. Otherwise, it will return null.
845 */
846CB_Modules.getProperty = function(moduleName, property)
847{
848 var module = CB_Modules.get(moduleName);
849 if (module !== null && typeof(module[property]) !== "undefined")
850 {
851 return module[property];
852 }
853 return null;
854}
855
856
857/**
858 * Modifies a desired property of a given module.
859 * @memberof CB_Modules
860 * @function
861 * @param {string} moduleName - Name of the module which contains the property to modify.
862 * @param {string} property - Name of the property to modify.
863 * @param {*} value - Value desired for the property.
864 * @param {('array'|'object'|'scalar')} [type='scalar']
865 Type that the property uses.
866 If it is "array", the given "value" will be attached at the end of the array (all in a new single index if the "iterateArray" parameter is set to false, or each value in a new index otherwise).
867 If it is "object", the given "value" and the given "property" to modify will be treated as objects and the members of the "value" will be copied one by one (overwriting previous members in the case they existed).
868 If it is "scalar" or any other, the given "property" value will be replaced with the given "value".
869 * @param {boolean} [iterateArray=false] - If is set to true and the given "type" is "array", the given "value" will be considered an array and will be iterated to copy each of its values to a new index in the destiny. Otherwise, if it is set to false and the given "type" is "array", the given "value" will be attached at the end of the array in a new single index.
870 * @returns {boolean} It will return true if succeeded or false otherwise.
871 */
872CB_Modules.editProperty = function(moduleName, property, value, type, iterateArray)
873{
874 if (typeof(moduleName) === "undefined" || moduleName === null || moduleName === "") { return false; }
875 if (typeof(property) === "undefined" || property === null || property === "") { return false; }
876 if (typeof(type) === "undefined" || type === null) { type = "scalar"; }
877 type += "";
878 type = type.toLowerCase();
879
880 var modified = false;
881
882 var module = CB_Modules.get(moduleName);
883 if (module !== null)
884 {
885 var propertyValue = CB_Modules.getProperty(moduleName, property);
886 if (type === "array")
887 {
888 if (propertyValue === null) { module[property] = []; }
889 if (!iterateArray)
890 {
891 module[property][module[property].length] = value;
892 modified = true;
893 }
894 else
895 {
896 var valueLength = value.length;
897 for (var x = 0; x < valueLength; x++)
898 {
899 module[property][module[property].length] = value[x];
900 }
901 if (x > 0) { modified = true; }
902 }
903 }
904 else if (type === "object")
905 {
906 if (propertyValue === null) { module[property] = {}; }
907 for (var propertyName in value)
908 {
909 module[property][propertyName] = value[propertyName];
910 modified = true;
911 }
912 }
913 else
914 {
915 if (propertyValue === null) { module[property] = null; }
916 module[property] = value;
917 modified = true;
918 }
919 }
920 return modified;
921}
922
923
924/**
925 * Attaches one module to another one.
926 * @memberof CB_Modules
927 * @function
928 * @param {string} moduleNameParent - Name of the parent module where the new child module will be attached to.
929 * @param {string} moduleName - Name of the new child module which will be attached to the given parent.
930 * @param {CB_Modules.NEEDED_FILES} neededFiles - The "neededFiles" parameter for the new child module.
931 * @returns {boolean} It will return true if succeeded or false otherwise.
932 */
933CB_Modules.addNeededModule = function(moduleNameParent, moduleName, neededFiles)
934{
935 return CB_Modules.editProperty(moduleNameParent, "neededModules", { "name" : moduleName, "neededFiles" : neededFiles }, "array");
936}
937
938
939/**
940 * Attaches files to a module.
941 * @memberof CB_Modules
942 * @function
943 * @param {string} moduleName - Name of the module which will contain the new files.
944 * @param {CB_Modules.NEEDED_FILES} neededFiles - The "neededFiles" parameter for the module.
945 * @returns {boolean} It will return true if succeeded or false otherwise.
946 */
947CB_Modules.addNeededFiles = function(moduleName, neededFiles)
948{
949 return CB_Modules.editProperty(moduleName, "neededFiles", neededFiles, "object");
950}
951
952
953function CB_getElementsByTagName(tagName)
954{
955 if (!tagName) { return []; }
956 var elementsFound = [];
957 if (typeof(document.getElementsByTagName) !== "undefined" && document.getElementsByTagName !== null)
958 {
959 elementsFound = document.getElementsByTagName(tagName);
960 }
961 else if (document.querySelectorAll)
962 {
963 elementsFound = document.querySelectorAll(tagName);
964 }
965 else if (document.querySelectorAll)
966 {
967 elementsFound = document.querySelectorAll(tagName);
968 }
969 else if (typeof(document.all) !== "undefined" && document.all !== null)
970 {
971 elementsFound = document.all.tags(tagName);
972 }
973 else if (document.layers)
974 {
975 var allElements = document.layers;
976
977 //Obtains all elements with the given tag name:
978 var allElementsLength = allElements.length;
979
980 var elementCurrent;
981 for (var x = 0; x < allElementsLength; x++)
982 {
983 elementCurrent = allElements[x];
984 if (elementCurrent !== null && typeof(elementCurrent.tagName) !== "undefined")
985 {
986 if (CB_trim(elementCurrent.tagName).toLowerCase() === tagName)
987 {
988 elementsFound.push(elementCurrent);
989 }
990 }
991 }
992 //elementsFound = document.layers[tagName];
993 }
994 return elementsFound;
995}
996
997
998var CB_scriptPathCalculateLastReturn = CB_this.CB_scriptPathCalculateLastReturn || null;
999/**
1000 * Tries to calculate and returns the path where the script is located.
1001 * @function
1002 * @returns {string} If it cannot be calculated, it will returns the value of {@link CB_Configuration[CB_NAME].SCRIPT_PATH_DEFAULT}.
1003 */
1004function CB_scriptPathCalculate()
1005{
1006 if (typeof(CB_scriptPathCalculateLastReturn) !== "undefined" && CB_scriptPathCalculateLastReturn !== null) { return CB_scriptPathCalculateLastReturn; }
1007
1008 //Gets the "SCRIPT" DOM elements:
1009 var scriptElements = CB_getElementsByTagName("script");
1010
1011 var scriptFileName = CB_NAME + ".js";
1012 for (var x = 0, scriptElementsLength = scriptElements.length; x < scriptElementsLength; x++)
1013 {
1014 if (scriptElements[x].src && scriptElements[x].src.length)
1015 {
1016 var src = scriptElements[x].src;
1017 if (src === scriptFileName || src.substring(src.length - scriptFileName.length - 1, src.length + 1) === "/" + scriptFileName)
1018 {
1019 CB_scriptPathCalculateLastReturn = src.substring(0, src.length - scriptFileName.length);
1020 return CB_scriptPathCalculateLastReturn;
1021 }
1022 }
1023 }
1024
1025 return CB_Configuration[CB_NAME].SCRIPT_PATH_DEFAULT;
1026}
1027
1028
1029var CB_ready = false; //Defines weather CrossBrowdy is ready or not.
1030var CB_initWait = true;
1031var CB_initWaitMs = 50;
1032var CB_readyInterval; //Interval that will execute the main function when CrossBrowdy is ready.
1033var CB_deviceReady = false;
1034var CB_initOnErrorLoadingFile; //Function to call if any required file fails to load.
1035/**
1036 * Callback for when the script is loaded successfully. Without parameters.
1037 * @callback CB_init_CALLBACK
1038 */
1039
1040/**
1041 * Starts CrossBrowdy.
1042 * @function
1043 * @param {CB_init_CALLBACK} [mainFunction] - Callback for when CrossBrowdy is loaded successfully. Recommended.
1044 * @param {string} [scriptPath={@link CB_scriptPathCalculate}()] - Path where the main script is located. If not provided (it is undefined or null), it will try to calculate it calling the {@link CB_scriptPathCalculate} function internally.
1045 * @param {CB_includeRequiredFileErrorCallback} [onErrorLoadingFile] - Function to call when any of the required files fails to load (because of an error or because its timeout was fired). It could be called more than once, for each file which failed loading. If a function is provided, it will be stored in the global 'CB_initOnErrorLoadingFile' variable.
1046 * @param {boolean} [showSplashScreen={@link CB_Configuration.CrossBrowdy.SHOW_SPLASH_SCREEN_DEFAULT}] - Defines whether to show the splash screen or not.
1047 */
1048function CB_init(mainFunction, scriptPath, onErrorLoadingFile, showSplashScreen)
1049{
1050 //If Cordova is detected, exits this function and it will be called again when the device is ready:
1051 if ((typeof(window.cordova) !== "undefined") && !CB_deviceReady && document.addEventListener) { document.addEventListener("deviceready", function() { CB_deviceReady = true; CB_init(mainFunction, scriptPath, onErrorLoadingFile, showSplashScreen) }, false); return; }
1052
1053 //Applies the options set by the user (if any):
1054 CB_applyOptions(CB_NAME, CB_this);
1055
1056 if (typeof(showSplashScreen) === "undefined" || showSplashScreen === null) { showSplashScreen = CB_Configuration[CB_NAME].SHOW_SPLASH_SCREEN_DEFAULT; }
1057
1058 //If defined, shows splash screen:
1059 if (showSplashScreen) { CB_showSplashScreen(); }
1060
1061 //Executes this same function only after some milliseconds (avoids problems with Internet Explorer and excanvas):
1062 if (CB_initWait)
1063 {
1064 setTimeout(function() { CB_initWait = false; CB_init(mainFunction, scriptPath, onErrorLoadingFile, showSplashScreen); }, CB_initWaitMs);
1065 return;
1066 }
1067
1068 //Applies default path if it was not sent:
1069 if (typeof(scriptPath) === "undefined" || scriptPath === null)
1070 {
1071 scriptPath = CB_scriptPathCalculate();
1072 //scriptPath = CB_Configuration[CB_NAME].SCRIPT_PATH_DEFAULT;
1073 }
1074
1075 //If given, sets the callback when a required file fails to load:
1076 if (typeof(onErrorLoadingFile) === "function") { CB_initOnErrorLoadingFile = onErrorLoadingFile; }
1077
1078 //Initializes the main module:
1079 CB_Modules._initializeModule(scriptPath, CB_NAME);
1080
1081 //If defined, the main function will be executed when CrossBrowdy is ready:
1082 if (typeof(mainFunction) === "function")
1083 {
1084 var CB_readyExecute =
1085 function()
1086 {
1087 var loopAgain = true;
1088 if (CB_ready)
1089 {
1090 setTimeout(mainFunction, 1); //Calls the function given.
1091 if (showSplashScreen) { CB_hideSplashScreen = true; } //If showing, hides splash screen.
1092 loopAgain = false;
1093 }
1094 if (loopAgain) { setTimeout(CB_readyExecute, 1); }
1095 };
1096 CB_readyExecute();
1097 }
1098}
1099
1100
1101//Function that applies the given options:
1102function CB_applyOptions(moduleName)//, containerObject)
1103{
1104 if (typeof(CB_OPTIONS) !== "undefined" && typeof(CB_OPTIONS[moduleName]) !== "undefined")
1105 {
1106 for (var option in CB_OPTIONS[moduleName])
1107 {
1108 CB_Configuration[moduleName][option] = CB_OPTIONS[moduleName][option];
1109 }
1110 }
1111}
1112
1113
1114/**
1115 * Returns the credits with the desired format.
1116 * @function
1117 * @param {string} [credits={@link CB_CREDITS_DEFAULT}] - Desired credits to be shown.
1118 * @param {boolean} [html=true] - Strips all HTML tags (if any) when it is false.
1119 * @param {boolean} [showPrefix=true] - Defines whether to show the "[CB]" prefix for every line or not (it will remove all "[CB]" occurrences if it is false).
1120 * @returns {string}
1121 */
1122function CB_credits(credits, html, showPrefix)
1123{
1124 if (typeof(html) === "undefined" || html === null) { html = true; }
1125 if (typeof(showPrefix) === "undefined" || showPrefix === null) { showPrefix = true; }
1126 if (typeof(credits) === "undefined" || credits === null || credits === "") { credits = CB_CREDITS_DEFAULT; }
1127 if (!html)
1128 {
1129 if (typeof(CB_br2nl) !== "undefined") { credits = CB_br2nl(credits); }
1130 else { credits = credits.replace(/<br \/>/gi, "\n"); }
1131 credits = credits.replace(/<[^>]*>?/gm, '');
1132 }
1133 if (!showPrefix) { credits = credits.replace(/\[CB\]/gi, ""); }
1134 return credits;
1135}
1136
1137
1138//Show a splash screen:
1139var CB_showSplashScreenInterval; //Checks when the body is ready to show the splash screen.
1140var CB_hideSplashScreen = false;
1141var CB_showSplashScreenExecuted = false;
1142function CB_showSplashScreen()
1143{
1144 if (CB_showSplashScreenExecuted) { return; }
1145 CB_showSplashScreenExecuted = true;
1146 var CB_showSplashScreenShow =
1147 function()
1148 {
1149 var loopAgain = true;
1150 //var bodyTag = document.getElementsByTagName("body");
1151 var bodyTag = CB_getElementsByTagName("body");
1152 if (typeof(bodyTag) !== "undefined" && bodyTag !== null && typeof(bodyTag[0]) !== "undefined" && bodyTag[0] !== null)
1153 {
1154 bodyTag = bodyTag[0];
1155 if (!CB_hideSplashScreen && document.getElementById("CB_splashScreenDiv") === null)
1156 {
1157 var splashScreenDivPosition = "fixed";
1158 var additionalCSS = "";
1159 //if (window.navigator.appName === "Microsoft Internet Explorer")
1160 if (navigator.userAgent.indexOf("MSIE") !== -1 && (navigator.appVersion.indexOf("MSIE 5") !== -1 || navigator.appVersion.indexOf("MSIE 6") !== -1 || navigator.appVersion.indexOf("MSIE 7") !== -1 || navigator.appVersion.indexOf("MSIE 8") !== -1))
1161 {
1162 /*
1163 if (typeof(document.compatMode) !== "undefined" && document.compatMode === "BackCompat" || typeof(document.documentMode) !== "undefined" && document.documentMode == 5)
1164 {
1165 additionalCSS = " _position:absolute; _top:expression(eval(document.body.scrollTop));";
1166 }
1167 else if (navigator.appVersion.indexOf("MSIE 8") === -1)
1168 {
1169 splashScreenDivPosition = "absolute";
1170 }
1171 */
1172
1173 //If it is not IE8 (but IE5, IE6 or IE7) or it is in quirks mode ("fixed" property is not supported in IE8 when it is in quirks mode):
1174 if (navigator.appVersion.indexOf("MSIE 8") === -1 || typeof(document.compatMode) !== "undefined" && document.compatMode === "BackCompat" || typeof(document.documentMode) !== "undefined" && document.documentMode == 5)
1175 {
1176 splashScreenDivPosition = "absolute";
1177 //additionalCSS = " _position:absolute; _top: expression(eval(document.compatMode && document.compatMode=='CSS1Compat') ? documentElement.scrollTop +(documentElement.clientHeight-this.clientHeight) : document.body.scrollTop +(document.body.clientHeight-this.clientHeight));";
1178 additionalCSS = " _position:absolute; _top: expression(eval(document.compatMode && document.compatMode=='CSS1Compat') ? documentElement.scrollTop : document.body.scrollTop);";
1179 additionalCSS += " _left: expression(eval(document.compatMode && document.compatMode=='CSS1Compat') ? documentElement.scrollLeft : document.body.scrollLeft);";
1180 }
1181
1182 bodyTag.style.width = bodyTag.style.height = "100%";
1183 }
1184 var splashScreenDiv = '\
1185 <div id="CB_splashScreenDiv" onmousedown="return false;" style="position:' + splashScreenDivPosition + '; top:0px; left:0px; width:100%; height:100%; background-color:#cccccc; z-index:999; opacity:0.95; transition:opacity 1000ms; -moz-transition:opacity 1000ms; -webkit-transition:opacity 1000ms; -o-transition:opacity 1000ms; -khtml-transition:opacity 1000ms; -ms-transition:opacity 1000ms;' + additionalCSS + '">\
1186 <table style="padding:0px; border:#ffffff solid 10px; width:100%; height:100%;">\
1187 <tr>\
1188 <td align="center" style="text-align:center; font-size:13px; font-family:terminal; color:#ffffff;">\
1189 <table style="width:100%; height:30px; background:#aa0000; margin:0px; padding:0px; width:100%; height:30px; line-height:30px; border:0px;">\
1190 <tr>\
1191 <td align="center" valign="middle" style="text-align:center; font-size:25px; font-family:terminal; color:#ffffff;">\
1192 CrossBrowdy<span style="font-size:10px;">' + CB_VERSION + '</span>\
1193 </td>\
1194 </tr>\
1195 </table>\
1196 <div style="font-family:arial; font-size:9px; line-height:10px; color:#696969; text-align:center;">\
1197 <div style="display:block; width:55%; text-align:left; margin:0px auto 0px auto;">\
1198 <div style="font-family:verdana; text-align:center;" id="CB_splashScreenDivCredits">' + CB_credits(CB_Modules.modules[CB_NAME]["credits"], true, false).replace(/<br \/>/i, "").replace(/<br \/>/gi, ". ").replace(/- /i, "</div>").replace(/- /gi, "") + '</div>\
1199 </div>\
1200 * <span id="CB_splashScreenDivLoadingBlink" style="color:#000000;">Loading...</span> *\
1201 <br />\
1202 <div id="CB_splashScreenDivLoader" style="color:#ffffff; text-align:center;"></div>\
1203 </td>\
1204 </tr>\
1205 </table>\
1206 </div>\
1207 ';
1208 bodyTag.innerHTML += splashScreenDiv;
1209 }
1210 else if (CB_hideSplashScreen && document.getElementById("CB_splashScreenDiv") !== null)
1211 {
1212 var CB_splashScreenDiv = document.getElementById("CB_splashScreenDiv");
1213 CB_splashScreenDiv.style.opacity = 0;
1214 setTimeout(function() { CB_splashScreenDiv.style.visibility = "hidden"; }, 1000);
1215 loopAgain = false;
1216 }
1217 if (document.getElementById("CB_splashScreenDivLoadingBlink") !== null)
1218 {
1219 document.getElementById("CB_splashScreenDivLoadingBlink").style.visibility = (document.getElementById("CB_splashScreenDivLoadingBlink").style.visibility === "visible") ? "hidden" : "visible";
1220 }
1221 if (document.getElementById("CB_splashScreenDivLoader") !== null)
1222 {
1223 var loader = "";
1224 for (var file in CB_filesRequested)
1225 {
1226 if (CB_filesRequested[file]) { loader += '<span style="color:#aa00aa;">Loading</span> ' + file; }
1227 else if (CB_filesRequested[file] === null) { loader += '<span style="color:#aa0000; font-weight:bold;">ERROR LOADING</span> ' + file; }
1228 //else { loader += file + ' <span style="color:#0000aa;">Loaded!</span>'; }
1229 loader += "<br />";
1230 }
1231 //if (typeof(CB_filesLoaded[CB_filesLoaded.length - 1]) !== "undefined") { loader += CB_filesLoaded[CB_filesLoaded.length - 1] + ' <span style="color:#aa0000;">Loaded</span>'; }
1232 document.getElementById("CB_splashScreenDivLoader").innerHTML = loader;
1233 }
1234 }
1235 if (loopAgain) { setTimeout(CB_showSplashScreenShow, 1); }
1236 };
1237 CB_showSplashScreenShow();
1238}
1239
1240
1241//Sends the statistics:
1242var CB_statsStored = false;
1243function CB_sendStats()
1244{
1245 //Gets the information:
1246 //var OS = "";
1247 var version = CB_VERSION;
1248 var url = typeof(window.location) !== "undefined" ? window.location : "";
1249 var time = Date.now();
1250
1251 if (typeof(encodeURIComponent) !== "undefined")
1252 {
1253 version = encodeURIComponent(version);
1254 url = encodeURIComponent(url);
1255 time = encodeURIComponent(time);
1256 }
1257 else if (typeof(escape) !== "undefined")
1258 {
1259 version = escape(version);
1260 url = escape(url);
1261 time = escape(time);
1262 }
1263
1264 /*
1265 txt = "<p>Browser CodeName: " + navigator.appCodeName + "</p>";
1266 txt+= "<p>Browser Name: " + navigator.appName + "</p>";
1267 txt+= "<p>Browser Version: " + navigator.appVersion + "</p>";
1268 txt+= "<p>Cookies Enabled: " + navigator.cookieEnabled + "</p>";
1269 txt+= "<p>Browser Language: " + navigator.language + "</p>";
1270 txt+= "<p>Browser Online: " + navigator.onLine + "</p>";
1271 txt+= "<p>Platform: " + navigator.platform + "</p>";
1272 txt+= "<p>User-agent header: " + navigator.userAgent + "</p>";
1273 txt+= "<p>User-agent language: " + navigator.systemLanguage + "</p>";
1274 */
1275
1276 //Sends the information by including the statistics file:
1277 CB_includeJSFile(CB_Configuration[CB_NAME].STATS_URL + "?cb=" + version + "&time=" + time + "&url=" + url, undefined, undefined, undefined, true, undefined, undefined, true);
1278}
\No newline at end of file