UNPKG

contracts-js

Version:

A contract library for JavaScript

1,824 lines (1,463 loc) 1.27 MB
/*! * @overview Ember - JavaScript Application Framework * @copyright Copyright 2011-2014 Tilde Inc. and contributors * Portions Copyright 2006-2011 Strobe Inc. * Portions Copyright 2008-2011 Apple Inc. All rights reserved. * @license Licensed under MIT license * See https://raw.github.com/emberjs/ember.js/master/LICENSE * @version 1.5.1 */ (function() { /*global __fail__*/ /** Ember Debug @module ember @submodule ember-debug */ /** @class Ember */ if ('undefined' === typeof Ember) { Ember = {}; if ('undefined' !== typeof window) { window.Em = window.Ember = Em = Ember; } } // This needs to be kept in sync with the logic in // `packages/ember-metal/lib/core.js`. // // This is duplicated here to ensure that `Ember.ENV` // is setup even if `Ember` is not loaded yet. if (Ember.ENV) { // do nothing if Ember.ENV is already setup } else if ('undefined' !== typeof EmberENV) { Ember.ENV = EmberENV; } else if('undefined' !== typeof ENV) { Ember.ENV = ENV; } else { Ember.ENV = {}; } if (!('MANDATORY_SETTER' in Ember.ENV)) { Ember.ENV.MANDATORY_SETTER = true; // default to true for debug dist } /** Define an assertion that will throw an exception if the condition is not met. Ember build tools will remove any calls to `Ember.assert()` when doing a production build. Example: ```javascript // Test for truthiness Ember.assert('Must pass a valid object', obj); // Fail unconditionally Ember.assert('This code path should never be run') ``` @method assert @param {String} desc A description of the assertion. This will become the text of the Error thrown if the assertion fails. @param {Boolean} test Must be truthy for the assertion to pass. If falsy, an exception will be thrown. */ Ember.assert = function(desc, test) { if (!test) { throw new Ember.Error("Assertion Failed: " + desc); } }; /** Display a warning with the provided message. Ember build tools will remove any calls to `Ember.warn()` when doing a production build. @method warn @param {String} message A warning to display. @param {Boolean} test An optional boolean. If falsy, the warning will be displayed. */ Ember.warn = function(message, test) { if (!test) { Ember.Logger.warn("WARNING: "+message); if ('trace' in Ember.Logger) Ember.Logger.trace(); } }; /** Display a debug notice. Ember build tools will remove any calls to `Ember.debug()` when doing a production build. ```javascript Ember.debug("I'm a debug notice!"); ``` @method debug @param {String} message A debug message to display. */ Ember.debug = function(message) { Ember.Logger.debug("DEBUG: "+message); }; /** Display a deprecation warning with the provided message and a stack trace (Chrome and Firefox only). Ember build tools will remove any calls to `Ember.deprecate()` when doing a production build. @method deprecate @param {String} message A description of the deprecation. @param {Boolean} test An optional boolean. If falsy, the deprecation will be displayed. */ Ember.deprecate = function(message, test) { if (test) { return; } if (Ember.ENV.RAISE_ON_DEPRECATION) { throw new Ember.Error(message); } var error; // When using new Error, we can't do the arguments check for Chrome. Alternatives are welcome try { __fail__.fail(); } catch (e) { error = e; } if (Ember.LOG_STACKTRACE_ON_DEPRECATION && error.stack) { var stack, stackStr = ''; if (error['arguments']) { // Chrome stack = error.stack.replace(/^\s+at\s+/gm, ''). replace(/^([^\(]+?)([\n$])/gm, '{anonymous}($1)$2'). replace(/^Object.<anonymous>\s*\(([^\)]+)\)/gm, '{anonymous}($1)').split('\n'); stack.shift(); } else { // Firefox stack = error.stack.replace(/(?:\n@:0)?\s+$/m, ''). replace(/^\(/gm, '{anonymous}(').split('\n'); } stackStr = "\n " + stack.slice(2).join("\n "); message = message + stackStr; } Ember.Logger.warn("DEPRECATION: "+message); }; /** Alias an old, deprecated method with its new counterpart. Display a deprecation warning with the provided message and a stack trace (Chrome and Firefox only) when the assigned method is called. Ember build tools will not remove calls to `Ember.deprecateFunc()`, though no warnings will be shown in production. ```javascript Ember.oldMethod = Ember.deprecateFunc("Please use the new, updated method", Ember.newMethod); ``` @method deprecateFunc @param {String} message A description of the deprecation. @param {Function} func The new function called to replace its deprecated counterpart. @return {Function} a new function that wrapped the original function with a deprecation warning */ Ember.deprecateFunc = function(message, func) { return function() { Ember.deprecate(message); return func.apply(this, arguments); }; }; /** Run a function meant for debugging. Ember build tools will remove any calls to `Ember.runInDebug()` when doing a production build. ```javascript Ember.runInDebug( function() { Ember.Handlebars.EachView.reopen({ didInsertElement: function() { console.log("I'm happy"); } }); }); ``` @method runInDebug @param {Function} func The function to be executed. */ Ember.runInDebug = function(func) { func() }; // Inform the developer about the Ember Inspector if not installed. if (!Ember.testing) { var isFirefox = typeof InstallTrigger !== 'undefined'; var isChrome = !!window.chrome && !window.opera; if (typeof window !== 'undefined' && (isFirefox || isChrome) && window.addEventListener) { window.addEventListener("load", function() { if (document.documentElement && document.documentElement.dataset && !document.documentElement.dataset.emberExtension) { var downloadURL; if(isChrome) { downloadURL = 'https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi'; } else if(isFirefox) { downloadURL = 'https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/'; } Ember.debug('For more advanced debugging, install the Ember Inspector from ' + downloadURL); } }, false); } } })(); /*! * @overview Ember - JavaScript Application Framework * @copyright Copyright 2011-2014 Tilde Inc. and contributors * Portions Copyright 2006-2011 Strobe Inc. * Portions Copyright 2008-2011 Apple Inc. All rights reserved. * @license Licensed under MIT license * See https://raw.github.com/emberjs/ember.js/master/LICENSE * @version 1.5.1 */ (function() { var define, requireModule, require, requirejs; (function() { var registry = {}, seen = {}; define = function(name, deps, callback) { registry[name] = { deps: deps, callback: callback }; }; requirejs = require = requireModule = function(name) { requirejs._eak_seen = registry; if (seen[name]) { return seen[name]; } seen[name] = {}; if (!registry[name]) { throw new Error("Could not find module " + name); } var mod = registry[name], deps = mod.deps, callback = mod.callback, reified = [], exports; for (var i=0, l=deps.length; i<l; i++) { if (deps[i] === 'exports') { reified.push(exports = {}); } else { reified.push(requireModule(resolve(deps[i]))); } } var value = callback.apply(this, reified); return seen[name] = exports || value; function resolve(child) { if (child.charAt(0) !== '.') { return child; } var parts = child.split("/"); var parentBase = name.split("/").slice(0, -1); for (var i=0, l=parts.length; i<l; i++) { var part = parts[i]; if (part === '..') { parentBase.pop(); } else if (part === '.') { continue; } else { parentBase.push(part); } } return parentBase.join("/"); } }; })(); (function() { /*globals Em:true ENV EmberENV MetamorphENV:true */ /** @module ember @submodule ember-metal */ /** All Ember methods and functions are defined inside of this namespace. You generally should not add new properties to this namespace as it may be overwritten by future versions of Ember. You can also use the shorthand `Em` instead of `Ember`. Ember-Runtime is a framework that provides core functions for Ember including cross-platform functions, support for property observing and objects. Its focus is on small size and performance. You can use this in place of or along-side other cross-platform libraries such as jQuery. The core Runtime framework is based on the jQuery API with a number of performance optimizations. @class Ember @static @version 1.5.1 */ if ('undefined' === typeof Ember) { // Create core object. Make it act like an instance of Ember.Namespace so that // objects assigned to it are given a sane string representation. Ember = {}; } // Default imports, exports and lookup to the global object; var imports = Ember.imports = Ember.imports || this; var exports = Ember.exports = Ember.exports || this; var lookup = Ember.lookup = Ember.lookup || this; // aliases needed to keep minifiers from removing the global context exports.Em = exports.Ember = Em = Ember; // Make sure these are set whether Ember was already defined or not Ember.isNamespace = true; Ember.toString = function() { return "Ember"; }; /** @property VERSION @type String @default '1.5.1' @static */ Ember.VERSION = '1.5.1'; /** Standard environmental variables. You can define these in a global `EmberENV` variable before loading Ember to control various configuration settings. For backwards compatibility with earlier versions of Ember the global `ENV` variable will be used if `EmberENV` is not defined. @property ENV @type Hash */ // This needs to be kept in sync with the logic in // `packages/ember-debug/lib/main.js`. if (Ember.ENV) { // do nothing if Ember.ENV is already setup } else if ('undefined' !== typeof EmberENV) { Ember.ENV = EmberENV; } else if('undefined' !== typeof ENV) { Ember.ENV = ENV; } else { Ember.ENV = {}; } Ember.config = Ember.config || {}; // We disable the RANGE API by default for performance reasons if ('undefined' === typeof Ember.ENV.DISABLE_RANGE_API) { Ember.ENV.DISABLE_RANGE_API = true; } if ("undefined" === typeof MetamorphENV) { exports.MetamorphENV = {}; } MetamorphENV.DISABLE_RANGE_API = Ember.ENV.DISABLE_RANGE_API; /** Hash of enabled Canary features. Add to before creating your application. You can also define `ENV.FEATURES` if you need to enable features flagged at runtime. @property FEATURES @type Hash */ Ember.FEATURES = Ember.ENV.FEATURES || {}; /** Test that a feature is enabled. Parsed by Ember's build tools to leave experimental features out of beta/stable builds. You can define the following configuration options: * `ENV.ENABLE_ALL_FEATURES` - force all features to be enabled. * `ENV.ENABLE_OPTIONAL_FEATURES` - enable any features that have not been explicitly enabled/disabled. @method isEnabled @param {string} feature */ Ember.FEATURES.isEnabled = function(feature) { var featureValue = Ember.FEATURES[feature]; if (Ember.ENV.ENABLE_ALL_FEATURES) { return true; } else if (featureValue === true || featureValue === false || featureValue === undefined) { return featureValue; } else if (Ember.ENV.ENABLE_OPTIONAL_FEATURES) { return true; } else { return false; } }; // .......................................................... // BOOTSTRAP // /** Determines whether Ember should enhances some built-in object prototypes to provide a more friendly API. If enabled, a few methods will be added to `Function`, `String`, and `Array`. `Object.prototype` will not be enhanced, which is the one that causes most trouble for people. In general we recommend leaving this option set to true since it rarely conflicts with other code. If you need to turn it off however, you can define an `ENV.EXTEND_PROTOTYPES` config to disable it. @property EXTEND_PROTOTYPES @type Boolean @default true */ Ember.EXTEND_PROTOTYPES = Ember.ENV.EXTEND_PROTOTYPES; if (typeof Ember.EXTEND_PROTOTYPES === 'undefined') { Ember.EXTEND_PROTOTYPES = true; } /** Determines whether Ember logs a full stack trace during deprecation warnings @property LOG_STACKTRACE_ON_DEPRECATION @type Boolean @default true */ Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !== false); /** Determines whether Ember should add ECMAScript 5 shims to older browsers. @property SHIM_ES5 @type Boolean @default Ember.EXTEND_PROTOTYPES */ Ember.SHIM_ES5 = (Ember.ENV.SHIM_ES5 === false) ? false : Ember.EXTEND_PROTOTYPES; /** Determines whether Ember logs info about version of used libraries @property LOG_VERSION @type Boolean @default true */ Ember.LOG_VERSION = (Ember.ENV.LOG_VERSION === false) ? false : true; /** Empty function. Useful for some operations. Always returns `this`. @method K @private @return {Object} */ Ember.K = function() { return this; }; // Stub out the methods defined by the ember-debug package in case it's not loaded if ('undefined' === typeof Ember.assert) { Ember.assert = Ember.K; } if ('undefined' === typeof Ember.warn) { Ember.warn = Ember.K; } if ('undefined' === typeof Ember.debug) { Ember.debug = Ember.K; } if ('undefined' === typeof Ember.runInDebug) { Ember.runInDebug = Ember.K; } if ('undefined' === typeof Ember.deprecate) { Ember.deprecate = Ember.K; } if ('undefined' === typeof Ember.deprecateFunc) { Ember.deprecateFunc = function(_, func) { return func; }; } /** Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from jQuery master. We'll just bootstrap our own uuid now. @property uuid @type Number @private */ Ember.uuid = 0; /** Merge the contents of two objects together into the first object. ```javascript Ember.merge({first: 'Tom'}, {last: 'Dale'}); // {first: 'Tom', last: 'Dale'} var a = {first: 'Yehuda'}, b = {last: 'Katz'}; Ember.merge(a, b); // a == {first: 'Yehuda', last: 'Katz'}, b == {last: 'Katz'} ``` @method merge @for Ember @param {Object} original The object to merge into @param {Object} updates The object to copy properties from @return {Object} */ Ember.merge = function(original, updates) { for (var prop in updates) { if (!updates.hasOwnProperty(prop)) { continue; } original[prop] = updates[prop]; } return original; }; /** Returns true if the passed value is null or undefined. This avoids errors from JSLint complaining about use of ==, which can be technically confusing. ```javascript Ember.isNone(); // true Ember.isNone(null); // true Ember.isNone(undefined); // true Ember.isNone(''); // false Ember.isNone([]); // false Ember.isNone(function() {}); // false ``` @method isNone @for Ember @param {Object} obj Value to test @return {Boolean} */ Ember.isNone = function(obj) { return obj === null || obj === undefined; }; Ember.none = Ember.deprecateFunc("Ember.none is deprecated. Please use Ember.isNone instead.", Ember.isNone); /** Verifies that a value is `null` or an empty string, empty array, or empty function. Constrains the rules on `Ember.isNone` by returning false for empty string and empty arrays. ```javascript Ember.isEmpty(); // true Ember.isEmpty(null); // true Ember.isEmpty(undefined); // true Ember.isEmpty(''); // true Ember.isEmpty([]); // true Ember.isEmpty('Adam Hawkins'); // false Ember.isEmpty([0,1,2]); // false ``` @method isEmpty @for Ember @param {Object} obj Value to test @return {Boolean} */ Ember.isEmpty = function(obj) { return Ember.isNone(obj) || (obj.length === 0 && typeof obj !== 'function') || (typeof obj === 'object' && Ember.get(obj, 'length') === 0); }; Ember.empty = Ember.deprecateFunc("Ember.empty is deprecated. Please use Ember.isEmpty instead.", Ember.isEmpty); /** A value is blank if it is empty or a whitespace string. ```javascript Ember.isBlank(); // true Ember.isBlank(null); // true Ember.isBlank(undefined); // true Ember.isBlank(''); // true Ember.isBlank([]); // true Ember.isBlank('\n\t'); // true Ember.isBlank(' '); // true Ember.isBlank({}); // false Ember.isBlank('\n\t Hello'); // false Ember.isBlank('Hello world'); // false Ember.isBlank([1,2,3]); // false ``` @method isBlank @for Ember @param {Object} obj Value to test @return {Boolean} */ Ember.isBlank = function(obj) { return Ember.isEmpty(obj) || (typeof obj === 'string' && obj.match(/\S/) === null); }; })(); (function() { /*globals Node */ /** @module ember-metal */ /** Platform specific methods and feature detectors needed by the framework. @class platform @namespace Ember @static */ var platform = Ember.platform = {}; /** Identical to `Object.create()`. Implements if not available natively. @method create @for Ember */ Ember.create = Object.create; // IE8 has Object.create but it couldn't treat property descriptors. if (Ember.create) { if (Ember.create({a: 1}, {a: {value: 2}}).a !== 2) { Ember.create = null; } } // STUB_OBJECT_CREATE allows us to override other libraries that stub // Object.create different than we would prefer if (!Ember.create || Ember.ENV.STUB_OBJECT_CREATE) { var K = function() {}; Ember.create = function(obj, props) { K.prototype = obj; obj = new K(); if (props) { K.prototype = obj; for (var prop in props) { K.prototype[prop] = props[prop].value; } obj = new K(); } K.prototype = null; return obj; }; Ember.create.isSimulated = true; } var defineProperty = Object.defineProperty; var canRedefineProperties, canDefinePropertyOnDOM; // Catch IE8 where Object.defineProperty exists but only works on DOM elements if (defineProperty) { try { defineProperty({}, 'a',{get:function() {}}); } catch (e) { defineProperty = null; } } if (defineProperty) { // Detects a bug in Android <3.2 where you cannot redefine a property using // Object.defineProperty once accessors have already been set. canRedefineProperties = (function() { var obj = {}; defineProperty(obj, 'a', { configurable: true, enumerable: true, get: function() { }, set: function() { } }); defineProperty(obj, 'a', { configurable: true, enumerable: true, writable: true, value: true }); return obj.a === true; })(); // This is for Safari 5.0, which supports Object.defineProperty, but not // on DOM nodes. canDefinePropertyOnDOM = (function() { try { defineProperty(document.createElement('div'), 'definePropertyOnDOM', {}); return true; } catch(e) { } return false; })(); if (!canRedefineProperties) { defineProperty = null; } else if (!canDefinePropertyOnDOM) { defineProperty = function(obj, keyName, desc) { var isNode; if (typeof Node === "object") { isNode = obj instanceof Node; } else { isNode = typeof obj === "object" && typeof obj.nodeType === "number" && typeof obj.nodeName === "string"; } if (isNode) { // TODO: Should we have a warning here? return (obj[keyName] = desc.value); } else { return Object.defineProperty(obj, keyName, desc); } }; } } /** @class platform @namespace Ember */ /** Identical to `Object.defineProperty()`. Implements as much functionality as possible if not available natively. @method defineProperty @param {Object} obj The object to modify @param {String} keyName property name to modify @param {Object} desc descriptor hash @return {void} */ platform.defineProperty = defineProperty; /** Set to true if the platform supports native getters and setters. @property hasPropertyAccessors @final */ platform.hasPropertyAccessors = true; if (!platform.defineProperty) { platform.hasPropertyAccessors = false; platform.defineProperty = function(obj, keyName, desc) { if (!desc.get) { obj[keyName] = desc.value; } }; platform.defineProperty.isSimulated = true; } if (Ember.ENV.MANDATORY_SETTER && !platform.hasPropertyAccessors) { Ember.ENV.MANDATORY_SETTER = false; } })(); (function() { /*jshint newcap:false*/ /** @module ember-metal */ // NOTE: There is a bug in jshint that doesn't recognize `Object()` without `new` // as being ok unless both `newcap:false` and not `use strict`. // https://github.com/jshint/jshint/issues/392 // Testing this is not ideal, but we want to use native functions // if available, but not to use versions created by libraries like Prototype var isNativeFunc = function(func) { // This should probably work in all browsers likely to have ES5 array methods return func && Function.prototype.toString.call(func).indexOf('[native code]') > -1; }; // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/map var arrayMap = isNativeFunc(Array.prototype.map) ? Array.prototype.map : function(fun /*, thisp */) { //"use strict"; if (this === void 0 || this === null) { throw new TypeError(); } var t = Object(this); var len = t.length >>> 0; if (typeof fun !== "function") { throw new TypeError(); } var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in t) { res[i] = fun.call(thisp, t[i], i, t); } } return res; }; // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/foreach var arrayForEach = isNativeFunc(Array.prototype.forEach) ? Array.prototype.forEach : function(fun /*, thisp */) { //"use strict"; if (this === void 0 || this === null) { throw new TypeError(); } var t = Object(this); var len = t.length >>> 0; if (typeof fun !== "function") { throw new TypeError(); } var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in t) { fun.call(thisp, t[i], i, t); } } }; var arrayIndexOf = isNativeFunc(Array.prototype.indexOf) ? Array.prototype.indexOf : function (obj, fromIndex) { if (fromIndex === null || fromIndex === undefined) { fromIndex = 0; } else if (fromIndex < 0) { fromIndex = Math.max(0, this.length + fromIndex); } for (var i = fromIndex, j = this.length; i < j; i++) { if (this[i] === obj) { return i; } } return -1; }; var arrayFilter = isNativeFunc(Array.prototype.filter) ? Array.prototype.filter : function (fn, context) { var i, value, result = [], length = this.length; for (i = 0; i < length; i++) { if (this.hasOwnProperty(i)) { value = this[i]; if (fn.call(context, value, i, this)) { result.push(value); } } } return result; }; /** Array polyfills to support ES5 features in older browsers. @namespace Ember @property ArrayPolyfills */ Ember.ArrayPolyfills = { map: arrayMap, forEach: arrayForEach, filter: arrayFilter, indexOf: arrayIndexOf }; if (Ember.SHIM_ES5) { if (!Array.prototype.map) { Array.prototype.map = arrayMap; } if (!Array.prototype.forEach) { Array.prototype.forEach = arrayForEach; } if (!Array.prototype.filter) { Array.prototype.filter = arrayFilter; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = arrayIndexOf; } } })(); (function() { var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; /** A subclass of the JavaScript Error object for use in Ember. @class Error @namespace Ember @extends Error @constructor */ Ember.Error = function() { var tmp = Error.apply(this, arguments); // Adds a `stack` property to the given error object that will yield the // stack trace at the time captureStackTrace was called. // When collecting the stack trace all frames above the topmost call // to this function, including that call, will be left out of the // stack trace. // This is useful because we can hide Ember implementation details // that are not very helpful for the user. if (Error.captureStackTrace) { Error.captureStackTrace(this, Ember.Error); } // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. for (var idx = 0; idx < errorProps.length; idx++) { this[errorProps[idx]] = tmp[errorProps[idx]]; } }; Ember.Error.prototype = Ember.create(Error.prototype); // .......................................................... // ERROR HANDLING // /** A function may be assigned to `Ember.onerror` to be called when Ember internals encounter an error. This is useful for specialized error handling and reporting code. ```javascript Ember.onerror = function(error) { Em.$.ajax('/report-error', 'POST', { stack: error.stack, otherInformation: 'whatever app state you want to provide' }); }; ``` @event onerror @for Ember @param {Exception} error the error object */ Ember.onerror = null; })(); (function() { /** @module ember-metal */ /** Prefix used for guids through out Ember. @private */ Ember.GUID_PREFIX = 'ember'; var o_defineProperty = Ember.platform.defineProperty, o_create = Ember.create, // Used for guid generation... GUID_KEY = '__ember'+ (+ new Date()), numberCache = [], stringCache = {}, uuid = 0; var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER; /** A unique key used to assign guids and other private metadata to objects. If you inspect an object in your browser debugger you will often see these. They can be safely ignored. On browsers that support it, these properties are added with enumeration disabled so they won't show up when you iterate over your properties. @private @property GUID_KEY @for Ember @type String @final */ Ember.GUID_KEY = GUID_KEY; var GUID_DESC = { writable: false, configurable: false, enumerable: false, value: null }; /** Generates a new guid, optionally saving the guid to the object that you pass in. You will rarely need to use this method. Instead you should call `Ember.guidFor(obj)`, which return an existing guid if available. @private @method generateGuid @for Ember @param {Object} [obj] Object the guid will be used for. If passed in, the guid will be saved on the object and reused whenever you pass the same object again. If no object is passed, just generate a new guid. @param {String} [prefix] Prefix to place in front of the guid. Useful when you want to separate the guid into separate namespaces. @return {String} the guid */ Ember.generateGuid = function generateGuid(obj, prefix) { if (!prefix) prefix = Ember.GUID_PREFIX; var ret = (prefix + (uuid++)); if (obj) { if (obj[GUID_KEY] === null) { obj[GUID_KEY] = ret; } else { GUID_DESC.value = ret; o_defineProperty(obj, GUID_KEY, GUID_DESC); } } return ret; }; /** Returns a unique id for the object. If the object does not yet have a guid, one will be assigned to it. You can call this on any object, `Ember.Object`-based or not, but be aware that it will add a `_guid` property. You can also use this method on DOM Element objects. @private @method guidFor @for Ember @param {Object} obj any object, string, number, Element, or primitive @return {String} the unique guid for this instance. */ Ember.guidFor = function guidFor(obj) { // special cases where we don't want to add a key to object if (obj === undefined) return "(undefined)"; if (obj === null) return "(null)"; var ret; var type = typeof obj; // Don't allow prototype changes to String etc. to change the guidFor switch(type) { case 'number': ret = numberCache[obj]; if (!ret) ret = numberCache[obj] = 'nu'+obj; return ret; case 'string': ret = stringCache[obj]; if (!ret) ret = stringCache[obj] = 'st'+(uuid++); return ret; case 'boolean': return obj ? '(true)' : '(false)'; default: if (obj[GUID_KEY]) return obj[GUID_KEY]; if (obj === Object) return '(Object)'; if (obj === Array) return '(Array)'; ret = 'ember' + (uuid++); if (obj[GUID_KEY] === null) { obj[GUID_KEY] = ret; } else { GUID_DESC.value = ret; o_defineProperty(obj, GUID_KEY, GUID_DESC); } return ret; } }; // .......................................................... // META // var META_DESC = Ember.META_DESC = { writable: true, configurable: false, enumerable: false, value: null }; var META_KEY = Ember.GUID_KEY+'_meta'; /** The key used to store meta information on object for property observing. @property META_KEY @for Ember @private @final @type String */ Ember.META_KEY = META_KEY; var isDefinePropertySimulated = Ember.platform.defineProperty.isSimulated; function Meta(obj) { this.descs = {}; this.watching = {}; this.cache = {}; this.cacheMeta = {}; this.source = obj; } Meta.prototype = { descs: null, deps: null, watching: null, listeners: null, cache: null, cacheMeta: null, source: null, mixins: null, bindings: null, chains: null, chainWatchers: null, values: null, proto: null }; if (isDefinePropertySimulated) { // on platforms that don't support enumerable false // make meta fail jQuery.isPlainObject() to hide from // jQuery.extend() by having a property that fails // hasOwnProperty check. Meta.prototype.__preventPlainObject__ = true; // Without non-enumerable properties, meta objects will be output in JSON // unless explicitly suppressed Meta.prototype.toJSON = function () { }; } // Placeholder for non-writable metas. var EMPTY_META = new Meta(null); if (MANDATORY_SETTER) { EMPTY_META.values = {}; } Ember.EMPTY_META = EMPTY_META; /** Retrieves the meta hash for an object. If `writable` is true ensures the hash is writable for this object as well. The meta object contains information about computed property descriptors as well as any watched properties and other information. You generally will not access this information directly but instead work with higher level methods that manipulate this hash indirectly. @method meta @for Ember @private @param {Object} obj The object to retrieve meta for @param {Boolean} [writable=true] Pass `false` if you do not intend to modify the meta hash, allowing the method to avoid making an unnecessary copy. @return {Object} the meta hash for an object */ Ember.meta = function meta(obj, writable) { var ret = obj[META_KEY]; if (writable===false) return ret || EMPTY_META; if (!ret) { if (!isDefinePropertySimulated) o_defineProperty(obj, META_KEY, META_DESC); ret = new Meta(obj); if (MANDATORY_SETTER) { ret.values = {}; } obj[META_KEY] = ret; // make sure we don't accidentally try to create constructor like desc ret.descs.constructor = null; } else if (ret.source !== obj) { if (!isDefinePropertySimulated) o_defineProperty(obj, META_KEY, META_DESC); ret = o_create(ret); ret.descs = o_create(ret.descs); ret.watching = o_create(ret.watching); ret.cache = {}; ret.cacheMeta = {}; ret.source = obj; if (MANDATORY_SETTER) { ret.values = o_create(ret.values); } obj[META_KEY] = ret; } return ret; }; Ember.getMeta = function getMeta(obj, property) { var meta = Ember.meta(obj, false); return meta[property]; }; Ember.setMeta = function setMeta(obj, property, value) { var meta = Ember.meta(obj, true); meta[property] = value; return value; }; /** @deprecated @private In order to store defaults for a class, a prototype may need to create a default meta object, which will be inherited by any objects instantiated from the class's constructor. However, the properties of that meta object are only shallow-cloned, so if a property is a hash (like the event system's `listeners` hash), it will by default be shared across all instances of that class. This method allows extensions to deeply clone a series of nested hashes or other complex objects. For instance, the event system might pass `['listeners', 'foo:change', 'ember157']` to `prepareMetaPath`, which will walk down the keys provided. For each key, if the key does not exist, it is created. If it already exists and it was inherited from its constructor, the constructor's key is cloned. You can also pass false for `writable`, which will simply return undefined if `prepareMetaPath` discovers any part of the path that shared or undefined. @method metaPath @for Ember @param {Object} obj The object whose meta we are examining @param {Array} path An array of keys to walk down @param {Boolean} writable whether or not to create a new meta (or meta property) if one does not already exist or if it's shared with its constructor */ Ember.metaPath = function metaPath(obj, path, writable) { Ember.deprecate("Ember.metaPath is deprecated and will be removed from future releases."); var meta = Ember.meta(obj, writable), keyName, value; for (var i=0, l=path.length; i<l; i++) { keyName = path[i]; value = meta[keyName]; if (!value) { if (!writable) { return undefined; } value = meta[keyName] = { __ember_source__: obj }; } else if (value.__ember_source__ !== obj) { if (!writable) { return undefined; } value = meta[keyName] = o_create(value); value.__ember_source__ = obj; } meta = value; } return value; }; /** Wraps the passed function so that `this._super` will point to the superFunc when the function is invoked. This is the primitive we use to implement calls to super. @private @method wrap @for Ember @param {Function} func The function to call @param {Function} superFunc The super function. @return {Function} wrapped function. */ Ember.wrap = function(func, superFunc) { function superWrapper() { var ret, sup = this.__nextSuper; this.__nextSuper = superFunc; ret = func.apply(this, arguments); this.__nextSuper = sup; return ret; } superWrapper.wrappedFunction = func; superWrapper.__ember_observes__ = func.__ember_observes__; superWrapper.__ember_observesBefore__ = func.__ember_observesBefore__; superWrapper.__ember_listens__ = func.__ember_listens__; return superWrapper; }; /** Returns true if the passed object is an array or Array-like. Ember Array Protocol: - the object has an objectAt property - the object is a native Array - the object is an Object, and has a length property Unlike `Ember.typeOf` this method returns true even if the passed object is not formally array but appears to be array-like (i.e. implements `Ember.Array`) ```javascript Ember.isArray(); // false Ember.isArray([]); // true Ember.isArray( Ember.ArrayProxy.create({ content: [] }) ); // true ``` @method isArray @for Ember @param {Object} obj The object to test @return {Boolean} true if the passed object is an array or Array-like */ Ember.isArray = function(obj) { if (!obj || obj.setInterval) { return false; } if (Array.isArray && Array.isArray(obj)) { return true; } if (Ember.Array && Ember.Array.detect(obj)) { return true; } if ((obj.length !== undefined) && 'object'===typeof obj) { return true; } return false; }; /** Forces the passed object to be part of an array. If the object is already an array or array-like, returns the object. Otherwise adds the object to an array. If obj is `null` or `undefined`, returns an empty array. ```javascript Ember.makeArray(); // [] Ember.makeArray(null); // [] Ember.makeArray(undefined); // [] Ember.makeArray('lindsay'); // ['lindsay'] Ember.makeArray([1,2,42]); // [1,2,42] var controller = Ember.ArrayProxy.create({ content: [] }); Ember.makeArray(controller) === controller; // true ``` @method makeArray @for Ember @param {Object} obj the object @return {Array} */ Ember.makeArray = function(obj) { if (obj === null || obj === undefined) { return []; } return Ember.isArray(obj) ? obj : [obj]; }; function canInvoke(obj, methodName) { return !!(obj && typeof obj[methodName] === 'function'); } /** Checks to see if the `methodName` exists on the `obj`. ```javascript var foo = {bar: Ember.K, baz: null}; Ember.canInvoke(foo, 'bar'); // true Ember.canInvoke(foo, 'baz'); // false Ember.canInvoke(foo, 'bat'); // false ``` @method canInvoke @for Ember @param {Object} obj The object to check for the method @param {String} methodName The method name to check for @return {Boolean} */ Ember.canInvoke = canInvoke; /** Checks to see if the `methodName` exists on the `obj`, and if it does, invokes it with the arguments passed. ```javascript var d = new Date('03/15/2013'); Ember.tryInvoke(d, 'getTime'); // 1363320000000 Ember.tryInvoke(d, 'setFullYear', [2014]); // 1394856000000 Ember.tryInvoke(d, 'noSuchMethod', [2014]); // undefined ``` @method tryInvoke @for Ember @param {Object} obj The object to check for the method @param {String} methodName The method name to check for @param {Array} [args] The arguments to pass to the method @return {*} the return value of the invoked method or undefined if it cannot be invoked */ Ember.tryInvoke = function(obj, methodName, args) { if (canInvoke(obj, methodName)) { return obj[methodName].apply(obj, args || []); } }; // https://github.com/emberjs/ember.js/pull/1617 var needsFinallyFix = (function() { var count = 0; try{ try { } finally { count++; throw new Error('needsFinallyFixTest'); } } catch (e) {} return count !== 1; })(); /** Provides try { } finally { } functionality, while working around Safari's double finally bug. ```javascript var tryable = function() { someResource.lock(); runCallback(); // May throw error. }; var finalizer = function() { someResource.unlock(); }; Ember.tryFinally(tryable, finalizer); ``` @method tryFinally @for Ember @param {Function} tryable The function to run the try callback @param {Function} finalizer The function to run the finally callback @param {Object} [binding] The optional calling object. Defaults to 'this' @return {*} The return value is the that of the finalizer, unless that value is undefined, in which case it is the return value of the tryable */ if (needsFinallyFix) { Ember.tryFinally = function(tryable, finalizer, binding) { var result, finalResult, finalError; binding = binding || this; try { result = tryable.call(binding); } finally { try { finalResult = finalizer.call(binding); } catch (e) { finalError = e; } } if (finalError) { throw finalError; } return (finalResult === undefined) ? result : finalResult; }; } else { Ember.tryFinally = function(tryable, finalizer, binding) { var result, finalResult; binding = binding || this; try { result = tryable.call(binding); } finally { finalResult = finalizer.call(binding); } return (finalResult === undefined) ? result : finalResult; }; } /** Provides try { } catch finally { } functionality, while working around Safari's double finally bug. ```javascript var tryable = function() { for (i=0, l=listeners.length; i<l; i++) { listener = listeners[i]; beforeValues[i] = listener.before(name, time(), payload); } return callback.call(binding); }; var catchable = function(e) { payload = payload || {}; payload.exception = e; }; var finalizer = function() { for (i=0, l=listeners.length; i<l; i++) { listener = listeners[i]; listener.after(name, time(), payload, beforeValues[i]); } }; Ember.tryCatchFinally(tryable, catchable, finalizer); ``` @method tryCatchFinally @for Ember @param {Function} tryable The function to run the try callback @param {Function} catchable The function to run the catchable callback @param {Function} finalizer The function to run the finally callback @param {Object} [binding] The optional calling object. Defaults to 'this' @return {*} The return value is the that of the finalizer, unless that value is undefined, in which case it is the return value of the tryable. */ if (needsFinallyFix) { Ember.tryCatchFinally = function(tryable, catchable, finalizer, binding) { var result, finalResult, finalError; binding = binding || this; try { result = tryable.call(binding); } catch(error) { result = catchable.call(binding, error); } finally { try { finalResult = finalizer.call(binding); } catch (e) { finalError = e; } } if (finalError) { throw finalError; } return (finalResult === undefined) ? result : finalResult; }; } else { Ember.tryCatchFinally = function(tryable, catchable, finalizer, binding) { var result, finalResult; binding = binding || this; try { result = tryable.call(binding); } catch(error) { result = catchable.call(binding, error); } finally { finalResult = finalizer.call(binding); } return (finalResult === undefined) ? result : finalResult; }; } // ........................................ // TYPING & ARRAY MESSAGING // var TYPE_MAP = {}; var t = "Boolean Number String Function Array Date RegExp Object".split(" "); Ember.ArrayPolyfills.forEach.call(t, function(name) { TYPE_MAP[ "[object " + name + "]" ] = name.toLowerCase(); }); var toString = Object.prototype.toString; /** Returns a consistent type for the passed item. Use this instead of the built-in `typeof` to get the type of an item. It will return the same result across all browsers and includes a bit more detail. Here is what will be returned: | Return Value | Meaning | |---------------|------------------------------------------------------| | 'string' | String primitive or String object. | | 'number' | Number primitive or Number object. | | 'boolean' | Boolean primitive or Boolean object. | | 'null' | Null value | | 'undefined' | Undefined value | | 'function' | A function | | 'array' | An instance of Array | | 'regexp' | An instance of RegExp | | 'date' | An instance of Date | | 'class' | An Ember class (created using Ember.Object.extend()) | | 'instance' | An Ember object instance | | 'error' | An instance of the Error object | | 'object' | A JavaScript object not inheriting from Ember.Object | Examples: ```javascript Ember.typeOf(); // 'undefined' Ember.typeOf(null); // 'null' Ember.typeOf(undefined); // 'undefined' Ember.typeOf('michael'); // 'string' Ember.typeOf(new String('michael')); // 'string' Ember.typeOf(101); // 'number' Ember.typeOf(new Number(101)); // 'number' Ember.typeOf(true); // 'boolean' Ember.typeOf(new Boolean(true)); // 'boolean' Ember.typeOf(Ember.makeArray); // 'function' Ember.typeOf([1,2,90]); // 'array' Ember.typeOf(/abc/); // 'regexp' Ember.typeOf(new Date()); // 'date' Ember.typeOf(Ember.Object.extend()); // 'class' Ember.typeOf(Ember.Object.create()); // 'instance' Ember.typeOf(new Error('teamocil')); // 'error' // "normal" JavaScript object Ember.typeOf({a: 'b'}); // 'object' ``` @method typeOf @for Ember @param {Object} item the item to check @return {String} the type */ Ember.typeOf = function(item) { var ret; ret = (item === null || item === undefined) ? String(item) : TYPE_MAP[toString.call(item)] || 'object'; if (ret === 'function') { if (Ember.Object && Ember.Object.detect(item)) ret = 'class'; } else if (ret === 'object') { if (item instanceof Error) ret = 'error'; else if (Ember.Object && item instanceof Ember.Object) ret = 'instance'; else if (item instanceof Date) ret = 'date'; } return ret; }; /** Convenience method to inspect an object. This method will attempt to convert the object into a useful string description. It is a pretty simple implementation. If you want something more robust, use something like JSDump: https://github.com/NV/jsDump @method inspect @for Ember @param {Object} obj The object you want to inspect. @return {String} A description of the object */ Ember.inspect = function(obj) { var type = Ember.typeOf(obj); if (type === 'array') { return '[' + obj + ']'; } if (type !== 'object') { return obj + ''; } var v, ret = []; for(var key in obj) { if (obj.hasOwnProperty(key)) { v = obj[key]; if (v === 'toString') { continue; } // ignore useless items if (Ember.typeOf(v) === 'function') { v = "function() { ... }"; } ret.push(key + ": " + v); } } return "{" + ret.join(", ") + "}"; }; })(); (function() { // Ember.tryCatchFinally /** The purpose of the Ember Instrumentation module is to provide efficient, general-purpose instrumentation for Ember. Subscribe to a listener by using `Ember.subscribe`: ```javascript Ember.subscribe("render", { before: function(name, timestamp, payload) { }, after: function(name, timestamp, payload) { } }); ``` If you return a value from the `before` callback, that same value will be passed as a fourth parameter to the `after` callback. Instrument a block of code by using `Ember.instrument`: ```javascript Ember.instrument("render.handlebars", payload, function() { // rendering logic }, binding); ``` Event names passed to `Ember.instrument` are namespaced by periods, from more general to more specific. Subscribers can listen for events by whatever level of granularity they are interested in. In the above example, the event is `render.handlebars`, and the subscriber listened for all events beginning with `render`. It would receive callbacks for events named `render`, `render.handlebars`, `render.container`, or even `render.handlebars.layout`. @class Instrumentation @namespace Ember @static */ Ember.Instrumentation = {}; var subscribers = [], cache = {}; var populateListeners = function(name) { var listeners = [], subscriber; for (var i=0, l=subscribers.length; i<l; i++) { subscriber = subscribers[i]; if (subscriber.regex.test(name)) { listeners.push(subscriber.object); } } cache[name] = listeners; return listeners; }; var time = (function() { var perf = 'undefined' !== typeof window ? window.performance || {} : {}; var fn = perf.now || perf.mozNow || perf.webkitNow || perf.msNow || perf.oNow; // fn.bind will be available in all the browsers that support the advanced window.performance... ;-) return fn ? fn.bind(perf) : function() { return +new Date(); }; })(); /** Notifies event's subscribers, calls `before` and `after` hooks. @method instrument @namespace Ember.Instrumentation @param {String} [name] Namespaced event name. @param {Object} payload @param {Function} callback Function that you're instrumenting. @param {Object} binding Context that instrument function is called with. */ Ember.Instrumentation.instrument = function(name, payload, callback, binding) { var listeners = cache[name], timeName, ret; if (Ember.STRUCTURED_PROFILE) { timeName = name + ": " + payload.object; console.time(timeName); } if (!listeners) { listeners = populateListeners(name); } if (listeners.length === 0) { ret = callback.call(binding); if (Ember.STRUCTURED_PROFILE) { console.timeEnd(timeName); } return ret; } var beforeValues = [], listener, i, l; function tryable() { for (i=0, l=listeners.length; i<l; i++) { listener = listeners[i]; beforeValues[i] = listener.before(name, time(), payload); } return callback.call(binding); } function catchable(e) { payload = payload || {}; payload.exception = e; } function finalizer() { for (i=0, l=listeners.length; i<l; i++) { listener = listeners[i]; listener.after(name, time(), payload, beforeValues[i]); } if (Ember.STRUCTURED_PROFILE) { console.timeEnd(timeName); } } return Ember.tryCatchFinally(tryable, catchable, finalizer); }; /** Subscribes to a particular event or instrumented block of code. @method subscribe @namespace Ember.Instrumentation @param {String} [pattern] Namespaced event name. @param {Object} [object] Before and After hooks. @return {Subscriber} */ Ember.Instrumentation.subscribe = function(pattern