diff --git a/CHANGELOG.md b/CHANGELOG.md index 869963c..d722de4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - #161 - Allow the http method of DSHttpAdapter methods to be configured - #166 - Add ID Resolver - #167 - Default params argument of bindAll to empty object +- #170 - Global callbacks - #171 - "not in" query ###### Backwards compatible bug fixes diff --git a/README.md b/README.md index e2e350c..59fd922 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Unlike Backbone and Ember Models, angular-data does not require the use of gette Supporting relations, computed properties, model lifecycle control and a slew of other features, angular-data is the tool for giving your data the respect it deserves. __Latest Release:__ [1.0.0-rc.1](http://angular-data.pseudobry.com/) -__master:__ [1.0.0-rc.1](http://angular-data-next.pseudobry.com/) +__master:__ [1.0.0-rc.2](http://angular-data-next.pseudobry.com/) Angular-data is in a 1.0.0 Beta. The API is rather stable and angular-data is well tested. diff --git a/bower.json b/bower.json index 9396688..98281cb 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,7 @@ "author": "Jason Dobry", "name": "angular-data", "description": "Data store for Angular.js.", - "version": "1.0.0-rc.1", + "version": "1.0.0-rc.2", "homepage": "http://angular-data.pseudobry.com/", "repository": { "type": "git", diff --git a/dist/angular-data.js b/dist/angular-data.js index a55534e..22e542e 100644 --- a/dist/angular-data.js +++ b/dist/angular-data.js @@ -846,7 +846,7 @@ var isFunction = require('../lang/isFunction'); module.exports = toLookup; -},{"../lang/isFunction":17}],11:[function(require,module,exports){ +},{"../lang/isFunction":19}],11:[function(require,module,exports){ /** @@ -896,7 +896,7 @@ var deepMatches = require('../object/deepMatches'); -},{"../object/deepMatches":22,"./identity":11,"./prop":13}],13:[function(require,module,exports){ +},{"../object/deepMatches":25,"./identity":11,"./prop":13}],13:[function(require,module,exports){ /** @@ -913,6 +913,107 @@ var deepMatches = require('../object/deepMatches'); },{}],14:[function(require,module,exports){ +var kindOf = require('./kindOf'); +var isPlainObject = require('./isPlainObject'); +var mixIn = require('../object/mixIn'); + + /** + * Clone native types. + */ + function clone(val){ + switch (kindOf(val)) { + case 'Object': + return cloneObject(val); + case 'Array': + return cloneArray(val); + case 'RegExp': + return cloneRegExp(val); + case 'Date': + return cloneDate(val); + default: + return val; + } + } + + function cloneObject(source) { + if (isPlainObject(source)) { + return mixIn({}, source); + } else { + return source; + } + } + + function cloneRegExp(r) { + var flags = ''; + flags += r.multiline ? 'm' : ''; + flags += r.global ? 'g' : ''; + flags += r.ignorecase ? 'i' : ''; + return new RegExp(r.source, flags); + } + + function cloneDate(date) { + return new Date(+date); + } + + function cloneArray(arr) { + return arr.slice(); + } + + module.exports = clone; + + + +},{"../object/mixIn":31,"./isPlainObject":22,"./kindOf":23}],15:[function(require,module,exports){ +var clone = require('./clone'); +var forOwn = require('../object/forOwn'); +var kindOf = require('./kindOf'); +var isPlainObject = require('./isPlainObject'); + + /** + * Recursively clone native types. + */ + function deepClone(val, instanceClone) { + switch ( kindOf(val) ) { + case 'Object': + return cloneObject(val, instanceClone); + case 'Array': + return cloneArray(val, instanceClone); + default: + return clone(val); + } + } + + function cloneObject(source, instanceClone) { + if (isPlainObject(source)) { + var out = {}; + forOwn(source, function(val, key) { + this[key] = deepClone(val, instanceClone); + }, out); + return out; + } else if (instanceClone) { + return instanceClone(source); + } else { + return source; + } + } + + function cloneArray(arr, instanceClone) { + var out = [], + i = -1, + n = arr.length, + val; + while (++i < n) { + out[i] = deepClone(arr[i], instanceClone); + } + return out; + } + + module.exports = deepClone; + + + + +},{"../object/forOwn":28,"./clone":14,"./isPlainObject":22,"./kindOf":23}],16:[function(require,module,exports){ var isKind = require('./isKind'); /** */ @@ -922,7 +1023,7 @@ var isKind = require('./isKind'); module.exports = isArray; -},{"./isKind":18}],15:[function(require,module,exports){ +},{"./isKind":20}],17:[function(require,module,exports){ var isKind = require('./isKind'); /** */ @@ -932,7 +1033,7 @@ var isKind = require('./isKind'); module.exports = isBoolean; -},{"./isKind":18}],16:[function(require,module,exports){ +},{"./isKind":20}],18:[function(require,module,exports){ var forOwn = require('../object/forOwn'); var isArray = require('./isArray'); @@ -958,7 +1059,7 @@ var isArray = require('./isArray'); -},{"../object/forOwn":25,"./isArray":14}],17:[function(require,module,exports){ +},{"../object/forOwn":28,"./isArray":16}],19:[function(require,module,exports){ var isKind = require('./isKind'); /** */ @@ -968,7 +1069,7 @@ var isKind = require('./isKind'); module.exports = isFunction; -},{"./isKind":18}],18:[function(require,module,exports){ +},{"./isKind":20}],20:[function(require,module,exports){ var kindOf = require('./kindOf'); /** * Check if value is from a specific "kind". @@ -979,7 +1080,17 @@ var kindOf = require('./kindOf'); module.exports = isKind; -},{"./kindOf":20}],19:[function(require,module,exports){ +},{"./kindOf":23}],21:[function(require,module,exports){ +var isKind = require('./isKind'); + /** + */ + function isObject(val) { + return isKind(val, 'Object'); + } + module.exports = isObject; + + +},{"./isKind":20}],22:[function(require,module,exports){ /** @@ -994,7 +1105,7 @@ var kindOf = require('./kindOf'); -},{}],20:[function(require,module,exports){ +},{}],23:[function(require,module,exports){ var _rKind = /^\[object (.*)\]$/, @@ -1016,7 +1127,7 @@ var kindOf = require('./kindOf'); module.exports = kindOf; -},{}],21:[function(require,module,exports){ +},{}],24:[function(require,module,exports){ /** @@ -1031,7 +1142,7 @@ var kindOf = require('./kindOf'); -},{}],22:[function(require,module,exports){ +},{}],25:[function(require,module,exports){ var forOwn = require('./forOwn'); var isArray = require('../lang/isArray'); @@ -1088,7 +1199,7 @@ var isArray = require('../lang/isArray'); -},{"../lang/isArray":14,"./forOwn":25}],23:[function(require,module,exports){ +},{"../lang/isArray":16,"./forOwn":28}],26:[function(require,module,exports){ var forOwn = require('./forOwn'); var isPlainObject = require('../lang/isPlainObject'); @@ -1124,7 +1235,7 @@ var isPlainObject = require('../lang/isPlainObject'); -},{"../lang/isPlainObject":19,"./forOwn":25}],24:[function(require,module,exports){ +},{"../lang/isPlainObject":22,"./forOwn":28}],27:[function(require,module,exports){ var hasOwn = require('./hasOwn'); var _hasDontEnumBug, @@ -1202,7 +1313,7 @@ var hasOwn = require('./hasOwn'); -},{"./hasOwn":26}],25:[function(require,module,exports){ +},{"./hasOwn":29}],28:[function(require,module,exports){ var hasOwn = require('./hasOwn'); var forIn = require('./forIn'); @@ -1223,7 +1334,7 @@ var forIn = require('./forIn'); -},{"./forIn":24,"./hasOwn":26}],26:[function(require,module,exports){ +},{"./forIn":27,"./hasOwn":29}],29:[function(require,module,exports){ /** @@ -1237,7 +1348,79 @@ var forIn = require('./forIn'); -},{}],27:[function(require,module,exports){ +},{}],30:[function(require,module,exports){ +var hasOwn = require('./hasOwn'); +var deepClone = require('../lang/deepClone'); +var isObject = require('../lang/isObject'); + + /** + * Deep merge objects. + */ + function merge() { + var i = 1, + key, val, obj, target; + + // make sure we don't modify source element and it's properties + // objects are passed by reference + target = deepClone( arguments[0] ); + + while (obj = arguments[i++]) { + for (key in obj) { + if ( ! hasOwn(obj, key) ) { + continue; + } + + val = obj[key]; + + if ( isObject(val) && isObject(target[key]) ){ + // inception, deep merge objects + target[key] = merge(target[key], val); + } else { + // make sure arrays, regexp, date, objects are cloned + target[key] = deepClone(val); + } + + } + } + + return target; + } + + module.exports = merge; + + + +},{"../lang/deepClone":15,"../lang/isObject":21,"./hasOwn":29}],31:[function(require,module,exports){ +var forOwn = require('./forOwn'); + + /** + * Combine properties from all the objects into first one. + * - This method affects target object in place, if you want to create a new Object pass an empty object as first param. + * @param {object} target Target Object + * @param {...object} objects Objects to be combined (0...n objects). + * @return {object} Target Object. + */ + function mixIn(target, objects){ + var i = 0, + n = arguments.length, + obj; + while(++i < n){ + obj = arguments[i]; + if (obj != null) { + forOwn(obj, copyProp, target); + } + } + return target; + } + + function copyProp(val, key){ + this[key] = val; + } + + module.exports = mixIn; + + +},{"./forOwn":28}],32:[function(require,module,exports){ var forEach = require('../array/forEach'); /** @@ -1258,7 +1441,7 @@ var forEach = require('../array/forEach'); -},{"../array/forEach":4}],28:[function(require,module,exports){ +},{"../array/forEach":4}],33:[function(require,module,exports){ var slice = require('../array/slice'); /** @@ -1278,7 +1461,7 @@ var slice = require('../array/slice'); -},{"../array/slice":8}],29:[function(require,module,exports){ +},{"../array/slice":8}],34:[function(require,module,exports){ var namespace = require('./namespace'); /** @@ -1297,7 +1480,7 @@ var namespace = require('./namespace'); -},{"./namespace":27}],30:[function(require,module,exports){ +},{"./namespace":32}],35:[function(require,module,exports){ var toString = require('../lang/toString'); var replaceAccents = require('./replaceAccents'); var removeNonWord = require('./removeNonWord'); @@ -1319,7 +1502,7 @@ var lowerCase = require('./lowerCase'); module.exports = camelCase; -},{"../lang/toString":21,"./lowerCase":31,"./removeNonWord":34,"./replaceAccents":35,"./upperCase":36}],31:[function(require,module,exports){ +},{"../lang/toString":24,"./lowerCase":36,"./removeNonWord":39,"./replaceAccents":40,"./upperCase":41}],36:[function(require,module,exports){ var toString = require('../lang/toString'); /** * "Safer" String.toLowerCase() @@ -1332,7 +1515,7 @@ var toString = require('../lang/toString'); module.exports = lowerCase; -},{"../lang/toString":21}],32:[function(require,module,exports){ +},{"../lang/toString":24}],37:[function(require,module,exports){ var join = require('../array/join'); var slice = require('../array/slice'); @@ -1349,7 +1532,7 @@ var slice = require('../array/slice'); module.exports = makePath; -},{"../array/join":6,"../array/slice":8}],33:[function(require,module,exports){ +},{"../array/join":6,"../array/slice":8}],38:[function(require,module,exports){ var toString = require('../lang/toString'); var camelCase = require('./camelCase'); var upperCase = require('./upperCase'); @@ -1364,7 +1547,7 @@ var upperCase = require('./upperCase'); module.exports = pascalCase; -},{"../lang/toString":21,"./camelCase":30,"./upperCase":36}],34:[function(require,module,exports){ +},{"../lang/toString":24,"./camelCase":35,"./upperCase":41}],39:[function(require,module,exports){ var toString = require('../lang/toString'); // This pattern is generated by the _build/pattern-removeNonWord.js script var PATTERN = /[^\x20\x2D0-9A-Z\x5Fa-z\xC0-\xD6\xD8-\xF6\xF8-\xFF]/g; @@ -1380,7 +1563,7 @@ var toString = require('../lang/toString'); module.exports = removeNonWord; -},{"../lang/toString":21}],35:[function(require,module,exports){ +},{"../lang/toString":24}],40:[function(require,module,exports){ var toString = require('../lang/toString'); /** * Replaces all accented chars with regular ones @@ -1418,7 +1601,7 @@ var toString = require('../lang/toString'); module.exports = replaceAccents; -},{"../lang/toString":21}],36:[function(require,module,exports){ +},{"../lang/toString":24}],41:[function(require,module,exports){ var toString = require('../lang/toString'); /** * "Safer" String.toUpperCase() @@ -1430,7 +1613,7 @@ var toString = require('../lang/toString'); module.exports = upperCase; -},{"../lang/toString":21}],37:[function(require,module,exports){ +},{"../lang/toString":24}],42:[function(require,module,exports){ /** * @doc function * @id DSHttpAdapterProvider @@ -1900,7 +2083,7 @@ function DSHttpAdapterProvider() { module.exports = DSHttpAdapterProvider; -},{}],38:[function(require,module,exports){ +},{}],43:[function(require,module,exports){ /*! * @doc function * @id DSLocalStorageAdapterProvider @@ -2187,7 +2370,7 @@ function DSLocalStorageAdapterProvider() { module.exports = DSLocalStorageAdapterProvider; -},{}],39:[function(require,module,exports){ +},{}],44:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.create(' + resourceName + ', attrs[, options]): '; } @@ -2287,6 +2470,7 @@ function create(resourceName, attrs, options) { return func.call(attrs, resourceName, attrs); }) .then(function (attrs) { + DS.notify(definition, 'beforeCreate', DS.utils.merge({}, attrs)); return DS.adapters[options.adapter || definition.defaultAdapter].create(definition, options.serialize ? options.serialize(resourceName, attrs) : definition.serialize(resourceName, attrs), options); }) .then(function (res) { @@ -2294,17 +2478,18 @@ function create(resourceName, attrs, options) { var attrs = options.deserialize ? options.deserialize(resourceName, res) : definition.deserialize(resourceName, res); return func.call(attrs, resourceName, attrs); }) - .then(function (data) { + .then(function (attrs) { + DS.notify(definition, 'afterCreate', DS.utils.merge({}, attrs)); if (options.cacheResponse) { var resource = DS.store[resourceName]; - var created = DS.inject(definition.name, data, options); + var created = DS.inject(definition.name, attrs, options); var id = created[definition.idAttribute]; resource.completedQueries[id] = new Date().getTime(); resource.previousAttributes[id] = DS.utils.deepMixIn({}, created); resource.saved[id] = DS.utils.updateTimestamp(resource.saved[id]); return DS.get(definition.name, id); } else { - return DS.createInstance(resourceName, data, options); + return DS.createInstance(resourceName, attrs, options); } }); } @@ -2316,7 +2501,7 @@ function create(resourceName, attrs, options) { module.exports = create; -},{}],40:[function(require,module,exports){ +},{}],45:[function(require,module,exports){ function errorPrefix(resourceName, id) { return 'DS.destroy(' + resourceName + ', ' + id + '[, options]): '; } @@ -2392,7 +2577,8 @@ function destroy(resourceName, id, options) { var func = options.beforeDestroy ? DS.$q.promisify(options.beforeDestroy) : definition.beforeDestroy; return func.call(attrs, resourceName, attrs); }) - .then(function () { + .then(function (attrs) { + DS.notify(definition, 'beforeDestroy', DS.utils.merge({}, attrs)); return DS.adapters[options.adapter || definition.defaultAdapter].destroy(definition, id, options); }) .then(function () { @@ -2400,6 +2586,7 @@ function destroy(resourceName, id, options) { return func.call(item, resourceName, item); }) .then(function () { + DS.notify(definition, 'afterDestroy', DS.utils.merge({}, item)); DS.eject(resourceName, id); return id; }); @@ -2411,7 +2598,7 @@ function destroy(resourceName, id, options) { module.exports = destroy; -},{}],41:[function(require,module,exports){ +},{}],46:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.destroyAll(' + resourceName + ', params[, options]): '; } @@ -2501,7 +2688,7 @@ function destroyAll(resourceName, params, options) { module.exports = destroyAll; -},{}],42:[function(require,module,exports){ +},{}],47:[function(require,module,exports){ function errorPrefix(resourceName, id) { return 'DS.find(' + resourceName + ', ' + id + '[, options]): '; } @@ -2610,7 +2797,7 @@ function find(resourceName, id, options) { module.exports = find; -},{}],43:[function(require,module,exports){ +},{}],48:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.findAll(' + resourceName + ', params[, options]): '; } @@ -2788,7 +2975,7 @@ function findAll(resourceName, params, options) { module.exports = findAll; -},{}],44:[function(require,module,exports){ +},{}],49:[function(require,module,exports){ module.exports = { /** * @doc method @@ -2891,7 +3078,7 @@ module.exports = { updateAll: require('./updateAll') }; -},{"./create":39,"./destroy":40,"./destroyAll":41,"./find":42,"./findAll":43,"./loadRelations":45,"./refresh":46,"./save":47,"./update":48,"./updateAll":49}],45:[function(require,module,exports){ +},{"./create":44,"./destroy":45,"./destroyAll":46,"./find":47,"./findAll":48,"./loadRelations":50,"./refresh":51,"./save":52,"./update":53,"./updateAll":54}],50:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.loadRelations(' + resourceName + ', instance(Id), relations[, options]): '; } @@ -3036,7 +3223,7 @@ function loadRelations(resourceName, instance, relations, options) { module.exports = loadRelations; -},{}],46:[function(require,module,exports){ +},{}],51:[function(require,module,exports){ function errorPrefix(resourceName, id) { return 'DS.refresh(' + resourceName + ', ' + id + '[, options]): '; } @@ -3118,7 +3305,7 @@ function refresh(resourceName, id, options) { module.exports = refresh; -},{}],47:[function(require,module,exports){ +},{}],52:[function(require,module,exports){ function errorPrefix(resourceName, id) { return 'DS.save(' + resourceName + ', ' + id + '[, options]): '; } @@ -3220,6 +3407,7 @@ function save(resourceName, id, options) { return func.call(attrs, resourceName, attrs); }) .then(function (attrs) { + DS.notify(definition, 'beforeUpdate', DS.utils.merge({}, attrs)); if (options.changesOnly) { var resource = DS.store[resourceName]; resource.observers[id].deliver(); @@ -3247,16 +3435,17 @@ function save(resourceName, id, options) { var attrs = options.deserialize ? options.deserialize(resourceName, res) : definition.deserialize(resourceName, res); return func.call(attrs, resourceName, attrs); }) - .then(function (data) { + .then(function (attrs) { + DS.notify(definition, 'afterUpdate', DS.utils.merge({}, attrs)); if (options.cacheResponse) { var resource = DS.store[resourceName]; - var saved = DS.inject(definition.name, data, options); + var saved = DS.inject(definition.name, attrs, options); resource.previousAttributes[id] = DS.utils.deepMixIn({}, saved); resource.saved[id] = DS.utils.updateTimestamp(resource.saved[id]); resource.observers[id].discardChanges(); return DS.get(resourceName, id); } else { - return data; + return attrs; } }); } catch (err) { @@ -3267,7 +3456,7 @@ function save(resourceName, id, options) { module.exports = save; -},{}],48:[function(require,module,exports){ +},{}],53:[function(require,module,exports){ function errorPrefix(resourceName, id) { return 'DS.update(' + resourceName + ', ' + id + ', attrs[, options]): '; } @@ -3368,6 +3557,7 @@ function update(resourceName, id, attrs, options) { return func.call(attrs, resourceName, attrs); }) .then(function (attrs) { + DS.notify(definition, 'beforeUpdate', DS.utils.merge({}, attrs)); return DS.adapters[options.adapter || definition.defaultAdapter].update(definition, id, options.serialize ? options.serialize(resourceName, attrs) : definition.serialize(resourceName, attrs), options); }) .then(function (res) { @@ -3375,17 +3565,18 @@ function update(resourceName, id, attrs, options) { var attrs = options.deserialize ? options.deserialize(resourceName, res) : definition.deserialize(resourceName, res); return func.call(attrs, resourceName, attrs); }) - .then(function (data) { + .then(function (attrs) { + DS.notify(definition, 'afterUpdate', DS.utils.merge({}, attrs)); if (options.cacheResponse) { var resource = DS.store[resourceName]; - var updated = DS.inject(definition.name, data, options); + var updated = DS.inject(definition.name, attrs, options); var id = updated[definition.idAttribute]; resource.previousAttributes[id] = DS.utils.deepMixIn({}, updated); resource.saved[id] = DS.utils.updateTimestamp(resource.saved[id]); resource.observers[id].discardChanges(); return DS.get(definition.name, id); } else { - return data; + return attrs; } }); } catch (err) { @@ -3396,7 +3587,7 @@ function update(resourceName, id, attrs, options) { module.exports = update; -},{}],49:[function(require,module,exports){ +},{}],54:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.updateAll(' + resourceName + ', attrs, params[, options]): '; } @@ -3508,6 +3699,7 @@ function updateAll(resourceName, attrs, params, options) { return func.call(attrs, resourceName, attrs); }) .then(function (attrs) { + DS.notify(definition, 'beforeUpdate', DS.utils.merge({}, attrs)); return DS.adapters[options.adapter || definition.defaultAdapter].updateAll(definition, options.serialize ? options.serialize(resourceName, attrs) : definition.serialize(resourceName, attrs), params, options); }) .then(function (res) { @@ -3515,11 +3707,12 @@ function updateAll(resourceName, attrs, params, options) { var attrs = options.deserialize ? options.deserialize(resourceName, res) : definition.deserialize(resourceName, res); return func.call(attrs, resourceName, attrs); }) - .then(function (data) { + .then(function (attrs) { + DS.notify(definition, 'afterUpdate', DS.utils.merge({}, attrs)); if (options.cacheResponse) { - return DS.inject(definition.name, data, options); + return DS.inject(definition.name, attrs, options); } else { - return data; + return attrs; } }); } catch (err) { @@ -3530,7 +3723,7 @@ function updateAll(resourceName, attrs, params, options) { module.exports = updateAll; -},{}],50:[function(require,module,exports){ +},{}],55:[function(require,module,exports){ var utils = require('../utils')[0](); function lifecycleNoop(resourceName, attrs, cb) { @@ -3609,7 +3802,7 @@ Defaults.prototype.defaultFilter = function (collection, resourceName, params, o keep = first ? (attrs[field] <= val) : keep && (attrs[field] <= val); } else if (op === 'in') { keep = first ? _this.utils.contains(val, attrs[field]) : keep && _this.utils.contains(val, attrs[field]); - } else if (op === 'notIn') { + } else if (op === 'notIn') { keep = first ? !_this.utils.contains(val, attrs[field]) : keep && !_this.utils.contains(val, attrs[field]); } else if (op === '|==') { keep = first ? (attrs[field] == val) : keep || (attrs[field] == val); @@ -4193,6 +4386,7 @@ function DSProvider() { var args = Array.prototype.slice.call(arguments, 2); args.unshift(definition.name); args.unshift('DS.' + event); + definition.emit.apply(definition, args); if (definition.events === 'broadcast') { $rootScope.$broadcast.apply($rootScope, args); } else if (definition.events === 'emit') { @@ -4290,7 +4484,7 @@ function DSProvider() { module.exports = DSProvider; -},{"../utils":75,"./async_methods":44,"./sync_methods":64}],51:[function(require,module,exports){ +},{"../utils":80,"./async_methods":49,"./sync_methods":69}],56:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.bindAll(scope, expr, ' + resourceName + ', params[, cb]): '; } @@ -4375,7 +4569,7 @@ function bindAll(scope, expr, resourceName, params, cb) { module.exports = bindAll; -},{}],52:[function(require,module,exports){ +},{}],57:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.bindOne(scope, expr, ' + resourceName + ', id[, cb]): '; } @@ -4447,7 +4641,7 @@ function bindOne(scope, expr, resourceName, id, cb) { module.exports = bindOne; -},{}],53:[function(require,module,exports){ +},{}],58:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.changeHistory(' + resourceName + ', id): '; } @@ -4516,7 +4710,7 @@ function changeHistory(resourceName, id) { module.exports = changeHistory; -},{}],54:[function(require,module,exports){ +},{}],59:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.changes(' + resourceName + ', id): '; } @@ -4590,7 +4784,7 @@ function changes(resourceName, id) { module.exports = changes; -},{}],55:[function(require,module,exports){ +},{}],60:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.compute(' + resourceName + ', instance): '; } @@ -4687,7 +4881,7 @@ module.exports = { _compute: _compute }; -},{}],56:[function(require,module,exports){ +},{}],61:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.createInstance(' + resourceName + '[, attrs][, options]): '; } @@ -4784,7 +4978,7 @@ function createInstance(resourceName, attrs, options) { module.exports = createInstance; -},{}],57:[function(require,module,exports){ +},{}],62:[function(require,module,exports){ /*jshint evil:true*/ var errorPrefix = 'DS.defineResource(definition): '; @@ -4894,22 +5088,23 @@ var methodsToProxy = [ */ function defineResource(definition) { var DS = this; + var DSUtils = DS.utils; var definitions = DS.definitions; var IA = DS.errors.IA; - if (DS.utils.isString(definition)) { + if (DSUtils.isString(definition)) { definition = definition.replace(/\s/gi, ''); definition = { name: definition }; } - if (!DS.utils.isObject(definition)) { + if (!DSUtils.isObject(definition)) { throw new IA(errorPrefix + 'definition: Must be an object!'); - } else if (!DS.utils.isString(definition.name)) { + } else if (!DSUtils.isString(definition.name)) { throw new IA(errorPrefix + 'definition.name: Must be a string!'); - } else if (definition.idAttribute && !DS.utils.isString(definition.idAttribute)) { + } else if (definition.idAttribute && !DSUtils.isString(definition.idAttribute)) { throw new IA(errorPrefix + 'definition.idAttribute: Must be a string!'); - } else if (definition.endpoint && !DS.utils.isString(definition.endpoint)) { + } else if (definition.endpoint && !DSUtils.isString(definition.endpoint)) { throw new IA(errorPrefix + 'definition.endpoint: Must be a string!'); } else if (DS.store[definition.name]) { throw new DS.errors.R(errorPrefix + definition.name + ' is already registered!'); @@ -4918,7 +5113,7 @@ function defineResource(definition) { try { // Inherit from global defaults Resource.prototype = DS.defaults; - definitions[definition.name] = new Resource(DS.utils, definition); + definitions[definition.name] = new Resource(DSUtils, definition); var def = definitions[definition.name]; @@ -4926,12 +5121,12 @@ function defineResource(definition) { if (def.relations) { def.relationList = []; def.relationFields = []; - DS.utils.forOwn(def.relations, function (relatedModels, type) { - DS.utils.forOwn(relatedModels, function (defs, relationName) { - if (!DS.utils.isArray(defs)) { + DSUtils.forOwn(def.relations, function (relatedModels, type) { + DSUtils.forOwn(relatedModels, function (defs, relationName) { + if (!DSUtils.isArray(defs)) { relatedModels[relationName] = [defs]; } - DS.utils.forEach(relatedModels[relationName], function (d) { + DSUtils.forEach(relatedModels[relationName], function (d) { d.type = type; d.relation = relationName; d.name = def.name; @@ -4941,8 +5136,8 @@ function defineResource(definition) { }); }); if (def.relations.belongsTo) { - DS.utils.forOwn(def.relations.belongsTo, function (relatedModel, modelName) { - DS.utils.forEach(relatedModel, function (relation) { + DSUtils.forOwn(def.relations.belongsTo, function (relatedModel, modelName) { + DSUtils.forEach(relatedModel, function (relation) { if (relation.parent) { def.parent = modelName; def.parentKey = relation.localKey; @@ -4950,8 +5145,8 @@ function defineResource(definition) { }); }); } - DS.utils.deepFreeze(def.relations); - DS.utils.deepFreeze(def.relationList); + DSUtils.deepFreeze(def.relations); + DSUtils.deepFreeze(def.relationList); } def.getEndpoint = function (attrs, options) { @@ -4964,17 +5159,17 @@ function defineResource(definition) { options = options || {}; options.params = options.params || {}; if (parent && parentKey && definitions[parent] && options.params[parentKey] !== false) { - if (DS.utils.isNumber(attrs) || DS.utils.isString(attrs)) { + if (DSUtils.isNumber(attrs) || DSUtils.isString(attrs)) { item = DS.get(this.name, attrs); } - if (DS.utils.isObject(attrs) && parentKey in attrs) { + if (DSUtils.isObject(attrs) && parentKey in attrs) { delete options.params[parentKey]; - endpoint = DS.utils.makePath(definitions[parent].getEndpoint(attrs, options), attrs[parentKey], thisEndpoint); + endpoint = DSUtils.makePath(definitions[parent].getEndpoint(attrs, options), attrs[parentKey], thisEndpoint); } else if (item && parentKey in item) { delete options.params[parentKey]; - endpoint = DS.utils.makePath(definitions[parent].getEndpoint(attrs, options), item[parentKey], thisEndpoint); + endpoint = DSUtils.makePath(definitions[parent].getEndpoint(attrs, options), item[parentKey], thisEndpoint); } else if (options && options.params[parentKey]) { - endpoint = DS.utils.makePath(definitions[parent].getEndpoint(attrs, options), options.params[parentKey], thisEndpoint); + endpoint = DSUtils.makePath(definitions[parent].getEndpoint(attrs, options), options.params[parentKey], thisEndpoint); delete options.params[parentKey]; } } @@ -4999,7 +5194,7 @@ function defineResource(definition) { deleteOnExpire: def.deleteOnExpire || 'none', onExpire: function (id) { var item = DS.eject(def.name, id); - if (DS.utils.isFunction(def.onExpire)) { + if (DSUtils.isFunction(def.onExpire)) { def.onExpire(id, item); } }, @@ -5011,18 +5206,18 @@ function defineResource(definition) { }); // Create the wrapper class for the new resource - def.class = DS.utils.pascalCase(definition.name); + def.class = DSUtils.pascalCase(definition.name); eval('function ' + def.class + '() {}'); def[def.class] = eval(def.class); // Apply developer-defined methods if (def.methods) { - DS.utils.deepMixIn(def[def.class].prototype, def.methods); + DSUtils.deepMixIn(def[def.class].prototype, def.methods); } // Prepare for computed properties if (def.computed) { - DS.utils.forOwn(def.computed, function (fn, field) { + DSUtils.forOwn(def.computed, function (fn, field) { if (angular.isFunction(fn)) { def.computed[field] = [fn]; fn = def.computed[field]; @@ -5044,7 +5239,7 @@ function defineResource(definition) { angular.forEach(deps, function (val, index) { deps[index] = val.trim(); }); - fn.deps = DS.utils.filter(deps, function (dep) { + fn.deps = DSUtils.filter(deps, function (dep) { return !!dep; }); }); @@ -5096,6 +5291,9 @@ function defineResource(definition) { def.beforeDestroy = DS.$q.promisify(def.beforeDestroy); def.afterDestroy = DS.$q.promisify(def.afterDestroy); + // Mix-in events + DSUtils.Events(def); + return def; } catch (err) { DS.$log.error(err); @@ -5107,7 +5305,7 @@ function defineResource(definition) { module.exports = defineResource; -},{}],58:[function(require,module,exports){ +},{}],63:[function(require,module,exports){ var observe = require('../../../lib/observe-js/observe-js'); /** @@ -5143,7 +5341,7 @@ function digest() { module.exports = digest; -},{"../../../lib/observe-js/observe-js":1}],59:[function(require,module,exports){ +},{"../../../lib/observe-js/observe-js":1}],64:[function(require,module,exports){ function errorPrefix(resourceName, id) { return 'DS.eject(' + resourceName + ', ' + id + '): '; } @@ -5244,7 +5442,7 @@ function eject(resourceName, id) { module.exports = eject; -},{}],60:[function(require,module,exports){ +},{}],65:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.ejectAll(' + resourceName + '[, params]): '; } @@ -5358,7 +5556,7 @@ function ejectAll(resourceName, params) { module.exports = ejectAll; -},{}],61:[function(require,module,exports){ +},{}],66:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.filter(' + resourceName + '[, params][, options]): '; } @@ -5441,7 +5639,7 @@ function filter(resourceName, params, options) { module.exports = filter; -},{}],62:[function(require,module,exports){ +},{}],67:[function(require,module,exports){ function errorPrefix(resourceName, id) { return 'DS.get(' + resourceName + ', ' + id + '): '; } @@ -5505,7 +5703,7 @@ function get(resourceName, id, options) { module.exports = get; -},{}],63:[function(require,module,exports){ +},{}],68:[function(require,module,exports){ function errorPrefix(resourceName, id) { return 'DS.hasChanges(' + resourceName + ', ' + id + '): '; } @@ -5570,7 +5768,7 @@ function hasChanges(resourceName, id) { module.exports = hasChanges; -},{}],64:[function(require,module,exports){ +},{}],69:[function(require,module,exports){ module.exports = { /** @@ -5784,7 +5982,7 @@ module.exports = { unlinkInverse: require('./unlinkInverse') }; -},{"./bindAll":51,"./bindOne":52,"./changeHistory":53,"./changes":54,"./compute":55,"./createInstance":56,"./defineResource":57,"./digest":58,"./eject":59,"./ejectAll":60,"./filter":61,"./get":62,"./hasChanges":63,"./inject":65,"./lastModified":66,"./lastSaved":67,"./link":68,"./linkAll":69,"./linkInverse":70,"./previous":71,"./unlinkInverse":72}],65:[function(require,module,exports){ +},{"./bindAll":56,"./bindOne":57,"./changeHistory":58,"./changes":59,"./compute":60,"./createInstance":61,"./defineResource":62,"./digest":63,"./eject":64,"./ejectAll":65,"./filter":66,"./get":67,"./hasChanges":68,"./inject":70,"./lastModified":71,"./lastSaved":72,"./link":73,"./linkAll":74,"./linkInverse":75,"./previous":76,"./unlinkInverse":77}],70:[function(require,module,exports){ var observe = require('../../../lib/observe-js/observe-js'); var _compute = require('./compute')._compute; var stack = 0; @@ -6100,7 +6298,7 @@ function inject(resourceName, attrs, options) { module.exports = inject; -},{"../../../lib/observe-js/observe-js":1,"./compute":55}],66:[function(require,module,exports){ +},{"../../../lib/observe-js/observe-js":1,"./compute":60}],71:[function(require,module,exports){ function errorPrefix(resourceName, id) { return 'DS.lastModified(' + resourceName + '[, ' + id + ']): '; } @@ -6159,7 +6357,7 @@ function lastModified(resourceName, id) { module.exports = lastModified; -},{}],67:[function(require,module,exports){ +},{}],72:[function(require,module,exports){ function errorPrefix(resourceName, id) { return 'DS.lastSaved(' + resourceName + '[, ' + id + ']): '; } @@ -6223,7 +6421,7 @@ function lastSaved(resourceName, id) { module.exports = lastSaved; -},{}],68:[function(require,module,exports){ +},{}],73:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.link(' + resourceName + ', id[, relations]): '; } @@ -6325,7 +6523,7 @@ function link(resourceName, id, relations) { module.exports = link; -},{}],69:[function(require,module,exports){ +},{}],74:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.linkAll(' + resourceName + '[, params][, relations]): '; } @@ -6442,7 +6640,7 @@ function linkAll(resourceName, params, relations) { module.exports = linkAll; -},{}],70:[function(require,module,exports){ +},{}],75:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.linkInverse(' + resourceName + ', id[, relations]): '; } @@ -6540,7 +6738,7 @@ function linkInverse(resourceName, id, relations) { module.exports = linkInverse; -},{}],71:[function(require,module,exports){ +},{}],76:[function(require,module,exports){ function errorPrefix(resourceName, id) { return 'DS.previous(' + resourceName + '[, ' + id + ']): '; } @@ -6597,7 +6795,7 @@ function previous(resourceName, id) { module.exports = previous; -},{}],72:[function(require,module,exports){ +},{}],77:[function(require,module,exports){ function errorPrefix(resourceName) { return 'DS.unlinkInverse(' + resourceName + ', id[, relations]): '; } @@ -6696,7 +6894,7 @@ function unlinkInverse(resourceName, id, relations) { module.exports = unlinkInverse; -},{}],73:[function(require,module,exports){ +},{}],78:[function(require,module,exports){ /** * @doc function * @id errors.types:IllegalArgumentError @@ -6829,7 +7027,7 @@ module.exports = [function () { }; }]; -},{}],74:[function(require,module,exports){ +},{}],79:[function(require,module,exports){ (function (window, angular, undefined) { 'use strict'; @@ -6917,7 +7115,51 @@ module.exports = [function () { })(window, window.angular); -},{"./adapters/http":37,"./adapters/localStorage":38,"./datastore":50,"./errors":73,"./utils":75}],75:[function(require,module,exports){ +},{"./adapters/http":42,"./adapters/localStorage":43,"./datastore":55,"./errors":78,"./utils":80}],80:[function(require,module,exports){ +function Events(target) { + var events = {}; + target = target || this; + /** + * On: listen to events + */ + target.on = function (type, func, ctx) { + events[type] = events[type] || []; + events[type].push({ + f: func, + c: ctx + }); + }; + + /** + * Off: stop listening to event / specific callback + */ + target.off = function (type, func) { + var listeners = events[type]; + if (!listeners) { + events = {}; + } else if (func) { + for (var i = 0; i < listeners.length; i++) { + if (listeners[i] === func) { + listeners.splice(i, 1); + break; + } + } + } else { + listeners.splice(0, listeners.length); + } + }; + + target.emit = function () { + var args = Array.prototype.slice.call(arguments); + var listeners = events[args.shift()] || []; + if (listeners) { + for (var i = 0; i < listeners.length; i++) { + listeners[i].f.apply(listeners[i].c, args); + } + } + }; +} + module.exports = [function () { return { isBoolean: require('mout/lang/isBoolean'), @@ -6936,6 +7178,7 @@ module.exports = [function () { forEach: angular.forEach, pick: require('mout/object/pick'), set: require('mout/object/set'), + merge: require('mout/object/merge'), contains: require('mout/array/contains'), filter: require('mout/array/filter'), toLookup: require('mout/array/toLookup'), @@ -7015,8 +7258,9 @@ module.exports = [function () { removed: removed, changed: changed }; - } + }, + Events: Events }; }]; -},{"mout/array/contains":2,"mout/array/filter":3,"mout/array/remove":7,"mout/array/slice":8,"mout/array/sort":9,"mout/array/toLookup":10,"mout/lang/isBoolean":15,"mout/lang/isEmpty":16,"mout/object/deepMixIn":23,"mout/object/forOwn":25,"mout/object/pick":28,"mout/object/set":29,"mout/string/makePath":32,"mout/string/pascalCase":33,"mout/string/upperCase":36}]},{},[74]); +},{"mout/array/contains":2,"mout/array/filter":3,"mout/array/remove":7,"mout/array/slice":8,"mout/array/sort":9,"mout/array/toLookup":10,"mout/lang/isBoolean":17,"mout/lang/isEmpty":18,"mout/object/deepMixIn":26,"mout/object/forOwn":28,"mout/object/merge":30,"mout/object/pick":33,"mout/object/set":34,"mout/string/makePath":37,"mout/string/pascalCase":38,"mout/string/upperCase":41}]},{},[79]); diff --git a/dist/angular-data.min.js b/dist/angular-data.min.js index 1206522..787098a 100644 --- a/dist/angular-data.min.js +++ b/dist/angular-data.min.js @@ -7,5 +7,5 @@ * * @overview Data store for Angular.js. */ -!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;gb&&a.check_();)b++;return global.testingExposeCycleCount&&(global.dirtyCheckCycleCount=b),b>0}function objectIsEmpty(a){for(var b in a)return!1;return!0}function diffIsEmpty(a){return objectIsEmpty(a.added)&&objectIsEmpty(a.removed)&&objectIsEmpty(a.changed)}function diffObjectFromOldObject(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var f in a)f in b||(c[f]=a[f]);return Array.isArray(a)&&a.length!==b.length&&(e.length=a.length),{added:c,removed:d,changed:e}}function runEOMTasks(){if(!eomTasks.length)return!1;for(var a=0;acycles&&anyChanged);global.testingExposeCycleCount&&(global.dirtyCheckCycleCount=cycles),runningMicrotaskCheckpoint=!1}}},collectObservers&&(global.Platform.clearObservers=function(){allObservers=[]}),ObjectObserver.prototype=createObject({__proto__:Observer.prototype,arrayObserve:!1,connect_:function(){hasObserve?this.directObserver_=getObservedObject(this,this.value_,this.arrayObserve):this.oldObject_=this.copyObject(this.value_)},copyObject:function(a){var b=Array.isArray(a)?[]:{};for(var c in a)b[c]=a[c];return Array.isArray(a)&&(b.length=a.length),b},check_:function(a){var b,c;if(hasObserve){if(!a)return!1;c={},b=diffObjectFromChangeRecords(this.value_,a,c)}else c=this.oldObject_,b=diffObjectFromOldObject(this.value_,this.oldObject_);return diffIsEmpty(b)?!1:(hasObserve||(this.oldObject_=this.copyObject(this.value_)),this.report_([b.added||{},b.removed||{},b.changed||{},function(a){return c[a]}]),!0)},disconnect_:function(){hasObserve?(this.directObserver_.close(),this.directObserver_=void 0):this.oldObject_=void 0},deliver:function(){this.state_==OPENED&&(hasObserve?this.directObserver_.deliver(!1):dirtyCheck(this))},discardChanges:function(){return this.directObserver_?this.directObserver_.deliver(!0):this.oldObject_=this.copyObject(this.value_),this.value_}});var observerSentinel={},expectedRecordTypes={add:!0,update:!0,"delete":!0};global.Observer=Observer,global.Observer.runEOM_=runEOM,global.Observer.observerSentinel_=observerSentinel,global.Observer.hasObjectObserve=hasObserve,global.ObjectObserver=ObjectObserver}((exports.Number={isNaN:window.isNaN})?exports:exports)},{}],2:[function(a,b){function c(a,b){return-1!==d(a,b)}var d=a("./indexOf");b.exports=c},{"./indexOf":5}],3:[function(a,b){function c(a,b,c){b=d(b,c);var e=[];if(null==a)return e;for(var f,g=-1,h=a.length;++gc?d+c:c;d>e;){if(a[e]===b)return e;e++}return-1}b.exports=c},{}],6:[function(a,b){function c(a){return null!=a&&""!==a}function d(a,b){return b=b||"",e(a,c).join(b)}var e=a("./filter");b.exports=d},{"./filter":3}],7:[function(a,b){function c(a,b){var c=d(a,b);-1!==c&&a.splice(c,1)}var d=a("./indexOf");b.exports=c},{"./indexOf":5}],8:[function(a,b){function c(a,b,c){var d=a.length;b=null==b?0:0>b?Math.max(d+b,0):Math.min(b,d),c=null==c?d:0>c?Math.max(d+c,0):Math.min(c,d);for(var e=[];c>b;)e.push(a[b++]);return e}b.exports=c},{}],9:[function(a,b){function c(a,b){if(null==a)return[];if(a.length<2)return a;null==b&&(b=d);var f,g,h;return f=~~(a.length/2),g=c(a.slice(0,f),b),h=c(a.slice(f,a.length),b),e(g,h,b)}function d(a,b){return b>a?-1:a>b?1:0}function e(a,b,c){for(var d=[];a.length&&b.length;)d.push(c(a[0],b[0])<=0?a.shift():b.shift());return a.length&&d.push.apply(d,a),b.length&&d.push.apply(d,b),d}b.exports=c},{}],10:[function(a,b){function c(a,b){var c={};if(null==a)return c;var e,f=-1,g=a.length;if(d(b))for(;++f-1&&(a=a.replace(/[\xC0-\xC5]/g,"A").replace(/[\xC6]/g,"AE").replace(/[\xC7]/g,"C").replace(/[\xC8-\xCB]/g,"E").replace(/[\xCC-\xCF]/g,"I").replace(/[\xD0]/g,"D").replace(/[\xD1]/g,"N").replace(/[\xD2-\xD6\xD8]/g,"O").replace(/[\xD9-\xDC]/g,"U").replace(/[\xDD]/g,"Y").replace(/[\xDE]/g,"P").replace(/[\xE0-\xE5]/g,"a").replace(/[\xE6]/g,"ae").replace(/[\xE7]/g,"c").replace(/[\xE8-\xEB]/g,"e").replace(/[\xEC-\xEF]/g,"i").replace(/[\xF1]/g,"n").replace(/[\xF2-\xF6\xF8]/g,"o").replace(/[\xF9-\xFC]/g,"u").replace(/[\xFE]/g,"p").replace(/[\xFD\xFF]/g,"y")),a}var d=a("../lang/toString");b.exports=c},{"../lang/toString":21}],36:[function(a,b){function c(a){return a=d(a),a.toUpperCase()}var d=a("../lang/toString");b.exports=c},{"../lang/toString":21}],37:[function(a,b){function c(){var a=this.defaults={queryTransform:function(a,b){return b},$httpConfig:{}};this.$get=["$http","$log","DSUtils",function(b,c,d){return{defaults:a,HTTP:function(e){var f=(new Date).getTime();return e=d.deepMixIn(e,a.$httpConfig),b(e).then(function(a){return c.debug(a.config.method+" request:"+a.config.url+" Time taken: "+((new Date).getTime()-f)+"ms",arguments),a})},GET:function(a,b){return b=b||{},"method"in b||(b.method="GET"),this.HTTP(d.deepMixIn(b,{url:a}))},POST:function(a,b,c){return c=c||{},"method"in c||(c.method="POST"),this.HTTP(d.deepMixIn(c,{url:a,data:b}))},PUT:function(a,b,c){return c=c||{},"method"in c||(c.method="PUT"),this.HTTP(d.deepMixIn(c,{url:a,data:b||{}}))},DEL:function(a,b){return b=b||{},"method"in b||(b.method="DELETE"),this.HTTP(d.deepMixIn(b,{url:a}))},find:function(a,b,c){return c=c||{},this.GET(d.makePath(c.baseUrl||a.baseUrl,a.getEndpoint(b,c),b),c)},findAll:function(b,c,e){return e=e||{},e.params=e.params||{},c&&(c=a.queryTransform(b.name,c),d.deepMixIn(e.params,c)),this.GET(d.makePath(e.baseUrl||b.baseUrl,b.getEndpoint(null,e)),e)},create:function(a,b,c){return c=c||{},this.POST(d.makePath(c.baseUrl||a.baseUrl,a.getEndpoint(b,c)),b,c)},update:function(a,b,c,e){return e=e||{},this.PUT(d.makePath(e.baseUrl||a.baseUrl,a.getEndpoint(b,e),b),c,e)},updateAll:function(b,c,e,f){return f=f||{},f.params=f.params||{},e&&(e=a.queryTransform(b.name,e),d.deepMixIn(f.params,e)),this.PUT(d.makePath(f.baseUrl||b.baseUrl,b.getEndpoint(null,f)),c,f)},destroy:function(a,b,c){return c=c||{},this.DEL(d.makePath(c.baseUrl||a.baseUrl,a.getEndpoint(b,c),b),c)},destroyAll:function(b,c,e){return e=e||{},e.params=e.params||{},c&&(c=a.queryTransform(b.name,c),d.deepMixIn(e.params,c)),this.DEL(d.makePath(e.baseUrl||b.baseUrl,b.getEndpoint(null,e)),e)}}}]}b.exports=c},{}],38:[function(a,b){function c(){this.$get=["$q","DSUtils","DSErrors",function(a,b,c){return{GET:function(b){var c=a.defer();try{var d=localStorage.getItem(b);c.resolve(d?angular.fromJson(d):void 0)}catch(e){c.reject(e)}return c.promise},PUT:function(a,c){var d=this;return d.GET(a).then(function(e){return e&&b.deepMixIn(e,c),localStorage.setItem(a,angular.toJson(e||c)),d.GET(a)})},DEL:function(b){var c=a.defer();try{localStorage.removeItem(b),c.resolve()}catch(d){c.reject(d)}return c.promise},find:function(a,c,d){return d=d||{},this.GET(b.makePath(d.baseUrl||a.baseUrl,a.endpoint,c))},findAll:function(){throw new Error("DSLocalStorageAdapter.findAll is not supported!")},create:function(a,d,e){if(!(a.idAttribute in d))throw new c.IA("DSLocalStorageAdapter.create: You must provide a primary key in the attrs object!");return e=e||{},this.PUT(b.makePath(e.baseUrl||a.baseUrl,a.getEndpoint(d,e),d[a.idAttribute]),d)},update:function(a,c,d,e){return e=e||{},this.PUT(b.makePath(e.baseUrl||a.baseUrl,a.getEndpoint(c,e),c),d)},updateAll:function(){throw new Error("DSLocalStorageAdapter.updateAll is not supported!")},destroy:function(a,c,d){return d=d||{},this.DEL(b.makePath(d.baseUrl||a.baseUrl,a.getEndpoint(c,d),c))},destroyAll:function(){throw new Error("Not supported!")}}}]}b.exports=c},{}],39:[function(a,b){function c(a){return"DS.create("+a+", attrs[, options]): "}function d(a,b,d){var e=this,f=e.$q.defer();try{var g=e.definitions[a];if(d=d||{},!g)throw new e.errors.NER(c(a)+a);if(!e.utils.isObject(b))throw new e.errors.IA(c(a)+"attrs: Must be an object!");return"cacheResponse"in d||(d.cacheResponse=!0),"upsert"in d||(d.upsert=!0),f.resolve(b),d.upsert&&b[g.idAttribute]?e.update(a,b[g.idAttribute],b,d):f.promise.then(function(b){var c=d.beforeValidate?e.$q.promisify(d.beforeValidate):g.beforeValidate;return c.call(b,a,b)}).then(function(b){var c=d.validate?e.$q.promisify(d.validate):g.validate;return c.call(b,a,b)}).then(function(b){var c=d.afterValidate?e.$q.promisify(d.afterValidate):g.afterValidate;return c.call(b,a,b)}).then(function(b){var c=d.beforeCreate?e.$q.promisify(d.beforeCreate):g.beforeCreate;return c.call(b,a,b)}).then(function(b){return e.adapters[d.adapter||g.defaultAdapter].create(g,d.serialize?d.serialize(a,b):g.serialize(a,b),d)}).then(function(b){var c=d.afterCreate?e.$q.promisify(d.afterCreate):g.afterCreate,f=d.deserialize?d.deserialize(a,b):g.deserialize(a,b);return c.call(f,a,f)}).then(function(b){if(d.cacheResponse){var c=e.store[a],f=e.inject(g.name,b,d),h=f[g.idAttribute];return c.completedQueries[h]=(new Date).getTime(),c.previousAttributes[h]=e.utils.deepMixIn({},f),c.saved[h]=e.utils.updateTimestamp(c.saved[h]),e.get(g.name,h)}return e.createInstance(a,b,d)})}catch(h){return f.reject(h),f.promise}}b.exports=d},{}],40:[function(a,b){function c(a,b){return"DS.destroy("+a+", "+b+"[, options]): "}function d(a,b,d){var e=this,f=e.$q.defer();try{var g=e.definitions[a];if(d=d||{},b=e.utils.resolveId(g,b),!g)throw new e.errors.NER(c(a,b)+a);if(!e.utils.isString(b)&&!e.utils.isNumber(b))throw new e.errors.IA(c(a,b)+"id: Must be a string or a number!");var h=e.get(a,b);if(!h)throw new e.errors.R(c(a,b)+'id: "'+b+'" not found!');return f.resolve(h),f.promise.then(function(b){var c=d.beforeDestroy?e.$q.promisify(d.beforeDestroy):g.beforeDestroy;return c.call(b,a,b)}).then(function(){return e.adapters[d.adapter||g.defaultAdapter].destroy(g,b,d)}).then(function(){var b=d.afterDestroy?e.$q.promisify(d.afterDestroy):g.afterDestroy;return b.call(h,a,h)}).then(function(){return e.eject(a,b),b})}catch(i){return f.reject(i),f.promise}}b.exports=d},{}],41:[function(a,b){function c(a){return"DS.destroyAll("+a+", params[, options]): "}function d(a,b,d){var e=this,f=e.$q.defer();try{var g=e.errors.IA,h=e.definitions[a];if(d=d||{},!h)throw new e.errors.NER(c(a)+a);if(!e.utils.isObject(b))throw new g(c(a)+"params: Must be an object!");if(!e.utils.isObject(d))throw new g(c(a)+"options: Must be an object!");return f.resolve(),f.promise.then(function(){return e.adapters[d.adapter||h.defaultAdapter].destroyAll(h,b,d)}).then(function(){return e.ejectAll(a,b)})}catch(i){return f.reject(i),f.promise}}b.exports=d},{}],42:[function(a,b){function c(a,b){return"DS.find("+a+", "+b+"[, options]): "}function d(a,b,d){var e=this,f=e.$q.defer(),g=f.promise;try{var h=e.errors.IA,i=e.definitions[a];if(d=d||{},!i)throw new e.errors.NER(c(a,b)+a);if(!e.utils.isString(b)&&!e.utils.isNumber(b))throw new h(c(a,b)+"id: Must be a string or a number!");if(!e.utils.isObject(d))throw new h(c(a,b)+"options: Must be an object!");"cacheResponse"in d||(d.cacheResponse=!0);var j=e.store[a];if((d.bypassCache||!d.cacheResponse)&&delete j.completedQueries[b],!(b in j.completedQueries))return b in j.pendingQueries||(g=j.pendingQueries[b]=e.adapters[d.adapter||i.defaultAdapter].find(i,b,d).then(function(c){var f=d.deserialize?d.deserialize(a,c):i.deserialize(a,c);return d.cacheResponse?(delete j.pendingQueries[b],j.completedQueries[b]=(new Date).getTime(),e.inject(a,f,d)):e.createInstance(a,f,d)},function(a){return delete j.pendingQueries[b],e.$q.reject(a)})),j.pendingQueries[b];f.resolve(e.get(a,b))}catch(k){f.reject(k)}return g}b.exports=d},{}],43:[function(a,b){function c(a){return"DS.findAll("+a+", params[, options]): "}function d(a,b,d,e){var f=this,g=f.store[b],h=f.definitions[b].idAttribute,i=(new Date).getTime();a=a||[],delete g.pendingQueries[d],g.completedQueries[d]=i,g.collectionModified=f.utils.updateTimestamp(g.collectionModified);var j=f.inject(b,a,e);return f.utils.isArray(j)?angular.forEach(j,function(a){a&&a[h]&&(g.completedQueries[a[h]]=i)}):(f.$log.warn(c(b)+"response is expected to be an array!"),g.completedQueries[j[h]]=i),j}function e(a,b,c){var e=this,f=e.definitions[a],g=e.store[a],h=e.utils.toJson(b);return(c.bypassCache||!c.cacheResponse)&&delete g.completedQueries[h],h in g.completedQueries?e.filter(a,b,c):(h in g.pendingQueries||(g.pendingQueries[h]=e.adapters[c.adapter||f.defaultAdapter].findAll(f,b,c).then(function(b){delete g.pendingQueries[h];var i=c.deserialize?c.deserialize(a,b):f.deserialize(a,b);if(!c.cacheResponse)return e.utils.forEach(i,function(b,d){i[d]=e.createInstance(a,b,c)}),i;try{return d.call(e,i,a,h,c)}catch(j){return e.$q.reject(j)}},function(a){return delete g.pendingQueries[h],e.$q.reject(a)})),g.pendingQueries[h])}function f(a,b,d){var f=this,g=f.$q.defer();try{var h=f.errors.IA;if(d=d||{},b=b||{},!f.definitions[a])throw new f.errors.NER(c(a)+a);if(!f.utils.isObject(b))throw new h(c(a)+"params: Must be an object!");if(!f.utils.isObject(d))throw new h(c(a)+"options: Must be an object!");return"cacheResponse"in d||(d.cacheResponse=!0),g.resolve(),g.promise.then(function(){return e.call(f,a,b,d)})}catch(i){return g.reject(i),g.promise}}b.exports=f},{}],44:[function(a,b){b.exports={create:a("./create"),destroy:a("./destroy"),destroyAll:a("./destroyAll"),find:a("./find"),findAll:a("./findAll"),loadRelations:a("./loadRelations"),refresh:a("./refresh"),save:a("./save"),update:a("./update"),updateAll:a("./updateAll")}},{"./create":39,"./destroy":40,"./destroyAll":41,"./find":42,"./findAll":43,"./loadRelations":45,"./refresh":46,"./save":47,"./update":48,"./updateAll":49}],45:[function(a,b){function c(a){return"DS.loadRelations("+a+", instance(Id), relations[, options]): "}function d(a,b,d,e){var f=this,g=f.$q.defer();try{var h=f.errors.IA,i=f.definitions[a];if(e=e||{},(angular.isString(b)||angular.isNumber(b))&&(b=f.get(a,b)),angular.isString(d)&&(d=[d]),!i)throw new f.errors.NER(c(a)+a);if(!f.utils.isObject(b))throw new h(c(a)+"instance(Id): Must be a string, number or object!");if(!f.utils.isArray(d))throw new h(c(a)+"relations: Must be a string or an array!");if(!f.utils.isObject(e))throw new h(c(a)+"options: Must be an object!");"findBelongsTo"in e||(e.findBelongsTo=!0),"findHasMany"in e||(e.findHasMany=!0);var j=[],k=[];return f.utils.forEach(i.relationList,function(a){var c=a.relation;if(f.utils.contains(d,c)){var g,h={};h[a.foreignKey]=b[i.idAttribute],"hasMany"===a.type&&h[a.foreignKey]?g=f.findAll(c,h,e):"hasOne"===a.type?a.localKey&&b[a.localKey]?g=f.find(c,b[a.localKey],e):a.foreignKey&&h[a.foreignKey]&&(g=f.findAll(c,h,e).then(function(a){return a.length?a[0]:null})):b[a.localKey]&&(g=f.find(c,b[a.localKey],e)),g&&(j.push(g),k.push(a.localField))}}),g.resolve(),g.promise.then(function(){return f.$q.all(j)}).then(function(a){return angular.forEach(k,function(c,d){b[c]=a[d]}),b})}catch(l){return g.reject(l),g.promise}}b.exports=d},{}],46:[function(a,b){function c(a,b){return"DS.refresh("+a+", "+b+"[, options]): "}function d(a,b,d){var e=this,f=e.errors.IA;if(d=d||{},b=e.utils.resolveId(e.definitions[a],b),e.definitions[a]){if(e.utils.isString(b)||e.utils.isNumber(b)){if(e.utils.isObject(d)){if(d.bypassCache=!0,e.get(a,b))return e.find(a,b,d);var g=e.$q.defer();return g.resolve(),g.promise}throw new f(c(a,b)+"options: Must be an object!")}throw new f(c(a,b)+"id: Must be a string or a number!")}throw new e.errors.NER(c(a,b)+a)}b.exports=d},{}],47:[function(a,b){function c(a,b){return"DS.save("+a+", "+b+"[, options]): "}function d(a,b,d){var e=this,f=e.$q.defer();try{var g=e.errors.IA,h=e.definitions[a];if(d=d||{},b=e.utils.resolveId(h,b),!h)throw new e.errors.NER(c(a,b)+a);if(!e.utils.isString(b)&&!e.utils.isNumber(b))throw new g(c(a,b)+"id: Must be a string or a number!");if(!e.utils.isObject(d))throw new g(c(a,b)+"options: Must be an object!");var i=e.get(a,b);if(!i)throw new e.errors.R(c(a,b)+'id: "'+b+'" not found!');return"cacheResponse"in d||(d.cacheResponse=!0),f.resolve(i),f.promise.then(function(b){var c=d.beforeValidate?e.$q.promisify(d.beforeValidate):h.beforeValidate;return c.call(b,a,b)}).then(function(b){var c=d.validate?e.$q.promisify(d.validate):h.validate;return c.call(b,a,b)}).then(function(b){var c=d.afterValidate?e.$q.promisify(d.afterValidate):h.afterValidate;return c.call(b,a,b)}).then(function(b){var c=d.beforeUpdate?e.$q.promisify(d.beforeUpdate):h.beforeUpdate;return c.call(b,a,b)}).then(function(c){if(d.changesOnly){var f=e.store[a];f.observers[b].deliver();var g=[],i=e.changes(a,b);for(var j in i.added)g.push(j);for(j in i.changed)g.push(j);if(i=e.utils.pick(c,g),e.utils.isEmpty(i))return c;c=i}return e.adapters[d.adapter||h.defaultAdapter].update(h,b,d.serialize?d.serialize(a,c):h.serialize(a,c),d)}).then(function(b){var c=d.afterUpdate?e.$q.promisify(d.afterUpdate):h.afterUpdate,f=d.deserialize?d.deserialize(a,b):h.deserialize(a,b);return c.call(f,a,f)}).then(function(c){if(d.cacheResponse){var f=e.store[a],g=e.inject(h.name,c,d);return f.previousAttributes[b]=e.utils.deepMixIn({},g),f.saved[b]=e.utils.updateTimestamp(f.saved[b]),f.observers[b].discardChanges(),e.get(a,b)}return c})}catch(j){return f.reject(j),f.promise}}b.exports=d},{}],48:[function(a,b){function c(a,b){return"DS.update("+a+", "+b+", attrs[, options]): "}function d(a,b,d,e){var f=this,g=f.$q.defer();try{var h=f.errors.IA,i=f.definitions[a];if(e=e||{},b=f.utils.resolveId(i,b),!i)throw new f.errors.NER(c(a,b)+a);if(!f.utils.isString(b)&&!f.utils.isNumber(b))throw new h(c(a,b)+"id: Must be a string or a number!");if(!f.utils.isObject(d))throw new h(c(a,b)+"attrs: Must be an object!");if(!f.utils.isObject(e))throw new h(c(a,b)+"options: Must be an object!");return"cacheResponse"in e||(e.cacheResponse=!0),g.resolve(d),g.promise.then(function(b){var c=e.beforeValidate?f.$q.promisify(e.beforeValidate):i.beforeValidate;return c.call(b,a,b)}).then(function(b){var c=e.validate?f.$q.promisify(e.validate):i.validate;return c.call(b,a,b)}).then(function(b){var c=e.afterValidate?f.$q.promisify(e.afterValidate):i.afterValidate;return c.call(b,a,b)}).then(function(b){var c=e.beforeUpdate?f.$q.promisify(e.beforeUpdate):i.beforeUpdate;return c.call(b,a,b)}).then(function(c){return f.adapters[e.adapter||i.defaultAdapter].update(i,b,e.serialize?e.serialize(a,c):i.serialize(a,c),e)}).then(function(b){var c=e.afterUpdate?f.$q.promisify(e.afterUpdate):i.afterUpdate,d=e.deserialize?e.deserialize(a,b):i.deserialize(a,b);return c.call(d,a,d)}).then(function(b){if(e.cacheResponse){var c=f.store[a],d=f.inject(i.name,b,e),g=d[i.idAttribute];return c.previousAttributes[g]=f.utils.deepMixIn({},d),c.saved[g]=f.utils.updateTimestamp(c.saved[g]),c.observers[g].discardChanges(),f.get(i.name,g)}return b})}catch(j){return g.reject(j),g.promise}}b.exports=d},{}],49:[function(a,b){function c(a){return"DS.updateAll("+a+", attrs, params[, options]): "}function d(a,b,d,e){var f=this,g=f.$q.defer();try{var h=f.errors.IA,i=f.definitions[a];if(e=e||{},!i)throw new f.errors.NER(c(a)+a);if(!f.utils.isObject(b))throw new h(c(a)+"attrs: Must be an object!");if(!f.utils.isObject(d))throw new h(c(a)+"params: Must be an object!");if(!f.utils.isObject(e))throw new h(c(a)+"options: Must be an object!");return"cacheResponse"in e||(e.cacheResponse=!0),g.resolve(b),g.promise.then(function(b){var c=e.beforeValidate?f.$q.promisify(e.beforeValidate):i.beforeValidate;return c.call(b,a,b)}).then(function(b){var c=e.validate?f.$q.promisify(e.validate):i.validate;return c.call(b,a,b)}).then(function(b){var c=e.afterValidate?f.$q.promisify(e.afterValidate):i.afterValidate;return c.call(b,a,b)}).then(function(b){var c=e.beforeUpdate?f.$q.promisify(e.beforeUpdate):i.beforeUpdate;return c.call(b,a,b)}).then(function(b){return f.adapters[e.adapter||i.defaultAdapter].updateAll(i,e.serialize?e.serialize(a,b):i.serialize(a,b),d,e)}).then(function(b){var c=e.afterUpdate?f.$q.promisify(e.afterUpdate):i.afterUpdate,d=e.deserialize?e.deserialize(a,b):i.deserialize(a,b);return c.call(d,a,d)}).then(function(a){return e.cacheResponse?f.inject(i.name,a,e):a})}catch(j){return g.reject(j),g.promise}}b.exports=d},{}],50:[function(a,b){function c(a,b,c){c(null,b)}function d(){}function e(){var b=this.defaults=new d;this.$get=["$rootScope","$log","$q","DSHttpAdapter","DSLocalStorageAdapter","DSUtils","DSErrors",function(c,d,e,f,g,h,i){var j,k=a("./sync_methods"),l=a("./async_methods");try{j=angular.injector(["angular-data.DSCacheFactory"]).get("DSCacheFactory")}catch(m){d.warn(m),d.warn("DSCacheFactory is unavailable. Resorting to the lesser capabilities of $cacheFactory."),j=angular.injector(["ng"]).get("$cacheFactory")}var n={notify:function(a,b){var d=Array.prototype.slice.call(arguments,2);d.unshift(a.name),d.unshift("DS."+b),"broadcast"===a.events?c.$broadcast.apply(c,d):"emit"===a.events&&c.$emit.apply(c,d)},$rootScope:c,$log:d,$q:e,cacheFactory:j,defaults:b,store:{},definitions:{},adapters:{DSHttpAdapter:f,DSLocalStorageAdapter:g},errors:i,utils:h};return h.deepFreeze(k),h.deepFreeze(l),h.deepMixIn(n,k),h.deepMixIn(n,l),h.deepFreeze(n.errors),h.deepFreeze(n.utils),("function"!=typeof Object.observe||"function"!=typeof Array.observe)&&c.$watch(function(){return(new Date).getTime()/100|0},function(){n.digest()}),n}]}a("../utils")[0]();d.prototype.idAttribute="id",d.prototype.defaultAdapter="DSHttpAdapter",d.prototype.defaultFilter=function(a,b,c,d){var e=this,f=a,g=null,h={skip:"",offset:"",where:"",limit:"",orderBy:"",sort:""};g=this.utils.isObject(c.where)?c.where:{},d.allowSimpleWhere&&this.utils.forOwn(c,function(a,b){b in h||b in g||(g[b]={"==":a})}),this.utils.isEmpty(g)&&(g=null),g&&(f=this.utils.filter(f,function(a){var b=!0,c=!0;return e.utils.forOwn(g,function(d,f){e.utils.isString(d)?d={"===":d}:(e.utils.isNumber(d)||e.utils.isBoolean(d))&&(d={"==":d}),e.utils.isObject(d)&&e.utils.forOwn(d,function(d,g){"=="===g?c=b?a[f]==d:c&&a[f]==d:"==="===g?c=b?a[f]===d:c&&a[f]===d:"!="===g?c=b?a[f]!=d:c&&a[f]!=d:"!=="===g?c=b?a[f]!==d:c&&a[f]!==d:">"===g?c=b?a[f]>d:c&&a[f]>d:">="===g?c=b?a[f]>=d:c&&a[f]>=d:"<"===g?c=b?a[f]"===g?c=b?a[f]>d:c||a[f]>d:"|>="===g?c=b?a[f]>=d:c||a[f]>=d:"|<"===g?c=b?a[f]f?-1:f>d?1:0:f>d?-1:d>f?1:0})});var j=angular.isNumber(c.limit)?c.limit:null,k=null;return angular.isNumber(c.skip)?k=c.skip:angular.isNumber(c.offset)&&(k=c.offset),j&&k?f=this.utils.slice(f,k,Math.min(f.length,k+j)):this.utils.isNumber(j)?f=this.utils.slice(f,0,Math.min(f.length,j)):this.utils.isNumber(k)&&(f=k=b?a+1:b},deepFreeze:function b(a){if("function"==typeof Object.freeze){var c,d;Object.freeze(a);for(d in a)c=a[d],a.hasOwnProperty(d)&&"object"==typeof c&&!Object.isFrozen(c)&&b(c)}},diffObjectFromOldObject:function(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var h in a)h in b||(c[h]=a[h]);return{added:c,removed:d,changed:e}}}}]},{"mout/array/contains":2,"mout/array/filter":3,"mout/array/remove":7,"mout/array/slice":8,"mout/array/sort":9,"mout/array/toLookup":10,"mout/lang/isBoolean":15,"mout/lang/isEmpty":16,"mout/object/deepMixIn":23,"mout/object/forOwn":25,"mout/object/pick":28,"mout/object/set":29,"mout/string/makePath":32,"mout/string/pascalCase":33,"mout/string/upperCase":36}]},{},[74]); \ No newline at end of file +!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;gb&&a.check_();)b++;return global.testingExposeCycleCount&&(global.dirtyCheckCycleCount=b),b>0}function objectIsEmpty(a){for(var b in a)return!1;return!0}function diffIsEmpty(a){return objectIsEmpty(a.added)&&objectIsEmpty(a.removed)&&objectIsEmpty(a.changed)}function diffObjectFromOldObject(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var f in a)f in b||(c[f]=a[f]);return Array.isArray(a)&&a.length!==b.length&&(e.length=a.length),{added:c,removed:d,changed:e}}function runEOMTasks(){if(!eomTasks.length)return!1;for(var a=0;acycles&&anyChanged);global.testingExposeCycleCount&&(global.dirtyCheckCycleCount=cycles),runningMicrotaskCheckpoint=!1}}},collectObservers&&(global.Platform.clearObservers=function(){allObservers=[]}),ObjectObserver.prototype=createObject({__proto__:Observer.prototype,arrayObserve:!1,connect_:function(){hasObserve?this.directObserver_=getObservedObject(this,this.value_,this.arrayObserve):this.oldObject_=this.copyObject(this.value_)},copyObject:function(a){var b=Array.isArray(a)?[]:{};for(var c in a)b[c]=a[c];return Array.isArray(a)&&(b.length=a.length),b},check_:function(a){var b,c;if(hasObserve){if(!a)return!1;c={},b=diffObjectFromChangeRecords(this.value_,a,c)}else c=this.oldObject_,b=diffObjectFromOldObject(this.value_,this.oldObject_);return diffIsEmpty(b)?!1:(hasObserve||(this.oldObject_=this.copyObject(this.value_)),this.report_([b.added||{},b.removed||{},b.changed||{},function(a){return c[a]}]),!0)},disconnect_:function(){hasObserve?(this.directObserver_.close(),this.directObserver_=void 0):this.oldObject_=void 0},deliver:function(){this.state_==OPENED&&(hasObserve?this.directObserver_.deliver(!1):dirtyCheck(this))},discardChanges:function(){return this.directObserver_?this.directObserver_.deliver(!0):this.oldObject_=this.copyObject(this.value_),this.value_}});var observerSentinel={},expectedRecordTypes={add:!0,update:!0,"delete":!0};global.Observer=Observer,global.Observer.runEOM_=runEOM,global.Observer.observerSentinel_=observerSentinel,global.Observer.hasObjectObserve=hasObserve,global.ObjectObserver=ObjectObserver}((exports.Number={isNaN:window.isNaN})?exports:exports)},{}],2:[function(a,b){function c(a,b){return-1!==d(a,b)}var d=a("./indexOf");b.exports=c},{"./indexOf":5}],3:[function(a,b){function c(a,b,c){b=d(b,c);var e=[];if(null==a)return e;for(var f,g=-1,h=a.length;++gc?d+c:c;d>e;){if(a[e]===b)return e;e++}return-1}b.exports=c},{}],6:[function(a,b){function c(a){return null!=a&&""!==a}function d(a,b){return b=b||"",e(a,c).join(b)}var e=a("./filter");b.exports=d},{"./filter":3}],7:[function(a,b){function c(a,b){var c=d(a,b);-1!==c&&a.splice(c,1)}var d=a("./indexOf");b.exports=c},{"./indexOf":5}],8:[function(a,b){function c(a,b,c){var d=a.length;b=null==b?0:0>b?Math.max(d+b,0):Math.min(b,d),c=null==c?d:0>c?Math.max(d+c,0):Math.min(c,d);for(var e=[];c>b;)e.push(a[b++]);return e}b.exports=c},{}],9:[function(a,b){function c(a,b){if(null==a)return[];if(a.length<2)return a;null==b&&(b=d);var f,g,h;return f=~~(a.length/2),g=c(a.slice(0,f),b),h=c(a.slice(f,a.length),b),e(g,h,b)}function d(a,b){return b>a?-1:a>b?1:0}function e(a,b,c){for(var d=[];a.length&&b.length;)d.push(c(a[0],b[0])<=0?a.shift():b.shift());return a.length&&d.push.apply(d,a),b.length&&d.push.apply(d,b),d}b.exports=c},{}],10:[function(a,b){function c(a,b){var c={};if(null==a)return c;var e,f=-1,g=a.length;if(d(b))for(;++f-1&&(a=a.replace(/[\xC0-\xC5]/g,"A").replace(/[\xC6]/g,"AE").replace(/[\xC7]/g,"C").replace(/[\xC8-\xCB]/g,"E").replace(/[\xCC-\xCF]/g,"I").replace(/[\xD0]/g,"D").replace(/[\xD1]/g,"N").replace(/[\xD2-\xD6\xD8]/g,"O").replace(/[\xD9-\xDC]/g,"U").replace(/[\xDD]/g,"Y").replace(/[\xDE]/g,"P").replace(/[\xE0-\xE5]/g,"a").replace(/[\xE6]/g,"ae").replace(/[\xE7]/g,"c").replace(/[\xE8-\xEB]/g,"e").replace(/[\xEC-\xEF]/g,"i").replace(/[\xF1]/g,"n").replace(/[\xF2-\xF6\xF8]/g,"o").replace(/[\xF9-\xFC]/g,"u").replace(/[\xFE]/g,"p").replace(/[\xFD\xFF]/g,"y")),a}var d=a("../lang/toString");b.exports=c},{"../lang/toString":24}],41:[function(a,b){function c(a){return a=d(a),a.toUpperCase()}var d=a("../lang/toString");b.exports=c},{"../lang/toString":24}],42:[function(a,b){function c(){var a=this.defaults={queryTransform:function(a,b){return b},$httpConfig:{}};this.$get=["$http","$log","DSUtils",function(b,c,d){return{defaults:a,HTTP:function(e){var f=(new Date).getTime();return e=d.deepMixIn(e,a.$httpConfig),b(e).then(function(a){return c.debug(a.config.method+" request:"+a.config.url+" Time taken: "+((new Date).getTime()-f)+"ms",arguments),a})},GET:function(a,b){return b=b||{},"method"in b||(b.method="GET"),this.HTTP(d.deepMixIn(b,{url:a}))},POST:function(a,b,c){return c=c||{},"method"in c||(c.method="POST"),this.HTTP(d.deepMixIn(c,{url:a,data:b}))},PUT:function(a,b,c){return c=c||{},"method"in c||(c.method="PUT"),this.HTTP(d.deepMixIn(c,{url:a,data:b||{}}))},DEL:function(a,b){return b=b||{},"method"in b||(b.method="DELETE"),this.HTTP(d.deepMixIn(b,{url:a}))},find:function(a,b,c){return c=c||{},this.GET(d.makePath(c.baseUrl||a.baseUrl,a.getEndpoint(b,c),b),c)},findAll:function(b,c,e){return e=e||{},e.params=e.params||{},c&&(c=a.queryTransform(b.name,c),d.deepMixIn(e.params,c)),this.GET(d.makePath(e.baseUrl||b.baseUrl,b.getEndpoint(null,e)),e)},create:function(a,b,c){return c=c||{},this.POST(d.makePath(c.baseUrl||a.baseUrl,a.getEndpoint(b,c)),b,c)},update:function(a,b,c,e){return e=e||{},this.PUT(d.makePath(e.baseUrl||a.baseUrl,a.getEndpoint(b,e),b),c,e)},updateAll:function(b,c,e,f){return f=f||{},f.params=f.params||{},e&&(e=a.queryTransform(b.name,e),d.deepMixIn(f.params,e)),this.PUT(d.makePath(f.baseUrl||b.baseUrl,b.getEndpoint(null,f)),c,f)},destroy:function(a,b,c){return c=c||{},this.DEL(d.makePath(c.baseUrl||a.baseUrl,a.getEndpoint(b,c),b),c)},destroyAll:function(b,c,e){return e=e||{},e.params=e.params||{},c&&(c=a.queryTransform(b.name,c),d.deepMixIn(e.params,c)),this.DEL(d.makePath(e.baseUrl||b.baseUrl,b.getEndpoint(null,e)),e)}}}]}b.exports=c},{}],43:[function(a,b){function c(){this.$get=["$q","DSUtils","DSErrors",function(a,b,c){return{GET:function(b){var c=a.defer();try{var d=localStorage.getItem(b);c.resolve(d?angular.fromJson(d):void 0)}catch(e){c.reject(e)}return c.promise},PUT:function(a,c){var d=this;return d.GET(a).then(function(e){return e&&b.deepMixIn(e,c),localStorage.setItem(a,angular.toJson(e||c)),d.GET(a)})},DEL:function(b){var c=a.defer();try{localStorage.removeItem(b),c.resolve()}catch(d){c.reject(d)}return c.promise},find:function(a,c,d){return d=d||{},this.GET(b.makePath(d.baseUrl||a.baseUrl,a.endpoint,c))},findAll:function(){throw new Error("DSLocalStorageAdapter.findAll is not supported!")},create:function(a,d,e){if(!(a.idAttribute in d))throw new c.IA("DSLocalStorageAdapter.create: You must provide a primary key in the attrs object!");return e=e||{},this.PUT(b.makePath(e.baseUrl||a.baseUrl,a.getEndpoint(d,e),d[a.idAttribute]),d)},update:function(a,c,d,e){return e=e||{},this.PUT(b.makePath(e.baseUrl||a.baseUrl,a.getEndpoint(c,e),c),d)},updateAll:function(){throw new Error("DSLocalStorageAdapter.updateAll is not supported!")},destroy:function(a,c,d){return d=d||{},this.DEL(b.makePath(d.baseUrl||a.baseUrl,a.getEndpoint(c,d),c))},destroyAll:function(){throw new Error("Not supported!")}}}]}b.exports=c},{}],44:[function(a,b){function c(a){return"DS.create("+a+", attrs[, options]): "}function d(a,b,d){var e=this,f=e.$q.defer();try{var g=e.definitions[a];if(d=d||{},!g)throw new e.errors.NER(c(a)+a);if(!e.utils.isObject(b))throw new e.errors.IA(c(a)+"attrs: Must be an object!");return"cacheResponse"in d||(d.cacheResponse=!0),"upsert"in d||(d.upsert=!0),f.resolve(b),d.upsert&&b[g.idAttribute]?e.update(a,b[g.idAttribute],b,d):f.promise.then(function(b){var c=d.beforeValidate?e.$q.promisify(d.beforeValidate):g.beforeValidate;return c.call(b,a,b)}).then(function(b){var c=d.validate?e.$q.promisify(d.validate):g.validate;return c.call(b,a,b)}).then(function(b){var c=d.afterValidate?e.$q.promisify(d.afterValidate):g.afterValidate;return c.call(b,a,b)}).then(function(b){var c=d.beforeCreate?e.$q.promisify(d.beforeCreate):g.beforeCreate;return c.call(b,a,b)}).then(function(b){return e.notify(g,"beforeCreate",e.utils.merge({},b)),e.adapters[d.adapter||g.defaultAdapter].create(g,d.serialize?d.serialize(a,b):g.serialize(a,b),d)}).then(function(b){var c=d.afterCreate?e.$q.promisify(d.afterCreate):g.afterCreate,f=d.deserialize?d.deserialize(a,b):g.deserialize(a,b);return c.call(f,a,f)}).then(function(b){if(e.notify(g,"afterCreate",e.utils.merge({},b)),d.cacheResponse){var c=e.store[a],f=e.inject(g.name,b,d),h=f[g.idAttribute];return c.completedQueries[h]=(new Date).getTime(),c.previousAttributes[h]=e.utils.deepMixIn({},f),c.saved[h]=e.utils.updateTimestamp(c.saved[h]),e.get(g.name,h)}return e.createInstance(a,b,d)})}catch(h){return f.reject(h),f.promise}}b.exports=d},{}],45:[function(a,b){function c(a,b){return"DS.destroy("+a+", "+b+"[, options]): "}function d(a,b,d){var e=this,f=e.$q.defer();try{var g=e.definitions[a];if(d=d||{},b=e.utils.resolveId(g,b),!g)throw new e.errors.NER(c(a,b)+a);if(!e.utils.isString(b)&&!e.utils.isNumber(b))throw new e.errors.IA(c(a,b)+"id: Must be a string or a number!");var h=e.get(a,b);if(!h)throw new e.errors.R(c(a,b)+'id: "'+b+'" not found!');return f.resolve(h),f.promise.then(function(b){var c=d.beforeDestroy?e.$q.promisify(d.beforeDestroy):g.beforeDestroy;return c.call(b,a,b)}).then(function(a){return e.notify(g,"beforeDestroy",e.utils.merge({},a)),e.adapters[d.adapter||g.defaultAdapter].destroy(g,b,d)}).then(function(){var b=d.afterDestroy?e.$q.promisify(d.afterDestroy):g.afterDestroy;return b.call(h,a,h)}).then(function(){return e.notify(g,"afterDestroy",e.utils.merge({},h)),e.eject(a,b),b})}catch(i){return f.reject(i),f.promise}}b.exports=d},{}],46:[function(a,b){function c(a){return"DS.destroyAll("+a+", params[, options]): "}function d(a,b,d){var e=this,f=e.$q.defer();try{var g=e.errors.IA,h=e.definitions[a];if(d=d||{},!h)throw new e.errors.NER(c(a)+a);if(!e.utils.isObject(b))throw new g(c(a)+"params: Must be an object!");if(!e.utils.isObject(d))throw new g(c(a)+"options: Must be an object!");return f.resolve(),f.promise.then(function(){return e.adapters[d.adapter||h.defaultAdapter].destroyAll(h,b,d)}).then(function(){return e.ejectAll(a,b)})}catch(i){return f.reject(i),f.promise}}b.exports=d},{}],47:[function(a,b){function c(a,b){return"DS.find("+a+", "+b+"[, options]): "}function d(a,b,d){var e=this,f=e.$q.defer(),g=f.promise;try{var h=e.errors.IA,i=e.definitions[a];if(d=d||{},!i)throw new e.errors.NER(c(a,b)+a);if(!e.utils.isString(b)&&!e.utils.isNumber(b))throw new h(c(a,b)+"id: Must be a string or a number!");if(!e.utils.isObject(d))throw new h(c(a,b)+"options: Must be an object!");"cacheResponse"in d||(d.cacheResponse=!0);var j=e.store[a];if((d.bypassCache||!d.cacheResponse)&&delete j.completedQueries[b],!(b in j.completedQueries))return b in j.pendingQueries||(g=j.pendingQueries[b]=e.adapters[d.adapter||i.defaultAdapter].find(i,b,d).then(function(c){var f=d.deserialize?d.deserialize(a,c):i.deserialize(a,c);return d.cacheResponse?(delete j.pendingQueries[b],j.completedQueries[b]=(new Date).getTime(),e.inject(a,f,d)):e.createInstance(a,f,d)},function(a){return delete j.pendingQueries[b],e.$q.reject(a)})),j.pendingQueries[b];f.resolve(e.get(a,b))}catch(k){f.reject(k)}return g}b.exports=d},{}],48:[function(a,b){function c(a){return"DS.findAll("+a+", params[, options]): "}function d(a,b,d,e){var f=this,g=f.store[b],h=f.definitions[b].idAttribute,i=(new Date).getTime();a=a||[],delete g.pendingQueries[d],g.completedQueries[d]=i,g.collectionModified=f.utils.updateTimestamp(g.collectionModified);var j=f.inject(b,a,e);return f.utils.isArray(j)?angular.forEach(j,function(a){a&&a[h]&&(g.completedQueries[a[h]]=i)}):(f.$log.warn(c(b)+"response is expected to be an array!"),g.completedQueries[j[h]]=i),j}function e(a,b,c){var e=this,f=e.definitions[a],g=e.store[a],h=e.utils.toJson(b);return(c.bypassCache||!c.cacheResponse)&&delete g.completedQueries[h],h in g.completedQueries?e.filter(a,b,c):(h in g.pendingQueries||(g.pendingQueries[h]=e.adapters[c.adapter||f.defaultAdapter].findAll(f,b,c).then(function(b){delete g.pendingQueries[h];var i=c.deserialize?c.deserialize(a,b):f.deserialize(a,b);if(!c.cacheResponse)return e.utils.forEach(i,function(b,d){i[d]=e.createInstance(a,b,c)}),i;try{return d.call(e,i,a,h,c)}catch(j){return e.$q.reject(j)}},function(a){return delete g.pendingQueries[h],e.$q.reject(a)})),g.pendingQueries[h])}function f(a,b,d){var f=this,g=f.$q.defer();try{var h=f.errors.IA;if(d=d||{},b=b||{},!f.definitions[a])throw new f.errors.NER(c(a)+a);if(!f.utils.isObject(b))throw new h(c(a)+"params: Must be an object!");if(!f.utils.isObject(d))throw new h(c(a)+"options: Must be an object!");return"cacheResponse"in d||(d.cacheResponse=!0),g.resolve(),g.promise.then(function(){return e.call(f,a,b,d)})}catch(i){return g.reject(i),g.promise}}b.exports=f},{}],49:[function(a,b){b.exports={create:a("./create"),destroy:a("./destroy"),destroyAll:a("./destroyAll"),find:a("./find"),findAll:a("./findAll"),loadRelations:a("./loadRelations"),refresh:a("./refresh"),save:a("./save"),update:a("./update"),updateAll:a("./updateAll")}},{"./create":44,"./destroy":45,"./destroyAll":46,"./find":47,"./findAll":48,"./loadRelations":50,"./refresh":51,"./save":52,"./update":53,"./updateAll":54}],50:[function(a,b){function c(a){return"DS.loadRelations("+a+", instance(Id), relations[, options]): "}function d(a,b,d,e){var f=this,g=f.$q.defer();try{var h=f.errors.IA,i=f.definitions[a];if(e=e||{},(angular.isString(b)||angular.isNumber(b))&&(b=f.get(a,b)),angular.isString(d)&&(d=[d]),!i)throw new f.errors.NER(c(a)+a);if(!f.utils.isObject(b))throw new h(c(a)+"instance(Id): Must be a string, number or object!");if(!f.utils.isArray(d))throw new h(c(a)+"relations: Must be a string or an array!");if(!f.utils.isObject(e))throw new h(c(a)+"options: Must be an object!");"findBelongsTo"in e||(e.findBelongsTo=!0),"findHasMany"in e||(e.findHasMany=!0);var j=[],k=[];return f.utils.forEach(i.relationList,function(a){var c=a.relation;if(f.utils.contains(d,c)){var g,h={};h[a.foreignKey]=b[i.idAttribute],"hasMany"===a.type&&h[a.foreignKey]?g=f.findAll(c,h,e):"hasOne"===a.type?a.localKey&&b[a.localKey]?g=f.find(c,b[a.localKey],e):a.foreignKey&&h[a.foreignKey]&&(g=f.findAll(c,h,e).then(function(a){return a.length?a[0]:null})):b[a.localKey]&&(g=f.find(c,b[a.localKey],e)),g&&(j.push(g),k.push(a.localField))}}),g.resolve(),g.promise.then(function(){return f.$q.all(j)}).then(function(a){return angular.forEach(k,function(c,d){b[c]=a[d]}),b})}catch(l){return g.reject(l),g.promise}}b.exports=d},{}],51:[function(a,b){function c(a,b){return"DS.refresh("+a+", "+b+"[, options]): "}function d(a,b,d){var e=this,f=e.errors.IA;if(d=d||{},b=e.utils.resolveId(e.definitions[a],b),e.definitions[a]){if(e.utils.isString(b)||e.utils.isNumber(b)){if(e.utils.isObject(d)){if(d.bypassCache=!0,e.get(a,b))return e.find(a,b,d);var g=e.$q.defer();return g.resolve(),g.promise}throw new f(c(a,b)+"options: Must be an object!")}throw new f(c(a,b)+"id: Must be a string or a number!")}throw new e.errors.NER(c(a,b)+a)}b.exports=d},{}],52:[function(a,b){function c(a,b){return"DS.save("+a+", "+b+"[, options]): "}function d(a,b,d){var e=this,f=e.$q.defer();try{var g=e.errors.IA,h=e.definitions[a];if(d=d||{},b=e.utils.resolveId(h,b),!h)throw new e.errors.NER(c(a,b)+a);if(!e.utils.isString(b)&&!e.utils.isNumber(b))throw new g(c(a,b)+"id: Must be a string or a number!");if(!e.utils.isObject(d))throw new g(c(a,b)+"options: Must be an object!");var i=e.get(a,b);if(!i)throw new e.errors.R(c(a,b)+'id: "'+b+'" not found!');return"cacheResponse"in d||(d.cacheResponse=!0),f.resolve(i),f.promise.then(function(b){var c=d.beforeValidate?e.$q.promisify(d.beforeValidate):h.beforeValidate;return c.call(b,a,b)}).then(function(b){var c=d.validate?e.$q.promisify(d.validate):h.validate;return c.call(b,a,b)}).then(function(b){var c=d.afterValidate?e.$q.promisify(d.afterValidate):h.afterValidate;return c.call(b,a,b)}).then(function(b){var c=d.beforeUpdate?e.$q.promisify(d.beforeUpdate):h.beforeUpdate;return c.call(b,a,b)}).then(function(c){if(e.notify(h,"beforeUpdate",e.utils.merge({},c)),d.changesOnly){var f=e.store[a];f.observers[b].deliver();var g=[],i=e.changes(a,b);for(var j in i.added)g.push(j);for(j in i.changed)g.push(j);if(i=e.utils.pick(c,g),e.utils.isEmpty(i))return c;c=i}return e.adapters[d.adapter||h.defaultAdapter].update(h,b,d.serialize?d.serialize(a,c):h.serialize(a,c),d)}).then(function(b){var c=d.afterUpdate?e.$q.promisify(d.afterUpdate):h.afterUpdate,f=d.deserialize?d.deserialize(a,b):h.deserialize(a,b);return c.call(f,a,f)}).then(function(c){if(e.notify(h,"afterUpdate",e.utils.merge({},c)),d.cacheResponse){var f=e.store[a],g=e.inject(h.name,c,d);return f.previousAttributes[b]=e.utils.deepMixIn({},g),f.saved[b]=e.utils.updateTimestamp(f.saved[b]),f.observers[b].discardChanges(),e.get(a,b)}return c})}catch(j){return f.reject(j),f.promise}}b.exports=d},{}],53:[function(a,b){function c(a,b){return"DS.update("+a+", "+b+", attrs[, options]): "}function d(a,b,d,e){var f=this,g=f.$q.defer();try{var h=f.errors.IA,i=f.definitions[a];if(e=e||{},b=f.utils.resolveId(i,b),!i)throw new f.errors.NER(c(a,b)+a);if(!f.utils.isString(b)&&!f.utils.isNumber(b))throw new h(c(a,b)+"id: Must be a string or a number!");if(!f.utils.isObject(d))throw new h(c(a,b)+"attrs: Must be an object!");if(!f.utils.isObject(e))throw new h(c(a,b)+"options: Must be an object!");return"cacheResponse"in e||(e.cacheResponse=!0),g.resolve(d),g.promise.then(function(b){var c=e.beforeValidate?f.$q.promisify(e.beforeValidate):i.beforeValidate;return c.call(b,a,b)}).then(function(b){var c=e.validate?f.$q.promisify(e.validate):i.validate;return c.call(b,a,b)}).then(function(b){var c=e.afterValidate?f.$q.promisify(e.afterValidate):i.afterValidate;return c.call(b,a,b)}).then(function(b){var c=e.beforeUpdate?f.$q.promisify(e.beforeUpdate):i.beforeUpdate;return c.call(b,a,b)}).then(function(c){return f.notify(i,"beforeUpdate",f.utils.merge({},c)),f.adapters[e.adapter||i.defaultAdapter].update(i,b,e.serialize?e.serialize(a,c):i.serialize(a,c),e)}).then(function(b){var c=e.afterUpdate?f.$q.promisify(e.afterUpdate):i.afterUpdate,d=e.deserialize?e.deserialize(a,b):i.deserialize(a,b);return c.call(d,a,d)}).then(function(b){if(f.notify(i,"afterUpdate",f.utils.merge({},b)),e.cacheResponse){var c=f.store[a],d=f.inject(i.name,b,e),g=d[i.idAttribute];return c.previousAttributes[g]=f.utils.deepMixIn({},d),c.saved[g]=f.utils.updateTimestamp(c.saved[g]),c.observers[g].discardChanges(),f.get(i.name,g)}return b})}catch(j){return g.reject(j),g.promise}}b.exports=d},{}],54:[function(a,b){function c(a){return"DS.updateAll("+a+", attrs, params[, options]): "}function d(a,b,d,e){var f=this,g=f.$q.defer();try{var h=f.errors.IA,i=f.definitions[a];if(e=e||{},!i)throw new f.errors.NER(c(a)+a);if(!f.utils.isObject(b))throw new h(c(a)+"attrs: Must be an object!");if(!f.utils.isObject(d))throw new h(c(a)+"params: Must be an object!");if(!f.utils.isObject(e))throw new h(c(a)+"options: Must be an object!");return"cacheResponse"in e||(e.cacheResponse=!0),g.resolve(b),g.promise.then(function(b){var c=e.beforeValidate?f.$q.promisify(e.beforeValidate):i.beforeValidate;return c.call(b,a,b)}).then(function(b){var c=e.validate?f.$q.promisify(e.validate):i.validate;return c.call(b,a,b)}).then(function(b){var c=e.afterValidate?f.$q.promisify(e.afterValidate):i.afterValidate;return c.call(b,a,b)}).then(function(b){var c=e.beforeUpdate?f.$q.promisify(e.beforeUpdate):i.beforeUpdate;return c.call(b,a,b)}).then(function(b){return f.notify(i,"beforeUpdate",f.utils.merge({},b)),f.adapters[e.adapter||i.defaultAdapter].updateAll(i,e.serialize?e.serialize(a,b):i.serialize(a,b),d,e)}).then(function(b){var c=e.afterUpdate?f.$q.promisify(e.afterUpdate):i.afterUpdate,d=e.deserialize?e.deserialize(a,b):i.deserialize(a,b);return c.call(d,a,d)}).then(function(a){return f.notify(i,"afterUpdate",f.utils.merge({},a)),e.cacheResponse?f.inject(i.name,a,e):a})}catch(j){return g.reject(j),g.promise}}b.exports=d},{}],55:[function(a,b){function c(a,b,c){c(null,b)}function d(){}function e(){var b=this.defaults=new d;this.$get=["$rootScope","$log","$q","DSHttpAdapter","DSLocalStorageAdapter","DSUtils","DSErrors",function(c,d,e,f,g,h,i){var j,k=a("./sync_methods"),l=a("./async_methods"); +try{j=angular.injector(["angular-data.DSCacheFactory"]).get("DSCacheFactory")}catch(m){d.warn(m),d.warn("DSCacheFactory is unavailable. Resorting to the lesser capabilities of $cacheFactory."),j=angular.injector(["ng"]).get("$cacheFactory")}var n={notify:function(a,b){var d=Array.prototype.slice.call(arguments,2);d.unshift(a.name),d.unshift("DS."+b),a.emit.apply(a,d),"broadcast"===a.events?c.$broadcast.apply(c,d):"emit"===a.events&&c.$emit.apply(c,d)},$rootScope:c,$log:d,$q:e,cacheFactory:j,defaults:b,store:{},definitions:{},adapters:{DSHttpAdapter:f,DSLocalStorageAdapter:g},errors:i,utils:h};return h.deepFreeze(k),h.deepFreeze(l),h.deepMixIn(n,k),h.deepMixIn(n,l),h.deepFreeze(n.errors),h.deepFreeze(n.utils),("function"!=typeof Object.observe||"function"!=typeof Array.observe)&&c.$watch(function(){return(new Date).getTime()/100|0},function(){n.digest()}),n}]}a("../utils")[0]();d.prototype.idAttribute="id",d.prototype.defaultAdapter="DSHttpAdapter",d.prototype.defaultFilter=function(a,b,c,d){var e=this,f=a,g=null,h={skip:"",offset:"",where:"",limit:"",orderBy:"",sort:""};g=this.utils.isObject(c.where)?c.where:{},d.allowSimpleWhere&&this.utils.forOwn(c,function(a,b){b in h||b in g||(g[b]={"==":a})}),this.utils.isEmpty(g)&&(g=null),g&&(f=this.utils.filter(f,function(a){var b=!0,c=!0;return e.utils.forOwn(g,function(d,f){e.utils.isString(d)?d={"===":d}:(e.utils.isNumber(d)||e.utils.isBoolean(d))&&(d={"==":d}),e.utils.isObject(d)&&e.utils.forOwn(d,function(d,g){"=="===g?c=b?a[f]==d:c&&a[f]==d:"==="===g?c=b?a[f]===d:c&&a[f]===d:"!="===g?c=b?a[f]!=d:c&&a[f]!=d:"!=="===g?c=b?a[f]!==d:c&&a[f]!==d:">"===g?c=b?a[f]>d:c&&a[f]>d:">="===g?c=b?a[f]>=d:c&&a[f]>=d:"<"===g?c=b?a[f]"===g?c=b?a[f]>d:c||a[f]>d:"|>="===g?c=b?a[f]>=d:c||a[f]>=d:"|<"===g?c=b?a[f]f?-1:f>d?1:0:f>d?-1:d>f?1:0})});var j=angular.isNumber(c.limit)?c.limit:null,k=null;return angular.isNumber(c.skip)?k=c.skip:angular.isNumber(c.offset)&&(k=c.offset),j&&k?f=this.utils.slice(f,k,Math.min(f.length,k+j)):this.utils.isNumber(j)?f=this.utils.slice(f,0,Math.min(f.length,j)):this.utils.isNumber(k)&&(f=k=b?a+1:b},deepFreeze:function b(a){if("function"==typeof Object.freeze){var c,d;Object.freeze(a);for(d in a)c=a[d],a.hasOwnProperty(d)&&"object"==typeof c&&!Object.isFrozen(c)&&b(c)}},diffObjectFromOldObject:function(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var h in a)h in b||(c[h]=a[h]);return{added:c,removed:d,changed:e}},Events:c}}]},{"mout/array/contains":2,"mout/array/filter":3,"mout/array/remove":7,"mout/array/slice":8,"mout/array/sort":9,"mout/array/toLookup":10,"mout/lang/isBoolean":17,"mout/lang/isEmpty":18,"mout/object/deepMixIn":26,"mout/object/forOwn":28,"mout/object/merge":30,"mout/object/pick":33,"mout/object/set":34,"mout/string/makePath":37,"mout/string/pascalCase":38,"mout/string/upperCase":41}]},{},[79]); \ No newline at end of file diff --git a/karma.start.js b/karma.start.js index fe57389..47b5cdd 100644 --- a/karma.start.js +++ b/karma.start.js @@ -1,6 +1,7 @@ // Setup global test variables var $rootScope, $q, $log, $timeout, DSHttpAdapterProvider, DSProvider, DSLocalStorageAdapter, DS, DSUtils, DSHttpAdapter, app, $httpBackend, p1, p2, p3, p4, p5; +var Post, User, Organization, Comment, Profile; var user1, organization2, comment3, profile4; var comment11, comment12, comment13, organization14, profile15, user10, user16, user17, user18, organization15, user19, user20, comment19, user22, profile21; @@ -128,12 +129,12 @@ function startInjector() { DSHttpAdapter = _DSHttpAdapter_; DSLocalStorageAdapter = _DSLocalStorageAdapter_; $httpBackend = _$httpBackend_; - DS.defineResource({ + Post = DS.defineResource({ name: 'post', keepChangeHistory: true, endpoint: '/posts' }); - DS.defineResource({ + User = DS.defineResource({ name: 'user', relations: { hasMany: { @@ -158,7 +159,7 @@ function startInjector() { } }); - DS.defineResource({ + Organization = DS.defineResource({ name: 'organization', relations: { hasMany: { @@ -170,7 +171,7 @@ function startInjector() { } }); - DS.defineResource({ + Profile = DS.defineResource({ name: 'profile', relations: { belongsTo: { @@ -182,7 +183,7 @@ function startInjector() { } }); - DS.defineResource({ + Comment = DS.defineResource({ name: 'comment', relations: { belongsTo: { diff --git a/package.json b/package.json index f1f0256..e6836b1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "angular-data", "description": "Data store for Angular.js.", - "version": "1.0.0-rc.1", + "version": "1.0.0-rc.2", "homepage": "http://angular-data.pseudobry.com", "repository": { "type": "git", diff --git a/src/datastore/async_methods/create.js b/src/datastore/async_methods/create.js index eeec354..733c464 100644 --- a/src/datastore/async_methods/create.js +++ b/src/datastore/async_methods/create.js @@ -97,6 +97,7 @@ function create(resourceName, attrs, options) { return func.call(attrs, resourceName, attrs); }) .then(function (attrs) { + DS.notify(definition, 'beforeCreate', DS.utils.merge({}, attrs)); return DS.adapters[options.adapter || definition.defaultAdapter].create(definition, options.serialize ? options.serialize(resourceName, attrs) : definition.serialize(resourceName, attrs), options); }) .then(function (res) { @@ -104,17 +105,18 @@ function create(resourceName, attrs, options) { var attrs = options.deserialize ? options.deserialize(resourceName, res) : definition.deserialize(resourceName, res); return func.call(attrs, resourceName, attrs); }) - .then(function (data) { + .then(function (attrs) { + DS.notify(definition, 'afterCreate', DS.utils.merge({}, attrs)); if (options.cacheResponse) { var resource = DS.store[resourceName]; - var created = DS.inject(definition.name, data, options); + var created = DS.inject(definition.name, attrs, options); var id = created[definition.idAttribute]; resource.completedQueries[id] = new Date().getTime(); resource.previousAttributes[id] = DS.utils.deepMixIn({}, created); resource.saved[id] = DS.utils.updateTimestamp(resource.saved[id]); return DS.get(definition.name, id); } else { - return DS.createInstance(resourceName, data, options); + return DS.createInstance(resourceName, attrs, options); } }); } diff --git a/src/datastore/async_methods/destroy.js b/src/datastore/async_methods/destroy.js index 7c37637..8c90327 100644 --- a/src/datastore/async_methods/destroy.js +++ b/src/datastore/async_methods/destroy.js @@ -73,7 +73,8 @@ function destroy(resourceName, id, options) { var func = options.beforeDestroy ? DS.$q.promisify(options.beforeDestroy) : definition.beforeDestroy; return func.call(attrs, resourceName, attrs); }) - .then(function () { + .then(function (attrs) { + DS.notify(definition, 'beforeDestroy', DS.utils.merge({}, attrs)); return DS.adapters[options.adapter || definition.defaultAdapter].destroy(definition, id, options); }) .then(function () { @@ -81,6 +82,7 @@ function destroy(resourceName, id, options) { return func.call(item, resourceName, item); }) .then(function () { + DS.notify(definition, 'afterDestroy', DS.utils.merge({}, item)); DS.eject(resourceName, id); return id; }); diff --git a/src/datastore/async_methods/save.js b/src/datastore/async_methods/save.js index e406c29..96c09a9 100644 --- a/src/datastore/async_methods/save.js +++ b/src/datastore/async_methods/save.js @@ -99,6 +99,7 @@ function save(resourceName, id, options) { return func.call(attrs, resourceName, attrs); }) .then(function (attrs) { + DS.notify(definition, 'beforeUpdate', DS.utils.merge({}, attrs)); if (options.changesOnly) { var resource = DS.store[resourceName]; resource.observers[id].deliver(); @@ -126,16 +127,17 @@ function save(resourceName, id, options) { var attrs = options.deserialize ? options.deserialize(resourceName, res) : definition.deserialize(resourceName, res); return func.call(attrs, resourceName, attrs); }) - .then(function (data) { + .then(function (attrs) { + DS.notify(definition, 'afterUpdate', DS.utils.merge({}, attrs)); if (options.cacheResponse) { var resource = DS.store[resourceName]; - var saved = DS.inject(definition.name, data, options); + var saved = DS.inject(definition.name, attrs, options); resource.previousAttributes[id] = DS.utils.deepMixIn({}, saved); resource.saved[id] = DS.utils.updateTimestamp(resource.saved[id]); resource.observers[id].discardChanges(); return DS.get(resourceName, id); } else { - return data; + return attrs; } }); } catch (err) { diff --git a/src/datastore/async_methods/update.js b/src/datastore/async_methods/update.js index 07b8755..2154eea 100644 --- a/src/datastore/async_methods/update.js +++ b/src/datastore/async_methods/update.js @@ -98,6 +98,7 @@ function update(resourceName, id, attrs, options) { return func.call(attrs, resourceName, attrs); }) .then(function (attrs) { + DS.notify(definition, 'beforeUpdate', DS.utils.merge({}, attrs)); return DS.adapters[options.adapter || definition.defaultAdapter].update(definition, id, options.serialize ? options.serialize(resourceName, attrs) : definition.serialize(resourceName, attrs), options); }) .then(function (res) { @@ -105,17 +106,18 @@ function update(resourceName, id, attrs, options) { var attrs = options.deserialize ? options.deserialize(resourceName, res) : definition.deserialize(resourceName, res); return func.call(attrs, resourceName, attrs); }) - .then(function (data) { + .then(function (attrs) { + DS.notify(definition, 'afterUpdate', DS.utils.merge({}, attrs)); if (options.cacheResponse) { var resource = DS.store[resourceName]; - var updated = DS.inject(definition.name, data, options); + var updated = DS.inject(definition.name, attrs, options); var id = updated[definition.idAttribute]; resource.previousAttributes[id] = DS.utils.deepMixIn({}, updated); resource.saved[id] = DS.utils.updateTimestamp(resource.saved[id]); resource.observers[id].discardChanges(); return DS.get(definition.name, id); } else { - return data; + return attrs; } }); } catch (err) { diff --git a/src/datastore/async_methods/updateAll.js b/src/datastore/async_methods/updateAll.js index d265bc8..075f718 100644 --- a/src/datastore/async_methods/updateAll.js +++ b/src/datastore/async_methods/updateAll.js @@ -109,6 +109,7 @@ function updateAll(resourceName, attrs, params, options) { return func.call(attrs, resourceName, attrs); }) .then(function (attrs) { + DS.notify(definition, 'beforeUpdate', DS.utils.merge({}, attrs)); return DS.adapters[options.adapter || definition.defaultAdapter].updateAll(definition, options.serialize ? options.serialize(resourceName, attrs) : definition.serialize(resourceName, attrs), params, options); }) .then(function (res) { @@ -116,11 +117,12 @@ function updateAll(resourceName, attrs, params, options) { var attrs = options.deserialize ? options.deserialize(resourceName, res) : definition.deserialize(resourceName, res); return func.call(attrs, resourceName, attrs); }) - .then(function (data) { + .then(function (attrs) { + DS.notify(definition, 'afterUpdate', DS.utils.merge({}, attrs)); if (options.cacheResponse) { - return DS.inject(definition.name, data, options); + return DS.inject(definition.name, attrs, options); } else { - return data; + return attrs; } }); } catch (err) { diff --git a/src/datastore/index.js b/src/datastore/index.js index c9c9fa4..deec5db 100644 --- a/src/datastore/index.js +++ b/src/datastore/index.js @@ -76,7 +76,7 @@ Defaults.prototype.defaultFilter = function (collection, resourceName, params, o keep = first ? (attrs[field] <= val) : keep && (attrs[field] <= val); } else if (op === 'in') { keep = first ? _this.utils.contains(val, attrs[field]) : keep && _this.utils.contains(val, attrs[field]); - } else if (op === 'notIn') { + } else if (op === 'notIn') { keep = first ? !_this.utils.contains(val, attrs[field]) : keep && !_this.utils.contains(val, attrs[field]); } else if (op === '|==') { keep = first ? (attrs[field] == val) : keep || (attrs[field] == val); @@ -660,6 +660,7 @@ function DSProvider() { var args = Array.prototype.slice.call(arguments, 2); args.unshift(definition.name); args.unshift('DS.' + event); + definition.emit.apply(definition, args); if (definition.events === 'broadcast') { $rootScope.$broadcast.apply($rootScope, args); } else if (definition.events === 'emit') { diff --git a/src/datastore/sync_methods/defineResource.js b/src/datastore/sync_methods/defineResource.js index 1fe41b4..a6ec5a9 100644 --- a/src/datastore/sync_methods/defineResource.js +++ b/src/datastore/sync_methods/defineResource.js @@ -107,22 +107,23 @@ var methodsToProxy = [ */ function defineResource(definition) { var DS = this; + var DSUtils = DS.utils; var definitions = DS.definitions; var IA = DS.errors.IA; - if (DS.utils.isString(definition)) { + if (DSUtils.isString(definition)) { definition = definition.replace(/\s/gi, ''); definition = { name: definition }; } - if (!DS.utils.isObject(definition)) { + if (!DSUtils.isObject(definition)) { throw new IA(errorPrefix + 'definition: Must be an object!'); - } else if (!DS.utils.isString(definition.name)) { + } else if (!DSUtils.isString(definition.name)) { throw new IA(errorPrefix + 'definition.name: Must be a string!'); - } else if (definition.idAttribute && !DS.utils.isString(definition.idAttribute)) { + } else if (definition.idAttribute && !DSUtils.isString(definition.idAttribute)) { throw new IA(errorPrefix + 'definition.idAttribute: Must be a string!'); - } else if (definition.endpoint && !DS.utils.isString(definition.endpoint)) { + } else if (definition.endpoint && !DSUtils.isString(definition.endpoint)) { throw new IA(errorPrefix + 'definition.endpoint: Must be a string!'); } else if (DS.store[definition.name]) { throw new DS.errors.R(errorPrefix + definition.name + ' is already registered!'); @@ -131,7 +132,7 @@ function defineResource(definition) { try { // Inherit from global defaults Resource.prototype = DS.defaults; - definitions[definition.name] = new Resource(DS.utils, definition); + definitions[definition.name] = new Resource(DSUtils, definition); var def = definitions[definition.name]; @@ -139,12 +140,12 @@ function defineResource(definition) { if (def.relations) { def.relationList = []; def.relationFields = []; - DS.utils.forOwn(def.relations, function (relatedModels, type) { - DS.utils.forOwn(relatedModels, function (defs, relationName) { - if (!DS.utils.isArray(defs)) { + DSUtils.forOwn(def.relations, function (relatedModels, type) { + DSUtils.forOwn(relatedModels, function (defs, relationName) { + if (!DSUtils.isArray(defs)) { relatedModels[relationName] = [defs]; } - DS.utils.forEach(relatedModels[relationName], function (d) { + DSUtils.forEach(relatedModels[relationName], function (d) { d.type = type; d.relation = relationName; d.name = def.name; @@ -154,8 +155,8 @@ function defineResource(definition) { }); }); if (def.relations.belongsTo) { - DS.utils.forOwn(def.relations.belongsTo, function (relatedModel, modelName) { - DS.utils.forEach(relatedModel, function (relation) { + DSUtils.forOwn(def.relations.belongsTo, function (relatedModel, modelName) { + DSUtils.forEach(relatedModel, function (relation) { if (relation.parent) { def.parent = modelName; def.parentKey = relation.localKey; @@ -163,8 +164,8 @@ function defineResource(definition) { }); }); } - DS.utils.deepFreeze(def.relations); - DS.utils.deepFreeze(def.relationList); + DSUtils.deepFreeze(def.relations); + DSUtils.deepFreeze(def.relationList); } def.getEndpoint = function (attrs, options) { @@ -177,17 +178,17 @@ function defineResource(definition) { options = options || {}; options.params = options.params || {}; if (parent && parentKey && definitions[parent] && options.params[parentKey] !== false) { - if (DS.utils.isNumber(attrs) || DS.utils.isString(attrs)) { + if (DSUtils.isNumber(attrs) || DSUtils.isString(attrs)) { item = DS.get(this.name, attrs); } - if (DS.utils.isObject(attrs) && parentKey in attrs) { + if (DSUtils.isObject(attrs) && parentKey in attrs) { delete options.params[parentKey]; - endpoint = DS.utils.makePath(definitions[parent].getEndpoint(attrs, options), attrs[parentKey], thisEndpoint); + endpoint = DSUtils.makePath(definitions[parent].getEndpoint(attrs, options), attrs[parentKey], thisEndpoint); } else if (item && parentKey in item) { delete options.params[parentKey]; - endpoint = DS.utils.makePath(definitions[parent].getEndpoint(attrs, options), item[parentKey], thisEndpoint); + endpoint = DSUtils.makePath(definitions[parent].getEndpoint(attrs, options), item[parentKey], thisEndpoint); } else if (options && options.params[parentKey]) { - endpoint = DS.utils.makePath(definitions[parent].getEndpoint(attrs, options), options.params[parentKey], thisEndpoint); + endpoint = DSUtils.makePath(definitions[parent].getEndpoint(attrs, options), options.params[parentKey], thisEndpoint); delete options.params[parentKey]; } } @@ -212,7 +213,7 @@ function defineResource(definition) { deleteOnExpire: def.deleteOnExpire || 'none', onExpire: function (id) { var item = DS.eject(def.name, id); - if (DS.utils.isFunction(def.onExpire)) { + if (DSUtils.isFunction(def.onExpire)) { def.onExpire(id, item); } }, @@ -224,18 +225,18 @@ function defineResource(definition) { }); // Create the wrapper class for the new resource - def.class = DS.utils.pascalCase(definition.name); + def.class = DSUtils.pascalCase(definition.name); eval('function ' + def.class + '() {}'); def[def.class] = eval(def.class); // Apply developer-defined methods if (def.methods) { - DS.utils.deepMixIn(def[def.class].prototype, def.methods); + DSUtils.deepMixIn(def[def.class].prototype, def.methods); } // Prepare for computed properties if (def.computed) { - DS.utils.forOwn(def.computed, function (fn, field) { + DSUtils.forOwn(def.computed, function (fn, field) { if (angular.isFunction(fn)) { def.computed[field] = [fn]; fn = def.computed[field]; @@ -257,7 +258,7 @@ function defineResource(definition) { angular.forEach(deps, function (val, index) { deps[index] = val.trim(); }); - fn.deps = DS.utils.filter(deps, function (dep) { + fn.deps = DSUtils.filter(deps, function (dep) { return !!dep; }); }); @@ -309,6 +310,9 @@ function defineResource(definition) { def.beforeDestroy = DS.$q.promisify(def.beforeDestroy); def.afterDestroy = DS.$q.promisify(def.afterDestroy); + // Mix-in events + DSUtils.Events(def); + return def; } catch (err) { DS.$log.error(err); diff --git a/src/utils.js b/src/utils.js index 1ccce2c..194b84e 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,3 +1,47 @@ +function Events(target) { + var events = {}; + target = target || this; + /** + * On: listen to events + */ + target.on = function (type, func, ctx) { + events[type] = events[type] || []; + events[type].push({ + f: func, + c: ctx + }); + }; + + /** + * Off: stop listening to event / specific callback + */ + target.off = function (type, func) { + var listeners = events[type]; + if (!listeners) { + events = {}; + } else if (func) { + for (var i = 0; i < listeners.length; i++) { + if (listeners[i] === func) { + listeners.splice(i, 1); + break; + } + } + } else { + listeners.splice(0, listeners.length); + } + }; + + target.emit = function () { + var args = Array.prototype.slice.call(arguments); + var listeners = events[args.shift()] || []; + if (listeners) { + for (var i = 0; i < listeners.length; i++) { + listeners[i].f.apply(listeners[i].c, args); + } + } + }; +} + module.exports = [function () { return { isBoolean: require('mout/lang/isBoolean'), @@ -16,6 +60,7 @@ module.exports = [function () { forEach: angular.forEach, pick: require('mout/object/pick'), set: require('mout/object/set'), + merge: require('mout/object/merge'), contains: require('mout/array/contains'), filter: require('mout/array/filter'), toLookup: require('mout/array/toLookup'), @@ -95,6 +140,7 @@ module.exports = [function () { removed: removed, changed: changed }; - } + }, + Events: Events }; }]; diff --git a/test/integration/datastore/async_methods/update.test.js b/test/integration/datastore/async_methods/update.test.js index eabfb7c..535dda5 100644 --- a/test/integration/datastore/async_methods/update.test.js +++ b/test/integration/datastore/async_methods/update.test.js @@ -115,11 +115,26 @@ describe('DS.update(resourceName, id, attrs[, options])', function () { $httpBackend.flush(); - $httpBackend.expectPUT('http://test.angular-cache.com/user/4/comment/6').respond(200, testComment2); + $httpBackend.expectPUT('http://test.angular-cache.com/user/4/comment/6', { content: 'stuff' }).respond(200, testComment2); - DS.inject('comment', testComment2); + var comment = DS.inject('comment', testComment2); - DS.update('comment', 6, { + function onBeforeUpdate (resourceName, attrs) { + attrs.other = 'stuff'; + assert.equal(resourceName, 'comment'); + assert.deepEqual(attrs, { content: 'stuff', other: 'stuff' }); + } + + function onAfterUpdate(resourceName, attrs) { + assert.equal(resourceName, 'comment'); + assert.deepEqual(attrs, testComment2); + assert.isFalse(testComment2 === attrs); + } + + Comment.on('DS.beforeUpdate', onBeforeUpdate); + Comment.on('DS.afterUpdate', onAfterUpdate); + + Comment.update(comment, { content: 'stuff' }, { params: {