/** * TORA Library: Core * * @author alucas Anthony_Lucas@discovery-europe.com * @projectDescription Javascript library which supports dynamic resource resolution & loading * @version 0.0.3 */ /** * TORA Library core object. This is a static class used to interact with the TORA library. * @alias $TORA * @type {Function} * * @return {OBJECT} */ var $TORA = {}; (function() { //##CORE DEFINITION $TORA = function ToraCore() { return $TORA._$public.apply(this, arguments); }; //core config $TORA._$config = { BASE_PKG_LOCATION: '/resources/static/libtora/packages/', BASE_RES_LOCATION: '/resources/static/libtora/resources/' } //to hold initialisation tasks var _ON_INIT = [], _READY_LISTENERS = []; //object to hold temporary data, will be cleared after core initialisation var CORE_RES = {}; $TORA._$tmp = {}; //other vars var DOC_LOADED = false; /** * Called when $TORA used as function object. * Queries TORA internal registry for an object key. * @alias $TORA._$public * @method * * @return {Object} */ $TORA._$public = function() { return _INTERNAL_REG(arguments[0]); }; //#HELPER METHOD DEFINITIONS _ON_INIT.push(function() { /** * Helper method to add listeners to the document's DOMContentLoaded events * @alias $TORA.whenReady * @memberOf $TORA * @method * * @param {Object} func */ $TORA.whenReady = function(func) { if (DOC_LOADED) func(); else if (func) _READY_LISTENERS.push(func); }; CORE_RES.common.dom.addEventListener.call(document, "DOMContentLoaded", function() { DOC_LOADED = true; for (var i=0,k;(k=_READY_LISTENERS[i]);i++) k(); }); }); //#REGISTRY DEFINITION var _INTERNAL_REG, _REG_SAFE, _OBJ_REG = { }; _ON_INIT.push(function() { var o = CORE_RES.common.object; _INTERNAL_REG = o.Registry(_OBJ_REG); _INTERNAL_REG.add("DEFAULTS", o.Registry(null, true)); _REG_SAFE = { get: function(){ return _INTERNAL_REG.lookup.apply(_INTERNAL_REG, arguments); }, add: function() { return _INTERNAL_REG.add.apply(_INTERNAL_REG, arguments); } }; registryReady(); }); function registryReady() { $TORA.registry = function() { return _REG_SAFE; } }; //#PACKAGE REGISTRY DEFINITION var _PKG_REG, _PKG_REPO, _PKG_STRUCT = {}; _ON_INIT.push(function() { var config = $TORA._$config, packaging = CORE_RES.packaging; _PKG_REG = packaging.PackageRegistry( config['BASE_PKG_LOCATION']); _PKG_REPO = packaging.PackageRepository(_PKG_REG, _PKG_STRUCT); _INTERNAL_REG.extend(($TORA.packages=_PKG_STRUCT)); /** * Add TORA package. * @alias $TORA.addPackages * @memberOf $TORA * @method * @see $TORA.packaging.PackageRepository.registerPackages * * @param {Object} pkgArr */ $TORA.addPackages = function addPackages(pkgArr) { _PKG_REPO.registerPackages(pkgArr); }; /** * Initialises a package. * * @alias $TORA.initModule * @memberOf $TORA * @method * @see $TORA.packaging.PackageRepository.insert * * @param {String} pkgName * @param {Function} pkgDef */ $TORA.initModule = $TORA.initCoreModule = function initModule(pkgName, pkgDef) { return _PKG_REPO.insert(pkgName, pkgDef({ resourceLocation: config['BASE_RES_LOCATION'], windowObject: window, packageRoot: _PKG_REPO.getPackageRoot() })); }; /** * Returns a Requirement instance. A Requirement takes a list * of tora feature paths and resolves them to code packages to be loaded. Allows code to be * executed once the package requirements are satisfied. Requires either only the * paths argument be specified or all 3. * @alias $TORA.Requirement * * @param {Object} [...] object 'initRequirements' method will be called on this object once rquirements are satisfied. * @param {Array} featurePaths * @param {Boolean} isUrgent Packages will be loaded as soon as possible. Usually unecessary. * @return {Requirement} */ $TORA.Requirement = function() { /** * @constructor * @param {Object} arg1 * @param {Object} arg2 * @param {Object} arg3 */ function Requirement(arg1, arg2, arg3) { var packageStatus = {}, executionQueue = []; this._$config = { packageStatus: packageStatus, executionQueue: executionQueue } this._$config.onComplete = onCompleteCallback(this); var now, target, reqs = (arg3 ? (target = arg1, now = true, arg2) : arg1), reqLen = reqs.length; var obj = { constructor: arguments.callee, prototype: arguments.callee.prototype }; if (target) { var e; if (e = target.initRequirements) executionQueue.push(function(){ e() }); } if (reqLen > 0) for (var i=reqLen-1,k;k=reqs[i];i--) { packageStatus[k] = false; this.loadFeaturePath(k,now); } }; //PROTOTYPED METHODS /** * Executes code once feature requirements are satisfied. * @method * @memberOf Requirement * * @param {Object} code */ Requirement.prototype.execute = function(code) { if (this.checkStatus()) code(); else this._$config.executionQueue.push(code); }; /** * Gets list of packages required to satisfy feature path. * @method * @memberOf Requirement * * @param {Object} str */ Requirement.prototype.getRequiredPackages = $TORA.Requirement.resolve; /** * Requests a feature path. * @method * @memberOf Requirement * * @param {Object} pkgName * @param {Object} now */ Requirement.prototype.loadFeaturePath = function(path, now) { if (DOC_LOADED||((!now)&&(!DOC_LOADED))) _PKG_REPO.loadFeature(path, this._$config.onComplete); else _PKG_REPO.loadFeature(path, this._$config.onComplete, true); }; /** * Checks whether requirements have been satisfied. * @method * @memberOf Requirement * * @return {Boolean} */ Requirement.prototype.checkStatus = function() { var e, config = this._$config; for (var i in (e = config.packageStatus)) if (!e[i]) return false; var queue = config.executionQueue, queueLen = queue.length; config.executionQueue = []; if (queueLen > 0) for (var i=0,k;k=queue[i];i++)k(); return true; }; //PRIVATE METHODS function onCompleteCallback(context) { var status = context._$config.packageStatus; return function(path) { status[path] = true; context.checkStatus(); }; }; //CLOSE FACTORY function getRequirement(arg1, arg2, arg3) { return getExecutionQueue(new Requirement(arg1, arg2, arg3)); }; function getExecutionQueue(context) { function ExecutionQueue(code){ context.execute(code); }; ExecutionQueue.constructor = Requirement; ExecutionQueue.instance = context; return ExecutionQueue; }; $TORA.Requirement = function() { return getRequirement.apply(this, arguments); }; $TORA.Requirement.resolve = Requirement.prototype.getRequiredPackages; return getRequirement.apply(this, arguments); }; /** * Gets list of packages required to satisfy feature path. * @method * @memberOf Requirement * * @param {Object} str * @param {Boolean} fullInfo */ $TORA.Requirement.resolve = function(str, fullInfo) { return _PKG_REPO.resolveFeaturePath(str, fullInfo); }; }); //#CORE INITIALISATION /** * Initialises a core TORA resource module used during initialisation. * @alias $TORA.initCoreModule * @memberOf $TORA * @method * * @param {Object} name * @param {Object} def */ $TORA.initCoreModule = function(name, def) { _RES_LOADED[name] = def; coreInit(); }; //PRIVATE METHODS var _RES_LOADED = { 'common-core': false, 'packaging': false }; function coreInit() { //check if all resources loaded for (var i in _RES_LOADED) if (!_RES_LOADED[i]) return; //if so define resources and initialise $TORA._$tmp.CORE_RES = CORE_RES; for (var i in _RES_LOADED) { var o = _RES_LOADED[i](); for (var m in o) CORE_RES[m] = o[m]; } runInitTasks(); }; function runInitTasks() { for (var i=0,k;k=_ON_INIT[i];i++) k(); //cleanup mergeCoreWithPackages(); delete $TORA._$tmp; delete $TORA.initCoreModule; coreInit = CORE_RES = _RES_LOADED = _ON_INIT = runInitTasks = null; }; function mergeCoreWithPackages() { var pkgs = []; for (var i in _RES_LOADED) _PKG_REPO.insert(i, CORE_RES); }; //##END CORE DEFINITION })(); /** * TORA Library: Core Resources - Common * * @author alucas * @projectDescription Common package core bundle required during TORA core initialisation * @version 0.0.3 */ $TORA.initCoreModule("common-core", function() { //INIT PACKAGE var $package = {}; var $lib = {common: $package}; //INIT MODULES var $moduleObject = ($package.object = {}), $moduleString = ($package.string = {}), $moduleHTML = ($package.html = {}), $moduleDOM = ($package.dom = {}), $moduleXHR = ($package.xhr = {}); //#OBJECT MODULE /** * Public Domain Code. Clones an object (deep copy). * @alias $TORA.packages.common.object.cloneObject * * @param {Object} o * @return {Object} */ $moduleObject.cloneObject = function cloneObject(o) { if(typeof(o) != "object") return o; if(o == null) return o; var newO = new o.constructor(); for(var i in o) newO[i] = $moduleObject.cloneObject(o[i]); return newO; }; /** * Iterates over an Array instance, Object instance, or Array-like object * and passes each item to a function. * *

Examples:

* each(array, function(index){ var value = this });

* each(object, function(prop){ var value = this });

* * @alias $TORA.packages.common.object.each * * @param {Object} obj * @param {Function} process * @param {Boolean} arraysForward */ $moduleObject.each = function each(obj, process, arraysForward) { if (obj) { var arrLen; if ((arrLen = obj.length)) { if (arrLen > 0) if (!arraysForward) for (var i=arrLen-1,k;(k=obj[i]);i--) process.call(k,i); else for (var i=0,k;(k=obj[i]);i++) process.call(k,i); } else { for (var i in obj) process.call(obj[i],i); } } }; /** * Converts an Object or Array-like object to an array. * @alias $TORA.packages.common.object.toArray * * @param {Object} obj * @param {Object} useValues * @return {Array} */ $moduleObject.toArray = function toArray(obj, useValues) { var returnValue = []; if (obj) { if (!obj.length) { if (!useValues) for (var i in obj) returnValue.push(i); else for (var i in obj) returnValue.push(obj[i]); } else if (typeof obj == "string") { returnValue.push(obj); } else { var objLen = obj.length; if (objLen > 0) for (var i=0,k;k=obj[i];i++) returnValue.push(k); } } return returnValue; }; /** * Merge Objects into main object. * @alias $TORA.packages.common.object.mergeObjects * * @param {Object} object Required. Main object. This object will be altered. * @param {Array} mergeArray Required. Array of objects to merge into the main object. * @param {Object} config Optional. Advanced configuration. * @return {Object} Main Object (object). */ $moduleObject.mergeObjects = function mergeObjects(object, mergeArray, config) { var p, merge = $moduleObject.mergeObjects; if (config) { var cloneFn = (!(p = config.noClone)&&(typeof(p) !== "undefined")) ? $moduleObject.cloneObject : null; var shallow = config.shallow||false; var clobber = config.clobber||false; var ignoreFalse = config.ignoreFalse||false; } var clone = cloneFn||function(t) { return t }; $moduleObject.each(mergeArray, function() { for (var i in this) { if (object[i]) { var val = object[i], thisVal = this[i], type = val.constructor; switch (type) { case Object: if ((!shallow)&&(object[i])) object[i] = merge(val, [thisVal], config); else if ((!clobber)&&(ignoreFalse) &&(!thisVal) &&(thisVal.constructor==Boolean)) { continue; } else { object[i] = clone(thisVal); } break; case Array: if (thisVal.constructor == Array) { object[i] = val.concat(thisVal); break; } case String || Number || Array: if ((clobber)||!((this[i] == false) &&(ignoreFalse))) object[i] = thisVal; break; default: continue; } } else { object[i] = clone(this[i]);} } }); return object; }; /** * Returns a Registry instance. * A Registry instance performs cascading lookups on a group of objects. * The lookups cascade according to the order the objects were supplied. * *

Examples:

* var myRegistry = Registry([someDocumentElement, otherDocumentElement]);

* myRegistry("someprop"); // returns "someprop" if it exists in either document

* myRegistry("title"); // returns the title property from the first document * * @alias $TORA.packages.common.object.Registry * @constructor * * @param {Array} objects Objects to perform lookups on. * @param {Boolean} noLookupWrapper Removes the wrapper which enables an instance to directly act as a lookup function. * @return {RegistryInstance} */ $moduleObject.Registry = function Registry(objects, noLookupWrapper) { /** * @constructor * * @param {Object} objects */ function Registry(objects) { var members = []; this._$members = members; if (!objects) var objects = {}; if (!objects.length > 0) members.push(objects); else $moduleObject.each(objects, function() { this.extend(objects); }); this._$ready = true; }; //PROTOTYPED METHODS /** * Adds a property. * @method * @memberOf $TORA.packages.common.object.Registry * * @param {Object} key * @param {Object} value */ Registry.prototype.add = function(key, value) { var returnValue, obj = this._$members[0]; if (!obj[key]) { obj[key] = value; returnValue = true; } else returnValue = false; return returnValue; }; /** * Retrieve a property. * @method * @memberOf $TORA.packages.common.object.Registry * * @param {Object} prop */ Registry.prototype.lookup = function(prop) { var e, members = this._$members; for (var i=0,k;k=members[i];i++) if ((e = k[prop]) != undefined) return e; return undefined; }; /** * Extend Registry instance. * * @param {Object} object */ Registry.prototype.extend = function(object) { this._$members.push(object); }; /** * Returns registry members. * * @param {Array} object */ Registry.prototype._$getMembers = function() { return this._$members; }; //CLOSE FACTORY return ($moduleObject.Registry = function (objects, noLookupWrapper) { var returnValue, inst = new Registry(objects); if (!noLookupWrapper) { returnValue = function registry(prop) { return inst.lookup(prop); } returnValue = $moduleObject.mergeObjects(returnValue, [inst], { noClone: true }); } else returnValue = inst; return returnValue; })(objects, noLookupWrapper); }; /** * Mixes type instances together. * *

Examples:

* function CatDog() { Mixin(this, [ new Cat(), new Dog() ]); }
* var catDog = new CatDog();
* catDog.sniffButts() && catDog.eatMice(); * * @alias $TORA.packages.common.object.Mixin * @constructor * * @param {Object} main main type instance * @param {Array|Object} instances type instances to mix * @return {Object} main type instance */ $moduleObject.Mixin = function Mixin() { if (arguments.length > 0) switch(arguments.length) { case 2: return arguments.callee.mix(arguments[0], arguments[1]); case 1: return arguments[0]; default: return arguments.callee.mix(arguments[0], Array.prototype.slice.call(arguments) .slice(1)); } else return {}; }; $moduleObject.Mixin.mix = function(target, mixins) { var options = {noClone: true}; for (var i=mixins.length-1,k;k=mixins[i];i--) { for (var p in k) { var e,l; if (!(e = target[p])) target[p] = k[p]; else if (typeof((l = k[p])) == "object") { target[p] = $moduleObject.mergeObjects(e, [l], options); } } } }; /** * Returns a Config instance. This can be used by Mixin compatible * types to allow subtypes to plug into their configuration process. * * @alias $TORA.packages.common.object.Mixin * @constructor * * @param {Object} main main type instance * @param {Array|Object} instances type instances to mix * @return {Object} main type instance */ $moduleObject.Config = function Config(target) { /** * @alias Config * @constructor * * @param {Object} target */ function ConfigInstance(target) { this._$targetList = [target]; this._$defaults = {}; this._$properties = {}; }; //#PROTOTYPED METHODS //PUBLIC METHODS /** * @method * @memberOf $TORA.packages.common.type.SimpleWidget * * @param {Object} properties */ ConfigInstance.prototype.update = function(properties) { $moduleObject.mergeObjects(this._$properties, [properties]); }; /** * @method * @memberOf $TORA.packages.common.type.SimpleWidget * * @param {Object} properties */ ConfigInstance.prototype.setDefaults = function(properties) { $moduleObject.mergeObjects(this._$defaults, [properties]); }; /** * Called by the object which owns the instance. * @method * @memberOf $TORA.packages.common.type.SimpleWidget * * @param {Object} target */ ConfigInstance.prototype.prepare = function(target) { if (target) { var targetList = this._$targetList; targetList.push(target); if (target == targetList[0]) { var config = {}, defaults = this._$defaults, properties = this._$properties; for (var i in defaults) if (!properties[i]) config[i] = defaults[i]; for (var i in properties) config[i] = properties[i]; this._$executeOnTargets("_$checkConfig", [config]); for (var i in config) if (!target[i]) target["_$"+i] = config[i]; this._$executeOnTargets("_$configReady"); } } }; //PROTECTED METHODS /** * @protected * @method * @memberOf $TORA.packages.common.type.SimpleWidget * * @param {Object} target */ ConfigInstance.prototype._$executeOnTargets = function(methodName, args) { var args = args||[], targetList = this._$targetList, target = targetList[0];; for (var i=1,k,m;(k=targetList[i]); i++) { if ((m = k[methodName])) m.apply(target, args); } if ((m = target[m])) m.apply(target, args); }; //CLOSE FACTORY return ($moduleObject.Config = function(target) { return new ConfigInstance(target); })(target); }; //#STRING MODULE /** * Takes a URL and adds query parameters. * * @param {String} url * @param{Object} data * @param {Boolean} noescape Optionally disables url encoding. * @return {String} */ $moduleString.buildURL = function buildUrl(url, data, noescape) { var _URL_PARTS = /([^\?]*)(\?|)([^#]*)/; return ($moduleString.buildUrl = function buildUrl(url, data, noescape) { var params = ""; for (var i in data) { params += i + "=" + (!noescape ? escape(data[i]) : data[i]) + "&"; } var urlParts = url.match(_URL_PARTS); var start = (urlParts[2] !== "?") ? "?" : "&"; return urlParts[1] + start + params.slice(0,params.length-1) + urlParts[3]; })(url, data, noescape); }; /** * Converts JSON string to object, falling back to eval in the absence * of native support. * @alias $TORA.packages.common.string.toObject * * @return {Object} */ $moduleString.toObject = function toObject(str) { var finalFunction = function toObject(str) { return eval("("+str+")"); }; return ($moduleString.toObject = function toObject(str) { var returnValue; try { returnValue = finalFunction(str); } catch(e) { returnValue = null; } return returnValue; })(str); }; //#DOM MODULE /** * Provides an HTMLElement.getElementsByClassName interface which falls back to a native implementation when available. * Needs to be called as a method of the element to search within. Defaults to window. * *

Examples:

* getElementsByClassName.call(containerElement, "...classNames"); * * @alias $TORA.packages.common.dom.getElementsByClassName * * @param {String} strClassName Required. The class name to search for. * @return {Array} */ $moduleDOM.getElementsByClassName = function getElementsByClassName(strClassName) { var arrReturnElements; if (this.getElementsByClassName) { arrReturnElements = this .getElementsByClassName(strClassName); if (arrReturnElements) arrReturnElements = Array.prototype.slice.call(arrReturnElements); return arrReturnElements; } else { var strTagName = "*"; var arrElements = (strTagName == "*" && this.all)? this.all : this.getElementsByTagName(strTagName); arrReturnElements = []; strClassName = strClassName.replace(/\-/g, "\\-"); var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)"); var oElement; for(var i=0; i
Examples:

* addEventListener.call(myElement, "click", handler);
* addEventListener.call(document, "ready", handler); * * @alias $TORA.packages.common.dom.addEventListener * * @param {String} event Required. Name of DOM event. * @param {Function} listener Required. Event listener. * @return {Boolean} false if unsupported browser. */ ($moduleDOM.addEventListener = function addEventListener(event, listener) { //CAPABILITY DETECTION var capabilityTest = function(elem) { if (elem.addEventListener) return 1; else if (elem.attachEvent) return 2; else return 0; }; var defineListenerFunc = function(envType) { switch(envType) { case 1: return function(event, listener) { if ((event !== "DOMContentLoaded") ||(this.constructor !== window.constructor)) { this.addEventListener(event, listener, false); } else { addDLoadedHdlr(listener); } }; case 2: return function(event, listener) { if (event !== "DOMContentLoaded") { this.attachEvent("on"+event, function() { listener(window.event); }); } else { addDLoadedHdlr(listener); } }; case 0: return function(event, listener) { if (event !== "DOMContentLoaded") self = this; else self = window, event = "load"; var oldFunc = this["on" + event]; this["on" + event] = function(ev) { if (oldFunc) oldFunc.call(self, ev); handler.call(self, ev); } } } }; //INITIALISE var envType = capabilityTest(window), finalFunction = defineListenerFunc(envType); listenDLoaded(envType); //DOM LOADED HANDLING var isDLoaded = false, dLoadedHdlrs = [], ie_interval; function addDLoadedHdlr(listener) { if (!isDLoaded) { dLoadedHdlrs.push(listener); } else { listener(isDLoaded); } }; function executeDHdlrs(event) { if (ie_interval) window.clearInterval(ie_interval); if (!isDLoaded) { isDLoaded = event; if (dLoadedHdlrs.length > 0) { for (var i=0,k;k=dLoadedHdlrs[i];i++) { k(event); } dLoadedHdlrs = []; } } }; function listenDLoaded(envType) { switch(envType) { case 1: window.addEventListener("DOMContentLoaded", executeDHdlrs, false); window.addEventListener("load", executeDHdlrs, false); break; case 2: ie_interval = window.setInterval(function() { try { document.documentElement.doScroll("left"); } catch(e) { return }; executeDHdlrs(true); }, 100); break; case 0: finalFunction.call(window, "load", executeDHdlrs); } }; //CLOSE FACTORY return ($moduleDOM.addEventListener = finalFunction) (event, listener); }).call(window, "fakeEvent", function(){}); //#XHR MODULE /** * Cross-browser XMLHttpRequest factory. * @alias $TORA.packages.common.xhr.XMLHttpRequest * @constructor * * @return {XMLHttpRequest} */ $moduleXHR.XMLHttpRequest = function() { if (window.ActiveXObject) { return ($moduleXHR.XMLHttpRequest = function() { return new ActiveXObject("Microsoft.XMLHTTP") })(); } else { return ($moduleXHR.XMLHttpRequest = function() { return new XMLHttpRequest(); })(); } }; /** * Makes a HTTP GET request and invokes callback once readyState reaches 4. * @alias $TORA.packages.common.xhr.httpGet * * @param {String} url * @param {Function} callback * @param {Boolean} isSync */ $moduleXHR.httpGet = function httpGet(url, callback, isSync) { var xhr = $moduleXHR.XMLHttpRequest(); function checkStatus() { if ((xhr.readyState == 4)&&(callback)) { callback(xhr); } }; if (isSync) { xhr.open('GET', url, false); xhr.send(null); checkStatus(); } else { xhr.open('GET', url, true); xhr.onreadystatechange = checkStatus; xhr.send(null); } }; //#RETURN PACKAGE return $lib; }); /** * TORA Library: Core Resources - Packaging * * @author alucas * @projectDescription Packaging package required during TORA core initialisation * @version 0.0.3 */ $TORA.initCoreModule("packaging", function(packageInfo) { //INIT PACKAGE var $package = {}; var $lib = {packaging: $package}; var each = $TORA._$tmp.CORE_RES.common.object.each, toArray = $TORA._$tmp.CORE_RES.common.object.toArray, cloneObject = $TORA._$tmp.CORE_RES.common.object.cloneObject, mergeObjects = $TORA._$tmp.CORE_RES.common.object.mergeObjects, Mixin = $TORA._$tmp.CORE_RES.common.object.Mixin; //#PACKAGE REGISTRY DEFINITION /** * Returns a PackageRegistry instance. A PackageRegistry keeps track of * javascript packages and allows lookups. * @alias $TORA.packages.packaging.PackageRegistry * @constructor * * @param {Object} location * @return {PackageRegistry} */ $package.PackageRegistry = function PackageRegistry(location) { /** * @constructor * * @param {Object} location */ function PackageRegistry(location) { this._$pkgdb = { packageInfo: {}, packageStruct: {}}; this._$config = { baseLocation: location } }; //PROTOTYPED METHODS /** * Registers new packages * @method * @memberOf $TORA.packages.packaging.PackageRegistry * * @param {Object} packages */ PackageRegistry.prototype.registerPackages = function registerPackages(packages) { var process = processPackage(this); this.registerPackages = function(packages) { each(packages, process); } each(packages, process); }; /** * Resolves a package, module, and method names to packages * @method * @memberOf $TORA.packages.packaging.PackageRegistry * * @param {String} pkgName * @param {String} modName * @param {String} methName * @param {Boolean} additionalInfo */ PackageRegistry.prototype.resolvePackages = function(pkgName, modName, methName, additionalInfo) { var returnValue, c, d, curPos, pkgdb = this._$pkgdb, pkgInfo = pkgdb.packageInfo; if ((curPos = pkgdb.packageStruct[pkgName])) if ((modName)&&(c = curPos[modName])) { if ((methName)&&(d = c[methName])) curPos = d; else if (c.ASSOC_PKG.length > 0) curPos = c; } if (curPos) { var resError; each(curPos.ASSOC_PKG, function() { if ((!resError)&&(!pkgInfo[this])) resError = true; }); if (!resError) if (additionalInfo) { if (curPos.ASSOC_PKG.length > 0) { returnValue = {}; each(curPos.ASSOC_PKG, function() { returnValue[this] = cloneObject(pkgdb .packageInfo[this]); }); } else { returnValue = null; } } else { returnValue = Array.prototype.slice.call(curPos.ASSOC_PKG); } } return returnValue||[]; }; /** * Resolves package dependencies. * @method * @memberOf $TORA.packages.packaging.PackageRegistry * * @param {Object} pkgName * @param {Object} additionalInfo */ PackageRegistry.prototype.resolveDependencies = function(pkgName, additionalInfo) { var deps, hasDeps, returnValue, pkgInfo = this._$pkgdb.packageInfo; if ((deps = pkgInfo[pkgName])) deps = deps['depends']; else return []; returnValue = {}; each(deps, function() { var e; hasDeps = true; if ((e = pkgInfo[this])) returnValue[this] = e; }); return hasDeps ? returnValue : null;; } //PRIVATE METHODS function processPackage(context) { function assocStruct(pkg, obj, name) { var t, struct = (t = obj[name]) ? t : (obj[name] = { ASSOC_PKG: [] }), arr = struct.ASSOC_PKG; if (pkg != null) if (!pkg.length) arr.push(pkg); else struct.ASSOC_PKG = arr.concat(pkg); return struct; }; var baseLocation = context._$config.baseLocation; return function() { var name = this['direct-name'], pkgName = this['provides-package'], pkgFilePath = this['file-path'], pkgDb = context._$pkgdb, pkgInfo = pkgDb.packageInfo, pkgStruct = pkgDb.packageStruct, isSpecialCase = null, modules = this['provides-modules']; if (modules) for (var i in modules) { if (typeof modules[i] == "object") isSpecialCase = true; break; } if ((pkgFilePath) && ((name && pkgName) || (name = pkgName)) && (!pkgInfo[name])) { var e, realNames = [name]; var finalNames = !isSpecialCase ? realNames : null; if (pkgFilePath.charAt(0) !== "/") this['file-path'] = baseLocation + pkgFilePath; this['depends'] = toArray(this['depends']); pkgInfo[name] = this; var struct = assocStruct(finalNames, pkgStruct, pkgName); each(modules, function(modName){ var mod = assocStruct(finalNames, struct, modName); each(this, function() { assocStruct(realNames, mod, this); }); }); } }; }; //CLOSE FACTORY $package.PackageRegistry = function(location) { return new PackageRegistry(location); }; return new PackageRegistry(location); }; //#SCRIPT RESOURCE LOADER DEFINITION /** * Returns a ScriptResourceLoader instance. A ScriptResourceLoader * loads scripts at runtime. * @alias $TORA.packages.packaging.PackageRegistry * @constructor * * @param {Object} location * @param {String} type * @param {String} lang * @return {ScriptResourceLoader} */ $package.ScriptResourceLoader = function ScriptResourceLoader(location, type, lang) { //PRIVATE VARS var scriptTemplate = document.createElement("script"); scriptTemplate.type = "text/javascript"; scriptTemplate.language = "Javascript"; //CONSTRUCTOR /** * @constructor * * @param {String} location * @param {String} [type] * @param {String} [lang] */ function ScriptResourceLoader(location, type, lang) { this._$config = { container: document.getElementsByTagName("head")[0], location: location, type: type, lang: lang } }; //PROTOTYPED METHODS /** * Returns the target location. * @method * @memberOf $TORA.packages.packaging.ScriptResourceLoader * * @return {String} */ ScriptResourceLoader.prototype.getLocation = function() { return this._$config.location; }; /** * Loads the target resource. * @method * @memberOf $TORA.packages.packaging.ScriptResourceLoader * * @param {Boolean} isInline * @void */ ScriptResourceLoader.prototype.load = function(isInline) { var e, config = this._$config, script = scriptTemplate.cloneNode(false); script.src = config.location; if ((e = config.lang)) script.language = e; if ((e = config.type)) script.type = e; if (!isInline) { var container = this._$config.container; container.appendChild(script); } else { var dummy = document.createElement("div"); dummy.appendChild(script); document.write(dummy.innerHTML); } }; //CLOSE FACTORY return ($package.ScriptResourceLoader = function(location, type, lang) { return new ScriptResourceLoader(location, type, lang); })(location, type, lang); }; //#PACKAGE REPOSITORY DEFINITION /** * Returns a PackageRepository instance. A PackageRepository combines * a PackageRegistry with the functionality of a ScriptResourceLoader * to allow overall management of the loading, resolution, and definition of packages. * @alias $TORA.packages.packaging.PackageRepository * @constructor * * @param {PackageRegistry} registry * @param {String} packageRoot * @return {PackageRepository} */ $package.PackageRepository = function PackageRepository(registry, packageRoot) { /** * @constructor * @param {PackageRegistry} registry */ function PackageRepository(registry, packageRoot, defaults) { this._$config = { waiting: {}, packageRoot: packageRoot||{}, isRequested: {}, isLoaded: {} } Mixin(this, [registry]); }; //PROTOTYPED METHODS /** * Resolves path string to a package and loads it. * @method * @memberOf $TORA.packages.packaging.PackageRepository * * @param {Object} str */ PackageRepository.prototype.loadFeature = function(str, callback, isInline) { var self = this, e, config = this._$config, siteDomain = getSiteDomain(); //lookup packages var request = this._$parseFeaturePath(str); request.push(true); var results = this.resolvePackages .apply(this, request); //load packages this._$loadPackages({ pkgInfo: results, request: request, callback: callback, now: isInline, rawRequest: str, additionalInfo: true }); }; PackageRepository.prototype._$loadDependencies = function(options) { var pkgList = options.pkgInfo; if (pkgList) { var hasInfo = options.aditionalInfo, callback = options.callback; //check for dependencies function process(name) { var deps = self.resolveDependencies(name, true); if ((deps)&&(hasDeps = true)) mergeObjects( depList, [deps], { shallow: true }); }; var self = this, depList = {}, hasDeps; if (hasInfo) for (var i in pkgList) process(i); else each(pkgList, process); //load dependencies if (hasDeps) { this._$loadPackages({ pkgInfo: depList, callback: callback, now: options.now }); } else callback(); } }; /** * Completes a load request. * @private * @method * @memberOf $TORA.packages.packaging.PackageRepository * * @param {Object} options */ PackageRepository.prototype._$loadPackages = function(options) { var config = this._$config, pkgInfo = options.pkgInfo, pkgNames = toArray(pkgInfo), isRequested = config.isRequested, isLoaded = config.isLoaded, isInline = config.now, request = options.request, self = this; this._$loadDependencies({ pkgInfo: pkgInfo, additionalInfo: true, callback: loadMain }); function loadMain() { if ((pkgNames) && (pkgNames.length > 0)) { //define function to check request progress var updateStatus, args = (args = options.rawRequest) ? [args] : null; (updateStatus = createPackageCheck(pkgNames, isLoaded, options.callback, args))(); //load package javascript and monitor status each(pkgInfo, function(name) { self._$monitorStatus(name, request, updateStatus); if ((!isLoaded[name])&&(!isRequested[name])) { isRequested[name] = true; loadFile(this['file-path'], isInline); } }, true); } else { options.callback(options.rawRequest); } } }; /** * Monitors the status of a package request. * @private * @method * @memberOf $TORA.packages.packaging.PackageRepository * * @param {Object} name * @param {Object} request * @param {Object} updateFn */ PackageRepository.prototype._$monitorStatus = function(name, request, updateFn) { var pkgRoot = this._$config.packageRoot, override = ((request)&&(request[2])) ? true : false; this._$waitPackage(name, function(pkgName) { if ((!request)||(verify(pkgRoot, request))) updateFn(name, override); }); }; /** * Waits for a package to load. * @private * @method * @memberOf $TORA.packages.packaging.PackageRepository * * @param {Object} name * @param {Object} fn */ PackageRepository.prototype._$waitPackage = function(name, fn) { var waiting = this._$config.waiting, arr = waiting[name]; if (!arr) if (typeof arr == "undefined") { waiting[name] = arr = []; } else { if (arr == null) fn(name); return; } arr.push(fn); }; /** * Breaks a feature path into its constituent parts. * @private * @method * @memberOf $TORA.packages.packaging.PackageRepository * * @param {Object} str */ PackageRepository.prototype._$parseFeaturePath = function(str) { var pathRegex = ".", methodRegex = "::"; return (PackageRepository.prototype. _$parseFeaturePath = function(str) { var returnValue = str.split(pathRegex), valLen = returnValue.length-1, method, methodParts = returnValue[valLen] .split(methodRegex); if (methodParts.length > 0) { method = methodParts[1]; returnValue[valLen] = methodParts[0]; } while(returnValue.length < 2) returnValue.push(null); returnValue.push(method||null); return returnValue; })(str); }; /** * Resolves a feature path to the required packages * @method * @memberOf $TORA.packages.packaging.PackageRepository * * @param {Object} path * @param {Object} additionalInfo * @return {Array} */ PackageRepository.prototype.resolveFeaturePath = function(path, additionalInfo) { var returnValue = (path ? this._$parseFeaturePath(path) : []); returnValue.push(additionalInfo||false); returnValue = this.resolvePackages.apply(this, returnValue); return returnValue; }; /** * Initialises a new package in the package root. * @method * @memberOf $TORA.packages.packaging.PackageRepository * * @param {Object} pkgName * @param {Object} def */ PackageRepository.prototype.insert = function(pkgName, def) { var config = this._$config; mergeObjects(config.packageRoot, [def]); executeCallbacks(this, pkgName); config.isLoaded[pkgName] = true; }; /** * Returns the package root object. * @method * @memberOf $TORA.packages.packaging.PackageRepository * * @return {Object} */ PackageRepository.prototype.getPackageRoot = function() { return this._$config.packageRoot; }; //PRIVATE METHODS function loadFile(path, isInline) { $package.ScriptResourceLoader(getSiteDomain() + path).load(isInline); } function getSiteDomain() { var returnValue, page; if ((page = $TORA("PAGE"))) returnValue = page.getRootDomain(); else returnValue = ""; return (getSiteDomain = function getSiteDomain() { return returnValue; })(); } function createPackageCheck(pkgList, pkgStatus, readyFn, args) { return function(pkgName, override) { if (pkgName) pkgStatus[pkgName] = true; if (!override) { for (var i=pkgList.length-1,k;(k=pkgList[i]);i--) if (!pkgStatus[k]) return; } readyFn.apply(this, args||[]); }; }; function verify(pkgRoot, request) { var returnValue, req1 = request[1], req2 = request[2], cur = pkgRoot[request[0]]; if (cur) { if (!req1) { if (!req2||cur[req2]) returnValue = true; } else if ((cur = cur[req1])) { if ((req2)&&!(cur = cur[req2])) returnValue = false; else returnValue = true; } else returnValue = false; } else returnValue = false; return returnValue; }; function executeCallbacks(context, name) { var waiting = context._$config.waiting, list; if ((list = waiting[name])) { delete waiting[name]; list = list.slice(); waiting[name] = null; each(list, function() { this(name) }, true); } }; //CLOSE FACTORY $package.PackageRepository = function(registry, packageRoot) { return new PackageRepository(registry, packageRoot); }; return new PackageRepository(registry, packageRoot); }; //#RETURN PACKAGE return $lib; }); /** * TORA Library: Core Resources - Base Packages * * @author alucas Anthony_Lucas@discovery-europe.com * @projectDescription Basic package definitions * @version 0.0.1a */ $TORA.addPackages([ { 'description': "Provides user, page, and site information.", 'file-path': "environment.js", 'provides-package': "environment" }, { 'description': "Provides common utility methods and types.", 'direct-name': "common-core", 'file-path': "common/common_core.js", 'provides-package': "common" }, { 'description': "Provides extra utility methods and types for objects.", 'direct-name': "common-object-extras", 'file-path': "common/common-object_extras.js", 'provides-package': "common", 'provides-modules': { "object": [ "Iterator" ] } }, { 'description': "Provides common AJAX components.", 'direct-name': "common-type-ajax", 'file-path': "common/common-type_ajax.js", 'depends': "common-core", 'provides-package': "common", 'provides-modules': { "type": [ "StateMachine", "EventObject", "EventManager", "SimpleWidget", "DataProvider" ] } }, { 'description': "Provides a base for interaction with external sources.", 'direct-name': "external-core", 'file-path': "external/external_core.js", 'provides-package': "external", 'depends': "common-type-ajax" }, { 'description': "Provides various interfaces for interaction with external sources.", 'direct-name': "external-interfaces", 'file-path': "external/external_interfaces.js", 'provides-package': "external", 'depends': "external-core" }, { 'direct-name': "content-frames", 'file-path': "content-frames.js", 'depends': "external-interfaces", 'provides-package': "content", 'provides-modules': { "frames": true } }, { 'description': "Provides a core UI framework", 'direct-name': "ui-core", 'file-path': "ui/ui_core.js", 'provides-package': "ui", 'provides-modules': { "control": true, "animation": true } }, { 'direct-name': "photogallery-core", 'file-path': "/resources/photogallery/js/photogallery_core.js", 'depends': [ "common-object-extras" ], 'provides-package': "photogallery", 'provides-modules': { "ui": true, "data": true } }, { 'direct-name': "photogallery-hp", 'file-path': "/resources/photogallery/js/photogallery_hp.js", 'depends': [ "photogallery-core", "common-type-ajax", "ui-core", "thirdparty-addthis" ], 'provides-package': "photogallery", 'provides-modules': { "ui": [ "LightGalleryWidget" ] } }, /* PAGE REPORTING PACKAGES */ { 'direct-name': "reporting-core", 'file-path': "reporting/reporting_core.js", 'provides-package': "reporting" }, { 'direct-name': "reporting-basic", 'file-path': "reporting/reporting_basic.js", 'depends': [ "reporting-core" ], 'provides-package': "reporting", 'provides-modules': { "processors": [ "NetworkInfoProcessor", "ComscoreProcessor", "OmnitureProcessor" ], "dispatchers": [ "ComscoreDispatcher", "OmnitureDispatcher" ] } }, /* THIRD PARTY PACKAGES */ { 'direct-name': "thirdparty-addthis", 'file-path': "thirdparty/addthis/thirdparty-addthis.js", 'provides-package': "3rdparty.AddThis" }, { 'direct-name': "thirdparty-omniture", 'file-path': "thirdparty/omniture/thirdparty-omniture.js", 'provides-package': "3rdparty", 'provides-modules': { "omniture": true } } ]); /** * $Id$ * * Project: DNI Javascript Site Configuration: * Discovery Channel Latam * Version: 0.0.2 * Author: alucas * */ //#SET SITE DEFAULTS //REPORTING DEFAULTS //INTERFACE DEFAULTS $TORA("DEFAULTS").add("BasicInteractive", { CLICK_REFRESH_LIMIT: 20, DISABLE_AD_REFRESH: false }); //#SITE INITIALISATION //START REPORTING $TORA.Requirement([ "environment::PageContext", "reporting.dispatchers::OmnitureDispatcher" ])(function() { var pageContext = $TORA("PAGE"), reporting = $TORA("reporting"), processors = reporting.processors, dispatchers = reporting.dispatchers; var report = reporting.PageReport({ context: pageContext, processorList: [ processors.NetworkInfoProcessor, processors.UserInfoProcessor, processors.OmnitureProcessor ], dispatcherMap: { "omniture": dispatchers.OmnitureDispatcher} }); $TORA("PAGE").setProperty("pageReport", report); /* $TORA.whenReady(function() { if (!pageContext.getProperty("noAutoReport")) report.run("omniture"); }); */ });