From be5eab5785091fccb1d295e33540394b30f33af1 Mon Sep 17 00:00:00 2001 From: Constantine Melnikov Date: Sun, 24 Jul 2016 23:58:01 +0800 Subject: [PATCH] fix build file order --- Gruntfile.js | 2 +- dist/knockout-es5.js | 1204 +++++++++++++++++++------------------- dist/knockout-es5.min.js | 92 +-- 3 files changed, 649 insertions(+), 649 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 8c964da..e0f7644 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -14,7 +14,7 @@ module.exports = function(grunt) { concat: { dist: { files: { - 'dist/knockout-es5.js': ['src/knockout-es5.js', 'lib/weakmap.js'], + 'dist/knockout-es5.js': ['lib/weakmap.js', 'src/knockout-es5.js'], 'dist/knockout-es5-clean.js': ['src/knockout-es5.js'] } } diff --git a/dist/knockout-es5.js b/dist/knockout-es5.js index a473628..3312deb 100644 --- a/dist/knockout-es5.js +++ b/dist/knockout-es5.js @@ -1,740 +1,740 @@ -/*! - * Knockout ES5 plugin - https://github.com/SteveSanderson/knockout-es5 - * Copyright (c) Steve Sanderson - * MIT license +/*! WeakMap shim + * (The MIT License) + * + * Copyright (c) 2012 Brandon Benvie + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the 'Software'), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included with all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -(function(global, undefined) { - 'use strict'; - - var ko; - - // A function that returns a new ES6-compatible WeakMap instance (using ES5 shim if needed). - // Instantiated by prepareExports, accounting for which module loader is being used. - var weakMapFactory; - - // Model tracking - // -------------- - // - // This is the central feature of Knockout-ES5. We augment model objects by converting properties - // into ES5 getter/setter pairs that read/write an underlying Knockout observable. This means you can - // use plain JavaScript syntax to read/write the property while still getting the full benefits of - // Knockout's automatic dependency detection and notification triggering. - // - // For comparison, here's Knockout ES3-compatible syntax: - // - // var firstNameLength = myModel.user().firstName().length; // Read - // myModel.user().firstName('Bert'); // Write - // - // ... versus Knockout-ES5 syntax: - // - // var firstNameLength = myModel.user.firstName.length; // Read - // myModel.user.firstName = 'Bert'; // Write +// Original WeakMap implementation by Gozala @ https://gist.github.com/1269991 +// Updated and bugfixed by Raynos @ https://gist.github.com/1638059 +// Expanded by Benvie @ https://github.com/Benvie/harmony-collections - // `ko.track(model)` converts each property on the given model object into a getter/setter pair that - // wraps a Knockout observable. Optionally specify an array of property names to wrap; otherwise we - // wrap all properties. If any of the properties are already observables, we replace them with - // ES5 getter/setter pairs that wrap your original observable instances. In the case of readonly - // ko.computed properties, we simply do not define a setter (so attempted writes will be ignored, - // which is how ES5 readonly properties normally behave). - // - // By design, this does *not* recursively walk child object properties, because making literally - // everything everywhere independently observable is usually unhelpful. When you do want to track - // child object properties independently, define your own class for those child objects and put - // a separate ko.track call into its constructor --- this gives you far more control. - /** - * @param {object} obj - * @param {object|array.} propertyNamesOrSettings - * @param {boolean} propertyNamesOrSettings.deep Use deep track. - * @param {array.} propertyNamesOrSettings.fields Array of property names to wrap. - * todo: @param {array.} propertyNamesOrSettings.exclude Array of exclude property names to wrap. - * todo: @param {function(string, *):boolean} propertyNamesOrSettings.filter Function to filter property - * names to wrap. A function that takes ... params - * @return {object} - */ - function track(obj, propertyNamesOrSettings) { - if (!obj || typeof obj !== 'object') { - throw new Error('When calling ko.track, you must pass an object as the first parameter.'); - } +// This is the version used by knockout-es5. Modified by Steve Sanderson as follows: +// [1] Deleted weakmap.min.js (it's not useful as it would be out of sync with weakmap.js now I'm editing it) +// [2] Since UglifyJS strips inline function names (and you can't disable that without disabling name mangling +// entirely), insert code that re-adds function names - var propertyNames; +void function(global, undefined_, undefined){ + var getProps = Object.getOwnPropertyNames, + cachedWindowNames = typeof window === 'object' ? Object.getOwnPropertyNames(window) : [], + defProp = Object.defineProperty, + toSource = Function.prototype.toString, + create = Object.create, + hasOwn = Object.prototype.hasOwnProperty, + funcName = /^\n?function\s?(\w*)?_?\(/; - if ( isPlainObject(propertyNamesOrSettings) ) { - // defaults - propertyNamesOrSettings.deep = propertyNamesOrSettings.deep || false; - propertyNamesOrSettings.fields = propertyNamesOrSettings.fields || Object.getOwnPropertyNames(obj); - propertyNamesOrSettings.lazy = propertyNamesOrSettings.lazy || false; - wrap(obj, propertyNamesOrSettings.fields, propertyNamesOrSettings); - } else { - propertyNames = propertyNamesOrSettings || Object.getOwnPropertyNames(obj); - wrap(obj, propertyNames, {}); + function define(object, key, value){ + if (typeof key === 'function') { + value = key; + key = nameOf(value).replace(/_$/, ''); } - - return obj; + return defProp(object, key, { configurable: true, writable: true, value: value }); } - // fix for ie - var rFunctionName = /^function\s*([^\s(]+)/; - function getFunctionName( ctor ){ - if (ctor.name) { - return ctor.name; - } - return (ctor.toString().trim().match( rFunctionName ) || [])[1]; + function nameOf(func){ + return typeof func !== 'function' + ? '' : '_name' in func + ? func._name : 'name' in func + ? func.name : toSource.call(func).match(funcName)[1]; } - function canTrack(obj) { - return obj && typeof obj === 'object' && getFunctionName(obj.constructor) === 'Object'; + function namedFunction(name, func) { + // Undo the name-stripping that UglifyJS does + func._name = name; + return func; } - function createPropertyDescriptor(originalValue, prop, map) { - var isObservable = ko.isObservable(originalValue); - var isArray = !isObservable && Array.isArray(originalValue); - var observable = isObservable ? originalValue - : isArray ? ko.observableArray(originalValue) - : ko.observable(originalValue); + // ############ + // ### Data ### + // ############ - map[prop] = function () { return observable; }; + var Data = (function(){ + var dataDesc = { value: { writable: true, value: undefined } }, + uids = create(null), - // add check in case the object is already an observable array - if (isArray || (isObservable && 'push' in observable)) { - notifyWhenPresentOrFutureArrayValuesMutate(ko, observable); - } + createUID = function(){ + var key = Math.random().toString(36).slice(2); + return key in uids ? createUID() : uids[key] = key; + }, - return { - configurable: true, - enumerable: true, - get: observable, - set: ko.isWriteableObservable(observable) ? observable : undefined - }; - } + globalID = createUID(), - function createLazyPropertyDescriptor(originalValue, prop, map) { - if (ko.isObservable(originalValue)) { - // no need to be lazy if we already have an observable - return createPropertyDescriptor(originalValue, prop, map); - } + storage = function(obj){ + if (hasOwn.call(obj, globalID)) + return obj[globalID]; - var observable; + if (!Object.isExtensible(obj)) + throw new TypeError("Object must be extensible"); - function getOrCreateObservable(value, writing) { - if (observable) { - return writing ? observable(value) : observable; - } + var store = create(null); + defProp(obj, globalID, { value: store }); + return store; + }; - if (Array.isArray(value)) { - observable = ko.observableArray(value); - notifyWhenPresentOrFutureArrayValuesMutate(ko, observable); - return observable; + // common per-object storage area made visible by patching getOwnPropertyNames' + define(Object, namedFunction('getOwnPropertyNames', function getOwnPropertyNames(obj){ + // gh-43 + var coercedObj = Object(obj), props; + // Fixes for debuggers: + // 1) Some objects lack .toString(), calling it on them make Chrome + // debugger fail when inspecting variables. + // 2) Window.prototype methods and properties are private in IE11 and + // throw 'Invalid calling object'. + if (coercedObj !== Window.prototype && 'toString' in coercedObj + && coercedObj.toString() === '[object Window]') + { + try { + props = getProps(obj); + } catch (e) { + props = cachedWindowNames; + } + } else { + props = getProps(obj); } + if (hasOwn.call(obj, globalID)) + props.splice(props.indexOf(globalID), 1); + return props; + })); - return (observable = ko.observable(value)); - } - - map[prop] = function () { return getOrCreateObservable(originalValue); }; - return { - configurable: true, - enumerable: true, - get: function () { return getOrCreateObservable(originalValue)(); }, - set: function (value) { getOrCreateObservable(value, true); } - }; - } - - function wrap(obj, props, options) { - if (!props.length) { - return; - } + function Data(){ + var puid = createUID(), + secret = {}; - var allObservablesForObject = getAllObservablesForObject(obj, true); - var descriptors = {}; + this.unlock = function(obj){ + var store = storage(obj); + if (hasOwn.call(store, puid)) + return store[puid](secret); - props.forEach(function (prop) { - // Skip properties that are already tracked - if (prop in allObservablesForObject) { - return; + var data = create(null, dataDesc); + defProp(store, puid, { + value: function(key){ if (key === secret) return data; } + }); + return data; } + } - // Skip properties where descriptor can't be redefined - if (Object.getOwnPropertyDescriptor(obj, prop).configurable === false){ - return; - } + define(Data.prototype, namedFunction('get', function get(o){ return this.unlock(o).value })); + define(Data.prototype, namedFunction('set', function set(o, v){ this.unlock(o).value = v })); - var originalValue = obj[prop]; - descriptors[prop] = (options.lazy ? createLazyPropertyDescriptor : createPropertyDescriptor) - (originalValue, prop, allObservablesForObject); + return Data; + }()); - if (options.deep && canTrack(originalValue)) { - wrap(originalValue, Object.keys(originalValue), options); - } - }); - Object.defineProperties(obj, descriptors); - } + var WM = (function(data){ + var validate = function(key){ + if (key == null || typeof key !== 'object' && typeof key !== 'function') + throw new TypeError("Invalid WeakMap key"); + } - function isPlainObject( obj ){ - return !!obj && typeof obj === 'object' && obj.constructor === Object; - } - - // Lazily created by `getAllObservablesForObject` below. Has to be created lazily because the - // WeakMap factory isn't available until the module has finished loading (may be async). - var objectToObservableMap; - - // Gets or creates the hidden internal key-value collection of observables corresponding to - // properties on the model object. - function getAllObservablesForObject(obj, createIfNotDefined) { - if (!objectToObservableMap) { - objectToObservableMap = weakMapFactory(); - } - - var result = objectToObservableMap.get(obj); - if (!result && createIfNotDefined) { - result = {}; - objectToObservableMap.set(obj, result); + var wrap = function(collection, value){ + var store = data.unlock(collection); + if (store.value) + throw new TypeError("Object is already a WeakMap"); + store.value = value; } - return result; - } - // Removes the internal references to observables mapped to the specified properties - // or the entire object reference if no properties are passed in. This allows the - // observables to be replaced and tracked again. - function untrack(obj, propertyNames) { - if (!objectToObservableMap) { - return; + var unwrap = function(collection){ + var storage = data.unlock(collection).value; + if (!storage) + throw new TypeError("WeakMap is not generic"); + return storage; } - if (arguments.length === 1) { - objectToObservableMap['delete'](obj); - } else { - var allObservablesForObject = getAllObservablesForObject(obj, false); - if (allObservablesForObject) { - propertyNames.forEach(function(propertyName) { - delete allObservablesForObject[propertyName]; + var initialize = function(weakmap, iterable){ + if (iterable !== null && typeof iterable === 'object' && typeof iterable.forEach === 'function') { + iterable.forEach(function(item, i){ + if (item instanceof Array && item.length === 2) + set.call(weakmap, iterable[i][0], iterable[i][1]); }); } } - } - // Computed properties - // ------------------- - // - // The preceding code is already sufficient to upgrade ko.computed model properties to ES5 - // getter/setter pairs (or in the case of readonly ko.computed properties, just a getter). - // These then behave like a regular property with a getter function, except they are smarter: - // your evaluator is only invoked when one of its dependencies changes. The result is cached - // and used for all evaluations until the next time a dependency changes). - // - // However, instead of forcing developers to declare a ko.computed property explicitly, it's - // nice to offer a utility function that declares a computed getter directly. - // Implements `ko.defineProperty` - function defineComputedProperty(obj, propertyName, evaluatorOrOptions) { - var ko = this, - computedOptions = { owner: obj, deferEvaluation: true }; + function WeakMap(iterable){ + if (this === global || this == null || this === WeakMap.prototype) + return new WeakMap(iterable); - if (typeof evaluatorOrOptions === 'function') { - computedOptions.read = evaluatorOrOptions; - } else { - if ('value' in evaluatorOrOptions) { - throw new Error('For ko.defineProperty, you must not specify a "value" for the property. ' + - 'You must provide a "get" function.'); - } + wrap(this, new Data); + initialize(this, iterable); + } - if (typeof evaluatorOrOptions.get !== 'function') { - throw new Error('For ko.defineProperty, the third parameter must be either an evaluator function, ' + - 'or an options object containing a function called "get".'); - } + function get(key){ + validate(key); + var value = unwrap(this).get(key); + return value === undefined_ ? undefined : value; + } - computedOptions.read = evaluatorOrOptions.get; - computedOptions.write = evaluatorOrOptions.set; + function set(key, value){ + validate(key); + // store a token for explicit undefined so that "has" works correctly + unwrap(this).set(key, value === undefined ? undefined_ : value); } - obj[propertyName] = ko.computed(computedOptions); - track.call(ko, obj, [propertyName]); - return obj; - } + function has(key){ + validate(key); + return unwrap(this).get(key) !== undefined; + } - // Array handling - // -------------- - // - // Arrays are special, because unlike other property types, they have standard mutator functions - // (`push`/`pop`/`splice`/etc.) and it's desirable to trigger a change notification whenever one of - // those mutator functions is invoked. - // - // Traditionally, Knockout handles this by putting special versions of `push`/`pop`/etc. on observable - // arrays that mutate the underlying array and then trigger a notification. That approach doesn't - // work for Knockout-ES5 because properties now return the underlying arrays, so the mutator runs - // in the context of the underlying array, not any particular observable: - // - // // Operates on the underlying array value - // myModel.someCollection.push('New value'); - // - // To solve this, Knockout-ES5 detects array values, and modifies them as follows: - // 1. Associates a hidden subscribable with each array instance that it encounters - // 2. Intercepts standard mutators (`push`/`pop`/etc.) and makes them trigger the subscribable - // Then, for model properties whose values are arrays, the property's underlying observable - // subscribes to the array subscribable, so it can trigger a change notification after mutation. + function delete_(key){ + validate(key); + var data = unwrap(this), + had = data.get(key) !== undefined; + data.set(key, undefined); + return had; + } - // Given an observable that underlies a model property, watch for any array value that might - // be assigned as the property value, and hook into its change events - function notifyWhenPresentOrFutureArrayValuesMutate(ko, observable) { - var watchingArraySubscription = null; - ko.computed(function () { - // Unsubscribe to any earlier array instance - if (watchingArraySubscription) { - watchingArraySubscription.dispose(); - watchingArraySubscription = null; - } + function toString(){ + unwrap(this); + return '[object WeakMap]'; + } - // Subscribe to the new array instance - var newArrayInstance = observable(); - if (newArrayInstance instanceof Array) { - watchingArraySubscription = startWatchingArrayInstance(ko, observable, newArrayInstance); - } + // Undo the function-name stripping that UglifyJS does + get._name = 'get'; + set._name = 'set'; + has._name = 'has'; + toString._name = 'toString'; + + var src = (''+Object).split('Object'); + var stringifier = namedFunction('toString', function toString(){ + return src[0] + nameOf(this) + src[1]; }); - } - // Listens for array mutations, and when they happen, cause the observable to fire notifications. - // This is used to make model properties of type array fire notifications when the array changes. - // Returns a subscribable that can later be disposed. - function startWatchingArrayInstance(ko, observable, arrayInstance) { - var subscribable = getSubscribableForArray(ko, arrayInstance); - return subscribable.subscribe(observable); - } + define(stringifier, stringifier); - // Lazily created by `getSubscribableForArray` below. Has to be created lazily because the - // WeakMap factory isn't available until the module has finished loading (may be async). - var arraySubscribablesMap; + var prep = { __proto__: [] } instanceof Array + ? function(f){ f.__proto__ = stringifier } + : function(f){ define(f, stringifier) }; - // Gets or creates a subscribable that fires after each array mutation - function getSubscribableForArray(ko, arrayInstance) { - if (!arraySubscribablesMap) { - arraySubscribablesMap = weakMapFactory(); - } + prep(WeakMap); - var subscribable = arraySubscribablesMap.get(arrayInstance); - if (!subscribable) { - subscribable = new ko.subscribable(); - arraySubscribablesMap.set(arrayInstance, subscribable); + [toString, get, set, has, delete_].forEach(function(method){ + define(WeakMap.prototype, method); + prep(method); + }); - var notificationPauseSignal = {}; - wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal); - addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal); - } + return WeakMap; + }(new Data)); - return subscribable; - } + var defaultCreator = Object.create + ? function(){ return Object.create(null) } + : function(){ return {} }; - // After each array mutation, fires a notification on the given subscribable - function wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal) { - ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'].forEach(function(fnName) { - var origMutator = arrayInstance[fnName]; - arrayInstance[fnName] = function() { - var result = origMutator.apply(this, arguments); - if (notificationPauseSignal.pause !== true) { - subscribable.notifySubscribers(this); + function createStorage(creator){ + var weakmap = new WM; + creator || (creator = defaultCreator); + + function storage(object, value){ + if (value || arguments.length === 2) { + weakmap.set(object, value); + } else { + value = weakmap.get(object); + if (value === undefined) { + value = creator(object); + weakmap.set(object, value); } - return result; - }; - }); + } + return value; + } + + return storage; } - // Adds Knockout's additional array mutation functions to the array - function addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal) { - ['remove', 'removeAll', 'destroy', 'destroyAll', 'replace'].forEach(function(fnName) { - // Make it a non-enumerable property for consistency with standard Array functions - Object.defineProperty(arrayInstance, fnName, { - enumerable: false, - value: function() { - var result; - // These additional array mutators are built using the underlying push/pop/etc. - // mutators, which are wrapped to trigger notifications. But we don't want to - // trigger multiple notifications, so pause the push/pop/etc. wrappers and - // delivery only one notification at the end of the process. - notificationPauseSignal.pause = true; - try { - // Creates a temporary observableArray that can perform the operation. - result = ko.observableArray.fn[fnName].apply(ko.observableArray(arrayInstance), arguments); - } - finally { - notificationPauseSignal.pause = false; - } - subscribable.notifySubscribers(arrayInstance); - return result; - } - }); - }); + if (typeof module !== 'undefined') { + module.exports = WM; + } else if (typeof exports !== 'undefined') { + exports.WeakMap = WM; + } else if (!('WeakMap' in global)) { + global.WeakMap = WM; } - // Static utility functions - // ------------------------ + WM.createStorage = createStorage; + if (global.WeakMap) + global.WeakMap.createStorage = createStorage; +}(function(){ return this }()); + +/*! + * Knockout ES5 plugin - https://github.com/SteveSanderson/knockout-es5 + * Copyright (c) Steve Sanderson + * MIT license + */ + +(function(global, undefined) { + 'use strict'; + + var ko; + + // A function that returns a new ES6-compatible WeakMap instance (using ES5 shim if needed). + // Instantiated by prepareExports, accounting for which module loader is being used. + var weakMapFactory; + + // Model tracking + // -------------- // - // Since Knockout-ES5 sets up properties that return values, not observables, you can't - // trivially subscribe to the underlying observables (e.g., `someProperty.subscribe(...)`), - // or tell them that object values have mutated, etc. To handle this, we set up some - // extra utility functions that can return or work with the underlying observables. + // This is the central feature of Knockout-ES5. We augment model objects by converting properties + // into ES5 getter/setter pairs that read/write an underlying Knockout observable. This means you can + // use plain JavaScript syntax to read/write the property while still getting the full benefits of + // Knockout's automatic dependency detection and notification triggering. + // + // For comparison, here's Knockout ES3-compatible syntax: + // + // var firstNameLength = myModel.user().firstName().length; // Read + // myModel.user().firstName('Bert'); // Write + // + // ... versus Knockout-ES5 syntax: + // + // var firstNameLength = myModel.user.firstName.length; // Read + // myModel.user.firstName = 'Bert'; // Write - // Returns the underlying observable associated with a model property (or `null` if the - // model or property doesn't exist, or isn't associated with an observable). This means - // you can subscribe to the property, e.g.: + // `ko.track(model)` converts each property on the given model object into a getter/setter pair that + // wraps a Knockout observable. Optionally specify an array of property names to wrap; otherwise we + // wrap all properties. If any of the properties are already observables, we replace them with + // ES5 getter/setter pairs that wrap your original observable instances. In the case of readonly + // ko.computed properties, we simply do not define a setter (so attempted writes will be ignored, + // which is how ES5 readonly properties normally behave). // - // ko.getObservable(model, 'propertyName') - // .subscribe(function(newValue) { ... }); - function getObservable(obj, propertyName) { + // By design, this does *not* recursively walk child object properties, because making literally + // everything everywhere independently observable is usually unhelpful. When you do want to track + // child object properties independently, define your own class for those child objects and put + // a separate ko.track call into its constructor --- this gives you far more control. + /** + * @param {object} obj + * @param {object|array.} propertyNamesOrSettings + * @param {boolean} propertyNamesOrSettings.deep Use deep track. + * @param {array.} propertyNamesOrSettings.fields Array of property names to wrap. + * todo: @param {array.} propertyNamesOrSettings.exclude Array of exclude property names to wrap. + * todo: @param {function(string, *):boolean} propertyNamesOrSettings.filter Function to filter property + * names to wrap. A function that takes ... params + * @return {object} + */ + function track(obj, propertyNamesOrSettings) { if (!obj || typeof obj !== 'object') { - return null; + throw new Error('When calling ko.track, you must pass an object as the first parameter.'); } - var allObservablesForObject = getAllObservablesForObject(obj, false); - if (allObservablesForObject && propertyName in allObservablesForObject) { - return allObservablesForObject[propertyName](); + var propertyNames; + + if ( isPlainObject(propertyNamesOrSettings) ) { + // defaults + propertyNamesOrSettings.deep = propertyNamesOrSettings.deep || false; + propertyNamesOrSettings.fields = propertyNamesOrSettings.fields || Object.getOwnPropertyNames(obj); + propertyNamesOrSettings.lazy = propertyNamesOrSettings.lazy || false; + + wrap(obj, propertyNamesOrSettings.fields, propertyNamesOrSettings); + } else { + propertyNames = propertyNamesOrSettings || Object.getOwnPropertyNames(obj); + wrap(obj, propertyNames, {}); } - return null; + return obj; } - - // Returns a boolean indicating whether the property on the object has an underlying - // observables. This does the check in a way not to create an observable if the - // object was created with lazily created observables - function isTracked(obj, propertyName) { - if (!obj || typeof obj !== 'object') { - return false; + + // fix for ie + var rFunctionName = /^function\s*([^\s(]+)/; + function getFunctionName( ctor ){ + if (ctor.name) { + return ctor.name; } - - var allObservablesForObject = getAllObservablesForObject(obj, false); - return !!allObservablesForObject && propertyName in allObservablesForObject; + return (ctor.toString().trim().match( rFunctionName ) || [])[1]; } - // Causes a property's associated observable to fire a change notification. Useful when - // the property value is a complex object and you've modified a child property. - function valueHasMutated(obj, propertyName) { - var observable = getObservable(obj, propertyName); - - if (observable) { - observable.valueHasMutated(); - } + function canTrack(obj) { + return obj && typeof obj === 'object' && getFunctionName(obj.constructor) === 'Object'; } - // Module initialisation - // --------------------- - // - // When this script is first evaluated, it works out what kind of module loading scenario - // it is in (Node.js or a browser `