/* **** CBDL - Cross-browser DirectMedia Layer * * look at: http://en.wikipedia.org/wiki/SFML */ var CBDL = CBDL || {}; CBDL.version = 0.1; // TODO: completely redo requires & library includes. At the moment, it is broken and disallows multiple Apps from starting if they both require libraries. /* =============================================================================== CBDL.App Object that should be the base for all CBDL-based applications. Contains the bare-minimum logic, members, and vars that any CBDL app should hold. Usage: some_app = new CBDL.App(); some_app.Init(); =============================================================================== */ CBDL.App = CBDL.App || function() {}; CBDL.App.prototype.Main = function() {}; CBDL.App.prototype.Go = function() { if (this.requires) { this._includes = new CBDL.Includes(this); for (var require in this.requires) { this._includes.add(this.requires[require]); } } if (this._includes) { if (this._includes.state != CBDL.states.LOADED) { this.includeCallback = function(return_value) { if (return_value < 0) { // fail console.log("CBDL error: includes failed to load!"); return return_value; } this.Main(); }; } else if (this._includes.state == CBDL.states.LOADED) { this.Main(); } } else { this.Main(); } }; CBDL.App.prototype.include = function(some_library) { if (!this._includes) { this._includes = new CBDL.Includes(this); } this._includes.add(some_library); }; /* called when all includes succeed or fail */ CBDL.App.prototype.includeCallback = function(return_value) { if (return_value < 0) { // fail console.log("CBDL error: includes failed to load!"); return return_value; } else { this.Main(); } }; /* =============================================================================== CBDL.Includes Object that manages includes for an App. Attempts to load all includes specified by the App, providing they are provided prior to the App's onExecute member function being called. =============================================================================== */ CBDL.Includes = function(app) { _Includes = this; this.app = app; this.state = 0x00; this.current = 0; this.includes = []; this.add = function(some_library) { if (this.state != CBDL.states.LOADED) { this.includes.push(some_library); if (this.state != CBDL.states.LOADING) { this.load(); } } }; this.load = function() { this.state = CBDL.states.LOADING; if (this.current < this.includes.length) { this.netLoad(); } else { this.state = CBDL.states.LOADED; this.app.includeCallback(); } }; this.netLoad = function() { var exists = false; // Compare some_library string to every script.src so as to disallow // multiple loading of the same library. // TODO: implement getElementsByTagName for <=IE8 var script_list = document.head.getElementsByTagName('script'); for(script in script_list) { if (script_list[script].src) { if (script_list[script].src.substring(script_list[script].src.length-_Includes.includes[_Includes.current].length) == _Includes.includes[_Includes.current]) { exists = true; } } } if (exists == false) { var element = document.createElement("script"); element.type = "text/javascript"; element.src = _Includes.includes[_Includes.current]; element.onload = function() { _Includes.state = 0x00; _Includes.current++; _Includes.load(); // load next file } document.getElementsByTagName('head')[0].appendChild(element); } else { _Includes.state = 0x00; _Includes.current++; _Includes.load(); // load next file } // if (!/*@cc_on!@*/false) { /* var request = new XMLHttpRequest(); } else { var request = new ActiveXObject("Microsoft.XMLHTTP"); } request.onreadystatechange = function() { if (this.readyState == 4) { // done loading console.log(this.status); if (this.status == 200) { var element = document.createElement("script"); element.type = "text/javascript"; element.text = this.responseText; document.getElementsByTagName('head')[0].appendChild(element); _Includes.state = 0x00; _Includes.current++; _Includes.load(); // load next file } else { _Includes.state = CBDL.states.FAILED; } } } request.open('GET', _Includes.includes[_Includes.current], true); request.send(null); */ }; } /* ================ CBDL.inherit(baseClass, newClass) Function that inherits the properties from baseClass into newClass ================ */ CBDL.inherit = function(base_class, new_class) { base_class.call(new_class); new_class.constructor = new_class; } CBDL.extend = function(base_class, new_class) { new_class.prototype = new base_class; new_class.prototype.constructor = base_class; // fix constructor } /* =============================================================================== CBDL.Loop(scope, callback, interval) Object that acts as a simple interface to creating and managing loops within the script. Attempts to call callback() after X interval has passed. Interval is modified internally to adjust for the time callback() takes to finish. If the time is beyond the defined interval, then callback() is called with a 0ms delay. If the interval is not passed, or is passed as 0, then the Loop will rely on the callback() to return an interval value. Usage: new_loop = new CBDL.Loop(some_func, 50); new_loop.start(50); // calls some_func() after 50ms and repeats every 50ms. Or: some_func = function() { return(1000); }; new_loop = new CBDL.Loop(some_func); new_loop.start(); // calls some_func() every 1000ms. =============================================================================== */ CBDL.Loop = function(scope, callback, interval) { this.scope = scope; this.callback = callback; this.interval = (interval ? interval : 0); this.time_start = 0; this.time_end = 0; this.time_delay = this.interval; this.running = false; this.start = function(delay) { this.running = true; if (delay) { setTimeout( (function(_Loop) { return function() { _Loop.loop.call(_Loop); } })(this), delay); //setTimeout(_Loop.loop, _Loop.time_delay); } else { this.loop(); } }; this.stop = function() { this.running = false; }; this.loop = function() { if (this.running) { this.time_start = new Date().getTime(); if (this.interval == 0) { // acquire time_delay from callback return this.time_delay = this.callback.call(this.scope, this.time_start - this.time_end); this.time_end = new Date().getTime(); } else { this.callback.call(this.scope, this.time_start-this.time_end); // return delta to callback this.time_end = new Date().getTime(); this.time_delay = this.time_end-this.time_start; this.time_delay = (this.time_delay > this.interval ? 0 : this.interval - this.time_delay); } setTimeout( (function(_Loop) { return function() { _Loop.loop.call(_Loop); } })(this), this.time_delay); //setTimeout(this.callLoop.call, this); } }; this.callLoop = function() { this.loop(); } } // TODO: Add CallbackLoop - an alternative object that loops only on some event /* ================ CBDL.useNamespace(object) Sets the window parent to own all of the defined object's members. Functions in a fashion similar to setting the namespace in C++. Usage: CBDL.dump(); // prints CBDL version CBDL.useNamespace(CBDL); dump(); // prints CBDL version ================ */ CBDL.useNamespace = function(object) { var parent = window; for (var member in object) { parent[member] = object[member]; } } /* ================ CBDL.globalize(name, variable) Adds the passed variable/function/object to a new var in the "global" namespace via the passed name. Usage: some_function() { var foo = 'bar'; } console.log(foo); // undefined some_function() { var foo = 'bar'; CBDL.globalize("foo", foo); // window.foo = 'bar', effectively } console.log(foo); // prints 'bar' ================ */ CBDL.globalize = function(name, variable) { var parent = window; parent[name] = parent[name] || variable; } /* =============================================================================== CBDL.Include(filename) Internal object created by calls to CBDL.include(filename). Simply stores the filename and the current state via the 'state' member (bitmask). =============================================================================== */ CBDL.Include = function(filename) { this.filename = filename; this.state = 0x00; } CBDL.current_include = 0; CBDL.includes = []; CBDL.states = {OPEN: 0x00, LOADING:0x01, LOADED:0x02, FAILED:0x03}; /* ================ CBDL.include(filename) Method which should be invoked by the program implementing CBDL. It provides a nice method for including new source files/libraries located within the same directory as the invoking script. Usage: CBDL.include("CBDL_video.js"); // loads CBDL_video.js, making all objects/vars, etc. available to the calling script. ================ */ CBDL.include = function(filename) { if (typeof filename == "string") { CBDL.includes.push(new CBDL.Include(filename)); if (CBDL.includes[CBDL.current_include].state === CBDL.states.OPEN) { CBDL.loadInclude(CBDL.includes[CBDL.current_include]); //CBDL.nextInclude(); } } else { for (var file in filename) { CBDL.include(filename[file]); } } } /* ================ CBDL.nextInclude() Internal method that is called when an Include finishes loading, so as to load the next Include within the includes list. Usage: CBDL.nextInclude(); ================ */ CBDL.nextInclude = function() { if (CBDL.includes[CBDL.current_include+1] instanceof CBDL.Include) { CBDL.current_include++; CBDL.loadInclude(CBDL.includes[CBDL.current_include]); } else { // CBDL.onReady(); // CBDL.onReady = function(){}; } } /* ================ CBDL.loadInclude(Include) Internal method that attempts to use XMLHttpRequest or otherwise to dynamically load the specified Include. Upon success, a new