UNPKG

vitruvio

Version:

Framework which extends JavaScript capabilities in order to allow developing OOP applications over an structural well designed architecture by defining: namespaces, classes, interfaces, enumerators, inheritance, exceptions and other resources.

1,541 lines (1,371 loc) 135 kB
/** * @module vitruvio * @version 1.1.0 * @description Framework which extends JavaScript capabilities in order to allow developing OOP applications over an structural well designed architecture by defining: namespaces, classes, interfaces, enumerators, inheritance, exceptions and other resources. * @author Yadir Hernandez <yadirhb@gmail.com> * @released 2017-06-29 */ (function () { var $global = this, stime = new Date().getMilliseconds(); var CONFIG = { 'GLOBAL': $global, 'DEBUG': false }; /** * JavaScript Support for older versions */ //Check if native implementation available /** * Object * */ if (!Object.create) { Object.create = function (o) { function F() { } // empty constructor F.prototype = o; // set base object as prototype return new F(); // return empty object with right [[Prototype]] }; } if (!Object.setPrototypeOf) { Object.setPrototypeOf = function (obj, proto) { obj.__proto__ = proto; return obj; }; } /*if(!Object.prototype.equals){ Object.prototype.equals = function(obj){ return this === obj; } }*/ if (!Object.getPrototypeOf) { if (({}).__proto__ === Object.prototype && ([]).__proto__ === Array.prototype) { Object.getPrototypeOf = function getPrototypeOf(object) { return object.__proto__; }; } else { Object.getPrototypeOf = function getPrototypeOf(object) { // May break if the constructor has been changed or removed return object.constructor ? object.constructor.prototype : void 0; }; } } if (!Object.prototype.hasOwnProperty) { Object.prototype.hasOwnProperty = function (prop) { return prop in this && !(prop in Object.getPrototypeOf(this)); } } /** * Array * */ if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (obj, start) { for (var i = (start || 0), j = this.length; i < j; i++) { if (this[i] === obj) { return i; } } return -1; } } if (!Array.prototype.each) { Array.prototype.each = function (func, direction) { return direction !== false ? each(this, func) : eachReverse(this, func); } } if (!Array.prototype.remove) { Array.prototype.remove = function (index) { if (typeof index == 'number') { if (index > -1) this.splice(parseInt(index), 1); } else { this.remove(this.indexOf(index)); } } } /** * Function * */ if (!Function.prototype.getName) { Function.prototype.getName = function () { var funcNameRegex = /function\s([^(]{1,})\(/; var results = (funcNameRegex).exec((this).toString()); return (results && results.length > 1) ? results[1].trim() : ""; } } if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== 'function') { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () { }, fBound = function () { return fToBind.apply(this instanceof fNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); }; if (this.prototype) { // Function.prototype doesn't have a prototype property fNOP.prototype = this.prototype; } fBound.prototype = new fNOP(); return fBound; }; } /** * String * */ if (!String.prototype.contains) { String.prototype.contains = function (substring) { return this.indexOf(substring) > -1; } } if (!String.prototype.trim) { String.prototype.trim = function () { var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; return this.replace(rtrim, ''); } } if (!String.prototype.replaceAll) { function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string } String.prototype.replaceAll = function (search, replacement) { var target = this; return target.replace(new RegExp(escapeRegExp(search), 'g'), replacement); }; } /** * JSON Support * */ if (!$global.JSON) { $global.JSON = { parse: function (sJSON) { return eval('(' + sJSON + ')'); }, stringify: (function () { var toString = Object.prototype.toString; var escMap = {'"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t'}; var escFunc = function (m) { return escMap[m] || '\\u' + (m.charCodeAt(0) + 0x10000).toString(16).substr(1); }; var escRE = /[\\"\u0000-\u001F\u2028\u2029]/g; return function stringify(value) { if (value == null) { return 'null'; } else if (isNumber(value)) { return isFinite(value) ? value.toString() : 'null'; } else if (isBoolean(value)) { return value.toString(); } else if (isObject(value)) { if (isFunction(value.toJSON)) { return stringify(value.toJSON()); } else if (isArray(value)) { var res = '['; for (var i = 0; i < value.length; i++) res += (i ? ', ' : '') + stringify(value[i]); return res + ']'; } else if (toString.call(value) === '[object Object]') { var tmp = []; for (var k in value) { if (value.hasOwnProperty(k)) tmp.push(stringify(k) + ': ' + stringify(value[k])); } return '{' + tmp.join(', ') + '}'; } } return '"' + value.toString().replace(escRE, escFunc) + '"'; }; })() }; } /** * JavaScript extensions */ // Object extensions /** * Returns true if the current instance is a subject instance. * @param subject * @returns {boolean} */ if (!Object.prototype.is) { Object.prototype.is = function (type) { return type && isFunction(type) ? this instanceof type : false; } } /** * The as operator is like a cast operation. * However, if the conversion isn't possible, as returns null instead of raising an exception. */ if (!Object.prototype.as) { Object.prototype.as = function (type) { if (type) { if (isFunction(type) && this.is(type)) { var args = Array.prototype.concat([null], arguments[1] || this.constructor.arguments); var $type = new (Function.prototype.bind.apply(type, args)); var context = this, proto = Object.getPrototypeOf(type.prototype); if (type.is(Interface)) { var patch = {}; for (var m in $type) { if (isFunction($type[m]) && ( (m in $type) && !(m in proto))) { if (!m.contains("$")) { eval("patch['" + m + "'] = function (" + getSignature(context[m]) + ") { return context['" + m + "'].apply(context, arguments);}"); } } } return apply($type, patch); } return supersede($type, this); } else if (isObject(type)) { return supersede(apply(new type.constructor, type), this); } } } } /** * Created by yadirhb on 12/26/2015. */ function isBrowser() { return typeof (window) != "undefined"; } function isNode() { return typeof(process) != 'undefined'; } function isCordova() { return isBrowser() && userAgent.isMobile() && document.URL.indexOf('http://') === -1 && document.URL.indexOf('https://') === -1; } function isMobile() { return isCordova(); } function isDesktop() { return isNode(); } var userAgent; if (isBrowser()) { userAgent = { /** * Returns if the Browser supports Blob * */ 'isBlobSupported': function () { return "Blob" in $global; }, /** * Nested static class to Internet Explorer solutions utilities * */ 'IE': { // Returns the version of Internet Explorer or a -1 // (indicating the use of another browser). 'getVersion': function () { var match = navigator.userAgent.match(/(?:MSIE |Trident\/.*; rv:)(\d+)/); return match ? parseFloat(match[1]) : -1; }, /** * Identify if IE version is below 10 */ 'isOldVersion': function () { var v = this.getVersion(); return v != -1 && v <= 9; } }, /** * Identify whether the browser is IE or not * @return True if the browser is IE, false otherwise */ 'isIE': function () { if ('navigator' in $global) { var ua = $global.navigator.userAgent; var newIe = ua.indexOf('Trident/'); return ((newIe > -1)); } }, 'isEdge': function () { return !this.isIE() && !!window.StyleMedia; }, /** * Identify whether the browser supports HTML5 <audio> or not * @returns True if the browser supports HTML5 <audio>, false otherwise * */ 'isAudioSupported': function () { try { if (typeof document.createElement("audio").play != "undefined") return true; } catch (ex) { return false; } }, 'isAndroid': function () { if ('navigator' in $global) return navigator.userAgent.indexOf('Android') > -1 && navigator.userAgent.indexOf('Mozilla/5.0') > -1 && navigator.userAgent.indexOf('AppleWebKit') > -1; return false; }, 'isBlackBerry': function () { if ('navigator' in $global) return navigator.userAgent.match(/BlackBerry/i); return false; }, 'isSafari': function () { return Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0; }, 'isiOS': function () { if ('navigator' in $global) return navigator.userAgent.match(/iPhone|iPad|iPod/i); return false; }, 'isOpera': function () { if ('navigator' in $global) return navigator.userAgent.match(/Opera Mini/i); return false; }, 'isWindowsPhone': function () { if ('navigator' in $global) return navigator.userAgent.match(/IEMobile/i) || navigator.userAgent.match(/WPDesktop/i); }, 'isFirefox': function () { return typeof InstallTrigger !== 'undefined'; }, 'isChrome': function () { return !!window.chrome && !!window.chrome.webstore; }, 'isMobile': function () { return (this.isAndroid() || this.isBlackBerry() || this.isiOS() || this.isOpera() || this.isWindowsPhone() || false); }, 'isBlink': function () { return (this.isChrome() || this.isOpera()) && !!window.CSS; }, 'isAOSPBrowser': function () { if ('navigator' in $global) { // Native Android Browser var navU = navigator.userAgent; // Android Browser (not Chrome) var regExAppleWebKit = new RegExp(/AppleWebKit\/([\d.]+)/); var resultAppleWebKitRegEx = regExAppleWebKit.exec(navU); var appleWebKitVersion = (resultAppleWebKitRegEx === null ? null : parseFloat(regExAppleWebKit.exec(navU)[1])); return this.isAndroid() && appleWebKitVersion !== null && appleWebKitVersion < 537; } return false; } }; } //###### Error functions /** * Represents errors that occur during application execution. * @param message Sets the message that describes the current exception. * @param name Sets a custom name for the instance or Exception by default. * */ function Exception(/*message[, name]*/) { if (arguments.length > 0) { if (this.is(Exception)) { var context = this, message = arguments[0], name = arguments[1] ? arguments[1] : name = arguments[1] ? arguments[1] : "getClass" in context ? context.getClass().getName() : "Exception", err = Error.apply(this, arguments); this.name = err.name = name; this.message = message = err.message; //check if there is a stack property supported in browser if (err.stack) { // remove one stack level: if (isBrowser() && userAgent.isFirefox()) { // Mozilla: this.stack = err.stack.substring(err.stack.indexOf('\n') + 1); } else if (isNode() || (isBrowser() && userAgent.isChrome())) { // Google Chrome/Node.js: this.stack = err.stack.replace(/\n[^\n]*/, ''); } else { this.stack = err.stack; } } return this; } } } Exception.prototype = Error.prototype; function defaultOnError(err) { throw err; } //#####Primary types functions var op = Object.prototype, ostring = op.toString; function isArray(it) { return getClassName(it) === 'Array'; } function isBoolean(it) { return typeof it === 'boolean'; } function isBooleanValue(it) { /^(?:true|false)$/i.test(it); } function isFloat(it) { return isNumber(it) && it === parseFloat(it.toString()); } function isFunction(it) { return getClassName(it) === 'Function'; } function isInteger(it) { return isNumber(it) && it === parseInt(it.toString()); } function isObject(it) { return typeof it === 'object'; } function isNull(it) { return it === null; } function isNullValue(it) { return /^\s*$/.test(it); } function isNumber(it) { return typeof it === 'number'; } function isString(it) { return typeof it === 'string'; } function isEmpty(obj) { // // null and undefined are "empty" if (obj == null) return true; if ('undefined' !== Object.keys) { // Using ECMAScript 5 feature. return (0 === Object.keys(obj).length); } else { // Using legacy compatibility mode. for (var key in obj) { if (obj.hasOwnProperty(key)) { return false; } } return true; } } /** * * @param obj * @param type * @returns {boolean} */ function is(obj, type) { try { return obj.is(type); } catch (e) { return obj instanceof type; } } /** * Gets objects class name * */ function getClassName(obj) { if (typeof obj === "undefined") return "undefined"; if (obj === null) return "null"; // if (obj.constructor != Object.constructor) { // var str = (obj.prototype ? obj.prototype.constructor : obj.constructor).toString(); // var cname = str.match(/function\s(\w*)/)[1]; // var aliases = ["", "anonymous", "Anonymous"]; // return aliases.indexOf(cname) > -1 ? "Function" : cname; // } return ostring.call(obj).match(/^\[object\s(.*)\]$/)[1]; } //#####Collection functions /** * Helper function for iterating over an array. If the func returns * a true value, it will break out of the loop. */ function each(ary, func) { if (ary) { var i; for (i = 0; i < ary.length; i += 1) { if (ary[i] && func(ary[i], i, ary)) { break; } } } } /** * Helper function for iterating over an array backwards. If the func * returns a true value, it will break out of the loop. */ function eachReverse(ary, func) { if (ary) { var i; for (i = ary.length - 1; i > -1; i -= 1) { if (ary[i] && func(ary[i], i, ary)) { break; } } } } //#####Object functions function hasProp(obj, prop) { return Object.hasOwnProperty.call(obj, prop); } function getOwn(obj, prop) { return hasProp(obj, prop) && obj[prop]; } /** * Cycles over properties in an object and calls a function for each * property value. If the function returns a truthy value, then the * iteration is stopped. */ function eachProp(obj, func) { var prop; for (prop in obj) { if (hasProp(obj, prop)) { if (func(obj[prop], prop)) { break; } } } } /** * The System.freeze() method freezes an object: that is, prevents new properties from being added to it; prevents * existing properties from being removed; and prevents existing properties, or their enumerability, configurability, * or writability, from being changed. In essence the object is made effectively immutable. The method returns the * object being frozen. * */ function freeze(it) { return Object.freeze ? Object.freeze(it) : it; } /** * Simple function to mix in properties from source into target, * but only if target does not already have a property of the same name. */ function mixin(target, source, force, deepStringMixin) { if (source) { eachProp(source, function (value, prop) { if (force || !hasProp(target, prop)) { if (deepStringMixin && typeof value === 'object' && value && !isArray(value) && !isFunction(value) && !(value instanceof RegExp)) { if (!target[prop]) { target[prop] = {}; } mixin(target[prop], value, force, deepStringMixin); } else { target[prop] = value; } } }); } return target; } /** * Simple function to make a supersede the properties between two objects. * The properties into the same. */ function supersede(target, source, force, deepStringMixin) { if (source) { eachProp(source, function (value, prop) { if (hasProp(target, prop)) { if (deepStringMixin && typeof value === 'object' && value && !isArray(value) && !isFunction(value) && !(value instanceof RegExp)) { if (!target[prop]) { target[prop] = {}; } supersede(target[prop], value, force, deepStringMixin); } else { target[prop] = value; } } }); } return target; } //#####Event functions /** * Alias a method while keeping the context correct, to allow for overwriting of target method. * * @param {String} name The name of the target method. * @param {Object} scope The scope of the target method. * @return {Function} The aliased method * @api private */ function alias(name, scope) { scope = scope || this; return function aliasClosure() { return scope[name].apply(scope, arguments); }; } /** * Similar to Function.prototype.bind, but the 'this' object is specified * first, since it is easier to read/figure out what 'this' will be. * */ function bind(scope, fn) { return function () { return fn.apply(scope, arguments); }; } function addListener(evt, listener, scope) { scope = scope || this; var listeners = getListenersAsObject.call(scope, evt); var listenerIsWrapped = typeof listener === 'object'; var key; for (key in listeners) { if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) { listeners[key].push(listenerIsWrapped ? listener : { listener: listener, once: false }); } } return scope; } function defineEvent(evt, scope) { scope = scope || this; getListeners.call(scope, evt); return scope; } function emitEvent(evt, args, scope) { scope = scope || this; var listenersMap = getListenersAsObject.call(scope, evt); var listeners; var listener; var i; var key; var response; for (key in listenersMap) { if (listenersMap.hasOwnProperty(key)) { listeners = listenersMap[key].slice(0); i = listeners.length; while (i--) { // If the listener returns true then it shall be removed from the event // The function is executed either with a basic call or an apply if there is an args array listener = listeners[i]; if (listener && listener.listener) { if (listener.once === true) { removeListener.call(scope, evt, listener.listener); } response = listener.listener.apply(this, args || []); if (response === getOnceReturnValue.call(scope)) { removeListener.call(scope, evt, listener.listener); } } } } } return scope; } /** * Fetches the events object and creates one if required. * * @return {Object} The events storage object. * @api private */ function getEvents(scope) { scope = scope || this; return scope._events || (scope._events = {}); } /** * Fetches the current value to check against when executing listeners. If * the listeners return value matches this one then it should be removed * automatically. It will return true by default. * * @return {*|Boolean} The current value to check for or the default, true. * @api private */ function getOnceReturnValue(scope) { scope = scope || this; if (scope.hasOwnProperty('_onceReturnValue')) { return scope._onceReturnValue; } else { return true; } } function getListeners(evt, scope) { scope = scope || this; var events = getEvents.call(scope); var response; var key; // Return a concatenated array of values matching events if // the selector is a regular expression. if (evt instanceof RegExp) { response = {}; for (key in events) { if (events.hasOwnProperty(key) && evt.test(key)) { response[key] = events[key]; } } } else { response = events[evt] || (events[evt] = []); } return response; } function getListenersAsObject(evt, scope) { scope = scope || this; var listeners = getListeners.call(scope, evt); var response; if (listeners instanceof Array) { response = {}; response[evt] = listeners; } return response || listeners; } /** * Finds the index of the listener for the event in its storage array. * * @param {Function[]} listeners Array of listeners to search through. * @param {Function} listener Method to look for. * @return {Number} Index of the specified listener, -1 if not found * @api private */ function indexOfListener(listeners, listener) { var i = listeners.length; while (i--) { if (listeners[i].listener === listener) { return i; } } return -1; } function removeEvent(evt, scope) { scope = scope || this; var type = typeof evt; var events = getEvents.call(scope); var key; // Remove different things depending on the state of evt if (type === 'string') { // Remove values listeners for the specified event delete events[evt]; } else if (evt instanceof RegExp) { // Remove values events matching the regex. for (key in events) { if (events.hasOwnProperty(key) && evt.test(key)) { delete events[key]; } } } else { // Remove values listeners in values events delete scope._events; } return scope; } function removeListener(evt, listener, scope) { scope = scope || this; var listeners = getListenersAsObject.call(scope, evt); var index; var key; for (key in listeners) { if (listeners.hasOwnProperty(key)) { index = indexOfListener(listeners[key], listener); if (index !== -1) { listeners[key].splice(index, 1); } } } return scope; } //#####DOM functions function scripts() { return document.getElementsByTagName('script'); } /** * Allow getting a global that is expressed in * dot notation, like 'a.b.c'. * */ function getGlobal(value, separator) { separator = separator || '.'; if (!value) { return value; } var g = global; each(value.split(separator), function (part) { g = g[part]; }); return g; } //##### Kernel FUNCTIONS /** * Copies the properties from as many source objects as defined into a container * object. * * @param container * {Object} The original object in which will be mixed values sources * properties. * @param source * {Object} The source of properties to be copied into the container * object. * @return {Object} The resultant container object. */ function apply(/*container[, source1,...sourceN] */) { if (arguments.length > 1 && arguments[0] != null) for (var i = 1; i < arguments.length; i++) for (var propName in arguments[i]) { var source = arguments[i]; if (source.hasOwnProperty(propName)) try { arguments[0][propName] = source[propName]; } catch (e) { } } return arguments[0]; } function getSignature(func) { if (func && isFunction(func)) { // First match everything inside the function argument parens. var args = func.toString().match(/function\s.*?\(([^)]*)\)/)[1]; // Split the arguments string into an array comma delimited. return args.split(',').map(function (arg) { // Ensure no inline comments are parsed and trim the whitespace. return arg.replace(/\/\*.*\*\//, '').trim(); }).filter(function (arg) { // Ensure no undefined values are added. return arg; }); } return ""; } /** * Instantiate a specific function, applies values definition properties and assign a proto object. * @param type {Function} */ function create(type, def, base) { // empty constructor type.prototype = base ? typeof base === 'function' ? new base() : base : new Class(); // set base object as prototype return apply(new type(), def); // return empty object with right [[Prototype]] } /** * Defines a new member and registers it into the wrapper object. * * @param memberName * {String} The name of the member to be defined. It must be a valid * namespace identifier. * @param definition * {Object} Contains the public class members. * @param wrapper * {Object} Defines the wrapper of the new Object, if not provided * window will be taken. */ function define(type, baseClass, members, statics) { // empty constructor type.prototype = baseClass ? typeof baseClass === "function" ? new baseClass() : baseClass : new Class(); // set base object as prototype type.prototype.constructor = type; type.prototype = apply(type.prototype, members || {}); return apply(type, statics || {}); // return empty object with right [[Prototype]] } /** * Global namespace definition */ var $root = "System", System = $global[$root] || {'$global': $global}, $original = $global[$root]; var packageRegex = "[a-z_A-Z]\\w+(?:\\.@?[a-z_A-Z]\\w+)*"; var validIdientifierRegex = new RegExp("^@?" + packageRegex + "$"); var urlExp = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/; /** * Parent class for inheritance into the System. * @returns {Type} * @constructor */ function Type(/*[Origin]*/) { if (this.is(Type)) { var $type = arguments[0]; /** * Gets the Type instance type. * @returns {Object} */ this.getType = function () { return $type; } return this; } } /** * * @param prev * @param current * @returns {DynamicContainer} * @constructor */ function DynamicContainer(prev, current) { if (this.is(DynamicContainer)) { var context = this; /** * * @param curr * @returns {DynamicContainer} */ this.updateCurrent = function (curr) { prev = current; current = curr; return context; } /** * * @returns {*} */ this.getCurrent = function () { return current; } /** * * @returns {*} */ this.getPrev = function () { return prev; } return this; } } /** * @param name * @param container * @returns {Member} * @constructor */ function Member(/*[Type]*/) { if (is(this, Member)) { var context = this, name = arguments[0], container = arguments[1], $type = arguments[2]; Type.call(this, $type || Member); /** * Gets the Member instance name; * @returns {String} */ this.getName = function () { return name; } /** * Gets the Member instance context. This method is suitable to be overwrote in inherited members. */ this.getContext = function () { return context; } /** * @protected * @returns {Object/Function} */ this.getParent = function () { var cont = container; if (cont && !is(cont, Member)) { cont = new OutsiderContainer(cont); } return cont; } /** * Gets the Member instance container. * @returns {Object/Function} */ this.getContainer = function () { var cont = this.getParent(); if (cont) { if (is(cont, DynamicContainer)) { cont = cont.getCurrent(); } else if (is(cont, OutsiderContainer)) { cont = cont.getContext(); } } return cont; } /** * Gets the Member instance's full path_module String. * @returns {String} */ this.getFullPath = function () { // global.A.B.C; A.B.C var path = ""; var cont = this.getContainer(); while (cont && is(cont, Member) && !is(cont, OutsiderContainer)) { path = cont.getName() + "." + path; cont = cont.getContainer(); } return path + this.getName(); } return this; } } define(Member, Type, { 'getMember': function (member) { // if(typeof member !== 'string' && // !Core.RegExp.Identifier.test(member)) // throw new Error("[InvalidArgumentException]"); return this.getContext()[member]; }, 'hasMember': function (member) { return this.getMember(member) != undefined; }, 'addMember': function (member) { if (member.is(Member)) { // Get the current container instance return this.getContext()[member.getName()] = Member.updateParent(member, this); } throw new System.exception.InvalidTypeException("The supplied object must be a instance"); }, 'removeMember': function (member) { if (member.is(Member)) { var m = this.getContext()[member.getName()]; if (m) { try { delete this.getContext()[member.getName()]; } catch (error) { this.getContext()[member.getName()] = undefined; } return Member.updateParent(m); } } throw new System.exception.InvalidArgumentsException("The supplied object must be a Member instance"); } }, { 'BuilderTemp': function BuilderTemp() { if (this.is(Member.BuilderTemp)) { this.onBuild = function () { }; } }, 'updateParent': function (member, current) { if (member.is(Member)) { var container = member.getContainer(), parent = typeof (container) == "undefined" || !container.is(DynamicContainer) ? new DynamicContainer(container, current) : container.updateCurrent(current); member.getParent = function () { return parent; } return member; } throw new System.exception.InvalidArgumentsException("The supplied object must be a Member instance"); }, 'register': function (member) { if (member.is(Member)) { return Loader.register(member.getFullPath(), member); } throw new System.exception.InvalidArgumentsException("The supplied object must be a Member instance"); } }); function OutsiderContainer(/*[Member]*/) { if (this.is(OutsiderContainer)) { var self = arguments[0]; Member.call(this, ""); this.getContext = function () { return self; } } } define(OutsiderContainer, Member); /** * The Namespace method can be used either to get a Namespace instance or to define a namespace object and attach inner members in it. * @param config String/Object * config object contains: * { * '$name': String, * '$container' : Object/Function // Specifies the container of the newly created Namespace instance, cannot be null, or undefined. Global is used by default. * } * @param member... If the Namespace is being instantiated, this argument could be the wrapper object which will contain the namespace instance. * Otherwise Member sequence, comma separated, which will represent the nested members of the current namespace. * @constructor */ function Namespace(/*[Member]*/) { if (arguments.length > 0) { var config = {}, cfx = arguments[0]; if (cfx != null && cfx != undefined) { // Check if not null or undefined // Extract the configurations for create the namespace if ir doesn't exist. if (isString(cfx)) { config['$name'] = cfx; } else if (isObject(cfx)) { config = cfx; } else throw new System.exception.InvalidTypeException("The first argument must be either a [String/Object], but " + getClassName(cfx) + " was supplied instead"); if (!(validIdientifierRegex.test(config.$name))) throw new Exception("Invalid namespace identifier: '" + config.$name + "'", 'InvalidIdentifierException'); var container = config.$container || (CONFIG.GLOBAL || $global); if (is(this, Namespace)) { // Check if is instantiation if (arguments.length <= 2) { container = arguments[1] || container; var wrapper = Namespace.getLastNode(container, config.$name), name = config.$name.replace(wrapper.name, ""); var extract = new RegExp("^.*?(" + packageRegex + ")", "gm").exec(name); name = extract ? extract[1] : name; container = wrapper.container; if (name != "") { var nsparts = name.split("."); // loop through the parts and create a nested namespace if necessary do { name = nsparts.shift(); // check if the current parent already has the namespace declared // if it isn't, then create it if (nsparts.length == 0) break; container = container[name] = new Namespace(name, container); } while (nsparts.length > 0) // Call the super for initialization Member.call(this, name, container, Namespace); /** * @override * @param member */ this.addMember = function (member) { return Member.register(Member.prototype.addMember.call(this, member)); } return container[name] = this; } return container; } throw new System.exception.InvalidArgumentsException("Invalid arguments number, expected no more than 2.") } else { var ns; if (!Namespace.contains(container, config.$name)) { ns = new Namespace(config.$name, container); } else { var node = Namespace.getLastNode(container, config.$name); if (node && ("container" in node)) ns = node["container"]; } if (ns) { function updateContainer(member, ns) { if (member && member.is(Member)) { Loader.unregister(member.getFullPath()); var cont = member.getContainer(); if (cont && cont.is(Member)) cont.removeMember(member); ns.addMember(member); } } Array.prototype.slice.call(arguments, 1, arguments.length).each(function (arg) { if (arg && arg.is(Member.BuilderTemp)) { arg.onBuild = function (member) { updateContainer(member, ns); } } else updateContainer(arg, ns); }); } return ns; } } } throw new System.exception.InvalidArgumentsException("The first argument must be specified"); } define(Namespace, Member, undefined, { 'contains': function (container, ns) { return Namespace.getLastNode(container, ns)['name'] == ns; }, 'getLastNode': function (container, ns) { if (!(ns && typeof ns === 'string') || !(container && typeof container === 'object' || typeof container === 'function')) throw new System.exception.InvalidArgumentsException("Expected types (String, [Object | Function]) to search into namespace."); if (!(validIdientifierRegex.test(ns))) { throw new Exception("Invalid namespace: '" + ns + "'", 'InvalidClassNameException'); } var nsparts = ns.split("."), result = {'name': "", 'container': container}, first = true; // loop through the parts and create a nested namespace if necessary while (nsparts.length > 0) { var node = nsparts.shift(); // check if the current parent already has the namespace declared // if it isn't, then create it if (node in container && container[node]) { result['container'] = container = container[node]; result['name'] += first ? node : "." + node; } else break; first = false; } return result; } }); function Loader() { } var map = {}; function DependencyRequest(name, module) { if (this.is(DependencyRequest)) { this.module = module; this.name = name; this.loaded = false; this.isSuccess = function () { return module && !is(module, Error); } } } var extractorRegex = new RegExp("^:([a-z][a-z_-]*)+:{0,1}(" + packageRegex + ")*$", "gm"); define(Loader, Function, undefined, { 'isAutoLoadDisabled': true, 'loaders': { "values": { // Platform "values": [] // Client } }, 'unresolved': [], 'using': function (dependency, callback) { if (dependency) { dependency = dependency.is(String) ? [dependency] : dependency; var requests = [], caller = arguments.callee.caller, async = false; dependency.each(function (dep, i) { var pkg, extract = extractorRegex.exec(dep); if (extract) { pkg = extract[1]; if (extract[2]) { dependency[i] = dep = extract[2]; } else { dependency.remove(i); } } else if (!urlExp.test(dep) && !validIdientifierRegex.test(dep)) { throw new System.exception.RuntimeException("Invalid dependency provided to load, was '" + dep + "'"); } if (dep in map) { if (requests.indexOf(map[dep]) == -1) { requests[i] = map[dep]; } } else if (pkg) { Loader.unresolved.push({ 'member': dep, 'pkg': pkg }); } else if (Loader.unresolved.indexOf(dep) == -1) { Loader.unresolved.push(dep); } }); if (Loader.unresolved.length > 0) { if (callback && isFunction(callback)) { async = true; Loader.observe(dependency, function onObserve() { if (isString(dependency)) { Loader.unresolved.remove(dependency); if (requests.indexOf(map[dependency]) == -1) requests.push(map[dependency]) } else if (isArray(dependency)) { dependency.each(function (dep, i) { Loader.unresolved.remove(dep); if (requests.indexOf(map[dep]) == -1) requests[i] = map[dep]; }) } try { return callback.apply(caller, requests); } catch (e) { throw new System.exception.RuntimeException("Execution failed during callback " + (e ? "because of: <" + e.message + ">" : "")); } }); } function identify(mods) { if (mods) { if (mods.is(Array)) { mods.each(function (module) { identify(module); }); } else { if (mods.isSuccess()) { var classpath = mods.name, module = mods.module, member; // var index = unresolved.indexOf(name); if (classpath in map) { member = map[classpath]; } else if (mods.loaded) { member = module; Loader.notify(classpath); } Loader.unresolved.remove(classpath); if (requests.indexOf(map[classpath]) == -1) requests[dependency.indexOf(classpath)] = member; } } } } function onload(modules) { return identify(modules); } var modules = Loader.load(Loader.unresolved, onload, async); identify(modules); } return dependency.length == 1 && requests.length == 1 ? requests[0] : undefined; } }, 'load': function load(deps, callback, async) { if (!Loader.isAutoLoadDisabled) { var info = Environment.getInfo(), loader; loader = Loader.getLoader(info) || Loader.getSystemLoader(); return loader ? loader.load(deps, callback, async) : undefined; } }, 'observers': { 'add': function add(index, observer) { if (!(index in this)) this[index] = []; if (this[index].indexOf(observer) == -1) this[index].push(observer); return observer; }, 'remove': function (index) { var dep = this[index]; if (dep) { try { delete this[index]; } catch (e) { this[index] = undefined; } return dep; } } }, /** * * @param dependency * @param callback * @returns {DependencyObserver} * @constructor */ 'DependencyObserver': function DependencyObserver(dependency, callback) { if (dependency && isFunction(callback)) { if (is(this, Loader.DependencyObserver)) { var context = this, deps = [], loadedDeps = []; /** * */ this.onLoaded = function (loaded, object) { var i = deps.indexOf(loaded); if (i != -1) { deps.remove(i); loadedDeps[i + 1] = object; } if (deps.length == 0) { callback.apply(callback, loadedDeps); } } if (isString(dependency)) { if (!map[dependency]) { deps.push(dependency); return Loader.observers.add(dependency, this); } } else if (isArray(dependency)) { each(dependency, function (dep) { if (!map[dep]) { deps.push(dep); Loader.observers.add(dep, context); } }); return this; } } } // throw new System.exception.InvalidArgumentsException("Invalid arguments supplied, expected (String/String[], Function)"); }, /** * * @param dependency * @param callback */ 'observe': function (dependency, callback) { if (dependency && callback && isFunction(callback)) { return new Loader.DependencyObserver(dependency, callback); } throw new System.exception.InvalidArgumentsException("Invalid arguments supplied, expected (String/String[], Function)"); }, 'notify': function (dependency) { if (dependency && isString(dependency)) { var observers = Loader.observers.remove(dependency); each(observers, function (observer) { if (observer.is(Loader.DependencyObserver)) { observer.onLoaded(dependency, map[dependency]); } }); return; } throw new System.exception.InvalidArgumentsException("Invalid arguments supplied, expected (String)"); }, 'register': function (classPath, object) { if (classPath && isString(classPath) && object && (isObject(object) || isFunction(object))) { var target = map[classPath] = object; Loader.unresolved.remove(classPath); Loader.notify(classPath); return target; } throw new System.exception.InvalidArgumentsException("Invalid arguments supplied, expected (String, Object/Function)"); }, 'unregister': function (classPath) { if (classPath && isString(classPath)) { var target = map[classPath]; try { delete map[classPath]; } catch (e) { map[classPath] = undefined; } return target; } throw new System.exception.InvalidArgumentsException("Invalid arguments supplied, expected (String, Object/Function)"); }, 'disableAutoLoad': function (disable) { Loader.isAutoLoadDisabled = disable === true; }, 'getLoader': function (descriptor) { if (descriptor && isObject(descriptor)) { var loader = Loader.loaders[descr