var BOTANJS_VERSION = "1.0.0b"; /*{{{ Shorthand Functions */ var __extends = function( obj, target ) { obj.prototype = Object.create( target.prototype ); obj.prototype.constructor = obj; }; var __readOnly = function( prototype, name, callback ) { Object.defineProperty( prototype, name, { get: callback , set: function( v ) { throw new Error( "Setting a read-only property: " + this.p ); }.bind( { p: name } ) } ); }; var __static_method = function( obj, name, callback ) { Object.defineProperty( obj, name, { get: function(){ return callback; } , set: function( v ) { throw new Error( "Setting a read-only property: " + this.p ); }.bind( { p: name } ) } ); }; var __const = __static_method; /* End Shorthand Functions }}}*/ /*{{{ BotanEvent & EventDispatcher */ /** @type {typeof _BotanEvent} */ var BotanEvent; BotanEvent = function( name, data ) { var __propagating = false; var __propagated = false; __static_method( this, "propagate" , function() { if( !__propagated ) { __propagating = true; } __propagated = true; } ); __static_method( this, "stopPropagating" , function() { __propagating = false; } ); __const( this, "type", name ); __readOnly( this, "propagating" , function() { return __propagating; } ); __const( this, "data", data ); this.setTarget = function( target ) { __const( this, "target", target ); this.setTarget = undefined; }.bind( this ); }; /** * @constructor */ var EventDispatcher = function() { var events = {}; var _self = this; var getStack = function(name) { if (!events[name]) events[name] = []; return events[name]; }; var _dispatch = function() { this.evt.propagate(); for (var i in this.stack) { if (this.evt.propagating) { this.stack[i](this.evt); } } this.evt.stopPropagating(); }; /** * @param {string} type * @param {function(!BotanEvent): void} handler * @return {void} */ this.addEventListener = function(type, handler) { var stack = getStack(type); stack[stack.length] = handler; }; /** * @param {string} type * @param {function(!BotanEvent): void} handler * @return {void} */ this.removeEventListener = function(type, handler) { var stack = getStack(type); var i = stack.indexOf(handler); if (i < 0) return; delete stack[i]; }; /** * @param {!BotanEvent} _evt * @return {boolean} */ this.dispatchEvent = function(_evt) { var _stack = getStack(_evt.type); if (_evt.setTarget) _evt.setTarget(_self); setTimeout(_dispatch.bind({ evt: _evt, stack: _stack }), 0); return true; }; }; /* End BotanEvent & EventDispatcher }}}*/ /** * @constructor * @extends {EventDispatcher} * @param {!Object} target * @param {string} name */ var NamespaceObj = function(target, name) { EventDispatcher.call(this); /** @private {!Object} */ this.t_ = target; /** @private {string} */ this.n_ = name; }; NamespaceObj.prototype = Object.create(EventDispatcher.prototype); NamespaceObj.prototype.constructor = NamespaceObj; /** * @param {string} type * @param {string} name * @param {*} obj * @return {void} */ NamespaceObj.prototype.exportSymbol = function(type, name, obj) { if (this.t_[name]) return; this.t_[name] = [type, obj]; var evt = new BotanEvent("NS_EXPORT", { "name": this.n_ + "." + name, "type": type }); BotanJS.dispatchEvent(evt); }; /** * @param {string} target * @return {*} */ NamespaceObj.prototype.invoke = function(target) { if (!this.t_[target]) { throw new Error( "[" + this.n_ + "] " + "Invoke failed: " + target + " does not exists" ); } return this.t_[target][1]; }; /** * @param {string} code * @param {function(...?): *} func * @return {void} */ NamespaceObj.prototype.trigger = function(code, func) { this.t_.__TRIGGERS[code] = func; }; /** * @param {string} message * @param {string=} subclass * @return {void} */ NamespaceObj.prototype.throwError = function(message, subclass) { subclass = subclass ? ("." + subclass) : ""; throw new Error( "[" + this.n_ + subclass + "] " + message ); }; var packages = {}; var _global = {}; var _NSs = {}; var _cacheIMP = {}; /*{{{ Constants */ var EX_CONST = 0; var EX_VAR = 1; var EX_CLASS = 2; var EX_FUNC = 3; var EX_READONLY_GETTER = 10; var NS_INVOKE = 0; var NS_EXPORT = 1; var NS_TRIGGER = 10; var NS_THROW = 11; var TGR_IMPORT = 0; /* End Constants }}}*/ /*{{{ Multi-instance handle */ // Check if we are being imported 2nd time // If yes, we get the instance and overload // some core methods var sGarden = window["BotanJS"]; var BotanJS = null; var __namespace = null; var __import = null; if( sGarden ) { BotanJS = sGarden["sg"][0]; __namespace = sGarden["sg"][1]; __import = sGarden["sg"][2]; } /* End Multi-instance handle }}}*/ /*{{{ Root level bug-free handlers */ BotanJS = BotanJS || (function() { var i = 0; var mesg = []; var structures = []; var edp = new EventDispatcher(); var log = {}; log.write = function( m ) { mesg[ mesg.length ] = m; }; __static_method( log, "read", function() { return mesg[ i ++ ]; } ); __static_method( log, "end", function() { return ( mesg.length <= i ); } ); __const( edp, "log", log ); __static_method( edp, "define", function( f ) { structures[ structures.length ] = f; } ); __static_method( edp, "getDef", function() { return structures.slice(); } ); return edp; })(); /* End Root level bug-free handlers }}}*/ /*{{{ Namespace declarator */ __namespace = __namespace || function(ns) { if (_NSs[ns]) return _NSs[ns]; var p = ns.split("."); var l = p.length; var target = packages; for (var i = 0; i < l; i++) { target[p[i]] = target[p[i]] || {}; target = target[p[i]]; } /** @type {!Object} */ target.__TRIGGERS = {}; var nsObj = new NamespaceObj(target, ns); BotanJS.dispatchEvent(new BotanEvent("NS_INIT", ns)); nsObj[NS_EXPORT] = nsObj.exportSymbol.bind(nsObj); nsObj[NS_INVOKE] = nsObj.invoke.bind(nsObj); nsObj[NS_TRIGGER] = nsObj.trigger.bind(nsObj); nsObj[NS_THROW] = nsObj.throwError.bind(nsObj); return (_NSs[ns] = nsObj); }; /* End Namespace declarator }}}*/ /*{{{ Import operator */ __import = __import || function( ns, noCache ) { var nss = ns.replace( ".*", "" ); if( _NSs[ nss ] ) { _NSs[ nss ].dispatchEvent( new BotanEvent( "NS_IMPORT", nss ) ); } // Read The Cache First if( !noCache && _cacheIMP[ ns ] ) return _cacheIMP[ ns ]; var p = ns.split("."); var l = p.length; var target = packages; var wildcard = false; for( var i = 0; i < l; i ++ ) { if( p[i] == "*" ) { wildcard = true; break; } target = target[ p[i] ]; if( !target ) throw new Error( "No such class: " + ns ); } if( target instanceof Array && p[i] != "*" ) { var rtarget = null; if( target[0] == EX_READONLY_GETTER ) { rtarget = target[1](); } else { rtarget = target[1]; } _cacheIMP[ ns ] = rtarget; return rtarget; } var nsObj = {}; for( var i in target ) { var j = target[i]; if( j instanceof Array ) { if( wildcard && j[0] == EX_CLASS ) { __const( nsObj, i, j[1] ); } else if( j[0] == EX_FUNC ) { __const( nsObj, i, j[1] ); } else if( j[0] == EX_CONST ) { Object.defineProperty( nsObj, i, { get: function() { return this.t[ this.p ][1]; }.bind( { p: i, t: target } ) , set: function( v ) { throw new Error( "Setting a read-only property: " + this.p ); }.bind( { p: i } ) }); } else if( j[0] == EX_VAR ) { Object.defineProperty( nsObj, i, { get: function() { return this.t[ this.p ][1](); }.bind( { p: i, t: target } ) , set: function( v ) { this.t[ this.p ][1]( v ); }.bind( { p: i, t: target } ) }); } else if( j[0] == EX_READONLY_GETTER ) { Object.defineProperty( nsObj, i, { get: j[1] , set: function( v ) { throw new Error( "Setting a read-only property: " + this.p ); }.bind( { p: i } ) }); } } // import the namespace else if( wildcard && j.__TRIGGERS ) { __const( nsObj, i, __import( nss + "." + i ) ); } } _cacheIMP[ ns ] = nsObj; return nsObj; }; /* End Import operator }}}*/ window["BotanJS"] = {}; window["BotanJS"]["version"] = BOTANJS_VERSION; window["BotanJS"]["codename"] = "Botanical framework.js"; window["BotanJS"]["import"] = function( p ) { try { return __import( p ); } catch( e ) { if( sGarden ) return sGarden["import"]( p ); throw e; } }; window["BotanJS"]["sg"] = [ BotanJS, __namespace, __import ];