From 3e5ab3f0b8b468ea6dd9caecc5fd16641cc54ebb Mon Sep 17 00:00:00 2001 From: Marcus Bernales Date: Wed, 12 Aug 2015 21:13:25 -0700 Subject: [PATCH] Ready to merge --- dist/dataloader.min.js | 16938 +------------------ lib/actions/DataActionGenerator.js | 1 + lib/components/FilteredDatasource.react.js | 7 +- lib/mixins/DataMixin.js | 16 +- lib/services/nsynchronizer.js | 3 + lib/stores/LokiStore.js | 31 +- public/assets/js/dataloader.min.js | 16938 +------------------ webpack.config.js | 10 +- 8 files changed, 67 insertions(+), 33877 deletions(-) diff --git a/dist/dataloader.min.js b/dist/dataloader.min.js index 29fdb3c..cefaf4e 100755 --- a/dist/dataloader.min.js +++ b/dist/dataloader.min.js @@ -1,8573 +1,9 @@ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("react")); - else if(typeof define === 'function' && define.amd) - define(["react"], factory); - else if(typeof exports === 'object') - exports["ReactDataloader"] = factory(require("react")); - else - root["ReactDataloader"] = factory(root["React"]); -})(this, function(__WEBPACK_EXTERNAL_MODULE_2__) { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var Datasource = __webpack_require__(4); - var DependentDatasource = __webpack_require__(44); - var BasicDatasource = __webpack_require__(45); - var FilteredDatasource = __webpack_require__(46); - var Collection = __webpack_require__(1); - var ObjectTest = __webpack_require__(47); - var DSManager = __webpack_require__(30); - var uuid = __webpack_require__(34); - // Exports components - module.exports = { - FilteredDatasource: FilteredDatasource, - Datasource: Datasource, - BasicDatasource: BasicDatasource, - Collection: Collection, - ObjectTest: ObjectTest, - DSManager: DSManager, - uuid: uuid - }; - -/***/ }, -/* 1 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var React = __webpack_require__(2); - var _ = __webpack_require__(3); - /** - * Generic Collection - */ - var Collection = React.createClass({ - displayName: 'Collection', - - propTypes: { - /** - * Array of objects to display - */ - data: React.PropTypes.array.isRequired - }, - getDefaultProps: function getDefaultProps() { - return { - data: [] - }; - }, - render: function render() { - var _this = this; - - var firstObject; - if (this.props.data) { - firstObject = Object.keys(this.props.data[0] || {}); - } else { - firstObject = []; - } - - return React.createElement( - 'section', - null, - React.createElement( - 'table', - { className: 'item-list' }, - React.createElement(TableHeader, { keys: firstObject }), - React.createElement( - 'tbody', - null, - _.isArray(this.props.data) && this.props.data.map(function (object, i) { - return React.createElement(TableRow, { - object: object, - key: object.id || i, - onClick: _this.props.handleSelect }); - }) - ) - ) - ); - } - }); - - var TableRow = React.createClass({ - displayName: 'TableRow', - - propTypes: { - object: React.PropTypes.object - }, - render: function render() { - var _this2 = this; - - var onClick = this.props.onClick && this.props.onClick.bind(null, this.props.object.id) || function () {}; - return React.createElement( - 'tr', - { onClick: onClick }, - Object.keys(this.props.object).map(function (key) { - return React.createElement( - 'td', - { key: key }, - JSON.stringify(_this2.props.object[key]) - ); - }) - ); - } - }); - - var TableHeader = React.createClass({ - displayName: 'TableHeader', - - propTypes: { - keys: React.PropTypes.array - }, - render: function render() { - return React.createElement( - 'thead', - null, - this.props.keys.map(function (key, i) { - return React.createElement( - 'th', - { key: i }, - key - ); - }) - ); - } - }); - - module.exports = Collection; - -/***/ }, -/* 2 */ -/***/ function(module, exports) { - - module.exports = __WEBPACK_EXTERNAL_MODULE_2__; - -/***/ }, -/* 3 */ -/***/ function(module, exports, __webpack_require__) { - - var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// Underscore.js 1.8.3 - // http://underscorejs.org - // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - // Underscore may be freely distributed under the MIT license. - - (function() { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `exports` on the server. - var root = this; - - // Save the previous value of the `_` variable. - var previousUnderscore = root._; - - // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; - - // Create quick reference variables for speed access to core prototypes. - var - push = ArrayProto.push, - slice = ArrayProto.slice, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; - - // All **ECMAScript 5** native function implementations that we hope to use - // are declared here. - var - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeBind = FuncProto.bind, - nativeCreate = Object.create; - - // Naked function reference for surrogate-prototype-swapping. - var Ctor = function(){}; - - // Create a safe reference to the Underscore object for use below. - var _ = function(obj) { - if (obj instanceof _) return obj; - if (!(this instanceof _)) return new _(obj); - this._wrapped = obj; - }; - - // Export the Underscore object for **Node.js**, with - // backwards-compatibility for the old `require()` API. If we're in - // the browser, add `_` as a global object. - if (true) { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = _; - } - exports._ = _; - } else { - root._ = _; - } - - // Current version. - _.VERSION = '1.8.3'; - - // Internal function that returns an efficient (for current engines) version - // of the passed-in callback, to be repeatedly applied in other Underscore - // functions. - var optimizeCb = function(func, context, argCount) { - if (context === void 0) return func; - switch (argCount == null ? 3 : argCount) { - case 1: return function(value) { - return func.call(context, value); - }; - case 2: return function(value, other) { - return func.call(context, value, other); - }; - case 3: return function(value, index, collection) { - return func.call(context, value, index, collection); - }; - case 4: return function(accumulator, value, index, collection) { - return func.call(context, accumulator, value, index, collection); - }; - } - return function() { - return func.apply(context, arguments); - }; - }; - - // A mostly-internal function to generate callbacks that can be applied - // to each element in a collection, returning the desired result — either - // identity, an arbitrary callback, a property matcher, or a property accessor. - var cb = function(value, context, argCount) { - if (value == null) return _.identity; - if (_.isFunction(value)) return optimizeCb(value, context, argCount); - if (_.isObject(value)) return _.matcher(value); - return _.property(value); - }; - _.iteratee = function(value, context) { - return cb(value, context, Infinity); - }; - - // An internal function for creating assigner functions. - var createAssigner = function(keysFunc, undefinedOnly) { - return function(obj) { - var length = arguments.length; - if (length < 2 || obj == null) return obj; - for (var index = 1; index < length; index++) { - var source = arguments[index], - keys = keysFunc(source), - l = keys.length; - for (var i = 0; i < l; i++) { - var key = keys[i]; - if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; - } - } - return obj; - }; - }; - - // An internal function for creating a new object that inherits from another. - var baseCreate = function(prototype) { - if (!_.isObject(prototype)) return {}; - if (nativeCreate) return nativeCreate(prototype); - Ctor.prototype = prototype; - var result = new Ctor; - Ctor.prototype = null; - return result; - }; - - var property = function(key) { - return function(obj) { - return obj == null ? void 0 : obj[key]; - }; - }; - - // Helper for collection methods to determine whether a collection - // should be iterated as an array or as an object - // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength - // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 - var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; - var getLength = property('length'); - var isArrayLike = function(collection) { - var length = getLength(collection); - return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; - }; - - // Collection Functions - // -------------------- - - // The cornerstone, an `each` implementation, aka `forEach`. - // Handles raw objects in addition to array-likes. Treats all - // sparse array-likes as if they were dense. - _.each = _.forEach = function(obj, iteratee, context) { - iteratee = optimizeCb(iteratee, context); - var i, length; - if (isArrayLike(obj)) { - for (i = 0, length = obj.length; i < length; i++) { - iteratee(obj[i], i, obj); - } - } else { - var keys = _.keys(obj); - for (i = 0, length = keys.length; i < length; i++) { - iteratee(obj[keys[i]], keys[i], obj); - } - } - return obj; - }; - - // Return the results of applying the iteratee to each element. - _.map = _.collect = function(obj, iteratee, context) { - iteratee = cb(iteratee, context); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length, - results = Array(length); - for (var index = 0; index < length; index++) { - var currentKey = keys ? keys[index] : index; - results[index] = iteratee(obj[currentKey], currentKey, obj); - } - return results; - }; - - // Create a reducing function iterating left or right. - function createReduce(dir) { - // Optimized iterator function as using arguments.length - // in the main function will deoptimize the, see #1991. - function iterator(obj, iteratee, memo, keys, index, length) { - for (; index >= 0 && index < length; index += dir) { - var currentKey = keys ? keys[index] : index; - memo = iteratee(memo, obj[currentKey], currentKey, obj); - } - return memo; - } - - return function(obj, iteratee, memo, context) { - iteratee = optimizeCb(iteratee, context, 4); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length, - index = dir > 0 ? 0 : length - 1; - // Determine the initial value if none is provided. - if (arguments.length < 3) { - memo = obj[keys ? keys[index] : index]; - index += dir; - } - return iterator(obj, iteratee, memo, keys, index, length); - }; - } - - // **Reduce** builds up a single result from a list of values, aka `inject`, - // or `foldl`. - _.reduce = _.foldl = _.inject = createReduce(1); - - // The right-associative version of reduce, also known as `foldr`. - _.reduceRight = _.foldr = createReduce(-1); - - // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, predicate, context) { - var key; - if (isArrayLike(obj)) { - key = _.findIndex(obj, predicate, context); - } else { - key = _.findKey(obj, predicate, context); - } - if (key !== void 0 && key !== -1) return obj[key]; - }; - - // Return all the elements that pass a truth test. - // Aliased as `select`. - _.filter = _.select = function(obj, predicate, context) { - var results = []; - predicate = cb(predicate, context); - _.each(obj, function(value, index, list) { - if (predicate(value, index, list)) results.push(value); - }); - return results; - }; - - // Return all the elements for which a truth test fails. - _.reject = function(obj, predicate, context) { - return _.filter(obj, _.negate(cb(predicate)), context); - }; - - // Determine whether all of the elements match a truth test. - // Aliased as `all`. - _.every = _.all = function(obj, predicate, context) { - predicate = cb(predicate, context); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length; - for (var index = 0; index < length; index++) { - var currentKey = keys ? keys[index] : index; - if (!predicate(obj[currentKey], currentKey, obj)) return false; - } - return true; - }; - - // Determine if at least one element in the object matches a truth test. - // Aliased as `any`. - _.some = _.any = function(obj, predicate, context) { - predicate = cb(predicate, context); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length; - for (var index = 0; index < length; index++) { - var currentKey = keys ? keys[index] : index; - if (predicate(obj[currentKey], currentKey, obj)) return true; - } - return false; - }; - - // Determine if the array or object contains a given item (using `===`). - // Aliased as `includes` and `include`. - _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) { - if (!isArrayLike(obj)) obj = _.values(obj); - if (typeof fromIndex != 'number' || guard) fromIndex = 0; - return _.indexOf(obj, item, fromIndex) >= 0; - }; - - // Invoke a method (with arguments) on every item in a collection. - _.invoke = function(obj, method) { - var args = slice.call(arguments, 2); - var isFunc = _.isFunction(method); - return _.map(obj, function(value) { - var func = isFunc ? method : value[method]; - return func == null ? func : func.apply(value, args); - }); - }; - - // Convenience version of a common use case of `map`: fetching a property. - _.pluck = function(obj, key) { - return _.map(obj, _.property(key)); - }; - - // Convenience version of a common use case of `filter`: selecting only objects - // containing specific `key:value` pairs. - _.where = function(obj, attrs) { - return _.filter(obj, _.matcher(attrs)); - }; - - // Convenience version of a common use case of `find`: getting the first object - // containing specific `key:value` pairs. - _.findWhere = function(obj, attrs) { - return _.find(obj, _.matcher(attrs)); - }; - - // Return the maximum element (or element-based computation). - _.max = function(obj, iteratee, context) { - var result = -Infinity, lastComputed = -Infinity, - value, computed; - if (iteratee == null && obj != null) { - obj = isArrayLike(obj) ? obj : _.values(obj); - for (var i = 0, length = obj.length; i < length; i++) { - value = obj[i]; - if (value > result) { - result = value; - } - } - } else { - iteratee = cb(iteratee, context); - _.each(obj, function(value, index, list) { - computed = iteratee(value, index, list); - if (computed > lastComputed || computed === -Infinity && result === -Infinity) { - result = value; - lastComputed = computed; - } - }); - } - return result; - }; - - // Return the minimum element (or element-based computation). - _.min = function(obj, iteratee, context) { - var result = Infinity, lastComputed = Infinity, - value, computed; - if (iteratee == null && obj != null) { - obj = isArrayLike(obj) ? obj : _.values(obj); - for (var i = 0, length = obj.length; i < length; i++) { - value = obj[i]; - if (value < result) { - result = value; - } - } - } else { - iteratee = cb(iteratee, context); - _.each(obj, function(value, index, list) { - computed = iteratee(value, index, list); - if (computed < lastComputed || computed === Infinity && result === Infinity) { - result = value; - lastComputed = computed; - } - }); - } - return result; - }; - - // Shuffle a collection, using the modern version of the - // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). - _.shuffle = function(obj) { - var set = isArrayLike(obj) ? obj : _.values(obj); - var length = set.length; - var shuffled = Array(length); - for (var index = 0, rand; index < length; index++) { - rand = _.random(0, index); - if (rand !== index) shuffled[index] = shuffled[rand]; - shuffled[rand] = set[index]; - } - return shuffled; - }; - - // Sample **n** random values from a collection. - // If **n** is not specified, returns a single random element. - // The internal `guard` argument allows it to work with `map`. - _.sample = function(obj, n, guard) { - if (n == null || guard) { - if (!isArrayLike(obj)) obj = _.values(obj); - return obj[_.random(obj.length - 1)]; - } - return _.shuffle(obj).slice(0, Math.max(0, n)); - }; - - // Sort the object's values by a criterion produced by an iteratee. - _.sortBy = function(obj, iteratee, context) { - iteratee = cb(iteratee, context); - return _.pluck(_.map(obj, function(value, index, list) { - return { - value: value, - index: index, - criteria: iteratee(value, index, list) - }; - }).sort(function(left, right) { - var a = left.criteria; - var b = right.criteria; - if (a !== b) { - if (a > b || a === void 0) return 1; - if (a < b || b === void 0) return -1; - } - return left.index - right.index; - }), 'value'); - }; - - // An internal function used for aggregate "group by" operations. - var group = function(behavior) { - return function(obj, iteratee, context) { - var result = {}; - iteratee = cb(iteratee, context); - _.each(obj, function(value, index) { - var key = iteratee(value, index, obj); - behavior(result, value, key); - }); - return result; - }; - }; - - // Groups the object's values by a criterion. Pass either a string attribute - // to group by, or a function that returns the criterion. - _.groupBy = group(function(result, value, key) { - if (_.has(result, key)) result[key].push(value); else result[key] = [value]; - }); - - // Indexes the object's values by a criterion, similar to `groupBy`, but for - // when you know that your index values will be unique. - _.indexBy = group(function(result, value, key) { - result[key] = value; - }); - - // Counts instances of an object that group by a certain criterion. Pass - // either a string attribute to count by, or a function that returns the - // criterion. - _.countBy = group(function(result, value, key) { - if (_.has(result, key)) result[key]++; else result[key] = 1; - }); - - // Safely create a real, live array from anything iterable. - _.toArray = function(obj) { - if (!obj) return []; - if (_.isArray(obj)) return slice.call(obj); - if (isArrayLike(obj)) return _.map(obj, _.identity); - return _.values(obj); - }; - - // Return the number of elements in an object. - _.size = function(obj) { - if (obj == null) return 0; - return isArrayLike(obj) ? obj.length : _.keys(obj).length; - }; - - // Split a collection into two arrays: one whose elements all satisfy the given - // predicate, and one whose elements all do not satisfy the predicate. - _.partition = function(obj, predicate, context) { - predicate = cb(predicate, context); - var pass = [], fail = []; - _.each(obj, function(value, key, obj) { - (predicate(value, key, obj) ? pass : fail).push(value); - }); - return [pass, fail]; - }; - - // Array Functions - // --------------- - - // Get the first element of an array. Passing **n** will return the first N - // values in the array. Aliased as `head` and `take`. The **guard** check - // allows it to work with `_.map`. - _.first = _.head = _.take = function(array, n, guard) { - if (array == null) return void 0; - if (n == null || guard) return array[0]; - return _.initial(array, array.length - n); - }; - - // Returns everything but the last entry of the array. Especially useful on - // the arguments object. Passing **n** will return all the values in - // the array, excluding the last N. - _.initial = function(array, n, guard) { - return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); - }; - - // Get the last element of an array. Passing **n** will return the last N - // values in the array. - _.last = function(array, n, guard) { - if (array == null) return void 0; - if (n == null || guard) return array[array.length - 1]; - return _.rest(array, Math.max(0, array.length - n)); - }; - - // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. - // Especially useful on the arguments object. Passing an **n** will return - // the rest N values in the array. - _.rest = _.tail = _.drop = function(array, n, guard) { - return slice.call(array, n == null || guard ? 1 : n); - }; - - // Trim out all falsy values from an array. - _.compact = function(array) { - return _.filter(array, _.identity); - }; - - // Internal implementation of a recursive `flatten` function. - var flatten = function(input, shallow, strict, startIndex) { - var output = [], idx = 0; - for (var i = startIndex || 0, length = getLength(input); i < length; i++) { - var value = input[i]; - if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { - //flatten current level of array or arguments object - if (!shallow) value = flatten(value, shallow, strict); - var j = 0, len = value.length; - output.length += len; - while (j < len) { - output[idx++] = value[j++]; - } - } else if (!strict) { - output[idx++] = value; - } - } - return output; - }; - - // Flatten out an array, either recursively (by default), or just one level. - _.flatten = function(array, shallow) { - return flatten(array, shallow, false); - }; - - // Return a version of the array that does not contain the specified value(s). - _.without = function(array) { - return _.difference(array, slice.call(arguments, 1)); - }; - - // Produce a duplicate-free version of the array. If the array has already - // been sorted, you have the option of using a faster algorithm. - // Aliased as `unique`. - _.uniq = _.unique = function(array, isSorted, iteratee, context) { - if (!_.isBoolean(isSorted)) { - context = iteratee; - iteratee = isSorted; - isSorted = false; - } - if (iteratee != null) iteratee = cb(iteratee, context); - var result = []; - var seen = []; - for (var i = 0, length = getLength(array); i < length; i++) { - var value = array[i], - computed = iteratee ? iteratee(value, i, array) : value; - if (isSorted) { - if (!i || seen !== computed) result.push(value); - seen = computed; - } else if (iteratee) { - if (!_.contains(seen, computed)) { - seen.push(computed); - result.push(value); - } - } else if (!_.contains(result, value)) { - result.push(value); - } - } - return result; - }; - - // Produce an array that contains the union: each distinct element from all of - // the passed-in arrays. - _.union = function() { - return _.uniq(flatten(arguments, true, true)); - }; - - // Produce an array that contains every item shared between all the - // passed-in arrays. - _.intersection = function(array) { - var result = []; - var argsLength = arguments.length; - for (var i = 0, length = getLength(array); i < length; i++) { - var item = array[i]; - if (_.contains(result, item)) continue; - for (var j = 1; j < argsLength; j++) { - if (!_.contains(arguments[j], item)) break; - } - if (j === argsLength) result.push(item); - } - return result; - }; - - // Take the difference between one array and a number of other arrays. - // Only the elements present in just the first array will remain. - _.difference = function(array) { - var rest = flatten(arguments, true, true, 1); - return _.filter(array, function(value){ - return !_.contains(rest, value); - }); - }; - - // Zip together multiple lists into a single array -- elements that share - // an index go together. - _.zip = function() { - return _.unzip(arguments); - }; - - // Complement of _.zip. Unzip accepts an array of arrays and groups - // each array's elements on shared indices - _.unzip = function(array) { - var length = array && _.max(array, getLength).length || 0; - var result = Array(length); - - for (var index = 0; index < length; index++) { - result[index] = _.pluck(array, index); - } - return result; - }; - - // Converts lists into objects. Pass either a single array of `[key, value]` - // pairs, or two parallel arrays of the same length -- one of keys, and one of - // the corresponding values. - _.object = function(list, values) { - var result = {}; - for (var i = 0, length = getLength(list); i < length; i++) { - if (values) { - result[list[i]] = values[i]; - } else { - result[list[i][0]] = list[i][1]; - } - } - return result; - }; - - // Generator function to create the findIndex and findLastIndex functions - function createPredicateIndexFinder(dir) { - return function(array, predicate, context) { - predicate = cb(predicate, context); - var length = getLength(array); - var index = dir > 0 ? 0 : length - 1; - for (; index >= 0 && index < length; index += dir) { - if (predicate(array[index], index, array)) return index; - } - return -1; - }; - } - - // Returns the first index on an array-like that passes a predicate test - _.findIndex = createPredicateIndexFinder(1); - _.findLastIndex = createPredicateIndexFinder(-1); - - // Use a comparator function to figure out the smallest index at which - // an object should be inserted so as to maintain order. Uses binary search. - _.sortedIndex = function(array, obj, iteratee, context) { - iteratee = cb(iteratee, context, 1); - var value = iteratee(obj); - var low = 0, high = getLength(array); - while (low < high) { - var mid = Math.floor((low + high) / 2); - if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; - } - return low; - }; - - // Generator function to create the indexOf and lastIndexOf functions - function createIndexFinder(dir, predicateFind, sortedIndex) { - return function(array, item, idx) { - var i = 0, length = getLength(array); - if (typeof idx == 'number') { - if (dir > 0) { - i = idx >= 0 ? idx : Math.max(idx + length, i); - } else { - length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; - } - } else if (sortedIndex && idx && length) { - idx = sortedIndex(array, item); - return array[idx] === item ? idx : -1; - } - if (item !== item) { - idx = predicateFind(slice.call(array, i, length), _.isNaN); - return idx >= 0 ? idx + i : -1; - } - for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { - if (array[idx] === item) return idx; - } - return -1; - }; - } - - // Return the position of the first occurrence of an item in an array, - // or -1 if the item is not included in the array. - // If the array is large and already in sort order, pass `true` - // for **isSorted** to use binary search. - _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex); - _.lastIndexOf = createIndexFinder(-1, _.findLastIndex); - - // Generate an integer Array containing an arithmetic progression. A port of - // the native Python `range()` function. See - // [the Python documentation](http://docs.python.org/library/functions.html#range). - _.range = function(start, stop, step) { - if (stop == null) { - stop = start || 0; - start = 0; - } - step = step || 1; - - var length = Math.max(Math.ceil((stop - start) / step), 0); - var range = Array(length); - - for (var idx = 0; idx < length; idx++, start += step) { - range[idx] = start; - } - - return range; - }; - - // Function (ahem) Functions - // ------------------ - - // Determines whether to execute a function as a constructor - // or a normal function with the provided arguments - var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { - if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); - var self = baseCreate(sourceFunc.prototype); - var result = sourceFunc.apply(self, args); - if (_.isObject(result)) return result; - return self; - }; - - // Create a function bound to a given object (assigning `this`, and arguments, - // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if - // available. - _.bind = function(func, context) { - if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); - if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); - var args = slice.call(arguments, 2); - var bound = function() { - return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); - }; - return bound; - }; - - // Partially apply a function by creating a version that has had some of its - // arguments pre-filled, without changing its dynamic `this` context. _ acts - // as a placeholder, allowing any combination of arguments to be pre-filled. - _.partial = function(func) { - var boundArgs = slice.call(arguments, 1); - var bound = function() { - var position = 0, length = boundArgs.length; - var args = Array(length); - for (var i = 0; i < length; i++) { - args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i]; - } - while (position < arguments.length) args.push(arguments[position++]); - return executeBound(func, bound, this, this, args); - }; - return bound; - }; - - // Bind a number of an object's methods to that object. Remaining arguments - // are the method names to be bound. Useful for ensuring that all callbacks - // defined on an object belong to it. - _.bindAll = function(obj) { - var i, length = arguments.length, key; - if (length <= 1) throw new Error('bindAll must be passed function names'); - for (i = 1; i < length; i++) { - key = arguments[i]; - obj[key] = _.bind(obj[key], obj); - } - return obj; - }; - - // Memoize an expensive function by storing its results. - _.memoize = function(func, hasher) { - var memoize = function(key) { - var cache = memoize.cache; - var address = '' + (hasher ? hasher.apply(this, arguments) : key); - if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); - return cache[address]; - }; - memoize.cache = {}; - return memoize; - }; - - // Delays a function for the given number of milliseconds, and then calls - // it with the arguments supplied. - _.delay = function(func, wait) { - var args = slice.call(arguments, 2); - return setTimeout(function(){ - return func.apply(null, args); - }, wait); - }; - - // Defers a function, scheduling it to run after the current call stack has - // cleared. - _.defer = _.partial(_.delay, _, 1); - - // Returns a function, that, when invoked, will only be triggered at most once - // during a given window of time. Normally, the throttled function will run - // as much as it can, without ever going more than once per `wait` duration; - // but if you'd like to disable the execution on the leading edge, pass - // `{leading: false}`. To disable execution on the trailing edge, ditto. - _.throttle = function(func, wait, options) { - var context, args, result; - var timeout = null; - var previous = 0; - if (!options) options = {}; - var later = function() { - previous = options.leading === false ? 0 : _.now(); - timeout = null; - result = func.apply(context, args); - if (!timeout) context = args = null; - }; - return function() { - var now = _.now(); - if (!previous && options.leading === false) previous = now; - var remaining = wait - (now - previous); - context = this; - args = arguments; - if (remaining <= 0 || remaining > wait) { - if (timeout) { - clearTimeout(timeout); - timeout = null; - } - previous = now; - result = func.apply(context, args); - if (!timeout) context = args = null; - } else if (!timeout && options.trailing !== false) { - timeout = setTimeout(later, remaining); - } - return result; - }; - }; - - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. If `immediate` is passed, trigger the function on the - // leading edge, instead of the trailing. - _.debounce = function(func, wait, immediate) { - var timeout, args, context, timestamp, result; - - var later = function() { - var last = _.now() - timestamp; - - if (last < wait && last >= 0) { - timeout = setTimeout(later, wait - last); - } else { - timeout = null; - if (!immediate) { - result = func.apply(context, args); - if (!timeout) context = args = null; - } - } - }; - - return function() { - context = this; - args = arguments; - timestamp = _.now(); - var callNow = immediate && !timeout; - if (!timeout) timeout = setTimeout(later, wait); - if (callNow) { - result = func.apply(context, args); - context = args = null; - } - - return result; - }; - }; - - // Returns the first function passed as an argument to the second, - // allowing you to adjust arguments, run code before and after, and - // conditionally execute the original function. - _.wrap = function(func, wrapper) { - return _.partial(wrapper, func); - }; - - // Returns a negated version of the passed-in predicate. - _.negate = function(predicate) { - return function() { - return !predicate.apply(this, arguments); - }; - }; - - // Returns a function that is the composition of a list of functions, each - // consuming the return value of the function that follows. - _.compose = function() { - var args = arguments; - var start = args.length - 1; - return function() { - var i = start; - var result = args[start].apply(this, arguments); - while (i--) result = args[i].call(this, result); - return result; - }; - }; - - // Returns a function that will only be executed on and after the Nth call. - _.after = function(times, func) { - return function() { - if (--times < 1) { - return func.apply(this, arguments); - } - }; - }; - - // Returns a function that will only be executed up to (but not including) the Nth call. - _.before = function(times, func) { - var memo; - return function() { - if (--times > 0) { - memo = func.apply(this, arguments); - } - if (times <= 1) func = null; - return memo; - }; - }; - - // Returns a function that will be executed at most one time, no matter how - // often you call it. Useful for lazy initialization. - _.once = _.partial(_.before, 2); - - // Object Functions - // ---------------- - - // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. - var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); - var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', - 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; - - function collectNonEnumProps(obj, keys) { - var nonEnumIdx = nonEnumerableProps.length; - var constructor = obj.constructor; - var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; - - // Constructor is a special case. - var prop = 'constructor'; - if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop); - - while (nonEnumIdx--) { - prop = nonEnumerableProps[nonEnumIdx]; - if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) { - keys.push(prop); - } - } - } - - // Retrieve the names of an object's own properties. - // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = function(obj) { - if (!_.isObject(obj)) return []; - if (nativeKeys) return nativeKeys(obj); - var keys = []; - for (var key in obj) if (_.has(obj, key)) keys.push(key); - // Ahem, IE < 9. - if (hasEnumBug) collectNonEnumProps(obj, keys); - return keys; - }; - - // Retrieve all the property names of an object. - _.allKeys = function(obj) { - if (!_.isObject(obj)) return []; - var keys = []; - for (var key in obj) keys.push(key); - // Ahem, IE < 9. - if (hasEnumBug) collectNonEnumProps(obj, keys); - return keys; - }; - - // Retrieve the values of an object's properties. - _.values = function(obj) { - var keys = _.keys(obj); - var length = keys.length; - var values = Array(length); - for (var i = 0; i < length; i++) { - values[i] = obj[keys[i]]; - } - return values; - }; - - // Returns the results of applying the iteratee to each element of the object - // In contrast to _.map it returns an object - _.mapObject = function(obj, iteratee, context) { - iteratee = cb(iteratee, context); - var keys = _.keys(obj), - length = keys.length, - results = {}, - currentKey; - for (var index = 0; index < length; index++) { - currentKey = keys[index]; - results[currentKey] = iteratee(obj[currentKey], currentKey, obj); - } - return results; - }; - - // Convert an object into a list of `[key, value]` pairs. - _.pairs = function(obj) { - var keys = _.keys(obj); - var length = keys.length; - var pairs = Array(length); - for (var i = 0; i < length; i++) { - pairs[i] = [keys[i], obj[keys[i]]]; - } - return pairs; - }; - - // Invert the keys and values of an object. The values must be serializable. - _.invert = function(obj) { - var result = {}; - var keys = _.keys(obj); - for (var i = 0, length = keys.length; i < length; i++) { - result[obj[keys[i]]] = keys[i]; - } - return result; - }; - - // Return a sorted list of the function names available on the object. - // Aliased as `methods` - _.functions = _.methods = function(obj) { - var names = []; - for (var key in obj) { - if (_.isFunction(obj[key])) names.push(key); - } - return names.sort(); - }; - - // Extend a given object with all the properties in passed-in object(s). - _.extend = createAssigner(_.allKeys); - - // Assigns a given object with all the own properties in the passed-in object(s) - // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) - _.extendOwn = _.assign = createAssigner(_.keys); - - // Returns the first key on an object that passes a predicate test - _.findKey = function(obj, predicate, context) { - predicate = cb(predicate, context); - var keys = _.keys(obj), key; - for (var i = 0, length = keys.length; i < length; i++) { - key = keys[i]; - if (predicate(obj[key], key, obj)) return key; - } - }; - - // Return a copy of the object only containing the whitelisted properties. - _.pick = function(object, oiteratee, context) { - var result = {}, obj = object, iteratee, keys; - if (obj == null) return result; - if (_.isFunction(oiteratee)) { - keys = _.allKeys(obj); - iteratee = optimizeCb(oiteratee, context); - } else { - keys = flatten(arguments, false, false, 1); - iteratee = function(value, key, obj) { return key in obj; }; - obj = Object(obj); - } - for (var i = 0, length = keys.length; i < length; i++) { - var key = keys[i]; - var value = obj[key]; - if (iteratee(value, key, obj)) result[key] = value; - } - return result; - }; - - // Return a copy of the object without the blacklisted properties. - _.omit = function(obj, iteratee, context) { - if (_.isFunction(iteratee)) { - iteratee = _.negate(iteratee); - } else { - var keys = _.map(flatten(arguments, false, false, 1), String); - iteratee = function(value, key) { - return !_.contains(keys, key); - }; - } - return _.pick(obj, iteratee, context); - }; - - // Fill in a given object with default properties. - _.defaults = createAssigner(_.allKeys, true); - - // Creates an object that inherits from the given prototype object. - // If additional properties are provided then they will be added to the - // created object. - _.create = function(prototype, props) { - var result = baseCreate(prototype); - if (props) _.extendOwn(result, props); - return result; - }; - - // Create a (shallow-cloned) duplicate of an object. - _.clone = function(obj) { - if (!_.isObject(obj)) return obj; - return _.isArray(obj) ? obj.slice() : _.extend({}, obj); - }; - - // Invokes interceptor with the obj, and then returns obj. - // The primary purpose of this method is to "tap into" a method chain, in - // order to perform operations on intermediate results within the chain. - _.tap = function(obj, interceptor) { - interceptor(obj); - return obj; - }; - - // Returns whether an object has a given set of `key:value` pairs. - _.isMatch = function(object, attrs) { - var keys = _.keys(attrs), length = keys.length; - if (object == null) return !length; - var obj = Object(object); - for (var i = 0; i < length; i++) { - var key = keys[i]; - if (attrs[key] !== obj[key] || !(key in obj)) return false; - } - return true; - }; - - - // Internal recursive comparison function for `isEqual`. - var eq = function(a, b, aStack, bStack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). - if (a === b) return a !== 0 || 1 / a === 1 / b; - // A strict comparison is necessary because `null == undefined`. - if (a == null || b == null) return a === b; - // Unwrap any wrapped objects. - if (a instanceof _) a = a._wrapped; - if (b instanceof _) b = b._wrapped; - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className !== toString.call(b)) return false; - switch (className) { - // Strings, numbers, regular expressions, dates, and booleans are compared by value. - case '[object RegExp]': - // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - return '' + a === '' + b; - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. - // Object(NaN) is equivalent to NaN - if (+a !== +a) return +b !== +b; - // An `egal` comparison is performed for other numeric values. - return +a === 0 ? 1 / +a === 1 / b : +a === +b; - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - return +a === +b; - } - - var areArrays = className === '[object Array]'; - if (!areArrays) { - if (typeof a != 'object' || typeof b != 'object') return false; - - // Objects with different constructors are not equivalent, but `Object`s or `Array`s - // from different frames are. - var aCtor = a.constructor, bCtor = b.constructor; - if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && - _.isFunction(bCtor) && bCtor instanceof bCtor) - && ('constructor' in a && 'constructor' in b)) { - return false; - } - } - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - - // Initializing stack of traversed objects. - // It's done here since we only need them for objects and arrays comparison. - aStack = aStack || []; - bStack = bStack || []; - var length = aStack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (aStack[length] === a) return bStack[length] === b; - } - - // Add the first object to the stack of traversed objects. - aStack.push(a); - bStack.push(b); - - // Recursively compare objects and arrays. - if (areArrays) { - // Compare array lengths to determine if a deep comparison is necessary. - length = a.length; - if (length !== b.length) return false; - // Deep compare the contents, ignoring non-numeric properties. - while (length--) { - if (!eq(a[length], b[length], aStack, bStack)) return false; - } - } else { - // Deep compare objects. - var keys = _.keys(a), key; - length = keys.length; - // Ensure that both objects contain the same number of properties before comparing deep equality. - if (_.keys(b).length !== length) return false; - while (length--) { - // Deep compare each member - key = keys[length]; - if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; - } - } - // Remove the first object from the stack of traversed objects. - aStack.pop(); - bStack.pop(); - return true; - }; - - // Perform a deep comparison to check if two objects are equal. - _.isEqual = function(a, b) { - return eq(a, b); - }; - - // Is a given array, string, or object empty? - // An "empty" object has no enumerable own-properties. - _.isEmpty = function(obj) { - if (obj == null) return true; - if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; - return _.keys(obj).length === 0; - }; - - // Is a given value a DOM element? - _.isElement = function(obj) { - return !!(obj && obj.nodeType === 1); - }; - - // Is a given value an array? - // Delegates to ECMA5's native Array.isArray - _.isArray = nativeIsArray || function(obj) { - return toString.call(obj) === '[object Array]'; - }; - - // Is a given variable an object? - _.isObject = function(obj) { - var type = typeof obj; - return type === 'function' || type === 'object' && !!obj; - }; - - // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. - _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { - _['is' + name] = function(obj) { - return toString.call(obj) === '[object ' + name + ']'; - }; - }); - - // Define a fallback version of the method in browsers (ahem, IE < 9), where - // there isn't any inspectable "Arguments" type. - if (!_.isArguments(arguments)) { - _.isArguments = function(obj) { - return _.has(obj, 'callee'); - }; - } - - // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, - // IE 11 (#1621), and in Safari 8 (#1929). - if (typeof /./ != 'function' && typeof Int8Array != 'object') { - _.isFunction = function(obj) { - return typeof obj == 'function' || false; - }; - } - - // Is a given object a finite number? - _.isFinite = function(obj) { - return isFinite(obj) && !isNaN(parseFloat(obj)); - }; - - // Is the given value `NaN`? (NaN is the only number which does not equal itself). - _.isNaN = function(obj) { - return _.isNumber(obj) && obj !== +obj; - }; - - // Is a given value a boolean? - _.isBoolean = function(obj) { - return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; - }; - - // Is a given value equal to null? - _.isNull = function(obj) { - return obj === null; - }; - - // Is a given variable undefined? - _.isUndefined = function(obj) { - return obj === void 0; - }; - - // Shortcut function for checking if an object has a given property directly - // on itself (in other words, not on a prototype). - _.has = function(obj, key) { - return obj != null && hasOwnProperty.call(obj, key); - }; - - // Utility Functions - // ----------------- - - // Run Underscore.js in *noConflict* mode, returning the `_` variable to its - // previous owner. Returns a reference to the Underscore object. - _.noConflict = function() { - root._ = previousUnderscore; - return this; - }; - - // Keep the identity function around for default iteratees. - _.identity = function(value) { - return value; - }; - - // Predicate-generating functions. Often useful outside of Underscore. - _.constant = function(value) { - return function() { - return value; - }; - }; - - _.noop = function(){}; - - _.property = property; - - // Generates a function for a given object that returns a given property. - _.propertyOf = function(obj) { - return obj == null ? function(){} : function(key) { - return obj[key]; - }; - }; - - // Returns a predicate for checking whether an object has a given set of - // `key:value` pairs. - _.matcher = _.matches = function(attrs) { - attrs = _.extendOwn({}, attrs); - return function(obj) { - return _.isMatch(obj, attrs); - }; - }; - - // Run a function **n** times. - _.times = function(n, iteratee, context) { - var accum = Array(Math.max(0, n)); - iteratee = optimizeCb(iteratee, context, 1); - for (var i = 0; i < n; i++) accum[i] = iteratee(i); - return accum; - }; - - // Return a random integer between min and max (inclusive). - _.random = function(min, max) { - if (max == null) { - max = min; - min = 0; - } - return min + Math.floor(Math.random() * (max - min + 1)); - }; - - // A (possibly faster) way to get the current timestamp as an integer. - _.now = Date.now || function() { - return new Date().getTime(); - }; - - // List of HTML entities for escaping. - var escapeMap = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '`': '`' - }; - var unescapeMap = _.invert(escapeMap); - - // Functions for escaping and unescaping strings to/from HTML interpolation. - var createEscaper = function(map) { - var escaper = function(match) { - return map[match]; - }; - // Regexes for identifying a key that needs to be escaped - var source = '(?:' + _.keys(map).join('|') + ')'; - var testRegexp = RegExp(source); - var replaceRegexp = RegExp(source, 'g'); - return function(string) { - string = string == null ? '' : '' + string; - return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; - }; - }; - _.escape = createEscaper(escapeMap); - _.unescape = createEscaper(unescapeMap); - - // If the value of the named `property` is a function then invoke it with the - // `object` as context; otherwise, return it. - _.result = function(object, property, fallback) { - var value = object == null ? void 0 : object[property]; - if (value === void 0) { - value = fallback; - } - return _.isFunction(value) ? value.call(object) : value; - }; - - // Generate a unique integer id (unique within the entire client session). - // Useful for temporary DOM ids. - var idCounter = 0; - _.uniqueId = function(prefix) { - var id = ++idCounter + ''; - return prefix ? prefix + id : id; - }; - - // By default, Underscore uses ERB-style template delimiters, change the - // following template settings to use alternative delimiters. - _.templateSettings = { - evaluate : /<%([\s\S]+?)%>/g, - interpolate : /<%=([\s\S]+?)%>/g, - escape : /<%-([\s\S]+?)%>/g - }; - - // When customizing `templateSettings`, if you don't want to define an - // interpolation, evaluation or escaping regex, we need one that is - // guaranteed not to match. - var noMatch = /(.)^/; - - // Certain characters need to be escaped so that they can be put into a - // string literal. - var escapes = { - "'": "'", - '\\': '\\', - '\r': 'r', - '\n': 'n', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - - var escaper = /\\|'|\r|\n|\u2028|\u2029/g; - - var escapeChar = function(match) { - return '\\' + escapes[match]; - }; - - // JavaScript micro-templating, similar to John Resig's implementation. - // Underscore templating handles arbitrary delimiters, preserves whitespace, - // and correctly escapes quotes within interpolated code. - // NB: `oldSettings` only exists for backwards compatibility. - _.template = function(text, settings, oldSettings) { - if (!settings && oldSettings) settings = oldSettings; - settings = _.defaults({}, settings, _.templateSettings); - - // Combine delimiters into one regular expression via alternation. - var matcher = RegExp([ - (settings.escape || noMatch).source, - (settings.interpolate || noMatch).source, - (settings.evaluate || noMatch).source - ].join('|') + '|$', 'g'); - - // Compile the template source, escaping string literals appropriately. - var index = 0; - var source = "__p+='"; - text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { - source += text.slice(index, offset).replace(escaper, escapeChar); - index = offset + match.length; - - if (escape) { - source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; - } else if (interpolate) { - source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; - } else if (evaluate) { - source += "';\n" + evaluate + "\n__p+='"; - } - - // Adobe VMs need the match returned to produce the correct offest. - return match; - }); - source += "';\n"; - - // If a variable is not specified, place data values in local scope. - if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; - - source = "var __t,__p='',__j=Array.prototype.join," + - "print=function(){__p+=__j.call(arguments,'');};\n" + - source + 'return __p;\n'; - - try { - var render = new Function(settings.variable || 'obj', '_', source); - } catch (e) { - e.source = source; - throw e; - } - - var template = function(data) { - return render.call(this, data, _); - }; - - // Provide the compiled source as a convenience for precompilation. - var argument = settings.variable || 'obj'; - template.source = 'function(' + argument + '){\n' + source + '}'; - - return template; - }; - - // Add a "chain" function. Start chaining a wrapped Underscore object. - _.chain = function(obj) { - var instance = _(obj); - instance._chain = true; - return instance; - }; - - // OOP - // --------------- - // If Underscore is called as a function, it returns a wrapped object that - // can be used OO-style. This wrapper holds altered versions of all the - // underscore functions. Wrapped objects may be chained. - - // Helper function to continue chaining intermediate results. - var result = function(instance, obj) { - return instance._chain ? _(obj).chain() : obj; - }; - - // Add your own custom functions to the Underscore object. - _.mixin = function(obj) { - _.each(_.functions(obj), function(name) { - var func = _[name] = obj[name]; - _.prototype[name] = function() { - var args = [this._wrapped]; - push.apply(args, arguments); - return result(this, func.apply(_, args)); - }; - }); - }; - - // Add all of the Underscore functions to the wrapper object. - _.mixin(_); - - // Add all mutator Array functions to the wrapper. - _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - var obj = this._wrapped; - method.apply(obj, arguments); - if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; - return result(this, obj); - }; - }); - - // Add all accessor Array functions to the wrapper. - _.each(['concat', 'join', 'slice'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - return result(this, method.apply(this._wrapped, arguments)); - }; - }); - - // Extracts the result from a wrapped and chained object. - _.prototype.value = function() { - return this._wrapped; - }; - - // Provide unwrapping proxy for some methods used in engine operations - // such as arithmetic and JSON stringification. - _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; - - _.prototype.toString = function() { - return '' + this._wrapped; - }; - - // AMD registration happens at the end for compatibility with AMD loaders - // that may not enforce next-turn semantics on modules. Even though general - // practice for AMD registration is to be anonymous, underscore registers - // as a named module because, like jQuery, it is a base library that is - // popular enough to be bundled in a third party lib, but not be part of - // an AMD load request. Those cases could generate an error when an - // anonymous define() is called outside of a loader request. - if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function() { - return _; - }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } - }.call(this)); - - -/***/ }, -/* 4 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var React = __webpack_require__(2); - var Reflux = __webpack_require__(5); - - var UtilityMixin = __webpack_require__(28); - var DataMixin = __webpack_require__(29); - var _ = __webpack_require__(3); - - /** - * Datasource - */ - var Datasource = React.createClass({ - displayName: 'Datasource', - - propTypes: { - config: React.PropTypes.shape({ - /** - * Resource Name - */ - name: React.PropTypes.string, - /** - * Resource BasePath - */ - basePath: React.PropTypes.string, - /** - * Resource endpoint - */ - endpoint: React.PropTypes.string, - /** - * Type of store, enum: [shared, unique] - */ - storeType: React.PropTypes.string.isRequired, - /** - * ID attr to query on - */ - idAttr: React.PropTypes.string, - /** - * Determine if the store should populate himself initially - */ - autoPopulate: React.PropTypes.bool - }), - /** - * Initial data - */ - data: React.PropTypes.array - }, - - getDefaultProps: function getDefaultProps() { - return { - autoPopulate: true, - config: { - idAttr: 'id', - storeType: 'unique' - } - }; - }, - - mixins: [Reflux.ListenerMixin, UtilityMixin, DataMixin], - - _reloadCollection: function _reloadCollection(props, state) { - var id = props.objectId; - var _props = this.props; - var onData = _props.onData; - var autoPopulate = _props.autoPopulate; - var dataSource = state.dataSource; - - if (dataSource) { - var data = id ? dataSource.get(id) : dataSource.getCollection(); - if (!data) { - autoPopulate && this._populate(props, state); - } else { - onData && onData(data); - this.setState({ data: data }); - } - } - }, - - componentWillReceiveProps: function componentWillReceiveProps(nextProps) { - var oldName = this.props.config && this.props.config.name; - var newName = nextProps.config && nextProps.config.name; - - if (newName !== oldName) { - this.stopListeningToAll(); - this._prepareDatasource(nextProps.config); - } else if (nextProps.objectId !== this.props.objectId) { - this._reloadCollection(nextProps, this.state); - } - }, - - componentWillUpdate: function componentWillUpdate(nextProps, nextState) { - if (this.state.dataSource != nextState.dataSource) { - this.props.autoPopulate && this._populate(nextProps, nextState); - } else {} - }, - - _populate: function _populate(props, state) { - var dataSource = state.dataSource; - - var object = props.objectId ? { id: props.objectId } : null; - dataSource.listenables.populate(object); - }, - - componentDidMount: function componentDidMount() { - this._prepareDatasource(this.props.config); - this._reloadCollection(this.props, this.state); - // todo instead of id use fkAttr or something - } - }); - - module.exports = Datasource; - - // this._reloadCollection(nextProps, nextState); - -/***/ }, -/* 5 */ -/***/ function(module, exports, __webpack_require__) { - - module.exports = __webpack_require__(6); - - -/***/ }, -/* 6 */ -/***/ function(module, exports, __webpack_require__) { - - exports.ActionMethods = __webpack_require__(8); - - exports.ListenerMethods = __webpack_require__(9); - - exports.PublisherMethods = __webpack_require__(21); - - exports.StoreMethods = __webpack_require__(22); - - exports.createAction = __webpack_require__(23); - - exports.createStore = __webpack_require__(17); - - exports.connect = __webpack_require__(24); - - exports.connectFilter = __webpack_require__(25); - - exports.ListenerMixin = __webpack_require__(26); - - exports.listenTo = __webpack_require__(7); - - exports.listenToMany = __webpack_require__(27); - - - var maker = __webpack_require__(16).staticJoinCreator; - - exports.joinTrailing = exports.all = maker("last"); // Reflux.all alias for backward compatibility - - exports.joinLeading = maker("first"); - - exports.joinStrict = maker("strict"); - - exports.joinConcat = maker("all"); - - var _ = __webpack_require__(10); - - exports.EventEmitter = _.EventEmitter; - - exports.Promise = _.Promise; - - /** - * Convenience function for creating a set of actions - * - * @param definitions the definitions for the actions to be created - * @returns an object with actions of corresponding action names - */ - exports.createActions = function(definitions) { - var actions = {}; - for (var k in definitions){ - if (definitions.hasOwnProperty(k)) { - var val = definitions[k], - actionName = _.isObject(val) ? k : val; - - actions[actionName] = exports.createAction(val); - } - } - return actions; - }; - - /** - * Sets the eventmitter that Reflux uses - */ - exports.setEventEmitter = function(ctx) { - var _ = __webpack_require__(10); - exports.EventEmitter = _.EventEmitter = ctx; - }; - - - /** - * Sets the Promise library that Reflux uses - */ - exports.setPromise = function(ctx) { - var _ = __webpack_require__(10); - exports.Promise = _.Promise = ctx; - }; - - - /** - * Sets the Promise factory that creates new promises - * @param {Function} factory has the signature `function(resolver) { return [new Promise]; }` - */ - exports.setPromiseFactory = function(factory) { - var _ = __webpack_require__(10); - _.createPromise = factory; - }; - - - /** - * Sets the method used for deferring actions and stores - */ - exports.nextTick = function(nextTick) { - var _ = __webpack_require__(10); - _.nextTick = nextTick; - }; - - /** - * Provides the set of created actions and stores for introspection - */ - exports.__keep = __webpack_require__(18); - - /** - * Warn if Function.prototype.bind not available - */ - if (!Function.prototype.bind) { - console.error( - 'Function.prototype.bind not available. ' + - 'ES5 shim required. ' + - 'https://github.com/spoike/refluxjs#es5' - ); - } - - -/***/ }, -/* 7 */ -/***/ function(module, exports, __webpack_require__) { - - var Reflux = __webpack_require__(6); - - - /** - * A mixin factory for a React component. Meant as a more convenient way of using the `ListenerMixin`, - * without having to manually set listeners in the `componentDidMount` method. - * - * @param {Action|Store} listenable An Action or Store that should be - * listened to. - * @param {Function|String} callback The callback to register as event handler - * @param {Function|String} defaultCallback The callback to register as default handler - * @returns {Object} An object to be used as a mixin, which sets up the listener for the given listenable. - */ - module.exports = function(listenable,callback,initial){ - return { - /** - * Set up the mixin before the initial rendering occurs. Import methods from `ListenerMethods` - * and then make the call to `listenTo` with the arguments provided to the factory function - */ - componentDidMount: function() { - for(var m in Reflux.ListenerMethods){ - if (this[m] !== Reflux.ListenerMethods[m]){ - if (this[m]){ - throw "Can't have other property '"+m+"' when using Reflux.listenTo!"; - } - this[m] = Reflux.ListenerMethods[m]; - } - } - this.listenTo(listenable,callback,initial); - }, - /** - * Cleans up all listener previously registered. - */ - componentWillUnmount: Reflux.ListenerMethods.stopListeningToAll - }; - }; - - -/***/ }, -/* 8 */ -/***/ function(module, exports) { - - /** - * A module of methods that you want to include in all actions. - * This module is consumed by `createAction`. - */ - module.exports = { - }; - - -/***/ }, -/* 9 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(10), - maker = __webpack_require__(16).instanceJoinCreator; - - /** - * Extract child listenables from a parent from their - * children property and return them in a keyed Object - * - * @param {Object} listenable The parent listenable - */ - var mapChildListenables = function(listenable) { - var i = 0, children = {}, childName; - for (;i < (listenable.children||[]).length; ++i) { - childName = listenable.children[i]; - if(listenable[childName]){ - children[childName] = listenable[childName]; - } - } - return children; - }; - - /** - * Make a flat dictionary of all listenables including their - * possible children (recursively), concatenating names in camelCase. - * - * @param {Object} listenables The top-level listenables - */ - var flattenListenables = function(listenables) { - var flattened = {}; - for(var key in listenables){ - var listenable = listenables[key]; - var childMap = mapChildListenables(listenable); - - // recursively flatten children - var children = flattenListenables(childMap); - - // add the primary listenable and chilren - flattened[key] = listenable; - for(var childKey in children){ - var childListenable = children[childKey]; - flattened[key + _.capitalize(childKey)] = childListenable; - } - } - - return flattened; - }; - - /** - * A module of methods related to listening. - */ - module.exports = { - - /** - * An internal utility function used by `validateListening` - * - * @param {Action|Store} listenable The listenable we want to search for - * @returns {Boolean} The result of a recursive search among `this.subscriptions` - */ - hasListener: function(listenable) { - var i = 0, j, listener, listenables; - for (;i < (this.subscriptions||[]).length; ++i) { - listenables = [].concat(this.subscriptions[i].listenable); - for (j = 0; j < listenables.length; j++){ - listener = listenables[j]; - if (listener === listenable || listener.hasListener && listener.hasListener(listenable)) { - return true; - } - } - } - return false; - }, - - /** - * A convenience method that listens to all listenables in the given object. - * - * @param {Object} listenables An object of listenables. Keys will be used as callback method names. - */ - listenToMany: function(listenables){ - var allListenables = flattenListenables(listenables); - for(var key in allListenables){ - var cbname = _.callbackName(key), - localname = this[cbname] ? cbname : this[key] ? key : undefined; - if (localname){ - this.listenTo(allListenables[key],localname,this[cbname+"Default"]||this[localname+"Default"]||localname); - } - } - }, - - /** - * Checks if the current context can listen to the supplied listenable - * - * @param {Action|Store} listenable An Action or Store that should be - * listened to. - * @returns {String|Undefined} An error message, or undefined if there was no problem. - */ - validateListening: function(listenable){ - if (listenable === this) { - return "Listener is not able to listen to itself"; - } - if (!_.isFunction(listenable.listen)) { - return listenable + " is missing a listen method"; - } - if (listenable.hasListener && listenable.hasListener(this)) { - return "Listener cannot listen to this listenable because of circular loop"; - } - }, - - /** - * Sets up a subscription to the given listenable for the context object - * - * @param {Action|Store} listenable An Action or Store that should be - * listened to. - * @param {Function|String} callback The callback to register as event handler - * @param {Function|String} defaultCallback The callback to register as default handler - * @returns {Object} A subscription obj where `stop` is an unsub function and `listenable` is the object being listened to - */ - listenTo: function(listenable, callback, defaultCallback) { - var desub, unsubscriber, subscriptionobj, subs = this.subscriptions = this.subscriptions || []; - _.throwIf(this.validateListening(listenable)); - this.fetchInitialState(listenable, defaultCallback); - desub = listenable.listen(this[callback]||callback, this); - unsubscriber = function() { - var index = subs.indexOf(subscriptionobj); - _.throwIf(index === -1,'Tried to remove listen already gone from subscriptions list!'); - subs.splice(index, 1); - desub(); - }; - subscriptionobj = { - stop: unsubscriber, - listenable: listenable - }; - subs.push(subscriptionobj); - return subscriptionobj; - }, - - /** - * Stops listening to a single listenable - * - * @param {Action|Store} listenable The action or store we no longer want to listen to - * @returns {Boolean} True if a subscription was found and removed, otherwise false. - */ - stopListeningTo: function(listenable){ - var sub, i = 0, subs = this.subscriptions || []; - for(;i < subs.length; i++){ - sub = subs[i]; - if (sub.listenable === listenable){ - sub.stop(); - _.throwIf(subs.indexOf(sub)!==-1,'Failed to remove listen from subscriptions list!'); - return true; - } - } - return false; - }, - - /** - * Stops all subscriptions and empties subscriptions array - */ - stopListeningToAll: function(){ - var remaining, subs = this.subscriptions || []; - while((remaining=subs.length)){ - subs[0].stop(); - _.throwIf(subs.length!==remaining-1,'Failed to remove listen from subscriptions list!'); - } - }, - - /** - * Used in `listenTo`. Fetches initial data from a publisher if it has a `getInitialState` method. - * @param {Action|Store} listenable The publisher we want to get initial state from - * @param {Function|String} defaultCallback The method to receive the data - */ - fetchInitialState: function (listenable, defaultCallback) { - defaultCallback = (defaultCallback && this[defaultCallback]) || defaultCallback; - var me = this; - if (_.isFunction(defaultCallback) && _.isFunction(listenable.getInitialState)) { - var data = listenable.getInitialState(); - if (data && _.isFunction(data.then)) { - data.then(function() { - defaultCallback.apply(me, arguments); - }); - } else { - defaultCallback.call(this, data); - } - } - }, - - /** - * The callback will be called once all listenables have triggered at least once. - * It will be invoked with the last emission from each listenable. - * @param {...Publishers} publishers Publishers that should be tracked. - * @param {Function|String} callback The method to call when all publishers have emitted - * @returns {Object} A subscription obj where `stop` is an unsub function and `listenable` is an array of listenables - */ - joinTrailing: maker("last"), - - /** - * The callback will be called once all listenables have triggered at least once. - * It will be invoked with the first emission from each listenable. - * @param {...Publishers} publishers Publishers that should be tracked. - * @param {Function|String} callback The method to call when all publishers have emitted - * @returns {Object} A subscription obj where `stop` is an unsub function and `listenable` is an array of listenables - */ - joinLeading: maker("first"), - - /** - * The callback will be called once all listenables have triggered at least once. - * It will be invoked with all emission from each listenable. - * @param {...Publishers} publishers Publishers that should be tracked. - * @param {Function|String} callback The method to call when all publishers have emitted - * @returns {Object} A subscription obj where `stop` is an unsub function and `listenable` is an array of listenables - */ - joinConcat: maker("all"), - - /** - * The callback will be called once all listenables have triggered. - * If a callback triggers twice before that happens, an error is thrown. - * @param {...Publishers} publishers Publishers that should be tracked. - * @param {Function|String} callback The method to call when all publishers have emitted - * @returns {Object} A subscription obj where `stop` is an unsub function and `listenable` is an array of listenables - */ - joinStrict: maker("strict") - }; - - -/***/ }, -/* 10 */ -/***/ function(module, exports, __webpack_require__) { - - /* - * isObject, extend, isFunction, isArguments are taken from undescore/lodash in - * order to remove the dependency - */ - var isObject = exports.isObject = function(obj) { - var type = typeof obj; - return type === 'function' || type === 'object' && !!obj; - }; - - exports.extend = function(obj) { - if (!isObject(obj)) { - return obj; - } - var source, prop; - for (var i = 1, length = arguments.length; i < length; i++) { - source = arguments[i]; - for (prop in source) { - if (Object.getOwnPropertyDescriptor && Object.defineProperty) { - var propertyDescriptor = Object.getOwnPropertyDescriptor(source, prop); - Object.defineProperty(obj, prop, propertyDescriptor); - } else { - obj[prop] = source[prop]; - } - } - } - return obj; - }; - - exports.isFunction = function(value) { - return typeof value === 'function'; - }; - - exports.EventEmitter = __webpack_require__(11); - - exports.nextTick = function(callback) { - setTimeout(callback, 0); - }; - - exports.capitalize = function(string){ - return string.charAt(0).toUpperCase()+string.slice(1); - }; - - exports.callbackName = function(string){ - return "on"+exports.capitalize(string); - }; - - exports.object = function(keys,vals){ - var o={}, i=0; - for(;i < keys.length; i++){ - o[keys[i]] = vals[i]; - } - return o; - }; - - exports.Promise = __webpack_require__(12); - - exports.createPromise = function(resolver) { - return new exports.Promise(resolver); - }; - - exports.isArguments = function(value) { - return typeof value === 'object' && ('callee' in value) && typeof value.length === 'number'; - }; - - exports.throwIf = function(val,msg){ - if (val){ - throw Error(msg||val); - } - }; - - -/***/ }, -/* 11 */ -/***/ function(module, exports) { - - 'use strict'; - - /** - * Representation of a single EventEmitter function. - * - * @param {Function} fn Event handler to be called. - * @param {Mixed} context Context for function execution. - * @param {Boolean} once Only emit once - * @api private - */ - function EE(fn, context, once) { - this.fn = fn; - this.context = context; - this.once = once || false; - } - - /** - * Minimal EventEmitter interface that is molded against the Node.js - * EventEmitter interface. - * - * @constructor - * @api public - */ - function EventEmitter() { /* Nothing to set */ } - - /** - * Holds the assigned EventEmitters by name. - * - * @type {Object} - * @private - */ - EventEmitter.prototype._events = undefined; - - /** - * Return a list of assigned event listeners. - * - * @param {String} event The events that should be listed. - * @returns {Array} - * @api public - */ - EventEmitter.prototype.listeners = function listeners(event) { - if (!this._events || !this._events[event]) return []; - if (this._events[event].fn) return [this._events[event].fn]; - - for (var i = 0, l = this._events[event].length, ee = new Array(l); i < l; i++) { - ee[i] = this._events[event][i].fn; - } - - return ee; - }; - - /** - * Emit an event to all registered event listeners. - * - * @param {String} event The name of the event. - * @returns {Boolean} Indication if we've emitted an event. - * @api public - */ - EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) { - if (!this._events || !this._events[event]) return false; - - var listeners = this._events[event] - , len = arguments.length - , args - , i; - - if ('function' === typeof listeners.fn) { - if (listeners.once) this.removeListener(event, listeners.fn, true); - - switch (len) { - case 1: return listeners.fn.call(listeners.context), true; - case 2: return listeners.fn.call(listeners.context, a1), true; - case 3: return listeners.fn.call(listeners.context, a1, a2), true; - case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true; - case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true; - case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true; - } - - for (i = 1, args = new Array(len -1); i < len; i++) { - args[i - 1] = arguments[i]; - } - - listeners.fn.apply(listeners.context, args); - } else { - var length = listeners.length - , j; - - for (i = 0; i < length; i++) { - if (listeners[i].once) this.removeListener(event, listeners[i].fn, true); - - switch (len) { - case 1: listeners[i].fn.call(listeners[i].context); break; - case 2: listeners[i].fn.call(listeners[i].context, a1); break; - case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break; - default: - if (!args) for (j = 1, args = new Array(len -1); j < len; j++) { - args[j - 1] = arguments[j]; - } - - listeners[i].fn.apply(listeners[i].context, args); - } - } - } - - return true; - }; - - /** - * Register a new EventListener for the given event. - * - * @param {String} event Name of the event. - * @param {Functon} fn Callback function. - * @param {Mixed} context The context of the function. - * @api public - */ - EventEmitter.prototype.on = function on(event, fn, context) { - var listener = new EE(fn, context || this); - - if (!this._events) this._events = {}; - if (!this._events[event]) this._events[event] = listener; - else { - if (!this._events[event].fn) this._events[event].push(listener); - else this._events[event] = [ - this._events[event], listener - ]; - } - - return this; - }; - - /** - * Add an EventListener that's only called once. - * - * @param {String} event Name of the event. - * @param {Function} fn Callback function. - * @param {Mixed} context The context of the function. - * @api public - */ - EventEmitter.prototype.once = function once(event, fn, context) { - var listener = new EE(fn, context || this, true); - - if (!this._events) this._events = {}; - if (!this._events[event]) this._events[event] = listener; - else { - if (!this._events[event].fn) this._events[event].push(listener); - else this._events[event] = [ - this._events[event], listener - ]; - } - - return this; - }; - - /** - * Remove event listeners. - * - * @param {String} event The event we want to remove. - * @param {Function} fn The listener that we need to find. - * @param {Boolean} once Only remove once listeners. - * @api public - */ - EventEmitter.prototype.removeListener = function removeListener(event, fn, once) { - if (!this._events || !this._events[event]) return this; - - var listeners = this._events[event] - , events = []; - - if (fn) { - if (listeners.fn && (listeners.fn !== fn || (once && !listeners.once))) { - events.push(listeners); - } - if (!listeners.fn) for (var i = 0, length = listeners.length; i < length; i++) { - if (listeners[i].fn !== fn || (once && !listeners[i].once)) { - events.push(listeners[i]); - } - } - } - - // - // Reset the array, or remove it completely if we have no more listeners. - // - if (events.length) { - this._events[event] = events.length === 1 ? events[0] : events; - } else { - delete this._events[event]; - } - - return this; - }; - - /** - * Remove all listeners or only the listeners for the specified event. - * - * @param {String} event The event want to remove all listeners for. - * @api public - */ - EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) { - if (!this._events) return this; - - if (event) delete this._events[event]; - else this._events = {}; - - return this; - }; - - // - // Alias methods names because people roll like that. - // - EventEmitter.prototype.off = EventEmitter.prototype.removeListener; - EventEmitter.prototype.addListener = EventEmitter.prototype.on; - - // - // This function doesn't apply anymore. - // - EventEmitter.prototype.setMaxListeners = function setMaxListeners() { - return this; - }; - - // - // Expose the module. - // - EventEmitter.EventEmitter = EventEmitter; - EventEmitter.EventEmitter2 = EventEmitter; - EventEmitter.EventEmitter3 = EventEmitter; - - // - // Expose the module. - // - module.exports = EventEmitter; - - -/***/ }, -/* 12 */ -/***/ function(module, exports, __webpack_require__) { - - var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(global, setImmediate) {/*! Native Promise Only +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("react")):"function"==typeof define&&define.amd?define(["react"],e):"object"==typeof exports?exports.ReactDataloader=e(require("react")):t.ReactDataloader=e(t.React)}(this,function(__WEBPACK_EXTERNAL_MODULE_2__){return function(t){function e(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return t[r].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict";var r=n(4),i=(n(44),n(45)),o=n(46),s=n(1),a=n(47),u=n(30),c=n(34);t.exports={FilteredDatasource:o,Datasource:r,BasicDatasource:i,Collection:s,ObjectTest:a,DSManager:u,uuid:c}},function(t,e,n){"use strict";var r=n(2),i=n(3),o=r.createClass({displayName:"Collection",propTypes:{data:r.PropTypes.array.isRequired},getDefaultProps:function(){return{data:[]}},render:function(){var t,e=this;return t=this.props.data?Object.keys(this.props.data[0]||{}):[],r.createElement("section",null,r.createElement("table",{className:"item-list"},r.createElement(a,{keys:t}),r.createElement("tbody",null,i.isArray(this.props.data)&&this.props.data.map(function(t,n){return r.createElement(s,{object:t,key:t.id||n,onClick:e.props.handleSelect})}))))}}),s=r.createClass({displayName:"TableRow",propTypes:{object:r.PropTypes.object},render:function(){var t=this,e=this.props.onClick&&this.props.onClick.bind(null,this.props.object.id)||function(){};return r.createElement("tr",{onClick:e},Object.keys(this.props.object).map(function(e){return r.createElement("td",{key:e},JSON.stringify(t.props.object[e]))}))}}),a=r.createClass({displayName:"TableHeader",propTypes:{keys:r.PropTypes.array},render:function(){return r.createElement("thead",null,this.props.keys.map(function(t,e){return r.createElement("th",{key:e},t)}))}});t.exports=o},function(t,e){t.exports=__WEBPACK_EXTERNAL_MODULE_2__},function(t,e,n){var r,i;(function(){function n(t){function e(e,n,r,i,o,s){for(;o>=0&&s>o;o+=t){var a=i?i[o]:o;r=n(r,e[a],a,e)}return r}return function(n,r,i,o){r=S(r,o,4);var s=!D(n)&&x.keys(n),a=(s||n).length,u=t>0?0:a-1;return arguments.length<3&&(i=n[s?s[u]:u],u+=t),e(n,r,i,s,u,a)}}function o(t){return function(e,n,r){n=I(n,r);for(var i=A(e),o=t>0?0:i-1;o>=0&&i>o;o+=t)if(n(e[o],o,e))return o;return-1}}function s(t,e,n){return function(r,i,o){var s=0,a=A(r);if("number"==typeof o)t>0?s=o>=0?o:Math.max(o+a,s):a=o>=0?Math.min(o+1,a):o+a+1;else if(n&&o&&a)return o=n(r,i),r[o]===i?o:-1;if(i!==i)return o=e(d.call(r,s,a),x.isNaN),o>=0?o+s:-1;for(o=t>0?s:a-1;o>=0&&a>o;o+=t)if(r[o]===i)return o;return-1}}function a(t,e){var n=q.length,r=t.constructor,i=x.isFunction(r)&&r.prototype||l,o="constructor";for(x.has(t,o)&&!x.contains(e,o)&&e.push(o);n--;)o=q[n],o in t&&t[o]!==i[o]&&!x.contains(e,o)&&e.push(o)}var u=this,c=u._,h=Array.prototype,l=Object.prototype,f=Function.prototype,p=h.push,d=h.slice,y=l.toString,v=l.hasOwnProperty,g=Array.isArray,m=Object.keys,_=f.bind,w=Object.create,b=function(){},x=function(t){return t instanceof x?t:this instanceof x?void(this._wrapped=t):new x(t)};"undefined"!=typeof t&&t.exports&&(e=t.exports=x),e._=x,x.VERSION="1.8.3";var S=function(t,e,n){if(void 0===e)return t;switch(null==n?3:n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,i){return t.call(e,n,r,i)};case 4:return function(n,r,i,o){return t.call(e,n,r,i,o)}}return function(){return t.apply(e,arguments)}},I=function(t,e,n){return null==t?x.identity:x.isFunction(t)?S(t,e,n):x.isObject(t)?x.matcher(t):x.property(t)};x.iteratee=function(t,e){return I(t,e,1/0)};var k=function(t,e){return function(n){var r=arguments.length;if(2>r||null==n)return n;for(var i=1;r>i;i++)for(var o=arguments[i],s=t(o),a=s.length,u=0;a>u;u++){var c=s[u];e&&void 0!==n[c]||(n[c]=o[c])}return n}},E=function(t){if(!x.isObject(t))return{};if(w)return w(t);b.prototype=t;var e=new b;return b.prototype=null,e},j=function(t){return function(e){return null==e?void 0:e[t]}},O=Math.pow(2,53)-1,A=j("length"),D=function(t){var e=A(t);return"number"==typeof e&&e>=0&&O>=e};x.each=x.forEach=function(t,e,n){e=S(e,n);var r,i;if(D(t))for(r=0,i=t.length;i>r;r++)e(t[r],r,t);else{var o=x.keys(t);for(r=0,i=o.length;i>r;r++)e(t[o[r]],o[r],t)}return t},x.map=x.collect=function(t,e,n){e=I(e,n);for(var r=!D(t)&&x.keys(t),i=(r||t).length,o=Array(i),s=0;i>s;s++){var a=r?r[s]:s;o[s]=e(t[a],a,t)}return o},x.reduce=x.foldl=x.inject=n(1),x.reduceRight=x.foldr=n(-1),x.find=x.detect=function(t,e,n){var r;return r=D(t)?x.findIndex(t,e,n):x.findKey(t,e,n),void 0!==r&&-1!==r?t[r]:void 0},x.filter=x.select=function(t,e,n){var r=[];return e=I(e,n),x.each(t,function(t,n,i){e(t,n,i)&&r.push(t)}),r},x.reject=function(t,e,n){return x.filter(t,x.negate(I(e)),n)},x.every=x.all=function(t,e,n){e=I(e,n);for(var r=!D(t)&&x.keys(t),i=(r||t).length,o=0;i>o;o++){var s=r?r[o]:o;if(!e(t[s],s,t))return!1}return!0},x.some=x.any=function(t,e,n){e=I(e,n);for(var r=!D(t)&&x.keys(t),i=(r||t).length,o=0;i>o;o++){var s=r?r[o]:o;if(e(t[s],s,t))return!0}return!1},x.contains=x.includes=x.include=function(t,e,n,r){return D(t)||(t=x.values(t)),("number"!=typeof n||r)&&(n=0),x.indexOf(t,e,n)>=0},x.invoke=function(t,e){var n=d.call(arguments,2),r=x.isFunction(e);return x.map(t,function(t){var i=r?e:t[e];return null==i?i:i.apply(t,n)})},x.pluck=function(t,e){return x.map(t,x.property(e))},x.where=function(t,e){return x.filter(t,x.matcher(e))},x.findWhere=function(t,e){return x.find(t,x.matcher(e))},x.max=function(t,e,n){var r,i,o=-(1/0),s=-(1/0);if(null==e&&null!=t){t=D(t)?t:x.values(t);for(var a=0,u=t.length;u>a;a++)r=t[a],r>o&&(o=r)}else e=I(e,n),x.each(t,function(t,n,r){i=e(t,n,r),(i>s||i===-(1/0)&&o===-(1/0))&&(o=t,s=i)});return o},x.min=function(t,e,n){var r,i,o=1/0,s=1/0;if(null==e&&null!=t){t=D(t)?t:x.values(t);for(var a=0,u=t.length;u>a;a++)r=t[a],o>r&&(o=r)}else e=I(e,n),x.each(t,function(t,n,r){i=e(t,n,r),(s>i||i===1/0&&o===1/0)&&(o=t,s=i)});return o},x.shuffle=function(t){for(var e,n=D(t)?t:x.values(t),r=n.length,i=Array(r),o=0;r>o;o++)e=x.random(0,o),e!==o&&(i[o]=i[e]),i[e]=n[o];return i},x.sample=function(t,e,n){return null==e||n?(D(t)||(t=x.values(t)),t[x.random(t.length-1)]):x.shuffle(t).slice(0,Math.max(0,e))},x.sortBy=function(t,e,n){return e=I(e,n),x.pluck(x.map(t,function(t,n,r){return{value:t,index:n,criteria:e(t,n,r)}}).sort(function(t,e){var n=t.criteria,r=e.criteria;if(n!==r){if(n>r||void 0===n)return 1;if(r>n||void 0===r)return-1}return t.index-e.index}),"value")};var P=function(t){return function(e,n,r){var i={};return n=I(n,r),x.each(e,function(r,o){var s=n(r,o,e);t(i,r,s)}),i}};x.groupBy=P(function(t,e,n){x.has(t,n)?t[n].push(e):t[n]=[e]}),x.indexBy=P(function(t,e,n){t[n]=e}),x.countBy=P(function(t,e,n){x.has(t,n)?t[n]++:t[n]=1}),x.toArray=function(t){return t?x.isArray(t)?d.call(t):D(t)?x.map(t,x.identity):x.values(t):[]},x.size=function(t){return null==t?0:D(t)?t.length:x.keys(t).length},x.partition=function(t,e,n){e=I(e,n);var r=[],i=[];return x.each(t,function(t,n,o){(e(t,n,o)?r:i).push(t)}),[r,i]},x.first=x.head=x.take=function(t,e,n){return null==t?void 0:null==e||n?t[0]:x.initial(t,t.length-e)},x.initial=function(t,e,n){return d.call(t,0,Math.max(0,t.length-(null==e||n?1:e)))},x.last=function(t,e,n){return null==t?void 0:null==e||n?t[t.length-1]:x.rest(t,Math.max(0,t.length-e))},x.rest=x.tail=x.drop=function(t,e,n){return d.call(t,null==e||n?1:e)},x.compact=function(t){return x.filter(t,x.identity)};var T=function(t,e,n,r){for(var i=[],o=0,s=r||0,a=A(t);a>s;s++){var u=t[s];if(D(u)&&(x.isArray(u)||x.isArguments(u))){e||(u=T(u,e,n));var c=0,h=u.length;for(i.length+=h;h>c;)i[o++]=u[c++]}else n||(i[o++]=u)}return i};x.flatten=function(t,e){return T(t,e,!1)},x.without=function(t){return x.difference(t,d.call(arguments,1))},x.uniq=x.unique=function(t,e,n,r){x.isBoolean(e)||(r=n,n=e,e=!1),null!=n&&(n=I(n,r));for(var i=[],o=[],s=0,a=A(t);a>s;s++){var u=t[s],c=n?n(u,s,t):u;e?(s&&o===c||i.push(u),o=c):n?x.contains(o,c)||(o.push(c),i.push(u)):x.contains(i,u)||i.push(u)}return i},x.union=function(){return x.uniq(T(arguments,!0,!0))},x.intersection=function(t){for(var e=[],n=arguments.length,r=0,i=A(t);i>r;r++){var o=t[r];if(!x.contains(e,o)){for(var s=1;n>s&&x.contains(arguments[s],o);s++);s===n&&e.push(o)}}return e},x.difference=function(t){var e=T(arguments,!0,!0,1);return x.filter(t,function(t){return!x.contains(e,t)})},x.zip=function(){return x.unzip(arguments)},x.unzip=function(t){for(var e=t&&x.max(t,A).length||0,n=Array(e),r=0;e>r;r++)n[r]=x.pluck(t,r);return n},x.object=function(t,e){for(var n={},r=0,i=A(t);i>r;r++)e?n[t[r]]=e[r]:n[t[r][0]]=t[r][1];return n},x.findIndex=o(1),x.findLastIndex=o(-1),x.sortedIndex=function(t,e,n,r){n=I(n,r,1);for(var i=n(e),o=0,s=A(t);s>o;){var a=Math.floor((o+s)/2);n(t[a])o;o++,t+=n)i[o]=t;return i};var C=function(t,e,n,r,i){if(!(r instanceof e))return t.apply(n,i);var o=E(t.prototype),s=t.apply(o,i);return x.isObject(s)?s:o};x.bind=function(t,e){if(_&&t.bind===_)return _.apply(t,d.call(arguments,1));if(!x.isFunction(t))throw new TypeError("Bind must be called on a function");var n=d.call(arguments,2),r=function(){return C(t,r,e,this,n.concat(d.call(arguments)))};return r},x.partial=function(t){var e=d.call(arguments,1),n=function(){for(var r=0,i=e.length,o=Array(i),s=0;i>s;s++)o[s]=e[s]===x?arguments[r++]:e[s];for(;r=r)throw new Error("bindAll must be passed function names");for(e=1;r>e;e++)n=arguments[e],t[n]=x.bind(t[n],t);return t},x.memoize=function(t,e){var n=function(r){var i=n.cache,o=""+(e?e.apply(this,arguments):r);return x.has(i,o)||(i[o]=t.apply(this,arguments)),i[o]};return n.cache={},n},x.delay=function(t,e){var n=d.call(arguments,2);return setTimeout(function(){return t.apply(null,n)},e)},x.defer=x.partial(x.delay,x,1),x.throttle=function(t,e,n){var r,i,o,s=null,a=0;n||(n={});var u=function(){a=n.leading===!1?0:x.now(),s=null,o=t.apply(r,i),s||(r=i=null)};return function(){var c=x.now();a||n.leading!==!1||(a=c);var h=e-(c-a);return r=this,i=arguments,0>=h||h>e?(s&&(clearTimeout(s),s=null),a=c,o=t.apply(r,i),s||(r=i=null)):s||n.trailing===!1||(s=setTimeout(u,h)),o}},x.debounce=function(t,e,n){var r,i,o,s,a,u=function(){var c=x.now()-s;e>c&&c>=0?r=setTimeout(u,e-c):(r=null,n||(a=t.apply(o,i),r||(o=i=null)))};return function(){o=this,i=arguments,s=x.now();var c=n&&!r;return r||(r=setTimeout(u,e)),c&&(a=t.apply(o,i),o=i=null),a}},x.wrap=function(t,e){return x.partial(e,t)},x.negate=function(t){return function(){return!t.apply(this,arguments)}},x.compose=function(){var t=arguments,e=t.length-1;return function(){for(var n=e,r=t[e].apply(this,arguments);n--;)r=t[n].call(this,r);return r}},x.after=function(t,e){return function(){return--t<1?e.apply(this,arguments):void 0}},x.before=function(t,e){var n;return function(){return--t>0&&(n=e.apply(this,arguments)),1>=t&&(e=null),n}},x.once=x.partial(x.before,2);var z=!{toString:null}.propertyIsEnumerable("toString"),q=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"];x.keys=function(t){if(!x.isObject(t))return[];if(m)return m(t);var e=[];for(var n in t)x.has(t,n)&&e.push(n);return z&&a(t,e),e},x.allKeys=function(t){if(!x.isObject(t))return[];var e=[];for(var n in t)e.push(n);return z&&a(t,e),e},x.values=function(t){for(var e=x.keys(t),n=e.length,r=Array(n),i=0;n>i;i++)r[i]=t[e[i]];return r},x.mapObject=function(t,e,n){e=I(e,n);for(var r,i=x.keys(t),o=i.length,s={},a=0;o>a;a++)r=i[a],s[r]=e(t[r],r,t);return s},x.pairs=function(t){for(var e=x.keys(t),n=e.length,r=Array(n),i=0;n>i;i++)r[i]=[e[i],t[e[i]]];return r},x.invert=function(t){for(var e={},n=x.keys(t),r=0,i=n.length;i>r;r++)e[t[n[r]]]=n[r];return e},x.functions=x.methods=function(t){var e=[];for(var n in t)x.isFunction(t[n])&&e.push(n);return e.sort()},x.extend=k(x.allKeys),x.extendOwn=x.assign=k(x.keys),x.findKey=function(t,e,n){e=I(e,n);for(var r,i=x.keys(t),o=0,s=i.length;s>o;o++)if(r=i[o],e(t[r],r,t))return r},x.pick=function(t,e,n){var r,i,o={},s=t;if(null==s)return o;x.isFunction(e)?(i=x.allKeys(s),r=S(e,n)):(i=T(arguments,!1,!1,1),r=function(t,e,n){return e in n},s=Object(s));for(var a=0,u=i.length;u>a;a++){var c=i[a],h=s[c];r(h,c,s)&&(o[c]=h)}return o},x.omit=function(t,e,n){if(x.isFunction(e))e=x.negate(e);else{var r=x.map(T(arguments,!1,!1,1),String);e=function(t,e){return!x.contains(r,e)}}return x.pick(t,e,n)},x.defaults=k(x.allKeys,!0),x.create=function(t,e){var n=E(t);return e&&x.extendOwn(n,e),n},x.clone=function(t){return x.isObject(t)?x.isArray(t)?t.slice():x.extend({},t):t},x.tap=function(t,e){return e(t),t},x.isMatch=function(t,e){var n=x.keys(e),r=n.length;if(null==t)return!r;for(var i=Object(t),o=0;r>o;o++){var s=n[o];if(e[s]!==i[s]||!(s in i))return!1}return!0};var M=function(t,e,n,r){if(t===e)return 0!==t||1/t===1/e;if(null==t||null==e)return t===e;t instanceof x&&(t=t._wrapped),e instanceof x&&(e=e._wrapped);var i=y.call(t);if(i!==y.call(e))return!1;switch(i){case"[object RegExp]":case"[object String]":return""+t==""+e;case"[object Number]":return+t!==+t?+e!==+e:0===+t?1/+t===1/e:+t===+e;case"[object Date]":case"[object Boolean]":return+t===+e}var o="[object Array]"===i;if(!o){if("object"!=typeof t||"object"!=typeof e)return!1;var s=t.constructor,a=e.constructor;if(s!==a&&!(x.isFunction(s)&&s instanceof s&&x.isFunction(a)&&a instanceof a)&&"constructor"in t&&"constructor"in e)return!1}n=n||[],r=r||[];for(var u=n.length;u--;)if(n[u]===t)return r[u]===e;if(n.push(t),r.push(e),o){if(u=t.length,u!==e.length)return!1;for(;u--;)if(!M(t[u],e[u],n,r))return!1}else{var c,h=x.keys(t);if(u=h.length,x.keys(e).length!==u)return!1;for(;u--;)if(c=h[u],!x.has(e,c)||!M(t[c],e[c],n,r))return!1}return n.pop(),r.pop(),!0};x.isEqual=function(t,e){return M(t,e)},x.isEmpty=function(t){return null==t?!0:D(t)&&(x.isArray(t)||x.isString(t)||x.isArguments(t))?0===t.length:0===x.keys(t).length},x.isElement=function(t){return!(!t||1!==t.nodeType)},x.isArray=g||function(t){return"[object Array]"===y.call(t)},x.isObject=function(t){var e=typeof t;return"function"===e||"object"===e&&!!t},x.each(["Arguments","Function","String","Number","Date","RegExp","Error"],function(t){x["is"+t]=function(e){return y.call(e)==="[object "+t+"]"}}),x.isArguments(arguments)||(x.isArguments=function(t){return x.has(t,"callee")}),"function"!=typeof/./&&"object"!=typeof Int8Array&&(x.isFunction=function(t){return"function"==typeof t||!1}),x.isFinite=function(t){return isFinite(t)&&!isNaN(parseFloat(t))},x.isNaN=function(t){return x.isNumber(t)&&t!==+t},x.isBoolean=function(t){return t===!0||t===!1||"[object Boolean]"===y.call(t)},x.isNull=function(t){return null===t},x.isUndefined=function(t){return void 0===t},x.has=function(t,e){return null!=t&&v.call(t,e)},x.noConflict=function(){return u._=c,this},x.identity=function(t){return t},x.constant=function(t){return function(){return t}},x.noop=function(){},x.property=j,x.propertyOf=function(t){return null==t?function(){}:function(e){return t[e]}},x.matcher=x.matches=function(t){return t=x.extendOwn({},t),function(e){return x.isMatch(e,t)}},x.times=function(t,e,n){var r=Array(Math.max(0,t));e=S(e,n,1);for(var i=0;t>i;i++)r[i]=e(i);return r},x.random=function(t,e){return null==e&&(e=t,t=0),t+Math.floor(Math.random()*(e-t+1))},x.now=Date.now||function(){return(new Date).getTime()};var R={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},L=x.invert(R),N=function(t){var e=function(e){return t[e]},n="(?:"+x.keys(t).join("|")+")",r=RegExp(n),i=RegExp(n,"g");return function(t){return t=null==t?"":""+t,r.test(t)?t.replace(i,e):t}};x.escape=N(R),x.unescape=N(L),x.result=function(t,e,n){var r=null==t?void 0:t[e];return void 0===r&&(r=n),x.isFunction(r)?r.call(t):r};var V=0;x.uniqueId=function(t){var e=++V+"";return t?t+e:e},x.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var F=/(.)^/,U={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},$=/\\|'|\r|\n|\u2028|\u2029/g,B=function(t){return"\\"+U[t]};x.template=function(t,e,n){!e&&n&&(e=n),e=x.defaults({},e,x.templateSettings);var r=RegExp([(e.escape||F).source,(e.interpolate||F).source,(e.evaluate||F).source].join("|")+"|$","g"),i=0,o="__p+='";t.replace(r,function(e,n,r,s,a){return o+=t.slice(i,a).replace($,B),i=a+e.length,n?o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'":r?o+="'+\n((__t=("+r+"))==null?'':__t)+\n'":s&&(o+="';\n"+s+"\n__p+='"),e}),o+="';\n",e.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{var s=new Function(e.variable||"obj","_",o)}catch(a){throw a.source=o,a}var u=function(t){return s.call(this,t,x)},c=e.variable||"obj";return u.source="function("+c+"){\n"+o+"}",u},x.chain=function(t){var e=x(t);return e._chain=!0,e};var W=function(t,e){return t._chain?x(e).chain():e};x.mixin=function(t){x.each(x.functions(t),function(e){var n=x[e]=t[e];x.prototype[e]=function(){var t=[this._wrapped];return p.apply(t,arguments),W(this,n.apply(x,t))}})},x.mixin(x),x.each(["pop","push","reverse","shift","sort","splice","unshift"],function(t){var e=h[t];x.prototype[t]=function(){var n=this._wrapped;return e.apply(n,arguments),"shift"!==t&&"splice"!==t||0!==n.length||delete n[0],W(this,n)}}),x.each(["concat","join","slice"],function(t){var e=h[t];x.prototype[t]=function(){return W(this,e.apply(this._wrapped,arguments))}}),x.prototype.value=function(){return this._wrapped},x.prototype.valueOf=x.prototype.toJSON=x.prototype.value,x.prototype.toString=function(){return""+this._wrapped},r=[],i=function(){return x}.apply(e,r),!(void 0!==i&&(t.exports=i))}).call(this)},function(t,e,n){"use strict";var r=n(2),i=n(5),o=n(28),s=n(29),a=(n(3),r.createClass({displayName:"Datasource",propTypes:{config:r.PropTypes.shape({name:r.PropTypes.string,basePath:r.PropTypes.string,endpoint:r.PropTypes.string,storeType:r.PropTypes.string.isRequired,idAttr:r.PropTypes.string,autoPopulate:r.PropTypes.bool}),data:r.PropTypes.array},getDefaultProps:function(){return{autoPopulate:!0,config:{idAttr:"id",storeType:"unique"}}},mixins:[i.ListenerMixin,o,s],_reloadCollection:function(t,e){var n=t.objectId,r=this.props,i=r.onData,o=r.autoPopulate,s=e.dataSource;if(s){var a=n?s.get(n):s.getCollection();a?(i&&i(a),this.setState({data:a})):o&&this._populate(t,e)}},componentWillReceiveProps:function(t){var e=this.props.config&&this.props.config.name,n=t.config&&t.config.name;n!==e?(this.stopListeningToAll(),this._prepareDatasource(t.config)):t.objectId!==this.props.objectId&&this._reloadCollection(t,this.state)},componentWillUpdate:function(t,e){this.state.dataSource!=e.dataSource&&this.props.autoPopulate&&this._populate(t,e)},_populate:function(t,e){var n=e.dataSource,r=t.objectId?{id:t.objectId}:null;n.listenables.populate(r)},componentDidMount:function(){this._prepareDatasource(this.props.config),this._reloadCollection(this.props,this.state)}}));t.exports=a},function(t,e,n){t.exports=n(6)},function(t,e,n){e.ActionMethods=n(8),e.ListenerMethods=n(9),e.PublisherMethods=n(21),e.StoreMethods=n(22),e.createAction=n(23),e.createStore=n(17),e.connect=n(24),e.connectFilter=n(25),e.ListenerMixin=n(26),e.listenTo=n(7),e.listenToMany=n(27);var r=n(16).staticJoinCreator;e.joinTrailing=e.all=r("last"),e.joinLeading=r("first"),e.joinStrict=r("strict"),e.joinConcat=r("all");var i=n(10);e.EventEmitter=i.EventEmitter,e.Promise=i.Promise,e.createActions=function(t){var n={};for(var r in t)if(t.hasOwnProperty(r)){var o=t[r],s=i.isObject(o)?r:o;n[s]=e.createAction(o)}return n},e.setEventEmitter=function(t){var r=n(10);e.EventEmitter=r.EventEmitter=t},e.setPromise=function(t){var r=n(10);e.Promise=r.Promise=t},e.setPromiseFactory=function(t){var e=n(10);e.createPromise=t},e.nextTick=function(t){var e=n(10);e.nextTick=t},e.__keep=n(18),Function.prototype.bind||console.error("Function.prototype.bind not available. ES5 shim required. https://github.com/spoike/refluxjs#es5")},function(t,e,n){var r=n(6);t.exports=function(t,e,n){return{componentDidMount:function(){for(var i in r.ListenerMethods)if(this[i]!==r.ListenerMethods[i]){if(this[i])throw"Can't have other property '"+i+"' when using Reflux.listenTo!";this[i]=r.ListenerMethods[i]}this.listenTo(t,e,n)},componentWillUnmount:r.ListenerMethods.stopListeningToAll}}},function(t,e){t.exports={}},function(t,e,n){var r=n(10),i=n(16).instanceJoinCreator,o=function(t){for(var e,n=0,r={};n<(t.children||[]).length;++n)e=t.children[n],t[e]&&(r[e]=t[e]);return r},s=function(t){var e={};for(var n in t){var i=t[n],a=o(i),u=s(a);e[n]=i;for(var c in u){var h=u[c];e[n+r.capitalize(c)]=h}}return e};t.exports={hasListener:function(t){for(var e,n,r,i=0;i<(this.subscriptions||[]).length;++i)for(r=[].concat(this.subscriptions[i].listenable),e=0;ei;i++){e=arguments[i];for(n in e)if(Object.getOwnPropertyDescriptor&&Object.defineProperty){var s=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,s)}else t[n]=e[n]}return t},e.isFunction=function(t){return"function"==typeof t},e.EventEmitter=n(11),e.nextTick=function(t){setTimeout(t,0)},e.capitalize=function(t){return t.charAt(0).toUpperCase()+t.slice(1)},e.callbackName=function(t){return"on"+e.capitalize(t)},e.object=function(t,e){for(var n={},r=0;re;e++)r[e]=this._events[t][e].fn;return r},r.prototype.emit=function(t,e,n,r,i,o){if(!this._events||!this._events[t])return!1;var s,a,u=this._events[t],c=arguments.length;if("function"==typeof u.fn){switch(u.once&&this.removeListener(t,u.fn,!0),c){case 1:return u.fn.call(u.context),!0;case 2:return u.fn.call(u.context,e),!0;case 3:return u.fn.call(u.context,e,n),!0;case 4:return u.fn.call(u.context,e,n,r),!0;case 5:return u.fn.call(u.context,e,n,r,i),!0;case 6:return u.fn.call(u.context,e,n,r,i,o),!0}for(a=1,s=new Array(c-1);c>a;a++)s[a-1]=arguments[a];u.fn.apply(u.context,s)}else{var h,l=u.length;for(a=0;l>a;a++)switch(u[a].once&&this.removeListener(t,u[a].fn,!0),c){case 1:u[a].fn.call(u[a].context);break;case 2:u[a].fn.call(u[a].context,e);break;case 3:u[a].fn.call(u[a].context,e,n);break;default:if(!s)for(h=1,s=new Array(c-1);c>h;h++)s[h-1]=arguments[h];u[a].fn.apply(u[a].context,s)}}return!0},r.prototype.on=function(t,e,r){var i=new n(e,r||this);return this._events||(this._events={}),this._events[t]?this._events[t].fn?this._events[t]=[this._events[t],i]:this._events[t].push(i):this._events[t]=i,this},r.prototype.once=function(t,e,r){var i=new n(e,r||this,!0);return this._events||(this._events={}),this._events[t]?this._events[t].fn?this._events[t]=[this._events[t],i]:this._events[t].push(i):this._events[t]=i,this},r.prototype.removeListener=function(t,e,n){if(!this._events||!this._events[t])return this;var r=this._events[t],i=[];if(e&&(r.fn&&(r.fn!==e||n&&!r.once)&&i.push(r),!r.fn))for(var o=0,s=r.length;s>o;o++)(r[o].fn!==e||n&&!r[o].once)&&i.push(r[o]);return i.length?this._events[t]=1===i.length?i[0]:i:delete this._events[t],this},r.prototype.removeAllListeners=function(t){return this._events?(t?delete this._events[t]:this._events={},this):this},r.prototype.off=r.prototype.removeListener,r.prototype.addListener=r.prototype.on,r.prototype.setMaxListeners=function(){return this},r.EventEmitter=r,r.EventEmitter2=r,r.EventEmitter3=r,t.exports=r},function(t,e,n){var r;(function(i,o){/*! Native Promise Only v0.7.8-a (c) Kyle Simpson MIT License: http://getify.mit-license.org */ - !function(t,n,e){n[t]=n[t]||e(),"undefined"!=typeof module&&module.exports?module.exports=n[t]:"function"=="function"&&__webpack_require__(15)&&!(__WEBPACK_AMD_DEFINE_RESULT__ = function(){return n[t]}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))}("Promise","undefined"!=typeof global?global:this,function(){"use strict";function t(t,n){l.add(t,n),h||(h=y(l.drain))}function n(t){var n,e=typeof t;return null==t||"object"!=e&&"function"!=e||(n=t.then),"function"==typeof n?n:!1}function e(){for(var t=0;t0&&t(e,a))}catch(s){i.call(u||new f(a),s)}}}function i(n){var o=this;o.triggered||(o.triggered=!0,o.def&&(o=o.def),o.msg=n,o.state=2,o.chain.length>0&&t(e,o))}function c(t,n,e,o){for(var r=0;r= 0) { - item._idleTimeoutId = setTimeout(function onTimeout() { - if (item._onTimeout) - item._onTimeout(); - }, msecs); - } - }; - - // That's not how node.js implements it but the exposed api is the same. - exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) { - var id = nextImmediateId++; - var args = arguments.length < 2 ? false : slice.call(arguments, 1); - - immediateIds[id] = true; - - nextTick(function onNextTick() { - if (immediateIds[id]) { - // fn.call() is faster so we optimize for the common use-case - // @see http://jsperf.com/call-apply-segu - if (args) { - fn.apply(null, args); - } else { - fn.call(null); - } - // Prevent ids from leaking - exports.clearImmediate(id); - } - }); - - return id; - }; - - exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) { - delete immediateIds[id]; - }; - /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(13).setImmediate, __webpack_require__(13).clearImmediate)) - -/***/ }, -/* 14 */ -/***/ function(module, exports) { - - // shim for using process in browser - - var process = module.exports = {}; - var queue = []; - var draining = false; - var currentQueue; - var queueIndex = -1; - - function cleanUpNextTick() { - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } - } - - function drainQueue() { - if (draining) { - return; - } - var timeout = setTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - currentQueue[queueIndex].run(); - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - clearTimeout(timeout); - } - - process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - setTimeout(drainQueue, 0); - } - }; - - // v8 likes predictible objects - function Item(fun, array) { - this.fun = fun; - this.array = array; - } - Item.prototype.run = function () { - this.fun.apply(null, this.array); - }; - process.title = 'browser'; - process.browser = true; - process.env = {}; - process.argv = []; - process.version = ''; // empty string to avoid regexp issues - process.versions = {}; - - function noop() {} - - process.on = noop; - process.addListener = noop; - process.once = noop; - process.off = noop; - process.removeListener = noop; - process.removeAllListeners = noop; - process.emit = noop; - - process.binding = function (name) { - throw new Error('process.binding is not supported'); - }; - - // TODO(shtylman) - process.cwd = function () { return '/' }; - process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); - }; - process.umask = function() { return 0; }; - - -/***/ }, -/* 15 */ -/***/ function(module, exports) { - - /* WEBPACK VAR INJECTION */(function(__webpack_amd_options__) {module.exports = __webpack_amd_options__; - - /* WEBPACK VAR INJECTION */}.call(exports, {})) - -/***/ }, -/* 16 */ -/***/ function(module, exports, __webpack_require__) { - - /** - * Internal module used to create static and instance join methods - */ - - var slice = Array.prototype.slice, - _ = __webpack_require__(10), - createStore = __webpack_require__(17), - strategyMethodNames = { - strict: "joinStrict", - first: "joinLeading", - last: "joinTrailing", - all: "joinConcat" - }; - - /** - * Used in `index.js` to create the static join methods - * @param {String} strategy Which strategy to use when tracking listenable trigger arguments - * @returns {Function} A static function which returns a store with a join listen on the given listenables using the given strategy - */ - exports.staticJoinCreator = function(strategy){ - return function(/* listenables... */) { - var listenables = slice.call(arguments); - return createStore({ - init: function(){ - this[strategyMethodNames[strategy]].apply(this,listenables.concat("triggerAsync")); - } - }); - }; - }; - - /** - * Used in `ListenerMethods.js` to create the instance join methods - * @param {String} strategy Which strategy to use when tracking listenable trigger arguments - * @returns {Function} An instance method which sets up a join listen on the given listenables using the given strategy - */ - exports.instanceJoinCreator = function(strategy){ - return function(/* listenables..., callback*/){ - _.throwIf(arguments.length < 3,'Cannot create a join with less than 2 listenables!'); - var listenables = slice.call(arguments), - callback = listenables.pop(), - numberOfListenables = listenables.length, - join = { - numberOfListenables: numberOfListenables, - callback: this[callback]||callback, - listener: this, - strategy: strategy - }, i, cancels = [], subobj; - for (i = 0; i < numberOfListenables; i++) { - _.throwIf(this.validateListening(listenables[i])); - } - for (i = 0; i < numberOfListenables; i++) { - cancels.push(listenables[i].listen(newListener(i,join),this)); - } - reset(join); - subobj = {listenable: listenables}; - subobj.stop = makeStopper(subobj,cancels,this); - this.subscriptions = (this.subscriptions || []).concat(subobj); - return subobj; - }; - }; - - // ---- internal join functions ---- - - function makeStopper(subobj,cancels,context){ - return function() { - var i, subs = context.subscriptions, - index = (subs ? subs.indexOf(subobj) : -1); - _.throwIf(index === -1,'Tried to remove join already gone from subscriptions list!'); - for(i=0;i < cancels.length; i++){ - cancels[i](); - } - subs.splice(index, 1); - }; - } - - function reset(join) { - join.listenablesEmitted = new Array(join.numberOfListenables); - join.args = new Array(join.numberOfListenables); - } - - function newListener(i,join) { - return function() { - var callargs = slice.call(arguments); - if (join.listenablesEmitted[i]){ - switch(join.strategy){ - case "strict": throw new Error("Strict join failed because listener triggered twice."); - case "last": join.args[i] = callargs; break; - case "all": join.args[i].push(callargs); - } - } else { - join.listenablesEmitted[i] = true; - join.args[i] = (join.strategy==="all"?[callargs]:callargs); - } - emitIfAllListenablesEmitted(join); - }; - } - - function emitIfAllListenablesEmitted(join) { - for (var i = 0; i < join.numberOfListenables; i++) { - if (!join.listenablesEmitted[i]) { - return; - } - } - join.callback.apply(join.listener,join.args); - reset(join); - } - - -/***/ }, -/* 17 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(10), - Reflux = __webpack_require__(6), - Keep = __webpack_require__(18), - mixer = __webpack_require__(19), - allowed = {preEmit:1,shouldEmit:1}, - bindMethods = __webpack_require__(20); - - /** - * Creates an event emitting Data Store. It is mixed in with functions - * from the `ListenerMethods` and `PublisherMethods` mixins. `preEmit` - * and `shouldEmit` may be overridden in the definition object. - * - * @param {Object} definition The data store object definition - * @returns {Store} A data store instance - */ - module.exports = function(definition) { - - definition = definition || {}; - - for(var a in Reflux.StoreMethods){ - if (!allowed[a] && (Reflux.PublisherMethods[a] || Reflux.ListenerMethods[a])){ - throw new Error("Cannot override API method " + a + - " in Reflux.StoreMethods. Use another method name or override it on Reflux.PublisherMethods / Reflux.ListenerMethods instead." - ); - } - } - - for(var d in definition){ - if (!allowed[d] && (Reflux.PublisherMethods[d] || Reflux.ListenerMethods[d])){ - throw new Error("Cannot override API method " + d + - " in store creation. Use another method name or override it on Reflux.PublisherMethods / Reflux.ListenerMethods instead." - ); - } - } - - definition = mixer(definition); - - function Store() { - var i=0, arr; - this.subscriptions = []; - this.emitter = new _.EventEmitter(); - this.eventLabel = "change"; - bindMethods(this, definition); - if (this.init && _.isFunction(this.init)) { - this.init(); - } - if (this.listenables){ - arr = [].concat(this.listenables); - for(;i < arr.length;i++){ - this.listenToMany(arr[i]); - } - } - } - - _.extend(Store.prototype, Reflux.ListenerMethods, Reflux.PublisherMethods, Reflux.StoreMethods, definition); - - var store = new Store(); - Keep.createdStores.push(store); - - return store; - }; - - -/***/ }, -/* 18 */ -/***/ function(module, exports) { - - exports.createdStores = []; - - exports.createdActions = []; - - exports.reset = function() { - while(exports.createdStores.length) { - exports.createdStores.pop(); - } - while(exports.createdActions.length) { - exports.createdActions.pop(); - } - }; - - -/***/ }, -/* 19 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(10); - - module.exports = function mix(def) { - var composed = { - init: [], - preEmit: [], - shouldEmit: [] - }; - - var updated = (function mixDef(mixin) { - var mixed = {}; - if (mixin.mixins) { - mixin.mixins.forEach(function (subMixin) { - _.extend(mixed, mixDef(subMixin)); - }); - } - _.extend(mixed, mixin); - Object.keys(composed).forEach(function (composable) { - if (mixin.hasOwnProperty(composable)) { - composed[composable].push(mixin[composable]); - } - }); - return mixed; - }(def)); - - if (composed.init.length > 1) { - updated.init = function () { - var args = arguments; - composed.init.forEach(function (init) { - init.apply(this, args); - }, this); - }; - } - if (composed.preEmit.length > 1) { - updated.preEmit = function () { - return composed.preEmit.reduce(function (args, preEmit) { - var newValue = preEmit.apply(this, args); - return newValue === undefined ? args : [newValue]; - }.bind(this), arguments); - }; - } - if (composed.shouldEmit.length > 1) { - updated.shouldEmit = function () { - var args = arguments; - return !composed.shouldEmit.some(function (shouldEmit) { - return !shouldEmit.apply(this, args); - }, this); - }; - } - Object.keys(composed).forEach(function (composable) { - if (composed[composable].length === 1) { - updated[composable] = composed[composable][0]; - } - }); - - return updated; - }; - - -/***/ }, -/* 20 */ -/***/ function(module, exports) { - - module.exports = function(store, definition) { - for (var name in definition) { - if (Object.getOwnPropertyDescriptor && Object.defineProperty) { - var propertyDescriptor = Object.getOwnPropertyDescriptor(definition, name); - - if (!propertyDescriptor.value || typeof propertyDescriptor.value !== 'function' || !definition.hasOwnProperty(name)) { - continue; - } - - store[name] = definition[name].bind(store); - } else { - var property = definition[name]; - - if (typeof property !== 'function' || !definition.hasOwnProperty(name)) { - continue; - } - - store[name] = property.bind(store); - } - } - - return store; - }; - - -/***/ }, -/* 21 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(10); - - /** - * A module of methods for object that you want to be able to listen to. - * This module is consumed by `createStore` and `createAction` - */ - module.exports = { - - /** - * Hook used by the publisher that is invoked before emitting - * and before `shouldEmit`. The arguments are the ones that the action - * is invoked with. If this function returns something other than - * undefined, that will be passed on as arguments for shouldEmit and - * emission. - */ - preEmit: function() {}, - - /** - * Hook used by the publisher after `preEmit` to determine if the - * event should be emitted with given arguments. This may be overridden - * in your application, default implementation always returns true. - * - * @returns {Boolean} true if event should be emitted - */ - shouldEmit: function() { return true; }, - - /** - * Subscribes the given callback for action triggered - * - * @param {Function} callback The callback to register as event handler - * @param {Mixed} [optional] bindContext The context to bind the callback with - * @returns {Function} Callback that unsubscribes the registered event handler - */ - listen: function(callback, bindContext) { - bindContext = bindContext || this; - var eventHandler = function(args) { - if (aborted){ - return; - } - callback.apply(bindContext, args); - }, me = this, aborted = false; - this.emitter.addListener(this.eventLabel, eventHandler); - return function() { - aborted = true; - me.emitter.removeListener(me.eventLabel, eventHandler); - }; - }, - - /** - * Attach handlers to promise that trigger the completed and failed - * child publishers, if available. - * - * @param {Object} The promise to attach to - */ - promise: function(promise) { - var me = this; - - var canHandlePromise = - this.children.indexOf('completed') >= 0 && - this.children.indexOf('failed') >= 0; - - if (!canHandlePromise){ - throw new Error('Publisher must have "completed" and "failed" child publishers'); - } - - promise.then(function(response) { - return me.completed(response); - }, function(error) { - return me.failed(error); - }); - }, - - /** - * Subscribes the given callback for action triggered, which should - * return a promise that in turn is passed to `this.promise` - * - * @param {Function} callback The callback to register as event handler - */ - listenAndPromise: function(callback, bindContext) { - var me = this; - bindContext = bindContext || this; - this.willCallPromise = (this.willCallPromise || 0) + 1; - - var removeListen = this.listen(function() { - - if (!callback) { - throw new Error('Expected a function returning a promise but got ' + callback); - } - - var args = arguments, - promise = callback.apply(bindContext, args); - return me.promise.call(me, promise); - }, bindContext); - - return function () { - me.willCallPromise--; - removeListen.call(me); - }; - - }, - - /** - * Publishes an event using `this.emitter` (if `shouldEmit` agrees) - */ - trigger: function() { - var args = arguments, - pre = this.preEmit.apply(this, args); - args = pre === undefined ? args : _.isArguments(pre) ? pre : [].concat(pre); - if (this.shouldEmit.apply(this, args)) { - this.emitter.emit(this.eventLabel, args); - } - }, - - /** - * Tries to publish the event on the next tick - */ - triggerAsync: function(){ - var args = arguments,me = this; - _.nextTick(function() { - me.trigger.apply(me, args); - }); - }, - - /** - * Returns a Promise for the triggered action - * - * @return {Promise} - * Resolved by completed child action. - * Rejected by failed child action. - * If listenAndPromise'd, then promise associated to this trigger. - * Otherwise, the promise is for next child action completion. - */ - triggerPromise: function(){ - var me = this; - var args = arguments; - - var canHandlePromise = - this.children.indexOf('completed') >= 0 && - this.children.indexOf('failed') >= 0; - - var promise = _.createPromise(function(resolve, reject) { - // If `listenAndPromise` is listening - // patch `promise` w/ context-loaded resolve/reject - if (me.willCallPromise) { - _.nextTick(function() { - var old_promise_method = me.promise; - me.promise = function (promise) { - promise.then(resolve, reject); - // Back to your regularly schedule programming. - me.promise = old_promise_method; - return me.promise.apply(me, arguments); - }; - me.trigger.apply(me, args); - }); - return; - } - - if (canHandlePromise) { - var removeSuccess = me.completed.listen(function(args) { - removeSuccess(); - removeFailed(); - resolve(args); - }); - - var removeFailed = me.failed.listen(function(args) { - removeSuccess(); - removeFailed(); - reject(args); - }); - } - - me.triggerAsync.apply(me, args); - - if (!canHandlePromise) { - resolve(); - } - }); - - return promise; - } - }; - - -/***/ }, -/* 22 */ -/***/ function(module, exports) { - - /** - * A module of methods that you want to include in all stores. - * This module is consumed by `createStore`. - */ - module.exports = { - }; - - -/***/ }, -/* 23 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(10), - Reflux = __webpack_require__(6), - Keep = __webpack_require__(18), - allowed = {preEmit:1,shouldEmit:1}; - - /** - * Creates an action functor object. It is mixed in with functions - * from the `PublisherMethods` mixin. `preEmit` and `shouldEmit` may - * be overridden in the definition object. - * - * @param {Object} definition The action object definition - */ - var createAction = function(definition) { - - definition = definition || {}; - if (!_.isObject(definition)){ - definition = {actionName: definition}; - } - - for(var a in Reflux.ActionMethods){ - if (!allowed[a] && Reflux.PublisherMethods[a]) { - throw new Error("Cannot override API method " + a + - " in Reflux.ActionMethods. Use another method name or override it on Reflux.PublisherMethods instead." - ); - } - } - - for(var d in definition){ - if (!allowed[d] && Reflux.PublisherMethods[d]) { - throw new Error("Cannot override API method " + d + - " in action creation. Use another method name or override it on Reflux.PublisherMethods instead." - ); - } - } - - definition.children = definition.children || []; - if (definition.asyncResult){ - definition.children = definition.children.concat(["completed","failed"]); - } - - var i = 0, childActions = {}; - for (; i < definition.children.length; i++) { - var name = definition.children[i]; - childActions[name] = createAction(name); - } - - var context = _.extend({ - eventLabel: "action", - emitter: new _.EventEmitter(), - _isAction: true - }, Reflux.PublisherMethods, Reflux.ActionMethods, definition); - - var functor = function() { - return functor[functor.sync?"trigger":"triggerPromise"].apply(functor, arguments); - }; - - _.extend(functor,childActions,context); - - Keep.createdActions.push(functor); - - return functor; - - }; - - module.exports = createAction; - - -/***/ }, -/* 24 */ -/***/ function(module, exports, __webpack_require__) { - - var Reflux = __webpack_require__(6), - _ = __webpack_require__(10); - - module.exports = function(listenable,key){ - return { - getInitialState: function(){ - if (!_.isFunction(listenable.getInitialState)) { - return {}; - } else if (key === undefined) { - return listenable.getInitialState(); - } else { - return _.object([key],[listenable.getInitialState()]); - } - }, - componentDidMount: function(){ - _.extend(this,Reflux.ListenerMethods); - var me = this, cb = (key === undefined ? this.setState : function(v){ - if (typeof me.isMounted === "undefined" || me.isMounted() === true) { - me.setState(_.object([key],[v])); - } - }); - this.listenTo(listenable,cb); - }, - componentWillUnmount: Reflux.ListenerMixin.componentWillUnmount - }; - }; - - -/***/ }, -/* 25 */ -/***/ function(module, exports, __webpack_require__) { - - var Reflux = __webpack_require__(6), - _ = __webpack_require__(10); - - module.exports = function(listenable, key, filterFunc) { - filterFunc = _.isFunction(key) ? key : filterFunc; - return { - getInitialState: function() { - if (!_.isFunction(listenable.getInitialState)) { - return {}; - } else if (_.isFunction(key)) { - return filterFunc.call(this, listenable.getInitialState()); - } else { - // Filter initial payload from store. - var result = filterFunc.call(this, listenable.getInitialState()); - if (result) { - return _.object([key], [result]); - } else { - return {}; - } - } - }, - componentDidMount: function() { - _.extend(this, Reflux.ListenerMethods); - var me = this; - var cb = function(value) { - if (_.isFunction(key)) { - me.setState(filterFunc.call(me, value)); - } else { - var result = filterFunc.call(me, value); - me.setState(_.object([key], [result])); - } - }; - - this.listenTo(listenable, cb); - }, - componentWillUnmount: Reflux.ListenerMixin.componentWillUnmount - }; - }; - - - -/***/ }, -/* 26 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(10), - ListenerMethods = __webpack_require__(9); - - /** - * A module meant to be consumed as a mixin by a React component. Supplies the methods from - * `ListenerMethods` mixin and takes care of teardown of subscriptions. - * Note that if you're using the `connect` mixin you don't need this mixin, as connect will - * import everything this mixin contains! - */ - module.exports = _.extend({ - - /** - * Cleans up all listener previously registered. - */ - componentWillUnmount: ListenerMethods.stopListeningToAll - - }, ListenerMethods); - - -/***/ }, -/* 27 */ -/***/ function(module, exports, __webpack_require__) { - - var Reflux = __webpack_require__(6); - - /** - * A mixin factory for a React component. Meant as a more convenient way of using the `listenerMixin`, - * without having to manually set listeners in the `componentDidMount` method. This version is used - * to automatically set up a `listenToMany` call. - * - * @param {Object} listenables An object of listenables - * @returns {Object} An object to be used as a mixin, which sets up the listeners for the given listenables. - */ - module.exports = function(listenables){ - return { - /** - * Set up the mixin before the initial rendering occurs. Import methods from `ListenerMethods` - * and then make the call to `listenTo` with the arguments provided to the factory function - */ - componentDidMount: function() { - for(var m in Reflux.ListenerMethods){ - if (this[m] !== Reflux.ListenerMethods[m]){ - if (this[m]){ - throw "Can't have other property '"+m+"' when using Reflux.listenToMany!"; - } - this[m] = Reflux.ListenerMethods[m]; - } - } - this.listenToMany(listenables); - }, - /** - * Cleans up all listener previously registered. - */ - componentWillUnmount: Reflux.ListenerMethods.stopListeningToAll - }; - }; - - -/***/ }, -/* 28 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var React = __webpack_require__(2); - var _ = __webpack_require__(3); - - /** - * @module UtilityMixin - * @type {Object} - */ - var UtilityMixin = { - - _buildProps: function _buildProps() { - var props = _.clone(this.props); - delete props.children; - delete props.className; - delete props.wrapper; - delete props.tag; - delete props.config; - return props; - }, - - /** - * Clones children with given props - * @param {object} props Props to give to children - * @return {array} Array of child components with new props - */ - _cloneWithProps: function _cloneWithProps(props) { - var children = React.Children.map(this.props.children, function (child) { - if (!child) { - return null; - } - return React.cloneElement(child, props); - }, this.context); - return children; - }, - - /** - * Console warns with component display name - * @param {string} warning Warning message - */ - _warn: function _warn(warning) { - console.warn(this.constructor.displayName, warning); - } - }; - - module.exports = UtilityMixin; - -/***/ }, -/* 29 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var React = __webpack_require__(2); - var _ = __webpack_require__(3); - var DSManager = __webpack_require__(30); - - module.exports = { - - getInitialState: function getInitialState() { - return { - data: [], - dataSource: null - }; - }, - - _buildDataProps: function _buildDataProps() { - var props = this._buildProps(); - // Nil hack basically. - var data = this.state.data || this.props.objectId && {} || []; - var actions = {}; - if (this.state.dataSource) { - actions = this.state.dataSource && this.state.dataSource.listenables; - } - return _.extend(props, { data: data, actions: actions }); - }, - - _prepareDatasource: function _prepareDatasource(config) { - var dataSource = DSManager.getStore(config); - this.listenTo(dataSource, this.onStoreChange); - this.setState({ dataSource: dataSource }); - }, - - _onViewRegistered: function _onViewRegistered() { - var dataSource = this.state.dataSource; - var _props = this.props; - var tag = _props.tag; - var autoPopulate = _props.autoPopulate; - - var data = dataSource.getCollection(tag); - _.isEmpty(data) && this._repopulate(this.props, this.state); - }, - - onStoreChange: function onStoreChange(type, payload) { - if (type === 'viewRegistered' && payload === this.props.tag) { - this._onViewRegistered(); - } - this._reloadCollection(this.props, this.state); - }, - render: function render() { - var children = this._cloneWithProps(this._buildDataProps()); - var Wrapper = this.props.wrapper || 'div'; - return React.createElement( - Wrapper, - { className: this.props.className }, - children - ); - } - }; - -/***/ }, -/* 30 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - - var Reflux = __webpack_require__(5); - var DataActionGenerator = __webpack_require__(35); - var nsync = __webpack_require__(36); - var client = __webpack_require__(37); - - var storeTemplates = { - // Shared/persistent stores are Loki - shared: __webpack_require__(31), - - // Unique/ephemeral stores are Immutable - unique: __webpack_require__(40) - }; - - var urlBuilders = { - 'default': __webpack_require__(42), - dependent: __webpack_require__(43) - }; - - function defaultErrorHandler(method, err) { - console.error(this.name + ' error', method, err); - } - - /** - * @class DataStoreManager - */ - - var DataStoreManager = (function () { - function DataStoreManager() { - _classCallCheck(this, DataStoreManager); - - this.generatedStores = {}; - this.headers = {}; - this.synchronizer = nsync; - this.client = client; - this.urlBuilders = urlBuilders; - this.onError = defaultErrorHandler; - } - - _createClass(DataStoreManager, [{ - key: 'implode', - - /** - * @public - * The nuclear option - */ - value: function implode() { - this.constructor(); - } - }, { - key: '_memoizeStore', - - /** - * @private - * Memoizes a store - * @param {RefluxStore} store Store to be memoized - * @return {RefluxStore} Memoized Store - */ - value: function _memoizeStore(store) { - if (!this.generatedStores[store.name]) { - this.generatedStores[store.name] = store; - } - return this.generatedStores[store.name]; - } - }, { - key: '_memoizeClient', - - /** - * @private - * Memoizes a store - * @param {RefluxStore} store Store to be memoized - * @return {RefluxStore} Memoized Store - */ - value: function _memoizeClient(client) { - if (!this.generatedClients[client.name]) { - this.generatedClients[client.name] = client; - } - return this.generatedClients[client.name]; - } - }, { - key: '_getStore', - - /** - * @private - * Gets a memoized store - * @param {string} name Store name - * @return {RefluxStore} MemoizedStore - */ - value: function _getStore(name) { - return this.generatedStores[name]; - } - }, { - key: 'setHeaders', - - /** - * @DEPRECATED - */ - value: function setHeaders(headers) { - console.warn('Deprecated Method, use setDefaultHeaders'); - this.setDefaultHeaders(headers); - } - }, { - key: 'setDefaultHeaders', - - /** - * onSyncError - */ - - /** - * @public - * Sets headers for synchronizer requests - * @param {object} headers Request Headers - */ - value: function setDefaultHeaders(headers) { - this.headers = headers; - } - }, { - key: 'getHeaders', - - /** - * @public - * Gets headers for synchronizer requests - * @param {object} headers Request Headers - */ - value: function getHeaders() { - return this.headers; - } - }, { - key: 'registerBuilder', - - /** - * @public - * Registers new url builder for synchronizers - * @param {string} name Name of builder - * @param {func} url builder - */ - value: function registerBuilder(name, builder) { - this.urlBuilders[name] = builder; - } - }, { - key: 'setSynchronizer', - - /** - * @public - * Sets synchronizer - * @param {object} synchronizer - */ - value: function setSynchronizer(storeName, synchronizer) { - this.generatedStores[storeName + 'Synchronizer'] = synchronizer; - } - }, { - key: 'getSynchronizer', - - /** - * @public - * Sets synchronizer - * @param {object} synchronizer - */ - value: function getSynchronizer(storeName) { - return this.generatedStores[storeName + 'Synchronizer']; - } - }, { - key: 'setErrorHandler', - - /** - * @public - * setErrorHandler - * @param {func} cb Error handler callback - */ - value: function setErrorHandler(cb) { - this.onError = cb; - } - }, { - key: 'on', - - /** - * @public - * Used to dispatch actions to stores - * @param Name of store - * @param actionType name of action to listen for - * @param func function to execute on event emit - */ - value: function on(storeName, actionType, func) { - var options = { - storeType: 'shared', - name: storeName, - builder: 'procore' - }; - var dispatcherOptions = { - storeType: 'shared', - name: 'dispatcher' - }; - - var store = this.getStore(options); - var dispatcherStore = this.getStore(dispatcherOptions); - - dispatcherStore.listenTo(store, function (type, data) { - if (actionType === type) { - func(data); - } - }); - } - }, { - key: 'getStore', - - /** - * @public - * Generates a store - * @param {object} options Store options - */ - value: function getStore(options) { - var name = options.name; - var storeType = options.storeType; - - var memoized = this._getStore(name); - - if (memoized) { - return memoized; - } - if (this.headers !== {}) { - options.headers = this.getHeaders.bind(this); - } - if (this.onError) { - options.onError = this.onError; - } - return this[storeType || 'unique'](options); - } - }, { - key: 'shared', - - /** - * @private - * Generates a singleton store - * @param {object} options Store options - * @return {RefluxStore} Generated store - */ - value: function shared(options) { - var name = options.name; - var builder = options.builder; - - // This seems like a code smell ~ - var chosenStore = new storeTemplates.shared(options); - chosenStore.listenables = DataActionGenerator(name); - var store = Reflux.createStore(chosenStore); - - // Probably need to move this logic - var urlBuilder = new this.urlBuilders[builder || 'default'](options); - var client = new this.client(urlBuilder, options); - var synchronizer = this.synchronizer(options, store, client); - - this._memoizeStore(synchronizer); - this._memoizeStore(store); - - return store; - } - }, { - key: 'unique', - - /** - * @private - * Generates an ephemeral store - * @param {object} options Store options - * @return {RefluxStore} Generated store - */ - value: function unique(options) { - var name = options.name; - var builder = options.builder; - - name = '' + name + Date.now(); - - // This seems like a code smell ~ - var chosenStore = new storeTemplates.shared(options); - chosenStore.listenables = DataActionGenerator(); - var store = Reflux.createStore(chosenStore); - - // Probably need to move this logic - var urlBuilder = new this.urlBuilders[builder || 'default'](options); - var client = new this.client(urlBuilder, options); - var synchronizer = this.synchronizer(options, store, client); - - return store; - } - }]); - - return DataStoreManager; - })(); - - /** - * Retrieves store generator from the window - * @return {object} DataStoreManager - */ - module.exports = window.DataStoreManager = new DataStoreManager(); - -/***/ }, -/* 31 */ -/***/ function(module, exports, __webpack_require__) { - - "use strict"; - - var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - - /** - * @module LokiStore - */ - var loki = __webpack_require__(32); - var _ = __webpack_require__(3); - var uuid = __webpack_require__(34); - /** - * @class LowkeySource - * @description Manages Loki datasource - */ - - var LowkeySource = (function () { - function LowkeySource() { - _classCallCheck(this, LowkeySource); - - this.dataSource = null; - this.resources = {}; - } - - _createClass(LowkeySource, [{ - key: "getDS", - - /** - * Initializes and returns a datasource - * @return {loki} loki datasource - */ - value: function getDS() { - if (this.dataSource) { - return this.dataSource; - } - this.dataSource = new loki(); - return this.dataSource; - } - }, { - key: "getResource", - - /** - * Initializes and returns a resource - * @param {string} name name of resource - * @return {object} Loki Collection - */ - value: function getResource(name) { - var resources = this.resources; - if (resources[name]) { - return resources[name]; - } - - var resource = this.getDS().addCollection(name, { disableChangesApi: false }); - resources[name] = resource; - - return resource; - } - }]); - - return LowkeySource; - })(); - - var $ds = new LowkeySource(); - - /** - * Generate Store - * @param {name} name name of resource - * @return {object} Loki store template - */ - function generateStore(options) { - var name = options.name; - var idAttr = options.idAttr; - var fk = options.fk; - - var collection = $ds.getResource(name); - return { - name: name, - collection: collection, - dynamicViews: {}, - - /** - * Initializes store - */ - init: function init() {}, - - resetChanges: function resetChanges() { - var _this = this; - - var changes = this.collection.getChanges(); - changes.forEach(function (change) { - var obj = change.obj; - - _this.setObject(obj); - }); - }, - - flushChanges: function flushChanges() { - this.collection.flushChanges(); - }, - - /** - * Adds an object to the store - * @param {object} object Object to add - * @return {event} Triggers event - */ - add: function add(object) { - var trigger = arguments[1] === undefined ? true : arguments[1]; - - var stale = this.getDatabaseEntity(object); - if (stale) { - console.warn("ProcoreReact: Trying to add an already existing element. Syncing instead"); - // if already exists. dont add it, just sync it. - this.trigger("add", object, trigger); - } else { - // =========================== - // TESTING TEMP IDS - // =========================== - // TODO we need a way to provide tmp_IDs to objects if we - // don't persist them on the DB (!trigger) - if (!trigger && !object[idAttr]) { - object[idAttr] = "temp" + uuid.v4(); - } - this.collection.insert(object); - this.trigger("add", object, trigger); - } - }, - - /** - * Sets collection - * @param {array} collection Collection to set - * @return {event} Triggers event - */ - setCollection: function setCollection(collection) { - var _this2 = this; - - _.map(collection, function (object) { - var stale = _this2.getDatabaseEntity(object); - if (stale) { - _this2.collection.update(_.extend(stale, object)); - } else { - _this2.collection.insert(object); - } - }); - this.flushChanges(); - this.trigger("setCollection", this.getCollection()); - }, - - /** - * Set object without triggering events - * @param {object} object Object to insert or update - */ - setObject: function setObject(object) { - var stale = this.getDatabaseEntity(object); - if (stale) { - this.update(object, false); - } else { - this.add(object, false); - } - this.flushChanges(); - }, - - /** - * Destroys object - * @param {number} id ID of object to destroy - * @return {event} Triggers event - */ - destroy: function destroy(id) { - var trigger = arguments[1] === undefined ? true : arguments[1]; - - this.collection.remove(this.get(id)); - this.trigger("destroy", id, trigger); - }, - - /** - * Destroys all objects in the store - * @return {event} Triggers event - */ - destroyAll: function destroyAll() { - var trigger = arguments[0] === undefined ? true : arguments[0]; - - this.collection.removeDataOnly(); - this.trigger("destroyAll", this.getCollection(), trigger); - }, - - /** - * Updates an object in the store - * @param {object} object Object to update - * @return {event} Triggers an event - */ - update: function update(updates) { - var trigger = arguments[1] === undefined ? true : arguments[1]; - - var stale = this.getDatabaseEntity(updates); - if (!stale) { - console.warn("ProcoreReact: Trying to update an inexisting element."); - } else { - var updated = _.extend({}, stale, updates); - this.collection.update(updated); - this.trigger("update", updated, trigger); - } - }, - - /** - * Builds a query to fetch an object - * @param {number} object[idAttr] ID of requested object - * @param {number} object.$loki LokiID of the requested object - * @return {object} Requested object - */ - getEntityQuery: function getEntityQuery(object) { - var query = {}; - if (object.$loki) { - query.$loki = object.$loki; - } else if (object[idAttr]) { - query[idAttr] = object[idAttr]; - } else { - query = null; - } - return query; - }, - - /** - * Gets an object's equivalent from dataSource - * @param {number} id ID of requested object - * @return {object} Requested object - */ - getDatabaseEntity: function getDatabaseEntity(object) { - var query = this.getEntityQuery(object); - return query ? this.collection.findOne(query) : null; - }, - - /** - * Gets an object by ID - * @param {number} id ID of object to get - * @return {object} Requested object - */ - get: function get(id) { - var query = {}; - query[idAttr] = id; - return this.getDatabaseEntity(query); - }, - - /** - * Queries store - * @param {object} query mongo-style query - * @return {array} Array of reuslts - */ - find: function find(query) { - return this.collection.find(query); - }, - - /** - * Gets collection of objects - * @param {number} parentId ParentID of objects, for relational data (optional) - * @return {array} Collection of objects - */ - getCollection: function getCollection(tag) { - var collection = []; - if (tag) { - var view = this.collection.getDynamicView(tag); - collection = view ? view.data() : []; - } else { - collection = this.find(); - } - return collection; - }, - - /** - * Creates a filter - * @param {string} tag Tag of Collection to be filtered - * @param {object} filterQuery filter query - * @return {event} Triggers event - */ - filter: function filter(tag, filterQuery) { - if (!this.dynamicViews[tag]) { - this.dynamicViews[tag] = { filters: {}, sortBy: {}, search: "" }; - } - this.collection.removeDynamicView(tag); - - var viewParams = this.dynamicViews[tag]; - _.extend(viewParams.filters, filterQuery); - this.registerView(tag, viewParams); - }, - - /** - * Creates a search - * @param {string} tag Tag of Collection to be searched - * @param {object} searchQuery search query - * @return {event} Triggers event - */ - search: function search(tag, searchQuery) { - if (!this.dynamicViews[tag]) { - this.dynamicViews[tag] = { filters: {}, sortBy: {}, search: "" }; - } - this.collection.removeDynamicView(tag); - - var viewParams = this.dynamicViews[tag]; - viewParams.search = searchQuery; - - this.registerView(tag, viewParams); - }, - - /** - * Adds a sort parameter - * @param {string} tag Tag of Collection to be filtered - * @param {object} sortParam sort parameter - */ - sort: function sort(tag, sortBy) { - if (!this.dynamicViews[tag]) { - this.dynamicViews[tag] = { filters: {}, sortBy: {}, search: "" }; - } - this.collection.removeDynamicView(tag); - - var viewParams = this.dynamicViews[tag]; - viewParams.sortBy = sortBy; - this.registerView(tag, viewParams); - }, - - /** - * Removes filter and sort parameters from view - * @param {string} tag Tag of Collection to be reset - */ - resetView: function resetView(tag, reregister) { - this.collection.removeDynamicView(tag); - if (reregister !== false) { - this.registerView(tag); - } - }, - - /** - * Generates new dynamic view - * @param {string} tag Tag of Collection to be filtered - * @param {object} sort and filter parameters - * @return {event} Triggers event - */ - registerView: function registerView(tag, viewParams) { - this.collection.removeDynamicView(tag); - var view = this.collection.addDynamicView(tag); - if (!viewParams) { - return this.trigger("viewRegistered", tag); - } - - var filters = viewParams.filters; - var sortBy = viewParams.sortBy; - var search = viewParams.search; - - sortBy && view.applySimpleSort(sortBy.attribute, sortBy.isDescending); - sortBy && view.applySort(caseInsensitiveSort(sortBy)); - filters && _applyViewFilters(view, filters); - search && view.applyWhere(_buildSearch(search)); - - this.trigger("viewRegistered", tag); - } - }; - } - - function caseInsensitiveSort(sortBy) { - return function (a, b) { - var aVal = a[sortBy.attribute]; - var bVal = b[sortBy.attribute]; - aVal = typeof aVal === "string" ? aVal.toLowerCase() : aVal; - bVal = typeof bVal === "string" ? bVal.toLowerCase() : bVal; - if (sortBy.isDescending) { - return aVal < bVal ? 1 : -1; - } else { - return aVal > bVal ? 1 : -1; - } - }; - } - - function _buildSearch(query) { - return function (object) { - var match = false; - Object.keys(object).forEach(function (key) { - if (!match) { - match = JSON.stringify(object[key]).toLowerCase().indexOf(query.toLowerCase()) !== -1; - } - }); - return match; - }; - } - - function _buildFilter(key, value) { - var formattedValue = String(value).toLowerCase(); - return function (object) { - if (value === undefined) { - return !object[key]; - } - return String(object[key]).toLowerCase().indexOf(formattedValue) !== -1; - }; - } - - function _applyViewFilters(view, filters) { - Object.keys(filters).forEach(function (key) { - var query = null; - switch (filters[key]) { - case null: - break; - default: - query = _buildFilter(key, filters[key]); - break; - } - query && view.applyWhere(query); - }); - } - - module.exports = generateStore; - -/***/ }, -/* 32 */ -/***/ function(module, exports, __webpack_require__) { - - var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(global) {/** - * LokiJS - * @author Joe Minichino - * - * A lightweight document oriented javascript database - */ - (function (root, factory) { - if (true) { - // AMD - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else if (typeof exports === 'object') { - // CommonJS - module.exports = factory(); - } else { - // Browser globals - root.loki = factory(); - } - }(this, function () { - - return (function () { - 'use strict'; - - var Utils = { - copyProperties: function (src, dest) { - var prop; - for (prop in src) { - dest[prop] = src[prop]; - } - } - }; - - // Sort helper that support null and undefined - function ltHelper(prop1, prop2, equal) { - if (prop1 === prop2) { - if (equal) { - return true; - } else { - return false; - } - } - - if (prop1 === undefined) { - return true; - } - if (prop2 === undefined) { - return false; - } - if (prop1 === null) { - return true; - } - if (prop2 === null) { - return false; - } - return prop1 < prop2; - } - - function gtHelper(prop1, prop2, equal) { - if (prop1 === prop2) { - if (equal) { - return true; - } else { - return false; - } - } - - if (prop1 === undefined) { - return false; - } - if (prop2 === undefined) { - return true; - } - if (prop1 === null) { - return false; - } - if (prop2 === null) { - return true; - } - return prop1 > prop2; - } - - function sortHelper(prop1, prop2, desc) { - if (prop1 === prop2) { - return 0; - } - if (desc) { - if (ltHelper(prop1, prop2)) { - return 1; - } else { - return -1; - } - } else { - if (gtHelper(prop1, prop2)) { - return 1; - } else { - return -1; - } - } - } - - function containsCheckFn(a, b) { - if (Array.isArray(a)) { - return function (curr) { - return a.indexOf(curr) !== -1; - }; - } else if (typeof a === 'string') { - return function (curr) { - return a.indexOf(curr) !== -1; - }; - } else if (a && typeof a === 'object') { - return function (curr) { - return a.hasOwnProperty(curr); - }; - } - } - - var LokiOps = { - // comparison operators - $eq: function (a, b) { - return a === b; - }, - - $gt: function (a, b) { - return gtHelper(a, b); - }, - - $gte: function (a, b) { - return gtHelper(a, b, true); - }, - - $lt: function (a, b) { - return ltHelper(a, b); - }, - - $lte: function (a, b) { - return ltHelper(a, b, true); - }, - - $ne: function (a, b) { - return a !== b; - }, - - $regex: function (a, b) { - return b.test(a); - }, - - $in: function (a, b) { - return b.indexOf(a) > -1; - }, - - $containsAny: function (a, b) { - var checkFn; - - if (!Array.isArray(b)) { - b = [b]; - } - - checkFn = containsCheckFn(a, b) || function () { - return false; - }; - - return b.reduce(function (prev, curr) { - if (prev) { - return prev; - } - - return checkFn(curr); - }, false); - }, - - $contains: function (a, b) { - var checkFn; - - if (!Array.isArray(b)) { - b = [b]; - } - - checkFn = containsCheckFn(a, b) || function () { - return true; - }; - - return b.reduce(function (prev, curr) { - if (!prev) { - return prev; - } - - return checkFn(curr); - }, true); - } - }; - - var operators = { - '$eq': LokiOps.$eq, - '$gt': LokiOps.$gt, - '$gte': LokiOps.$gte, - '$lt': LokiOps.$lt, - '$lte': LokiOps.$lte, - '$ne': LokiOps.$ne, - '$regex': LokiOps.$regex, - '$in': LokiOps.$in, - '$contains': LokiOps.$contains, - '$containsAny': LokiOps.$containsAny - }; - - function clone(data, method) { - var cloneMethod = method || 'parse-stringify', - cloned; - if (cloneMethod === 'parse-stringify') { - cloned = JSON.parse(JSON.stringify(data)); - } - return cloned; - } - - function localStorageAvailable() { - try { - return ('localStorage' in window && window.localStorage !== null); - } catch (e) { - return false; - } - } - - - /** - * LokiEventEmitter is a minimalist version of EventEmitter. It enables any - * constructor that inherits EventEmitter to emit events and trigger - * listeners that have been added to the event through the on(event, callback) method - * - * @constructor - */ - function LokiEventEmitter() {} - - /** - * @prop Events property is a hashmap, with each property being an array of callbacks - */ - LokiEventEmitter.prototype.events = {}; - - /** - * @prop asyncListeners - boolean determines whether or not the callbacks associated with each event - * should happen in an async fashion or not - * Default is false, which means events are synchronous - */ - LokiEventEmitter.prototype.asyncListeners = false; - - /** - * @prop on(eventName, listener) - adds a listener to the queue of callbacks associated to an event - * @returns {int} the index of the callback in the array of listeners for a particular event - */ - LokiEventEmitter.prototype.on = function (eventName, listener) { - var event = this.events[eventName]; - if (!event) { - event = this.events[eventName] = []; - } - event.push(listener); - return listener; - }; - - /** - * @propt emit(eventName, data) - emits a particular event - * with the option of passing optional parameters which are going to be processed by the callback - * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters) - * @param {string} eventName - the name of the event - * @param {object} data - optional object passed with the event - */ - LokiEventEmitter.prototype.emit = function (eventName, data) { - var self = this; - if (eventName && this.events[eventName]) { - this.events[eventName].forEach(function (listener) { - if (self.asyncListeners) { - setTimeout(function () { - listener(data); - }, 1); - } else { - listener(data); - } - - }); - } else { - throw new Error('No event ' + eventName + ' defined'); - } - }; - - /** - * @prop remove() - removes the listener at position 'index' from the event 'eventName' - */ - LokiEventEmitter.prototype.removeListener = function (eventName, listener) { - if (this.events[eventName]) { - var listeners = this.events[eventName]; - listeners.splice(listeners.indexOf(listener), 1); - } - }; - - /** - * Loki: The main database class - * @constructor - * @param {string} filename - name of the file to be saved to - * @param {object} options - config object - */ - function Loki(filename, options) { - this.filename = filename || 'loki.db'; - this.collections = []; - - // persist version of code which created the database to the database. - // could use for upgrade scenarios - this.databaseVersion = 1.1; - this.engineVersion = 1.1; - - // autosave support (disabled by default) - // pass autosave: true, autosaveInterval: 6000 in options to set 6 second autosave - this.autosave = false; - this.autosaveInterval = 5000; - this.autosaveHandle = null; - - this.options = {}; - - // currently keeping persistenceMethod and persistenceAdapter as loki level properties that - // will not or cannot be deserialized. You are required to configure persistence every time - // you instantiate a loki object (or use default environment detection) in order to load the database anyways. - - // persistenceMethod could be 'fs', 'localStorage', or 'adapter' - // this is optional option param, otherwise environment detection will be used - // if user passes their own adapter we will force this method to 'adapter' later, so no need to pass method option. - this.persistenceMethod = null; - - // retain reference to optional (non-serializable) persistenceAdapter 'instance' - this.persistenceAdapter = null; - - - - this.events = { - 'init': [], - 'flushChanges': [], - 'close': [], - 'changes': [], - 'warning': [] - }; - - var getENV = function () { - if (typeof window === 'undefined') { - return 'NODEJS'; - } - - if (typeof global !== 'undefined' && global.window) { - return 'NODEJS'; //node-webkit - } - - if (typeof document !== 'undefined') { - if (document.URL.indexOf('http://') === -1 && document.URL.indexOf('https://') === -1) { - return 'CORDOVA'; - } - return 'BROWSER'; - } - return 'CORDOVA'; - }; - - // refactored environment detection due to invalid detection for browser environments. - // if they do not specify an options.env we want to detect env rather than default to nodejs. - // currently keeping two properties for similar thing (options.env and options.persistenceMethod) - // might want to review whether we can consolidate. - if (options && options.hasOwnProperty('env')) { - this.ENV = options.env; - } else { - this.ENV = getENV(); - } - - // not sure if this is necessary now that i have refactored the line above - if (this.ENV === 'undefined') { - this.ENV = 'NODEJS'; - } - - //if (typeof (options) !== 'undefined') { - this.configureOptions(options, true); - //} - - this.on('init', this.clearChanges); - - } - - // db class is an EventEmitter - Loki.prototype = new LokiEventEmitter(); - - /** - * configureOptions - allows reconfiguring database options - * - * @param {object} options - configuration options to apply to loki db object - * @param {boolean} initialConfig - (optional) if this is a reconfig, don't pass this - */ - Loki.prototype.configureOptions = function (options, initialConfig) { - var defaultPersistence = { - 'NODEJS': 'fs', - 'BROWSER': 'localStorage', - 'CORDOVA': 'localStorage' - }, - persistenceMethods = { - 'fs': LokiFsAdapter, - 'localStorage': LokiLocalStorageAdapter - }; - - this.options = {}; - - this.persistenceMethod = null; - // retain reference to optional persistence adapter 'instance' - // currently keeping outside options because it can't be serialized - this.persistenceAdapter = null; - - // process the options - if (typeof (options) !== 'undefined') { - this.options = options; - - - if (this.options.hasOwnProperty('persistenceMethod')) { - // check if the specified persistence method is known - if (typeof (persistenceMethods[options.persistenceMethod]) == 'function') { - this.persistenceMethod = options.persistenceMethod; - this.persistenceAdapter = new persistenceMethods[options.persistenceMethod](); - } - // should be throw an error here, or just fall back to defaults ?? - } - - // if user passes adapter, set persistence mode to adapter and retain persistence adapter instance - if (this.options.hasOwnProperty('adapter')) { - this.persistenceMethod = 'adapter'; - this.persistenceAdapter = options.adapter; - } - - - // if they want to load database on loki instantiation, now is a good time to load... after adapter set and before possible autosave initiation - if (options.hasOwnProperty('autoload') && typeof (initialConfig) !== 'undefined' && initialConfig) { - // for autoload, let the constructor complete before firing callback - var self = this; - setTimeout(function () { - self.loadDatabase(options, options.autoloadCallback); - }, 1); - } - - if (this.options.hasOwnProperty('autosaveInterval')) { - this.autosaveDisable(); - this.autosaveInterval = parseInt(this.options.autosaveInterval, 10); - } - - if (this.options.hasOwnProperty('autosave') && this.options.autosave) { - this.autosaveDisable(); - this.autosave = true; - this.autosaveEnable(); - } - } // end of options processing - - // if by now there is no adapter specified by user nor derived from persistenceMethod: use sensible defaults - if (this.persistenceAdapter === null) { - this.persistenceMethod = defaultPersistence[this.ENV]; - if (this.persistenceMethod) { - this.persistenceAdapter = new persistenceMethods[this.persistenceMethod](); - } - } - - }; - - /** - * anonym() - shorthand method for quickly creating and populating an anonymous collection. - * This collection is not referenced internally so upon losing scope it will be garbage collected. - * - * Example : var results = new loki().anonym(myDocArray).find({'age': {'$gt': 30} }); - * - * @param {Array} docs - document array to initialize the anonymous collection with - * @param {Array} indexesArray - (Optional) array of property names to index - * @returns {Collection} New collection which you can query or chain - */ - Loki.prototype.anonym = function (docs, indexesArray) { - var collection = new Collection('anonym', indexesArray); - collection.insert(docs); - return collection; - }; - - Loki.prototype.addCollection = function (name, options) { - var collection = new Collection(name, options); - this.collections.push(collection); - - return collection; - }; - - Loki.prototype.loadCollection = function (collection) { - if (!collection.name) { - throw new Error('Collection must be have a name property to be loaded'); - } - this.collections.push(collection); - }; - - Loki.prototype.getCollection = function (collectionName) { - var i, - len = this.collections.length; - - for (i = 0; i < len; i += 1) { - if (this.collections[i].name === collectionName) { - return this.collections[i]; - } - } - - // no such collection - this.emit('warning', 'collection ' + collectionName + ' not found'); - return null; - }; - - Loki.prototype.listCollections = function () { - - var i = this.collections.length, - colls = []; - - while (i--) { - colls.push({ - name: this.collections[i].name, - type: this.collections[i].objType, - count: this.collections[i].data.length - }); - } - return colls; - }; - - Loki.prototype.removeCollection = function (collectionName) { - var i, - len = this.collections.length; - - for (i = 0; i < len; i += 1) { - if (this.collections[i].name === collectionName) { - this.collections.splice(i, 1); - return; - } - } - }; - - Loki.prototype.getName = function () { - return this.name; - }; - - /** - * serializeReplacer - used to prevent certain properties from being serialized - * - */ - Loki.prototype.serializeReplacer = function (key, value) { - switch (key) { - case 'autosaveHandle': - case 'persistenceAdapter': - case 'constraints': - return null; - default: - return value; - } - }; - - // toJson - Loki.prototype.serialize = function () { - return JSON.stringify(this, this.serializeReplacer); - }; - // alias of serialize - Loki.prototype.toJson = Loki.prototype.serialize; - - /** - * loadJSON - inflates a loki database from a serialized JSON string - * - * @param {string} serializedDb - a serialized loki database string - * @param {object} options - apply or override collection level settings - */ - Loki.prototype.loadJSON = function (serializedDb, options) { - - var obj = JSON.parse(serializedDb), - i = 0, - len = obj.collections.length, - coll, - copyColl, - clen, - j; - - this.name = obj.name; - - // restore database version - this.databaseVersion = 1.0; - if (obj.hasOwnProperty('databaseVersion')) { - this.databaseVersion = obj.databaseVersion; - } - - this.collections = []; - - for (i; i < len; i += 1) { - coll = obj.collections[i]; - copyColl = this.addCollection(coll.name); - - // load each element individually - clen = coll.data.length; - j = 0; - if (options && options.hasOwnProperty(coll.name)) { - - var loader = options[coll.name].inflate ? options[coll.name].inflate : Utils.copyProperties; - - for (j; j < clen; j++) { - var collObj = new(options[coll.name].proto)(); - loader(coll.data[j], collObj); - copyColl.data[j] = collObj; - - } - } else { - - for (j; j < clen; j++) { - copyColl.data[j] = coll.data[j]; - } - } - - copyColl.transactional = coll.transactional; - copyColl.asyncListeners = coll.asyncListeners; - copyColl.disableChangesApi = coll.disableChangesApi; - copyColl.cloneObjects = coll.cloneObjects; - - copyColl.maxId = (coll.data.length === 0) ? 0 : coll.maxId; - copyColl.idIndex = coll.idIndex; - // if saved in previous format recover id index out of it - if (typeof (coll.indices) !== 'undefined') { - copyColl.idIndex = coll.indices.id; - } - if (typeof (coll.binaryIndices) !== 'undefined') { - copyColl.binaryIndices = coll.binaryIndices; - } - - - copyColl.ensureId(); - - // in case they are loading a database created before we added dynamic views, handle undefined - if (typeof (coll.DynamicViews) === 'undefined') continue; - - // reinflate DynamicViews and attached Resultsets - for (var idx = 0; idx < coll.DynamicViews.length; idx++) { - var colldv = coll.DynamicViews[idx]; - - var dv = copyColl.addDynamicView(colldv.name, colldv.persistent); - dv.resultdata = colldv.resultdata; - dv.resultsdirty = colldv.resultsdirty; - dv.filterPipeline = colldv.filterPipeline; - - dv.sortCriteria = colldv.sortCriteria; - dv.sortFunction = null; - - dv.sortDirty = colldv.sortDirty; - dv.resultset.filteredrows = colldv.resultset.filteredrows; - dv.resultset.searchIsChained = colldv.resultset.searchIsChained; - dv.resultset.filterInitialized = colldv.resultset.filterInitialized; - - dv.rematerialize({ - removeWhereFilters: true - }); - } - } - }; - - /** - * close(callback) - emits the close event with an optional callback. Does not actually destroy the db - * but useful from an API perspective - */ - Loki.prototype.close = function (callback) { - // for autosave scenarios, we will let close perform final save (if dirty) - // For web use, you might call from window.onbeforeunload to shutdown database, saving pending changes - if (this.autosave) { - this.autosaveDisable(); - if (this.autosaveDirty()) { - this.saveDatabase(); - } - } - - if (callback) { - this.on('close', callback); - } - this.emit('close'); - }; - - /**-------------------------+ - | Changes API | - +--------------------------*/ - - /** - * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session, - * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db) - */ - - /** - * generateChangesNotification() - takes all the changes stored in each - * collection and creates a single array for the entire database. If an array of names - * of collections is passed then only the included collections will be tracked. - * - * @param {array} optional array of collection names. No arg means all collections are processed. - * @returns {array} array of changes - * @see private method createChange() in Collection - */ - Loki.prototype.generateChangesNotification = function (arrayOfCollectionNames) { - function getCollName(coll) { - return coll.name; - } - var changes = [], - selectedCollections = arrayOfCollectionNames || this.collections.map(getCollName); - - this.collections.forEach(function (coll) { - if (selectedCollections.indexOf(getCollName(coll)) !== -1) { - changes = changes.concat(coll.getChanges()); - } - }); - return changes; - }; - - /** - * serializeChanges() - stringify changes for network transmission - * @returns {string} string representation of the changes - */ - Loki.prototype.serializeChanges = function (collectionNamesArray) { - return JSON.stringify(this.generateChangesNotification(collectionNamesArray)); - }; - - /** - * clearChanges() - clears all the changes in all collections. - */ - Loki.prototype.clearChanges = function () { - this.collections.forEach(function (coll) { - if (coll.flushChanges) { - coll.flushChanges(); - } - }); - }; - - /*------------------+ - | PERSISTENCE | - -------------------*/ - - - /** there are two build in persistence adapters for internal use - * fs for use in Nodejs type environments - * localStorage for use in browser environment - * defined as helper classes here so its easy and clean to use - */ - - /** - * constructor for fs - */ - function LokiFsAdapter() { - this.fs = __webpack_require__(33); - } - - /** - * loadDatabase() - Load data from file, will throw an error if the file does not exist - * @param {string} dbname - the filename of the database to load - * @param {function} callback - the callback to handle the result - */ - LokiFsAdapter.prototype.loadDatabase = function loadDatabase(dbname, callback) { - this.fs.readFile(dbname, { - encoding: 'utf8' - }, function readFileCallback(err, data) { - if (err) { - callback(new Error(err)); - } else { - callback(data); - } - }); - }; - - /** - * saveDatabase() - save data to file, will throw an error if the file can't be saved - * might want to expand this to avoid dataloss on partial save - * @param {string} dbname - the filename of the database to load - * @param {function} callback - the callback to handle the result - */ - LokiFsAdapter.prototype.saveDatabase = function saveDatabase(dbname, dbstring, callback) { - this.fs.writeFile(dbname, dbstring, callback); - }; - - - /** - * constructor for local storage - */ - function LokiLocalStorageAdapter() {} - - /** - * loadDatabase() - Load data from localstorage - * @param {string} dbname - the name of the database to load - * @param {function} callback - the callback to handle the result - */ - LokiLocalStorageAdapter.prototype.loadDatabase = function loadDatabase(dbname, callback) { - if (localStorageAvailable()) { - callback(localStorage.getItem(dbname)); - } else { - callback(new Error('localStorage is not available')); - } - }; - - /** - * saveDatabase() - save data to localstorage, will throw an error if the file can't be saved - * might want to expand this to avoid dataloss on partial save - * @param {string} dbname - the filename of the database to load - * @param {function} callback - the callback to handle the result - */ - LokiLocalStorageAdapter.prototype.saveDatabase = function saveDatabase(dbname, dbstring, callback) { - if (localStorageAvailable()) { - localStorage.setItem(dbname, dbstring); - callback(null); - } else { - callback(new Error('localStorage is not available')); - } - }; - - /** - * loadDatabase - Handles loading from file system, local storage, or adapter (indexeddb) - * This method utilizes loki configuration options (if provided) to determine which - * persistence method to use, or environment detection (if configuration was not provided). - * - * @param {object} options - not currently used (remove or allow overrides?) - * @param {function} callback - (Optional) user supplied async callback / error handler - */ - Loki.prototype.loadDatabase = function (options, callback) { - var cFun = callback || function (err, data) { - if (err) { - throw err; - } - return; - }, - self = this; - - // the persistenceAdapter should be present if all is ok, but check to be sure. - if (this.persistenceAdapter !== null) { - - this.persistenceAdapter.loadDatabase(this.filename, function loadDatabaseCallback(dbString) { - if (typeof (dbString) === 'string') { - self.loadJSON(dbString, options || {}); - cFun(null); - } else { - console.warn('lokijs loadDatabase : Database not found'); - if (typeof (dbString) === "object") { - cFun(dbString); - } else { - cFun('Database not found'); - } - } - }); - - } else { - cFun(new Error('persistenceAdapter not configured')); - } - }; - - /** - * saveDatabase - Handles saving to file system, local storage, or adapter (indexeddb) - * This method utilizes loki configuration options (if provided) to determine which - * persistence method to use, or environment detection (if configuration was not provided). - * - * @param {object} options - not currently used (remove or allow overrides?) - * @param {function} callback - (Optional) user supplied async callback / error handler - */ - Loki.prototype.saveDatabase = function (callback) { - var cFun = callback || function (err) { - if (err) { - throw err; - } - return; - }, - self = this; - - // the persistenceAdapter should be present if all is ok, but check to be sure. - if (this.persistenceAdapter !== null) { - this.persistenceAdapter.saveDatabase(this.filename, self.serialize(), function saveDatabasecallback() { - // for now assume that save went ok and reset dirty flags - // in future we may move this into each if block if no exceptions occur. - self.autosaveClearFlags(); - cFun(null); - }); - } else { - cFun(new Error('persistenceAdapter not configured')); - } - - }; - - // alias - Loki.prototype.save = Loki.prototype.saveDatabase; - - /** - * autosaveDirty - check whether any collections are 'dirty' meaning we need to save (entire) database - * - * @returns {boolean} - true if database has changed since last autosave, false if not. - */ - Loki.prototype.autosaveDirty = function () { - for (var idx = 0; idx < this.collections.length; idx++) { - if (this.collections[idx].dirty) { - return true; - } - } - - return false; - }; - - /** - * autosaveClearFlags - resets dirty flags on all collections. - * Called from saveDatabase() after db is saved. - * - */ - Loki.prototype.autosaveClearFlags = function () { - for (var idx = 0; idx < this.collections.length; idx++) { - this.collections[idx].dirty = false; - } - }; - - /** - * autosaveEnable - begin a javascript interval to periodically save the database. - * - */ - Loki.prototype.autosaveEnable = function () { - this.autosave = true; - - var delay = 5000, - self = this; - - if (typeof (this.autosaveInterval) !== 'undefined' && this.autosaveInterval !== null) { - delay = this.autosaveInterval; - } - - this.autosaveHandle = setInterval(function autosaveHandleInterval() { - // use of dirty flag will need to be hierarchical since mods are done at collection level with no visibility of 'db' - // so next step will be to implement collection level dirty flags set on insert/update/remove - // along with loki level isdirty() function which iterates all collections to see if any are dirty - - if (self.autosaveDirty()) { - self.saveDatabase(); - } - }, delay); - }; - - /** - * autosaveDisable - stop the autosave interval timer. - * - */ - Loki.prototype.autosaveDisable = function () { - if (typeof (this.autosaveHandle) !== 'undefined' && this.autosaveHandle !== null) { - clearInterval(this.autosaveHandle); - this.autosaveHandle = null; - } - }; - - - /** - * Resultset class allowing chainable queries. Intended to be instanced internally. - * Collection.find(), Collection.where(), and Collection.chain() instantiate this. - * - * Example: - * mycollection.chain() - * .find({ 'doors' : 4 }) - * .where(function(obj) { return obj.name === 'Toyota' }) - * .data(); - * - * @constructor - * @param {Collection} collection - The collection which this Resultset will query against. - * @param {string} queryObj - Optional mongo-style query object to initialize resultset with. - * @param {function} queryFunc - Optional javascript filter function to initialize resultset with. - * @param {bool} firstOnly - Optional boolean used by collection.findOne(). - */ - function Resultset(collection, queryObj, queryFunc, firstOnly) { - // retain reference to collection we are querying against - this.collection = collection; - - // if chain() instantiates with null queryObj and queryFunc, so we will keep flag for later - this.searchIsChained = (!queryObj && !queryFunc); - this.filteredrows = []; - this.filterInitialized = false; - - // if user supplied initial queryObj or queryFunc, apply it - if (typeof (queryObj) !== "undefined" && queryObj !== null) { - return this.find(queryObj, firstOnly); - } - if (typeof (queryFunc) !== "undefined" && queryFunc !== null) { - return this.where(queryFunc); - } - - // otherwise return unfiltered Resultset for future filtering - return this; - } - - /** - * toJSON() - Override of toJSON to avoid circular references - * - */ - Resultset.prototype.toJSON = function () { - var copy = this.copy(); - copy.collection = null; - return copy; - }; - - /** - * limit() - Allows you to limit the number of documents passed to next chain operation. - * A resultset copy() is made to avoid altering original resultset. - * - * @param {int} qty - The number of documents to return. - * @returns {Resultset} Returns a copy of the resultset, limited by qty, for subsequent chain ops. - */ - Resultset.prototype.limit = function (qty) { - // if this is chained resultset with no filters applied, we need to populate filteredrows first - if (this.searchIsChained && !this.filterInitialized && this.filteredrows.length === 0) { - this.filteredrows = Object.keys(this.collection.data); - } - - var rscopy = this.copy(); - - rscopy.filteredrows = rscopy.filteredrows.slice(0, qty); - - return rscopy; - }; - - /** - * offset() - Used for skipping 'pos' number of documents in the resultset. - * - * @param {int} pos - Number of documents to skip; all preceding documents are filtered out. - * @returns {Resultset} Returns a copy of the resultset, containing docs starting at 'pos' for subsequent chain ops. - */ - Resultset.prototype.offset = function (pos) { - // if this is chained resultset with no filters applied, we need to populate filteredrows first - if (this.searchIsChained && !this.filterInitialized && this.filteredrows.length === 0) { - this.filteredrows = Object.keys(this.collection.data); - } - - var rscopy = this.copy(); - - rscopy.filteredrows = rscopy.filteredrows.splice(pos, rscopy.filteredrows.length); - - return rscopy; - }; - - /** - * copy() - To support reuse of resultset in branched query situations. - * - * @returns {Resultset} Returns a copy of the resultset (set) but the underlying document references will be the same. - */ - Resultset.prototype.copy = function () { - var result = new Resultset(this.collection, null, null); - - result.filteredrows = this.filteredrows.slice(); - result.filterInitialized = this.filterInitialized; - - return result; - }; - - // add branch() as alias of copy() - Resultset.prototype.branch = Resultset.prototype.copy; - - /** - * sort() - User supplied compare function is provided two documents to compare. (chainable) - * Example: - * rslt.sort(function(obj1, obj2) { - * if (obj1.name === obj2.name) return 0; - * if (obj1.name > obj2.name) return 1; - * if (obj1.name < obj2.name) return -1; - * }); - * - * @param {function} comparefun - A javascript compare function used for sorting. - * @returns {Resultset} Reference to this resultset, sorted, for future chain operations. - */ - Resultset.prototype.sort = function (comparefun) { - // if this is chained resultset with no filters applied, just we need to populate filteredrows first - if (this.searchIsChained && !this.filterInitialized && this.filteredrows.length === 0) { - this.filteredrows = Object.keys(this.collection.data); - } - - var wrappedComparer = - (function (userComparer, rslt) { - return function (a, b) { - var obj1 = rslt.collection.data[a]; - var obj2 = rslt.collection.data[b]; - - return userComparer(obj1, obj2); - }; - })(comparefun, this); - - this.filteredrows.sort(wrappedComparer); - - return this; - }; - - /** - * simplesort() - Simpler, loose evaluation for user to sort based on a property name. (chainable) - * - * @param {string} propname - name of property to sort by. - * @param {bool} isdesc - (Optional) If true, the property will be sorted in descending order - * @returns {Resultset} Reference to this resultset, sorted, for future chain operations. - */ - Resultset.prototype.simplesort = function (propname, isdesc) { - // if this is chained resultset with no filters applied, just we need to populate filteredrows first - if (this.searchIsChained && !this.filterInitialized && this.filteredrows.length === 0) { - this.filteredrows = Object.keys(this.collection.data); - } - - if (typeof (isdesc) === 'undefined') { - isdesc = false; - } - - var wrappedComparer = - (function (prop, desc, rslt) { - return function (a, b) { - var obj1 = rslt.collection.data[a]; - var obj2 = rslt.collection.data[b]; - - return sortHelper(obj1[prop], obj2[prop], desc); - - }; - })(propname, isdesc, this); - - this.filteredrows.sort(wrappedComparer); - - return this; - }; - - /** - * compoundeval() - helper method for compoundsort(), performing individual object comparisons - * - * @param {array} properties - array of property names, in order, by which to evaluate sort order - * @param {object} obj1 - first object to compare - * @param {object} obj2 - second object to compare - * @returns {integer} 0, -1, or 1 to designate if identical (sortwise) or which should be first - */ - Resultset.prototype.compoundeval = function (properties, obj1, obj2) { - var propertyCount = properties.length; - - if (propertyCount === 0) { - throw new Error("Invalid call to compoundeval, need at least one property"); - } - - // decode property, whether just a string property name or subarray [propname, isdesc] - var isdesc = false; - var firstProp = properties[0]; - if (typeof (firstProp) !== 'string') { - if (Array.isArray(firstProp)) { - isdesc = firstProp[1]; - firstProp = firstProp[0]; - } - } - - if (obj1[firstProp] === obj2[firstProp]) { - if (propertyCount === 1) { - return 0; - } else { - return this.compoundeval(properties.slice(1), obj1, obj2, isdesc); - } - } - - return sortHelper(obj1[firstProp], obj2[firstProp], isdesc); - }; - - /** - * compoundsort() - Allows sorting a resultset based on multiple columns. - * Example : rs.compoundsort(['age', 'name']); to sort by age and then name (both ascending) - * Example : rs.compoundsort(['age', ['name', true]); to sort by age (ascending) and then by name (descending) - * - * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order - * @returns {Resultset} Reference to this resultset, sorted, for future chain operations. - */ - Resultset.prototype.compoundsort = function (properties) { - - // if this is chained resultset with no filters applied, just we need to populate filteredrows first - if (this.searchIsChained && !this.filterInitialized && this.filteredrows.length === 0) { - this.filteredrows = Object.keys(this.collection.data); - } - - var wrappedComparer = - (function (props, rslt) { - return function (a, b) { - var obj1 = rslt.collection.data[a]; - var obj2 = rslt.collection.data[b]; - - return rslt.compoundeval(props, obj1, obj2); - }; - })(properties, this); - - this.filteredrows.sort(wrappedComparer); - - return this; - }; - - /** - * calculateRange() - Binary Search utility method to find range/segment of values matching criteria. - * this is used for collection.find() and first find filter of resultset/dynview - * slightly different than get() binary search in that get() hones in on 1 value, - * but we have to hone in on many (range) - * @param {string} op - operation, such as $eq - * @param {string} prop - name of property to calculate range for - * @param {object} val - value to use for range calculation. - * @returns {array} [start, end] index array positions - */ - Resultset.prototype.calculateRange = function (op, prop, val) { - var rcd = this.collection.data; - var index = this.collection.binaryIndices[prop].values; - var min = 0; - var max = index.length - 1; - var mid = null; - var lbound = 0; - var ubound = index.length - 1; - - // when no documents are in collection, return empty range condition - if (rcd.length === 0) { - return [0, -1]; - } - - var minVal = rcd[index[min]][prop]; - var maxVal = rcd[index[max]][prop]; - - // if value falls outside of our range return [0, -1] to designate no results - switch (op) { - case '$eq': - if (ltHelper(val, minVal) || gtHelper(val, maxVal)) { - return [0, -1]; - } - break; - case '$gt': - if (gtHelper(val, maxVal, true)) { - return [0, -1]; - } - break; - case '$gte': - if (gtHelper(val, maxVal)) { - return [0, -1]; - } - break; - case '$lt': - if (ltHelper(val, minVal, true)) { - return [0, -1]; - } - break; - case '$lte': - if (ltHelper(val, minVal)) { - return [0, -1]; - } - break; - } - - // hone in on start position of value - while (min < max) { - mid = Math.floor((min + max) / 2); - - if (ltHelper(rcd[index[mid]][prop], val)) { - min = mid + 1; - } else { - max = mid; - } - } - - lbound = min; - - min = 0; - max = index.length - 1; - - // hone in on end position of value - while (min < max) { - mid = Math.floor((min + max) / 2); - - if (ltHelper(val, rcd[index[mid]][prop])) { - max = mid; - } else { - min = mid + 1; - } - } - - ubound = max; - - var lval = rcd[index[lbound]][prop]; - var uval = rcd[index[ubound]][prop]; - - switch (op) { - case '$eq': - if (lval !== val) { - return [0, -1]; - } - if (uval !== val) { - ubound--; - } - - return [lbound, ubound]; - - case '$gt': - if (ltHelper(uval, val, true)) { - return [0, -1]; - } - - return [ubound, rcd.length - 1]; - - case '$gte': - if (ltHelper(lval, val)) { - return [0, -1]; - } - - return [lbound, rcd.length - 1]; - - case '$lt': - if (lbound === 0 && ltHelper(lval, val)) { - return [0, 0]; - } - return [0, lbound - 1]; - - case '$lte': - if (uval !== val) { - ubound--; - } - - if (ubound === 0 && ltHelper(uval, val)) { - return [0, 0]; - } - return [0, ubound]; - - default: - return [0, rcd.length - 1]; - } - }; - - /** - * findOr() - oversee the operation of OR'ed query expressions. - * OR'ed expression evaluation runs each expression individually against the full collection, - * and finally does a set OR on each expression's results. - * Each evaluation can utilize a binary index to prevent multiple linear array scans. - * - * @param {array} expressionArray - array of expressions - * @returns {Resultset} this resultset for further chain ops. - */ - Resultset.prototype.findOr = function (expressionArray) { - var fri = 0, - ei = 0, - fr = null, - docset = [], - expResultset = null; - - // if filter is already initialized we need to query against only those items already in filter. - // This means no index utilization for fields, so hopefully its filtered to a smallish filteredrows. - if (this.filterInitialized) { - docset = []; - - for (ei = 0; ei < expressionArray.length; ei++) { - // we need to branch existing query to run each filter separately and combine results - expResultset = this.branch(); - expResultset.find(expressionArray[ei]); - expResultset.data(); - - // add any document 'hits' - fr = expResultset.filteredrows; - for (fri = 0; fri < fr.length; fri++) { - if (docset.indexOf(fr[fri]) === -1) { - docset.push(fr[fri]); - } - } - } - - this.filteredrows = docset; - } else { - for (ei = 0; ei < expressionArray.length; ei++) { - // we will let each filter run independently against full collection and mashup document hits later - expResultset = this.collection.chain(); - expResultset.find(expressionArray[ei]); - expResultset.data(); - - // add any document 'hits' - fr = expResultset.filteredrows; - for (fri = 0; fri < fr.length; fri++) { - if (this.filteredrows.indexOf(fr[fri]) === -1) { - this.filteredrows.push(fr[fri]); - } - } - } - } - - this.filterInitialized = true; - - // possibly sort indexes - return this; - }; - - /** - * findAnd() - oversee the operation of AND'ed query expressions. - * AND'ed expression evaluation runs each expression progressively against the full collection, - * internally utilizing existing chained resultset functionality. - * Only the first filter can utilize a binary index. - * - * @param {array} expressionArray - array of expressions - * @returns {Resultset} this resultset for further chain ops. - */ - Resultset.prototype.findAnd = function (expressionArray) { - // we have already implementing method chaining in this (our Resultset class) - // so lets just progressively apply user supplied and filters - for (var i = 0; i < expressionArray.length; i++) { - this.find(expressionArray[i]); - } - - return this; - }; - - /** - * dotSubScan - helper function used for dot notation queries. - */ - Resultset.prototype.dotSubScan = function (root, property, fun, value) { - var arrayRef = null; - var pathIndex, subIndex; - var paths = property.split('.'); - var path; - - for (pathIndex = 0; pathIndex < paths.length; pathIndex++) { - path = paths[pathIndex]; - - // foreach already detected parent was array so this must be where we iterate - if (arrayRef) { - // iterate all sub-array items to see if any yield hits - for (subIndex = 0; subIndex < arrayRef.length; subIndex++) { - if (fun(arrayRef[subIndex][path], value)) { - return true; - } - } - } - // else not yet determined if subarray scan is involved - else { - root = root[path]; - if (Array.isArray(root)) { - arrayRef = root; - } - } - } - - // made it this far so must be dot notation on non-array property - return fun(root, value); - }; - - /** - * find() - Used for querying via a mongo-style query object. - * - * @param {object} query - A mongo-style query object used for filtering current results. - * @param {boolean} firstOnly - (Optional) Used by collection.findOne() - * @returns {Resultset} this resultset for further chain ops. - */ - Resultset.prototype.find = function (query, firstOnly) { - if (this.collection.data.length === 0) { - if (this.searchIsChained) { - this.filteredrows = []; - this.filterInitialized = true; - return this; - } - return []; - } - - - var queryObject = query || 'getAll', - property, - value, - operator, - p, - key, - searchByIndex = false, - result = [], - index = null, - // comparison function - fun, - // collection data - t, - // collection data length - i, - emptyQO = true; - - // if this was note invoked via findOne() - firstOnly = firstOnly || false; - - // if passed in empty object {}, interpret as 'getAll' - // more performant than object.keys - for (p in queryObject) { - emptyQO = false; - break; - } - if (emptyQO) { - queryObject = 'getAll'; - } - - // apply no filters if they want all - if (queryObject === 'getAll') { - // chained queries can just do coll.chain().data() but let's - // be versatile and allow this also coll.chain().find().data() - if (this.searchIsChained) { - this.filteredrows = Object.keys(this.collection.data); - return this; - } - // not chained, so return collection data array - else { - return this.collection.data; - } - } - - // if user is deep querying the object such as find('name.first': 'odin') - var usingDotNotation = false; - - for (p in queryObject) { - if (queryObject.hasOwnProperty(p)) { - property = p; - - // injecting $and and $or expression tree evaluation here. - if (p === '$and') { - if (this.searchIsChained) { - this.findAnd(queryObject[p]); - - // for chained find with firstonly, - if (firstOnly && this.filteredrows.length > 1) { - this.filteredrows = this.filteredrows.slice(0, 1); - } - - return this; - } else { - // our $and operation internally chains filters - result = this.collection.chain().findAnd(queryObject[p]).data(); - - // if this was coll.findOne() return first object or empty array if null - // since this is invoked from a constructor we can't return null, so we will - // make null in coll.findOne(); - if (firstOnly) { - if (result.length === 0) return []; - - return result[0]; - } - - // not first only return all results - return result; - } - } - - if (p === '$or') { - if (this.searchIsChained) { - this.findOr(queryObject[p]); - - if (firstOnly && this.filteredrows.length > 1) { - this.filteredrows = this.filteredrows.slice(0, 1); - } - - return this; - } else { - // call out to helper function to determine $or results - result = this.collection.chain().findOr(queryObject[p]).data(); - - if (firstOnly) { - if (result.length === 0) return []; - - return result[0]; - } - - // not first only return all results - return result; - } - } - - if (p.indexOf('.') != -1) { - usingDotNotation = true; - } - if (typeof queryObject[p] !== 'object') { - operator = '$eq'; - value = queryObject[p]; - } else if (typeof queryObject[p] === 'object') { - for (key in queryObject[p]) { - if (queryObject[p].hasOwnProperty(key)) { - operator = key; - value = queryObject[p][key]; - } - } - } else { - throw 'Do not know what you want to do.'; - } - break; - } - } - - // for regex ops, precompile - if (operator === '$regex') value = new RegExp(value); - - if (this.collection.data === null) { - throw new TypeError(); - } - - // if an index exists for the property being queried against, use it - // for now only enabling for non-chained query (who's set of docs matches index) - // or chained queries where it is the first filter applied and prop is indexed - if ((!this.searchIsChained || (this.searchIsChained && !this.filterInitialized)) && - operator !== '$ne' && operator !== '$regex' && operator !== '$contains' && operator !== '$containsAny' && operator !== '$in' && this.collection.binaryIndices.hasOwnProperty(property)) { - // this is where our lazy index rebuilding will take place - // basically we will leave all indexes dirty until we need them - // so here we will rebuild only the index tied to this property - // ensureIndex() will only rebuild if flagged as dirty since we are not passing force=true param - this.collection.ensureIndex(property); - - searchByIndex = true; - index = this.collection.binaryIndices[property]; - } - - // the comparison function - fun = operators[operator]; - - // Query executed differently depending on : - // - whether it is chained or not - // - whether the property being queried has an index defined - // - if chained, we handle first pass differently for initial filteredrows[] population - // - // For performance reasons, each case has its own if block to minimize in-loop calculations - - // If not a chained query, bypass filteredrows and work directly against data - if (!this.searchIsChained) { - if (!searchByIndex) { - t = this.collection.data; - i = t.length; - - if (firstOnly) { - while (i--) { - if (fun(t[i][property], value)) { - return (t[i]); - } - } - - return []; - } else { - // if using dot notation then treat property as keypath such as 'name.first'. - // currently supporting dot notation for non-indexed conditions only - if (usingDotNotation) { - while (i--) { - if (this.dotSubScan(t[i], property, fun, value)) { - result.push(t[i]); - } - } - } else { - while (i--) { - if (fun(t[i][property], value)) { - result.push(t[i]); - } - } - } - } - } else { - // searching by binary index via calculateRange() utility method - t = this.collection.data; - - var seg = this.calculateRange(operator, property, value, this); - - // not chained so this 'find' was designated in Resultset constructor - // so return object itself - if (firstOnly) { - if (seg[1] !== -1) { - return t[index.values[seg[0]]]; - } - - return []; - } - - for (i = seg[0]; i <= seg[1]; i++) { - result.push(t[index.values[i]]); - } - - this.filteredrows = result; - } - - // not a chained query so return result as data[] - return result; - } - // Otherwise this is a chained query - else { - // If the filteredrows[] is already initialized, use it - if (this.filterInitialized) { - // not searching by index - if (!searchByIndex) { - t = this.collection.data; - i = this.filteredrows.length; - - // currently supporting dot notation for non-indexed conditions only - if (usingDotNotation) { - while (i--) { - if (this.dotSubScan(t[this.filteredrows[i]], property, fun, value)) { - result.push(this.filteredrows[i]); - } - } - } else { - while (i--) { - if (fun(t[this.filteredrows[i]][property], value)) { - result.push(this.filteredrows[i]); - } - } - } - } else { - // search by index - t = index; - i = this.filteredrows.length; - while (i--) { - if (fun(t[this.filteredrows[i]], value)) { - result.push(this.filteredrows[i]); - } - } - } - - this.filteredrows = result; - - return this; - } - // first chained query so work against data[] but put results in filteredrows - else { - // if not searching by index - if (!searchByIndex) { - t = this.collection.data; - i = t.length; - - if (usingDotNotation) { - while (i--) { - if (this.dotSubScan(t[i], property, fun, value)) { - result.push(i); - } - } - } else { - while (i--) { - if (fun(t[i][property], value)) { - result.push(i); - } - } - } - } else { - // search by index - t = this.collection.data; - var segm = this.calculateRange(operator, property, value, this); - - for (var idx = segm[0]; idx <= segm[1]; idx++) { - result.push(index.values[idx]); - } - - this.filteredrows = result; - } - - this.filteredrows = result; - this.filterInitialized = true; // next time work against filteredrows[] - - return this; - } - - } - }; - - - /** - * where() - Used for filtering via a javascript filter function. - * - * @param {function} fun - A javascript function used for filtering current results by. - * @returns {Resultset} this resultset for further chain ops. - */ - Resultset.prototype.where = function (fun) { - - var viewFunction, - result = []; - - if ('function' === typeof fun) { - viewFunction = fun; - } else { - throw 'Argument is not a stored view or a function'; - } - try { - // if not a chained query then run directly against data[] and return object [] - if (!this.searchIsChained) { - var i = this.collection.data.length; - - while (i--) { - if (viewFunction(this.collection.data[i]) === true) { - result.push(this.collection.data[i]); - } - } - - // not a chained query so returning result as data[] - return result; - } - // else chained query, so run against filteredrows - else { - // If the filteredrows[] is already initialized, use it - if (this.filterInitialized) { - var j = this.filteredrows.length; - - while (j--) { - if (viewFunction(this.collection.data[this.filteredrows[j]]) === true) { - result.push(this.filteredrows[j]); - } - } - - this.filteredrows = result; - - return this; - } - // otherwise this is initial chained op, work against data, push into filteredrows[] - else { - var k = this.collection.data.length; - - while (k--) { - if (viewFunction(this.collection.data[k]) === true) { - result.push(k); - } - } - - this.filteredrows = result; - this.filterInitialized = true; - - return this; - } - } - } catch (err) { - throw err; - } - }; - - /** - * data() - Terminates the chain and returns array of filtered documents - * - * @returns {array} Array of documents in the resultset - */ - Resultset.prototype.data = function () { - var result = []; - - // if this is chained resultset with no filters applied, just return collection.data - if (this.searchIsChained && !this.filterInitialized) { - if (this.filteredrows.length === 0) { - return this.collection.data; - } else { - // filteredrows must have been set manually, so use it - this.filterInitialized = true; - } - } - - var data = this.collection.data, - fr = this.filteredrows; - - var i, - len = this.filteredrows.length; - - for (i = 0; i < len; i++) { - result.push(data[fr[i]]); - } - return result; - }; - - /** - * update() - used to run an update operation on all documents currently in the resultset. - * - * @param {function} updateFunction - User supplied updateFunction(obj) will be executed for each document object. - * @returns {Resultset} this resultset for further chain ops. - */ - Resultset.prototype.update = function (updateFunction) { - - if (typeof (updateFunction) !== "function") { - throw 'Argument is not a function'; - } - - // if this is chained resultset with no filters applied, we need to populate filteredrows first - if (this.searchIsChained && !this.filterInitialized && this.filteredrows.length === 0) { - this.filteredrows = Object.keys(this.collection.data); - } - - var len = this.filteredrows.length, - rcd = this.collection.data; - - for (var idx = 0; idx < len; idx++) { - // pass in each document object currently in resultset to user supplied updateFunction - updateFunction(rcd[this.filteredrows[idx]]); - - // notify collection we have changed this object so it can update meta and allow DynamicViews to re-evaluate - this.collection.update(rcd[this.filteredrows[idx]]); - } - - return this; - }; - - /** - * remove() - removes all document objects which are currently in resultset from collection (as well as resultset) - * - * @returns {Resultset} this (empty) resultset for further chain ops. - */ - Resultset.prototype.remove = function () { - - // if this is chained resultset with no filters applied, we need to populate filteredrows first - if (this.searchIsChained && !this.filterInitialized && this.filteredrows.length === 0) { - this.filteredrows = Object.keys(this.collection.data); - } - - var len = this.filteredrows.length; - - for (var idx = 0; idx < len; idx++) { - this.collection.remove(this.filteredrows[idx]); - } - - this.filteredrows = []; - - return this; - }; - - /** - * mapReduce() - data transformation via user supplied functions - * - * @param {function} mapFunction - this function accepts a single document for you to transform and return - * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value - * @returns The output of your reduceFunction - */ - Resultset.prototype.mapReduce = function (mapFunction, reduceFunction) { - try { - return reduceFunction(this.data().map(mapFunction)); - } catch (err) { - throw err; - } - }; - - /** - * eqJoin() - Left joining two sets of data. Join keys can be defined or calculated properties - * eqJoin expects the right join key values to be unique. Otherwise left data will be joined on the last joinData object with that key - * @param {Array} joinData - Data array to join to. - * @param {String,function} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on - * @param {String,function} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on - * @param {function} (optional) mapFun - A function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject} - * @returns {Resultset} A resultset with data in the format [{left: leftObj, right: rightObj}] - */ - Resultset.prototype.eqJoin = function (joinData, leftJoinKey, rightJoinKey, mapFun) { - - var leftData = [], - leftDataLength, - rightData = [], - rightDataLength, - key, - result = [], - obj, - leftKeyisFunction = typeof leftJoinKey === 'function', - rightKeyisFunction = typeof rightJoinKey === 'function', - joinMap = {}; - - //get the left data - leftData = this.data(); - leftDataLength = leftData.length; - - //get the right data - if (joinData instanceof Resultset) { - rightData = joinData.data(); - } else if (Array.isArray(joinData)) { - rightData = joinData; - } else { - throw new TypeError('joinData needs to be an array or result set'); - } - rightDataLength = rightData.length; - - //construct a lookup table - - for (var i = 0; i < rightDataLength; i++) { - key = rightKeyisFunction ? rightJoinKey(rightData[i]) : rightData[i][rightJoinKey]; - joinMap[key] = rightData[i]; - } - - if (!mapFun) { - mapFun = function (left, right) { - return { - left: left, - right: right - }; - }; - } - - //Run map function over each object in the resultset - for (var j = 0; j < leftDataLength; j++) { - key = leftKeyisFunction ? leftJoinKey(leftData[j]) : leftData[j][leftJoinKey]; - result.push(mapFun(leftData[j], joinMap[key] || {})); - } - - //return return a new resultset with no filters - this.collection = new Collection('joinData'); - this.collection.insert(result); - this.filteredrows = []; - this.filterInitialized = false; - - return this; - }; - - Resultset.prototype.map = function (mapFun) { - var data = this.data().map(mapFun); - //return return a new resultset with no filters - this.collection = new Collection('mappedData'); - this.collection.insert(data); - this.filteredrows = []; - this.filterInitialized = false; - - return this; - }; - - /** - * DynamicView class is a versatile 'live' view class which can have filters and sorts applied. - * Collection.addDynamicView(name) instantiates this DynamicView object and notifies it - * whenever documents are add/updated/removed so it can remain up-to-date. (chainable) - * - * Examples: - * var mydv = mycollection.addDynamicView('test'); // default is non-persistent - * mydv.applyWhere(function(obj) { return obj.name === 'Toyota'; }); - * mydv.applyFind({ 'doors' : 4 }); - * var results = mydv.data(); - * - * @constructor - * @param {Collection} collection - A reference to the collection to work against - * @param {string} name - The name of this dynamic view - * @param {boolean} persistent - (Optional) If true, the results will be copied into an internal array for read efficiency or binding to. - */ - function DynamicView(collection, name, persistent) { - this.collection = collection; - this.name = name; - - this.persistent = false; - if (typeof (persistent) !== 'undefined') this.persistent = persistent; - - this.resultset = new Resultset(collection); - this.resultdata = []; - this.resultsdirty = false; - - this.cachedresultset = null; - - // keep ordered filter pipeline - this.filterPipeline = []; - - // sorting member variables - // we only support one active search, applied using applySort() or applySimpleSort() - this.sortFunction = null; - this.sortCriteria = null; - this.sortDirty = false; - - // for now just have 1 event for when we finally rebuilt lazy view - // once we refactor transactions, i will tie in certain transactional events - - this.events = { - 'rebuild': [] - }; - } - - DynamicView.prototype = new LokiEventEmitter(); - - - /** - * rematerialize() - intended for use immediately after deserialization (loading) - * This will clear out and reapply filterPipeline ops, recreating the view. - * Since where filters do not persist correctly, this method allows - * restoring the view to state where user can re-apply those where filters. - * - * @param {Object} options - (Optional) allows specification of 'removeWhereFilters' option - * @returns {DynamicView} This dynamic view for further chained ops. - */ - DynamicView.prototype.rematerialize = function (options) { - var fpl, - fpi, - idx; - - options = options || {}; - - this.resultdata = []; - this.resultsdirty = true; - this.resultset = new Resultset(this.collection); - - if (this.sortFunction || this.sortCriteria) { - this.sortDirty = true; - } - - if (options.hasOwnProperty('removeWhereFilters')) { - // for each view see if it had any where filters applied... since they don't - // serialize those functions lets remove those invalid filters - fpl = this.filterPipeline.length; - fpi = fpl; - while (fpi--) { - if (this.filterPipeline[fpi].type === 'where') { - if (fpi !== this.filterPipeline.length - 1) { - this.filterPipeline[fpi] = this.filterPipeline[this.filterPipeline.length - 1]; - } - - this.filterPipeline.length--; - } - } - } - - // back up old filter pipeline, clear filter pipeline, and reapply pipeline ops - var ofp = this.filterPipeline; - this.filterPipeline = []; - - // now re-apply 'find' filterPipeline ops - fpl = ofp.length; - for (idx = 0; idx < fpl; idx++) { - this.applyFind(ofp[idx].val); - } - - // during creation of unit tests, i will remove this forced refresh and leave lazy - this.data(); - - // emit rebuild event in case user wants to be notified - this.emit('rebuild', this); - - return this; - }; - - /** - * branchResultset() - Makes a copy of the internal resultset for branched queries. - * Unlike this dynamic view, the branched resultset will not be 'live' updated, - * so your branched query should be immediately resolved and not held for future evaluation. - * - * @returns {Resultset} A copy of the internal resultset for branched queries. - */ - DynamicView.prototype.branchResultset = function () { - return this.resultset.copy(); - }; - - /** - * toJSON() - Override of toJSON to avoid circular references - * - */ - DynamicView.prototype.toJSON = function () { - var copy = new DynamicView(this.collection, this.name, this.persistent); - - copy.resultset = this.resultset; - copy.resultdata = []; // let's not save data (copy) to minimize size - copy.resultsdirty = true; - copy.filterPipeline = this.filterPipeline; - copy.sortFunction = this.sortFunction; - copy.sortCriteria = this.sortCriteria; - copy.sortDirty = this.sortDirty; - - // avoid circular reference, reapply in db.loadJSON() - copy.collection = null; - - return copy; - }; - - /** - * applySort() - Used to apply a sort to the dynamic view - * - * @param {function} comparefun - a javascript compare function used for sorting - * @returns {DynamicView} this DynamicView object, for further chain ops. - */ - DynamicView.prototype.applySort = function (comparefun) { - this.sortFunction = comparefun; - this.sortCriteria = null; - - this.queueSortPhase(); - - return this; - }; - - /** - * applySimpleSort() - Used to specify a property used for view translation. - * - * @param {string} propname - Name of property by which to sort. - * @param {boolean} isdesc - (Optional) If true, the sort will be in descending order. - * @returns {DynamicView} this DynamicView object, for further chain ops. - */ - DynamicView.prototype.applySimpleSort = function (propname, isdesc) { - - if (typeof (isdesc) === 'undefined') { - isdesc = false; - } - - this.sortCriteria = [ - [propname, isdesc] - ]; - this.sortFunction = null; - - this.queueSortPhase(); - - return this; - }; - - /** - * applySortCriteria() - Allows sorting a resultset based on multiple columns. - * Example : dv.applySortCriteria(['age', 'name']); to sort by age and then name (both ascending) - * Example : dv.applySortCriteria(['age', ['name', true]); to sort by age (ascending) and then by name (descending) - * Example : dv.applySortCriteria(['age', true], ['name', true]); to sort by age (descending) and then by name (descending) - * - * @param {array} properties - array of property names or subarray of [propertyname, isdesc] used evaluate sort order - * @returns {DynamicView} Reference to this DynamicView, sorted, for future chain operations. - */ - DynamicView.prototype.applySortCriteria = function (criteria) { - this.sortCriterial = criteria; - this.sortFunction = null; - - this.queueSortPhase(); - - return this; - }; - - /** - * startTransaction() - marks the beginning of a transaction. - * - * @returns {DynamicView} this DynamicView object, for further chain ops. - */ - DynamicView.prototype.startTransaction = function () { - this.cachedresultset = this.resultset.copy(); - - return this; - }; - - /** - * commit() - commits a transaction. - * - * @returns {DynamicView} this DynamicView object, for further chain ops. - */ - DynamicView.prototype.commit = function () { - this.cachedresultset = null; - - return this; - }; - - /** - * rollback() - rolls back a transaction. - * - * @returns {DynamicView} this DynamicView object, for further chain ops. - */ - DynamicView.prototype.rollback = function () { - this.resultset = this.cachedresultset; - - if (this.persistent) { - // for now just rebuild the persistent dynamic view data in this worst case scenario - // (a persistent view utilizing transactions which get rolled back), we already know the filter so not too bad. - this.resultdata = this.resultset.data(); - - this.emit('rebuild', this); - } - - return this; - }; - - /** - * applyFind() - Adds a mongo-style query option to the DynamicView filter pipeline - * - * @param {object} query - A mongo-style query object to apply to pipeline - * @returns {DynamicView} this DynamicView object, for further chain ops. - */ - DynamicView.prototype.applyFind = function (query) { - this.filterPipeline.push({ - type: 'find', - val: query - }); - - // Apply immediately to Resultset; if persistent we will wait until later to build internal data - this.resultset.find(query); - - if (this.sortFunction || this.sortCriteria) { - this.sortDirty = true; - this.queueSortPhase(); - } - - if (this.persistent) { - this.resultsdirty = true; - this.queueSortPhase(); - } - - return this; - }; - - /** - * applyWhere() - Adds a javascript filter function to the DynamicView filter pipeline - * - * @param {function} fun - A javascript filter function to apply to pipeline - * @returns {DynamicView} this DynamicView object, for further chain ops. - */ - DynamicView.prototype.applyWhere = function (fun) { - this.filterPipeline.push({ - type: 'where', - val: fun - }); - - // Apply immediately to Resultset; if persistent we will wait until later to build internal data - this.resultset.where(fun); - - if (this.sortFunction || this.sortCriteria) { - this.sortDirty = true; - this.queueSortPhase(); - } - if (this.persistent) { - this.resultsdirty = true; - this.queueSortPhase(); - } - return this; - }; - - /** - * data() - resolves and pending filtering and sorting, then returns document array as result. - * - * @returns {array} An array of documents representing the current DynamicView contents. - */ - DynamicView.prototype.data = function () { - // using final sort phase as 'catch all' for a few use cases which require full rebuild - if (this.sortDirty || this.resultsdirty || !this.resultset.filterInitialized) { - this.performSortPhase(); - } - - if (!this.persistent) { - return this.resultset.data(); - } - - return this.resultdata; - }; - - /** - * - */ - DynamicView.prototype.queueSortPhase = function () { - var self = this; - - // already queued? exit without queuing again - if (this.sortDirty) { - return; - } - - this.sortDirty = true; - - // queue async call to performSortPhase() - setTimeout(function () { - self.performSortPhase(); - }, 1); - }; - - /** - * performSortPhase() - invoked synchronously or asynchronously to perform final sort phase (if needed) - * - */ - DynamicView.prototype.performSortPhase = function () { - // async call to this may have been pre-empted by synchronous call to data before async could fire - if (!this.sortDirty && !this.resultsdirty && this.resultset.filterInitialized) { - return; - } - - if (this.sortFunction) { - this.resultset.sort(this.sortFunction); - } - - if (this.sortCriteria) { - this.resultset.compoundsort(this.sortCriteria); - } - - if (!this.persistent) { - this.sortDirty = false; - return; - } - - // persistent view, rebuild local resultdata array - this.resultdata = this.resultset.data(); - this.resultsdirty = false; - this.sortDirty = false; - - this.emit('rebuild', this); - }; - - /** - * evaluateDocument() - internal method for (re)evaluating document inclusion. - * Called by : collection.insert() and collection.update(). - * - * @param {int} objIndex - index of document to (re)run through filter pipeline. - */ - DynamicView.prototype.evaluateDocument = function (objIndex) { - var ofr = this.resultset.filteredrows; - var oldPos = ofr.indexOf(objIndex); - var oldlen = ofr.length; - - // creating a 1-element resultset to run filter chain ops on to see if that doc passes filters; - // mostly efficient algorithm, slight stack overhead price (this function is called on inserts and updates) - var evalResultset = new Resultset(this.collection); - evalResultset.filteredrows = [objIndex]; - evalResultset.filterInitialized = true; - for (var idx = 0; idx < this.filterPipeline.length; idx++) { - switch (this.filterPipeline[idx].type) { - case 'find': - evalResultset.find(this.filterPipeline[idx].val); - break; - case 'where': - evalResultset.where(this.filterPipeline[idx].val); - break; - } - } - - // not a true position, but -1 if not pass our filter(s), 0 if passed filter(s) - var newPos = (evalResultset.filteredrows.length === 0) ? -1 : 0; - - // wasn't in old, shouldn't be now... do nothing - if (oldPos == -1 && newPos == -1) return; - - // wasn't in resultset, should be now... add - if (oldPos === -1 && newPos !== -1) { - ofr.push(objIndex); - - if (this.persistent) { - this.resultdata.push(this.collection.data[objIndex]); - } - - // need to re-sort to sort new document - if (this.sortFunction || this.sortCriteria) { - this.queueSortPhase(); - } - - return; - } - - // was in resultset, shouldn't be now... delete - if (oldPos !== -1 && newPos === -1) { - if (oldPos < oldlen - 1) { - // http://dvolvr.davidwaterston.com/2013/06/09/restating-the-obvious-the-fastest-way-to-truncate-an-array-in-javascript/comment-page-1/ - ofr[oldPos] = ofr[oldlen - 1]; - ofr.length = oldlen - 1; - - if (this.persistent) { - this.resultdata[oldPos] = this.resultdata[oldlen - 1]; - this.resultdata.length = oldlen - 1; - } - } else { - ofr.length = oldlen - 1; - - if (this.persistent) { - this.resultdata.length = oldlen - 1; - } - } - - // in case changes to data altered a sort column - if (this.sortFunction || this.sortCriteria) { - this.queueSortPhase(); - } - - return; - } - - // was in resultset, should still be now... (update persistent only?) - if (oldPos !== -1 && newPos !== -1) { - if (this.persistent) { - // in case document changed, replace persistent view data with the latest collection.data document - this.resultdata[oldPos] = this.collection.data[objIndex]; - } - - // in case changes to data altered a sort column - if (this.sortFunction || this.sortCriteria) { - this.sortDirty = true; - } - - return; - } - }; - - /** - * removeDocument() - internal function called on collection.delete() - */ - DynamicView.prototype.removeDocument = function (objIndex) { - var ofr = this.resultset.filteredrows; - var oldPos = ofr.indexOf(objIndex); - var oldlen = ofr.length; - var idx; - - if (oldPos !== -1) { - // if not last row in resultdata, swap last to hole and truncate last row - if (oldPos < oldlen - 1) { - ofr[oldPos] = ofr[oldlen - 1]; - ofr.length = oldlen - 1; - - if (this.persistent) { - this.resultdata[oldPos] = this.resultdata[oldlen - 1]; - this.resultdata.length = oldlen - 1; - } - } - // last row, so just truncate last row - else { - ofr.length = oldlen - 1; - - if (this.persistent) { - this.resultdata.length = oldlen - 1; - } - } - - // in case changes to data altered a sort column - if (this.sortFunction || this.sortCriteria) { - this.queueSortPhase(); - } - } - - // since we are using filteredrows to store data array positions - // if they remove a document (whether in our view or not), - // we need to adjust array positions -1 for all document array references after that position - oldlen = ofr.length; - for (idx = 0; idx < oldlen; idx++) { - if (ofr[idx] > objIndex) { - ofr[idx] --; - } - } - }; - - /** - * mapReduce() - data transformation via user supplied functions - * - * @param {function} mapFunction - this function accepts a single document for you to transform and return - * @param {function} reduceFunction - this function accepts many (array of map outputs) and returns single value - * @returns The output of your reduceFunction - */ - DynamicView.prototype.mapReduce = function (mapFunction, reduceFunction) { - try { - return reduceFunction(this.data().map(mapFunction)); - } catch (err) { - throw err; - } - }; - - - /** - * @constructor - * Collection class that handles documents of same type - * @param {stirng} collection name - * @param {array} array of property names to be indicized - * @param {object} configuration object - */ - function Collection(name, options) { - // the name of the collection - - this.name = name; - // the data held by the collection - this.data = []; - this.idIndex = []; // index of id - this.binaryIndices = {}; // user defined indexes - this.constraints = { - unique: {}, - exact: {} - }; - - // the object type of the collection - this.objType = name; - - // in autosave scenarios we will use collection level dirty flags to determine whether save is needed. - // currently, if any collection is dirty we will autosave the whole database if autosave is configured. - // defaulting to true since this is called from addCollection and adding a collection should trigger save - this.dirty = true; - - // private holders for cached data - this.cachedIndex = null; - this.cachedBinaryIndex = null; - this.cachedData = null; - var self = this; - - /* OPTIONS */ - options = options || {}; - - // exact match and unique constraints - if (options.hasOwnProperty('unique')) { - if (!Array.isArray(options.unique)) { - options.unique = [options.unique]; - } - options.unique.forEach(function (prop) { - self.constraints.unique[prop] = new UniqueIndex(prop); - }); - } - - if (options.hasOwnProperty('exact')) { - options.exact.forEach(function (prop) { - self.constraints.exact[prop] = new ExactIndex(prop); - }); - } - - // is collection transactional - this.transactional = options.hasOwnProperty('transactional') ? options.transactional : false; - - // options to clone objects when inserting them - this.cloneObjects = options.hasOwnProperty('clone') ? options.clone : false; - - // option to make event listeners async, default is sync - this.asyncListeners = options.hasOwnProperty('asyncListeners') ? options.asyncListeners : false; - - // disable track changes - this.disableChangesApi = options.hasOwnProperty('disableChangesApi') ? options.disableChangesApi : true; - - - // currentMaxId - change manually at your own peril! - this.maxId = 0; - - this.DynamicViews = []; - - // events - this.events = { - 'insert': [], - 'update': [], - 'pre-insert': [], - 'pre-update': [], - 'close': [], - 'flushbuffer': [], - 'error': [], - 'delete': [], - 'warning': [] - }; - - // changes are tracked by collection and aggregated by the db - this.changes = []; - - // initialize the id index - this.ensureId(); - var indices = []; - // initialize optional user-supplied indices array ['age', 'lname', 'zip'] - //if (typeof (indices) !== 'undefined') { - if (options && options.indices) { - if (Object.prototype.toString.call(options.indices) === '[object Array]') { - indices = options.indices; - } else if (typeof options.indices === 'string') { - indices = [options.indices]; - } else { - throw new TypeError('Indices needs to be a string or an array of strings'); - } - } - - for (var idx = 0; idx < indices.length; idx++) { - this.ensureIndex(indices[idx]); - } - - /** - * This method creates a clone of the current status of an object and associates operation and collection name, - * so the parent db can aggregate and generate a changes object for the entire db - */ - function createChange(name, op, obj) { - self.changes.push({ - name: name, - operation: op, - obj: JSON.parse(JSON.stringify(obj)) - }); - } - - // clear all the changes - function flushChanges() { - self.changes = []; - } - - this.getChanges = function () { - return self.changes; - }; - - this.flushChanges = flushChanges; - - /** - * If the changes API is disabled make sure only metadata is added without re-evaluating everytime if the changesApi is enabled - */ - function insertMeta(obj) { - if (!obj) { - return; - } - if (!obj.meta) { - obj.meta = {}; - } - - obj.meta.created = (new Date()).getTime(); - obj.meta.revision = 0; - } - - function updateMeta(obj) { - if (!obj) { - return; - } - obj.meta.updated = (new Date()).getTime(); - obj.meta.revision += 1; - } - - function createInsertChange(obj) { - createChange(self.name, 'I', obj); - } - - function createUpdateChange(obj) { - createChange(self.name, 'U', obj); - } - - function insertMetaWithChange(obj) { - insertMeta(obj); - createInsertChange(obj); - } - - function updateMetaWithChange(obj) { - updateMeta(obj); - createUpdateChange(obj); - } - - - /* assign correct handler based on ChangesAPI flag */ - var insertHandler, updateHandler; - - function setHandlers() { - insertHandler = self.disableChangesApi ? insertMeta : insertMetaWithChange; - updateHandler = self.disableChangesApi ? updateMeta : updateMetaWithChange; - } - - setHandlers(); - - this.setChangesApi = function (enabled) { - self.disableChangesApi = !enabled; - setHandlers(); - }; - /** - * built-in events - */ - this.on('insert', function insertCallback(obj) { - insertHandler(obj); - }); - - this.on('update', function updateCallback(obj) { - updateHandler(obj); - }); - - this.on('delete', function deleteCallback(obj) { - if (!self.disableChangesApi) { - createChange(self.name, 'R', obj); - } - }); - - this.on('warning', console.warn); - // for de-serialization purposes - flushChanges(); - } - - Collection.prototype = new LokiEventEmitter(); - - Collection.prototype.byExample = function(template) { - var k, obj, query; - query = []; - for (k in template) { - if (!template.hasOwnProperty(k)) continue; - query.push(( - obj = {}, - obj[k] = template[k], - obj - )); - } - return { '$and': query }; - }; - - Collection.prototype.findObject = function(template) { return this.findOne(this.byExample(template)); }; - - Collection.prototype.findObjects = function(template) { return this.find(this.byExample(template)); }; - - /*----------------------------+ - | INDEXING | - +----------------------------*/ - - /** - * Ensure binary index on a certain field - */ - Collection.prototype.ensureIndex = function (property, force) { - // optional parameter to force rebuild whether flagged as dirty or not - if (typeof (force) === 'undefined') { - force = false; - } - - if (property === null || property === undefined) { - throw 'Attempting to set index without an associated property'; - } - - if (this.binaryIndices.hasOwnProperty(property) && !force) { - if (!this.binaryIndices[property].dirty) return; - } - - this.binaryIndices[property] = { - 'name': property, - 'dirty': true, - 'values': [] - }; - - var index, len = this.data.length, - i = 0; - - index = this.binaryIndices[property]; - - // initialize index values - for (i; i < len; i += 1) { - index.values.push(i); - } - - var wrappedComparer = - (function (prop, coll) { - return function (a, b) { - var obj1 = coll.data[a]; - var obj2 = coll.data[b]; - - if (obj1[prop] === obj2[prop]) return 0; - if (gtHelper(obj1[prop], obj2[prop])) return 1; - if (ltHelper(obj1[prop], obj2[prop])) return -1; - }; - })(property, this); - - index.values.sort(wrappedComparer); - index.dirty = false; - - this.dirty = true; // for autosave scenarios - }; - - Collection.prototype.ensureUniqueIndex = function (field) { - - var index = this.constraints.unique[field]; - if (!index) { - this.constraints.unique[field] = index = new UniqueIndex(field); - } - var self = this; - this.data.forEach(function (obj) { - index.set(obj); - }); - return index; - }; - - /** - * Ensure all binary indices - */ - Collection.prototype.ensureAllIndexes = function (force) { - var objKeys = Object.keys(this.binaryIndices); - - var i = objKeys.length; - while (i--) { - this.ensureIndex(objKeys[i], force); - } - }; - - Collection.prototype.flagBinaryIndexesDirty = function () { - var objKeys = Object.keys(this.binaryIndices); - - var i = objKeys.length; - while (i--) { - this.binaryIndices[objKeys[i]].dirty = true; - } - }; - - Collection.prototype.count = function () { - return this.data.length; - }; - - /** - * Rebuild idIndex - */ - Collection.prototype.ensureId = function () { - - var len = this.data.length, - i = 0; - - this.idIndex = []; - for (i; i < len; i += 1) { - this.idIndex.push(this.data[i].$loki); - } - }; - - /** - * Rebuild idIndex async with callback - useful for background syncing with a remote server - */ - Collection.prototype.ensureIdAsync = function (callback) { - this.async(function () { - this.ensureId(); - }, callback); - }; - - /** - * Each collection maintains a list of DynamicViews associated with it - **/ - - Collection.prototype.addDynamicView = function (name, persistent) { - var dv = new DynamicView(this, name, persistent); - this.DynamicViews.push(dv); - - return dv; - }; - - Collection.prototype.removeDynamicView = function (name) { - for (var idx = 0; idx < this.DynamicViews.length; idx++) { - if (this.DynamicViews[idx].name === name) { - this.DynamicViews.splice(idx, 1); - } - } - }; - - Collection.prototype.getDynamicView = function (name) { - for (var idx = 0; idx < this.DynamicViews.length; idx++) { - if (this.DynamicViews[idx].name === name) { - return this.DynamicViews[idx]; - } - } - - return null; - }; - - /** - * find and update: pass a filtering function to select elements to be updated - * and apply the updatefunctino to those elements iteratively - */ - Collection.prototype.findAndUpdate = function (filterFunction, updateFunction) { - - var results = this.where(filterFunction), - i = 0, - obj; - try { - for (i; i < results.length; i++) { - obj = updateFunction(results[i]); - this.update(obj); - } - - } catch (err) { - this.rollback(); - console.error(err.message); - } - }; - - /** - * generate document method - ensure objects have id and objType properties - * @param {object} the document to be inserted (or an array of objects) - * @returns document or documents (if passed an array of objects) - */ - Collection.prototype.insert = function (doc) { - - if (!doc) { - var error = new Error('Object cannot be null'); - this.emit('error', error); - throw error; - } - - var self = this; - // holder to the clone of the object inserted if collections is set to clone objects - var obj; - var docs = Array.isArray(doc) ? doc : [doc]; - var results = []; - docs.forEach(function (d) { - if (typeof d !== 'object') { - throw new TypeError('Document needs to be an object'); - } - - obj = self.cloneObjects ? JSON.parse(JSON.stringify(d)) : d; - if (typeof obj.meta === 'undefined') { - obj.meta = { - revision: 0, - created: 0 - }; - } - self.emit('pre-insert', obj); - if (self.add(obj)) { - self.emit('insert', obj); - results.push(obj); - } else { - return undefined; - } - }); - return results.length === 1 ? results[0] : results; - }; - - Collection.prototype.clear = function () { - this.data = []; - this.idIndex = []; - this.binaryIndices = {}; - this.cachedIndex = null; - this.cachedData = null; - this.maxId = 0; - this.DynamicViews = []; - this.dirty = true; - }; - - /** - * Update method - */ - Collection.prototype.update = function (doc) { - if (Object.keys(this.binaryIndices).length > 0) { - this.flagBinaryIndexesDirty(); - } - - if (Array.isArray(doc)) { - var k = 0, - len = doc.length; - for (k; k < len; k += 1) { - this.update(doc[k]); - } - return; - } - - // verify object is a properly formed document - if (!doc.hasOwnProperty('$loki')) { - throw 'Trying to update unsynced document. Please save the document first by using insert() or addMany()'; - } - try { - this.startTransaction(); - var arr = this.get(doc.$loki, true), - obj, - position, - self = this; - - if (!arr) { - throw new Error('Trying to update a document not in collection.'); - } - this.emit('pre-update', doc); - - obj = arr[0]; - Object.keys(this.constraints.unique).forEach(function (key) { - self.constraints.unique[key].update(obj); - }); - // get current position in data array - position = arr[1]; - - // operate the update - this.data[position] = doc; - - - // now that we can efficiently determine the data[] position of newly added document, - // submit it for all registered DynamicViews to evaluate for inclusion/exclusion - for (var idx = 0; idx < this.DynamicViews.length; idx++) { - this.DynamicViews[idx].evaluateDocument(position); - } - - this.idIndex[position] = obj.$loki; - - this.commit(); - this.dirty = true; // for autosave scenarios - this.emit('update', doc); - - } catch (err) { - this.rollback(); - console.error(err.message); - this.emit('error', err); - throw (err); // re-throw error so user does not think it succeeded - } - }; - - /** - * Add object to collection - */ - Collection.prototype.add = function (obj) { - var dvlen = this.DynamicViews.length; - - // if parameter isn't object exit with throw - if ('object' !== typeof obj) { - throw 'Object being added needs to be an object'; - } - /* - * try adding object to collection - */ - - if (Object.keys(this.binaryIndices).length > 0) { - this.flagBinaryIndexesDirty(); - } - - // if object you are adding already has id column it is either already in the collection - // or the object is carrying its own 'id' property. If it also has a meta property, - // then this is already in collection so throw error, otherwise rename to originalId and continue adding. - if (typeof (obj.$loki) !== "undefined") { - throw 'Document is already in collection, please use update()'; - } - - try { - this.startTransaction(); - this.maxId++; - - if (isNaN(this.maxId)) { - this.maxId = (this.data[this.data.length - 1].$loki + 1); - } - - obj.$loki = this.maxId; - obj.meta.version = 0; - - // add the object - this.data.push(obj); - - var self = this; - Object.keys(this.constraints.unique).forEach(function (key) { - self.constraints.unique[key].set(obj); - }); - - // now that we can efficiently determine the data[] position of newly added document, - // submit it for all registered DynamicViews to evaluate for inclusion/exclusion - for (var i = 0; i < dvlen; i++) { - this.DynamicViews[i].evaluateDocument(this.data.length - 1); - } - - // add new obj id to idIndex - this.idIndex.push(obj.$loki); - - this.commit(); - this.dirty = true; // for autosave scenarios - return obj; - } catch (err) { - this.rollback(); - console.error(err.message); - } - }; - - - Collection.prototype.removeWhere = function (query) { - var list; - if (typeof query === 'function') { - list = this.data.filter(query); - } else { - list = new Resultset(this, query); - } - var len = list.length; - while (len--) { - this.remove(list[len]); - } - var dv; - for (dv in this.DynamicViews) { - this.DynamicViews[dv].rematerialize(); - } - - }; - - Collection.prototype.removeDataOnly = function () { - this.removeWhere(function (obj) { - return true; - }); - }; - - /** - * delete wrapped - */ - Collection.prototype.remove = function (doc) { - if (typeof doc === 'number') { - doc = this.get(doc); - } - - if ('object' !== typeof doc) { - throw new Error('Parameter is not an object'); - } - if (Array.isArray(doc)) { - var k = 0, - len = doc.length; - for (k; k < len; k += 1) { - this.remove(doc[k]); - } - return; - } - - if (!doc.hasOwnProperty('$loki')) { - throw new Error('Object is not a document stored in the collection'); - } - - if (Object.keys(this.binaryIndices).length > 0) { - this.flagBinaryIndexesDirty(); - } - - try { - this.startTransaction(); - var arr = this.get(doc.$loki, true), - // obj = arr[0], - position = arr[1]; - var self = this; - Object.keys(this.constraints.unique).forEach(function (key) { - self.constraints.unique[key].remove(doc); - }); - // now that we can efficiently determine the data[] position of newly added document, - // submit it for all registered DynamicViews to remove - for (var idx = 0; idx < this.DynamicViews.length; idx++) { - this.DynamicViews[idx].removeDocument(position); - } - - this.data.splice(position, 1); - - // remove id from idIndex - this.idIndex.splice(position, 1); - - this.commit(); - this.dirty = true; // for autosave scenarios - this.emit('delete', arr[0]); - delete doc.$loki; - delete doc.meta; - return doc; - - } catch (err) { - this.rollback(); - console.error(err.message); - this.emit('error', err); - return null; - } - }; - - /*---------------------+ - | Finding methods | - +----------------------*/ - - /** - * Get by Id - faster than other methods because of the searching algorithm - */ - Collection.prototype.get = function (id, returnPosition) { - - var retpos = returnPosition || false, - data = this.idIndex, - max = data.length - 1, - min = 0, - mid = Math.floor(min + (max - min) / 2); - - id = typeof id === 'number' ? id : parseInt(id, 10); - - if (isNaN(id)) { - throw 'Passed id is not an integer'; - } - - while (data[min] < data[max]) { - - mid = Math.floor((min + max) / 2); - - if (data[mid] < id) { - min = mid + 1; - } else { - max = mid; - } - } - - if (max === min && data[min] === id) { - - if (retpos) { - return [this.data[min], min]; - } - return this.data[min]; - } - return null; - - }; - - Collection.prototype.by = function (field, value) { - var self; - if (!value) { - self = this; - return function (value) { - return self.by(field, value); - }; - } - return this.constraints.unique[field].get(value); - }; - - /** - * Find one object by index property, by property equal to value - */ - Collection.prototype.findOne = function (query) { - // Instantiate Resultset and exec find op passing firstOnly = true param - var result = new Resultset(this, query, null, true); - if (Array.isArray(result) && result.length === 0) { - return null; - } else { - return result; - } - }; - - /** - * Chain method, used for beginning a series of chained find() and/or view() operations - * on a collection. - */ - Collection.prototype.chain = function () { - return new Resultset(this, null, null); - }; - - /** - * Find method, api is similar to mongodb except for now it only supports one search parameter. - * for more complex queries use view() and storeView() - */ - Collection.prototype.find = function (query) { - if (typeof (query) === 'undefined') { - query = 'getAll'; - } - // find logic moved into Resultset class - return new Resultset(this, query, null); - }; - - /** - * Find object by unindexed field by property equal to value, - * simply iterates and returns the first element matching the query - */ - Collection.prototype.findOneUnindexed = function (prop, value) { - - var i = this.data.length, - doc; - while (i--) { - if (this.data[i][prop] === value) { - doc = this.data[i]; - return doc; - } - } - return null; - }; - - /** - * Transaction methods - */ - - /** start the transation */ - Collection.prototype.startTransaction = function () { - if (this.transactional) { - this.cachedData = clone(this.data, 'parse-stringify'); - this.cachedIndex = this.idIndex; - this.cachedBinaryIndex = this.binaryIndices; - - // propagate startTransaction to dynamic views - for (var idx = 0; idx < this.DynamicViews.length; idx++) { - this.DynamicViews[idx].startTransaction(); - } - } - }; - - /** commit the transation */ - Collection.prototype.commit = function () { - if (this.transactional) { - this.cachedData = null; - this.cachedIndex = null; - this.cachedBinaryIndices = null; - - // propagate commit to dynamic views - for (var idx = 0; idx < this.DynamicViews.length; idx++) { - this.DynamicViews[idx].commit(); - } - } - }; - - /** roll back the transation */ - Collection.prototype.rollback = function () { - if (this.transactional) { - if (this.cachedData !== null && this.cachedIndex !== null) { - this.data = this.cachedData; - this.idIndex = this.cachedIndex; - this.binaryIndices = this.cachedBinaryIndex; - } - - // propagate rollback to dynamic views - for (var idx = 0; idx < this.DynamicViews.length; idx++) { - this.DynamicViews[idx].rollback(); - } - } - }; - - // async executor. This is only to enable callbacks at the end of the execution. - Collection.prototype.async = function (fun, callback) { - setTimeout(function () { - if (typeof fun === 'function') { - fun(); - callback(); - } else { - throw 'Argument passed for async execution is not a function'; - } - }, 0); - }; - - /** - * Create view function - filter - */ - Collection.prototype.where = function (fun) { - // find logic moved into Resultset class - return new Resultset(this, null, fun); - }; - - /** - * Map Reduce - */ - Collection.prototype.mapReduce = function (mapFunction, reduceFunction) { - try { - return reduceFunction(this.data.map(mapFunction)); - } catch (err) { - throw err; - } - }; - - /** - * eqJoin - Join two collections on specified properties - */ - Collection.prototype.eqJoin = function (joinData, leftJoinProp, rightJoinProp, mapFun) { - // logic in Resultset class - return new Resultset(this).eqJoin(joinData, leftJoinProp, rightJoinProp, mapFun); - }; - - /* ------ STAGING API -------- */ - /** - * stages: a map of uniquely identified 'stages', which hold copies of objects to be - * manipulated without affecting the data in the original collection - */ - Collection.prototype.stages = {}; - - /** - * create a stage and/or retrieve it - */ - Collection.prototype.getStage = function (name) { - if (!this.stages[name]) { - this.stages[name] = {}; - } - return this.stages[name]; - }; - /** - * a collection of objects recording the changes applied through a commmitStage - */ - Collection.prototype.commitLog = []; - - /** - * create a copy of an object and insert it into a stage - */ - Collection.prototype.stage = function (stageName, obj) { - var copy = JSON.parse(JSON.stringify(obj)); - this.getStage(stageName)[obj.$loki] = copy; - return copy; - }; - - /** - * re-attach all objects to the original collection, so indexes and views can be rebuilt - * then create a message to be inserted in the commitlog - */ - Collection.prototype.commitStage = function (stageName, message) { - var stage = this.getStage(stageName), - prop, - timestamp = new Date().getTime(); - - for (prop in stage) { - - this.update(stage[prop]); - this.commitLog.push({ - timestamp: timestamp, - message: message, - data: JSON.parse(JSON.stringify(stage[prop])) - }); - } - this.stages[stageName] = {}; - }; - - Collection.prototype.no_op = function () { - return; - }; - - Collection.prototype.extract = function (field) { - var i = 0, - len = this.data.length, - isDotNotation = isDeepProperty(field), - result = []; - for (i; i < len; i += 1) { - result.push(deepProperty(this.data[i], field, isDotNotation)); - } - return result; - }; - - Collection.prototype.max = function (field) { - return Math.max.apply(null, this.extract(field)); - }; - - Collection.prototype.min = function (field) { - return Math.min.apply(null, this.extract(field)); - }; - - Collection.prototype.maxRecord = function (field) { - var i = 0, - len = this.data.length, - deep = isDeepProperty(field), - result = { - index: 0, - value: undefined - }, - max; - - for (i; i < len; i += 1) { - if (max !== undefined) { - if (max < deepProperty(this.data[i], field, deep)) { - max = deepProperty(this.data[i], field, deep); - result.index = this.data[i].$loki; - } - } else { - max = deepProperty(this.data[i], field, deep); - result.index = this.data[i].$loki; - } - } - result.value = max; - return result; - }; - - Collection.prototype.minRecord = function (field) { - var i = 0, - len = this.data.length, - deep = isDeepProperty(field), - result = { - index: 0, - value: undefined - }, - min; - - for (i; i < len; i += 1) { - if (min !== undefined) { - if (min > deepProperty(this.data[i], field, deep)) { - min = deepProperty(this.data[i], field, deep); - result.index = this.data[i].$loki; - } - } else { - min = deepProperty(this.data[i], field, deep); - result.index = this.data[i].$loki; - } - } - result.value = min; - return result; - }; - - Collection.prototype.extractNumerical = function (field) { - return this.extract(field).map(parseBase10).filter(Number).filter(function (n) { - return !(isNaN(n)); - }); - }; - - Collection.prototype.avg = function (field) { - return average(this.extractNumerical(field)); - }; - - Collection.prototype.stdDev = function (field) { - return standardDeviation(this.extractNumerical(field)); - }; - - Collection.prototype.mode = function (field) { - var dict = {}, - data = this.extract(field); - data.forEach(function (obj) { - if (dict[obj]) { - dict[obj] += 1; - } else { - dict[obj] = 1; - } - }); - var max, - prop, mode; - for (prop in dict) { - if (max) { - if (max < dict[prop]) { - mode = prop; - } - } else { - mode = prop; - max = dict[prop]; - } - } - return mode; - }; - - Collection.prototype.median = function (field) { - var values = this.extractNumerical(field); - values.sort(sub); - - var half = Math.floor(values.length / 2); - - if (values.length % 2) { - return values[half]; - } else { - return (values[half - 1] + values[half]) / 2.0; - } - }; - - /** - * General utils, including statistical functions - */ - function isDeepProperty(field) { - return field.indexOf('.') !== -1; - } - - function parseBase10(num) { - return parseFloat(num, 10); - } - - function isNotUndefined(obj) { - return obj !== undefined; - } - - function add(a, b) { - return a + b; - } - - function sub(a, b) { - return a - b; - } - - function median(values) { - values.sort(sub); - var half = Math.floor(values.length / 2); - return (values.length % 2) ? values[half] : ((values[half - 1] + values[half]) / 2.0); - } - - function average(array) { - return (array.reduce(add, 0)) / array.length; - } - - function standardDeviation(values) { - var avg = average(values); - var squareDiffs = values.map(function (value) { - var diff = value - avg; - var sqrDiff = diff * diff; - return sqrDiff; - }); - - var avgSquareDiff = average(squareDiffs); - - var stdDev = Math.sqrt(avgSquareDiff); - return stdDev; - } - - function deepProperty(obj, property, isDeep) { - if (isDeep === false) { - // pass without processing - return obj[property]; - } - var pieces = property.split('.'), - root = obj; - while (pieces.length > 0) { - root = root[pieces.shift()]; - } - return root; - } - - function binarySearch(array, item, fun) { - var lo = 0, - hi = array.length, - compared, - mid; - while (lo < hi) { - mid = ((lo + hi) / 2) | 0; - compared = fun.apply(null, [item, array[mid]]); - if (compared === 0) { - return { - found: true, - index: mid - }; - } else if (compared < 0) { - hi = mid; - } else { - lo = mid + 1; - } - } - return { - found: false, - index: hi - }; - } - - function BSonSort(fun) { - return function (array, item) { - return binarySearch(array, item, fun); - }; - } - - function KeyValueStore() {} - - KeyValueStore.prototype = { - keys: [], - values: [], - sort: function (a, b) { - return (a < b) ? -1 : ((a > b) ? 1 : 0); - }, - setSort: function (fun) { - this.bs = new BSonSort(fun); - }, - bs: function () { - return new BSonSort(this.sort); - }, - set: function (key, value) { - var pos = this.bs(this.keys, key); - if (pos.found) { - this.values[pos.index] = value; - } else { - this.keys.splice(pos.index, 0, key); - this.values.splice(pos.index, 0, value); - } - }, - get: function (key) { - return this.values[binarySearch(this.keys, key, this.sort).index]; - } - }; - - function UniqueIndex(uniqueField) { - this.field = uniqueField; - this.keyMap = {}; - this.lokiMap = {}; - } - UniqueIndex.prototype.keyMap = {}; - UniqueIndex.prototype.lokiMap = {}; - UniqueIndex.prototype.set = function (obj) { - if (this.keyMap[obj[this.field]]) { - throw new Error('Duplicate key for property ' + this.field + ': ' + obj[this.field]); - } else { - this.keyMap[obj[this.field]] = obj; - this.lokiMap[obj.$loki] = obj[this.field]; - } - }; - UniqueIndex.prototype.get = function (key) { - return this.keyMap[key]; - }; - - UniqueIndex.prototype.byId = function (id) { - return this.keyMap[this.lokiMap[id]]; - }; - UniqueIndex.prototype.update = function (obj) { - if (this.lokiMap[obj.$loki] !== obj[this.field]) { - var old = this.lokiMap[obj.$loki]; - this.set(obj); - // make the old key fail bool test, while avoiding the use of delete (mem-leak prone) - this.keyMap[old] = undefined; - } else { - this.keyMap[obj[this.field]] = obj; - } - }; - UniqueIndex.prototype.remove = function (key) { - var obj = this.keyMap[key]; - this.keyMap[key] = undefined; - this.lokiMap[obj.$loki] = undefined; - }; - UniqueIndex.prototype.clear = function () { - this.keyMap = {}; - this.lokiMap = {}; - }; - - function ExactIndex(exactField) { - this.index = {}; - this.field = exactField; - } - - // add the value you want returned to the key in the index - ExactIndex.prototype = { - set: function add(key, val) { - if (this.index[key]) { - this.index[key].push(val); - } else { - this.index[key] = [val]; - } - }, - - // remove the value from the index, if the value was the last one, remove the key - remove: function remove(key, val) { - var idxSet = this.index[key]; - for (var i in idxSet) { - if (idxSet[i] == val) { - idxSet.splice(i, 1); - } - } - if (idxSet.length < 1) { - this.index[key] = undefined; - } - }, - - // get the values related to the key, could be more than one - get: function get(key) { - return this.index[key]; - }, - - // clear will zap the index - clear: function clear(key) { - this.index = {}; - } - }; - - function SortedIndex(sortedField) { - this.field = sortedField; - } - - SortedIndex.prototype = { - keys: [], - values: [], - // set the default sort - sort: function (a, b) { - return (a < b) ? -1 : ((a > b) ? 1 : 0); - }, - bs: function () { - return new BSonSort(this.sort); - }, - // and allow override of the default sort - setSort: function (fun) { - this.bs = new BSonSort(fun); - }, - // add the value you want returned to the key in the index - set: function (key, value) { - var pos = binarySearch(this.keys, key, this.sort); - if (pos.found) { - this.values[pos.index].push(value); - } else { - this.keys.splice(pos.index, 0, key); - this.values.splice(pos.index, 0, [value]); - } - }, - // get all values which have a key == the given key - get: function (key) { - var bsr = binarySearch(this.keys, key, this.sort); - if (bsr.found) { - return this.values[bsr.index]; - } else { - return []; - } - }, - // get all values which have a key < the given key - getLt: function (key) { - var bsr = binarySearch(this.keys, key, this.sort); - var pos = bsr.index; - if (bsr.found) pos--; - return this.getAll(key, 0, pos); - }, - // get all values which have a key > the given key - getGt: function (key) { - var bsr = binarySearch(this.keys, key, this.sort); - var pos = bsr.index; - if (bsr.found) pos++; - return this.getAll(key, pos, this.keys.length); - }, - - // get all vals from start to end - getAll: function (key, start, end) { - var results = []; - for (var i = start; i < end; i++) { - results = results.concat(this.values[i]); - } - return results; - }, - // just in case someone wants to do something smart with ranges - getPos: function (key) { - return binarySearch(this.keys, key, this.sort); - }, - // remove the value from the index, if the value was the last one, remove the key - remove: function (key, value) { - var pos = binarySearch(this.keys, key, this.sort).index; - var idxSet = this.values[pos]; - for (var i in idxSet) { - if (idxSet[i] == value) idxSet.splice(i, 1); - } - if (idxSet.length < 1) { - this.keys.splice(pos, 1); - this.values.splice(pos, 1); - } - }, - // clear will zap the index - clear: function (key) { - this.keys = []; - this.values = []; - } - }; - - - Loki.Collection = Collection; - Loki.KeyValueStore = KeyValueStore; - return Loki; - }()); - - })); - - /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - -/***/ }, -/* 33 */ -/***/ function(module, exports) { - - console.log("I'm `fs` modules"); - - -/***/ }, -/* 34 */ -/***/ function(module, exports) { - - "use strict"; - - var uuid = { - v4: function v4() { - var id = Math.round(1000000 - Math.random() * 500000); - return id; - } - - }; - - module.exports = uuid; - -/***/ }, -/* 35 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var Reflux = __webpack_require__(5); - var cached = {}; - - /** - * DataActionGenerator - Generates Reflux Actions - * @param {string} resourceName name of resource for memoization (optional) - * @returns {RefluxActions} returns reflux actions - */ - var DataActionGenerator = function DataActionGenerator(resourceName) { - if (cached[resourceName]) { - return cached[resourceName]; - } - - var actions = Reflux.createActions(['add', 'update', 'destroy', 'filter', 'sort', 'search', 'registerView', 'resetView', 'reload', 'populate', 'destroyAll', 'setObject', 'setCollection']); - - if (resourceName) { - cached[resourceName] = actions; - } - - return actions; - }; - - module.exports = DataActionGenerator; - -/***/ }, -/* 36 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var Reflux = __webpack_require__(5); - var _ = __webpack_require__(3); - - function defaultDeserializer(query, object) { - if (query === undefined) query = null; - - return object; - } - - /** - * @class Store Synchronizer - */ - - var Nsynchronizer = { - /** - * @public Initializer - * @param {object} options hash of options - * @param {string} options.idAttribute idAttribute of resource - * @param {string} options.basePath basePath of resource - * @param {string} options.endpoint endpoint of resource - * - * @param {RefluxStore} store Store to synchronize - */ - registerStore: function registerStore(options, store, client) { - this.store = store; - this.name = store.name + 'Synchronizer'; - this.idAttribute = options.idAttribute; - this.client = client; - this.onError = options.onError; - - this.setDeserializer(); - this.listenTo(store, this.onStoreChange); - this.listenTo(store.listenables.populate, this.populate); - }, - - /** - * @public Persists store to remote when updated - */ - onStoreChange: function onStoreChange(action, data) { - var trigger = arguments[2] === undefined ? true : arguments[2]; - - // move me out - var allowedActions = ['add', 'update', 'destroy']; - if (trigger && _.contains(allowedActions, action)) { - this[action](data); - } - }, - - /** - * @public Sets serializer - */ - - setSerializer: function setSerializer(serializer) { - this.serializer = serializer; - }, - - /** - * @public Sets deserializer - */ - - setDeserializer: function setDeserializer() { - var deserializer = arguments[0] === undefined ? defaultDeserializer : arguments[0]; - - this.deserializer = deserializer; - }, - - /** - * @public Sets client - */ - setClient: function setClient(client) { - this.client = client; - }, - - /** - * Log errors - */ - - _logError: function _logError(method, err) { - this.onError && this.onError(this.name, method, err); - }, - - /** - * @public Populates store from remote - */ - populate: function populate(object, params) { - var _this = this; - - this.client.getAll(object, params).then(function (objects) { - // @todo: find a better way to sync w/ remote - // this.store.listenables.destroyAll(); - var formatted; - - if (objects.constructor === Array) { - formatted = objects.map(_this.deserializer.bind(null, object)); - _this.store.listenables.setCollection(formatted); - } else { - formatted = _this.deserializer(object, objects); - _this.store.listenables.setObject(formatted); - } - - _this.trigger('populate', objects); - }).fail(function (err) { - _this._logError('populate', err); - console.error(err); - }); - }, - - /** - * @public Fetch Object from remote - */ - reload: function reload(object) { - var _this2 = this; - - this.client.get(object.id).then(function (responseObject) { - _this2._updateSuccess(object, responseObject); - }).fail(function (err) { - _this2._logError('reload', err); - console.error(err); - }); - }, - - /** - * @public Push store updates to remote - */ - update: function update(object) { - var _this3 = this; - - this.client.update(object, this.serializer).then(function (responseObject) { - _this3._updateSuccess(object, responseObject); - _this3.store.flushChanges(); - }).fail(function (err) { - _this3._logError('update', err); - console.error(err); - }); - }, - - _updateSuccess: function _updateSuccess(stale, updated) { - var object = _.extend({}, stale, updated); - this.store.listenables.setObject(object); - this.trigger('update', object); - }, - - /** - * @public Push store deletions to remote - */ - destroy: function destroy(id) { - var _this4 = this; - - this.client.destroy(id).then(function (result) { - _this4.trigger('destroy', result); - _this4.store.flushChanges(); - }).fail(function (err) { - _this4._logError('destroy', err); - console.error(err); - }); - }, - - /** - * @public Push store additions to remote - */ - add: function add(addedObject) { - var _this5 = this; - - var object = _.clone(addedObject); - delete object.id; - - this.client.add(object, this.serializer).then(function (responseObject) { - _this5.store.listenables.setObject(_.extend({}, object, responseObject)); - _this5.store.flushChanges(); - responseObject.oldId = addedObject.id; - _this5.trigger('add', responseObject); - }).fail(function (err) { - _this5._logError('add', err); - console.error(err); - }); - } - }; - - module.exports = function (options, store, client) { - var nsync = Reflux.createStore(Nsynchronizer); - nsync.registerStore(options, store, client); - return nsync; - }; - -/***/ }, -/* 37 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - - var q = __webpack_require__(38); - var _ = __webpack_require__(3); - var reqwest = __webpack_require__(39); - - /** - * @class Client - * @description REST Client for Dataloader - */ - - var Client = (function () { - /** - * @constructor - * @param {object} urlBuilder functions for building URLs - * @param {object} options client config options - * @param {string} options.basePath API basepath - * @param {string} options.endpoint resource API endpoint - * @param {string} options.resource resource name - * @param {object} options.headers Headers for requests - */ - - function Client(urlBuilder, options) { - var _this = this; - - _classCallCheck(this, Client); - - this.basePath = options.basePath; - this.endpoint = options.endpoint; - this.resource = options.resource; - this.headers = options.headers; - this.name = options.name; - - Object.keys(urlBuilder).forEach(function (key) { - _this[key] = urlBuilder[key].bind(_this); - }); - } - - _createClass(Client, [{ - key: 'defaultSerializer', - value: function defaultSerializer(object) { - var formatted = _.clone(object); - var payload = {}; - delete formatted.$loki; - delete formatted.meta; - - if (this.resource) { - payload[this.resource] = formatted; - } else { - payload = formatted; - } - return JSON.stringify(payload); - } - }, { - key: '_success', - - /** - * Generic success handler - * @param {object} deferred Promise to resolve on success - * @return {string} resource API url - */ - value: function _success(deferred, res) { - return deferred.resolve(res); - } - }, { - key: '_error', - - /** - * Generic failure handler - * @param {object} deferred Promise to resolve on success - * @return {string} resource API url - */ - value: function _error(deferred, err) { - return deferred.reject(err); - } - }, { - key: 'serialize', - value: function serialize(object) { - return this._serialize ? this._serialize(object) : object; - } - }, { - key: 'add', - - /** - * Creates object on remote server - * @param {object} object Object to create - */ - value: function add(object) { - var serializer = arguments[1] === undefined ? this.defaultSerializer : arguments[1]; - - var deferred = q.defer(); - var params = { - url: this._getResourceUrl(object), - method: 'post', - data: serializer.call(this, object), - headers: this.headers(), - error: this._error.bind(null, deferred), - success: this._success.bind(null, deferred) - }; - if (params.url) { - reqwest(params); - } - - return deferred.promise; - } - }, { - key: 'destroy', - - /** - * Destroys object on remote server - * @param {number} id ID of object to destroy on server - * @return {promise} promise - */ - value: function destroy(id) { - var deferred = q.defer(); - - var params = { - url: this._getObjectUrl(id), - method: 'delete', - headers: this.headers(), - error: this._error.bind(null, deferred), - success: this._success.bind(null, deferred) - }; - if (params.url) { - reqwest(params); - } - - return deferred.promise; - } - }, { - key: 'update', - - /** - * Updates object on remote server - * @param {object} object Object to update - * @return {promise} promise - */ - value: function update(object) { - var serializer = arguments[1] === undefined ? this.defaultSerializer : arguments[1]; - - var deferred = q.defer(); - - var params = { - url: this._getObjectUrl(object.id), - method: 'put', - data: serializer.call(this, object), - headers: this.headers(), - error: this._error.bind(null, deferred), - success: this._success.bind(null, deferred) - }; - if (params.url) { - reqwest(params); - } - - return deferred.promise; - } - }, { - key: 'get', - - /** - * Get an object from remote server - * @param {number} id ID of object to retrieve - * @return {promise} promise - */ - value: function get(id) { - var deferred = q.defer(); - - var params = { - url: this._getObjectUrl(id), - method: 'get', - headers: this.headers(), - error: this._error.bind(null, deferred), - success: this._success.bind(null, deferred) - }; - if (params.url) { - reqwest(params); - } - - return deferred.promise; - } - }, { - key: 'getAll', - - /** - * Get collection from remote server - * @return {promise} promise - */ - value: function getAll(object, queryParams) { - var deferred = q.defer(); - - var params = { - url: this._getResourceUrl(object, queryParams), - method: 'get', - headers: this.headers(), - error: this._error.bind(null, deferred), - success: this._success.bind(null, deferred) - }; - if (params.url) { - reqwest(params); - } - - return deferred.promise; - } - }]); - - return Client; - })(); - - module.exports = Client; - -/***/ }, -/* 38 */ -/***/ function(module, exports, __webpack_require__) { - - /* WEBPACK VAR INJECTION */(function(process, setImmediate) {// vim:ts=4:sts=4:sw=4: - /*! +!function(i,o,s){o[i]=o[i]||s(),"undefined"!=typeof t&&t.exports?t.exports=o[i]:!0&&n(15)&&(r=function(){return o[i]}.call(e,n,e,t),!(void 0!==r&&(t.exports=r)))}("Promise","undefined"!=typeof i?i:this,function(){"use strict";function t(t,e){p.add(t,e),f||(f=y(p.drain))}function e(t){var e,n=typeof t;return null==t||"object"!=n&&"function"!=n||(e=t.then),"function"==typeof e?e:!1}function n(){for(var t=0;t0&&t(n,c))}catch(h){s.call(a||new u(c),h)}}}function s(e){var r=this;r.triggered||(r.triggered=!0,r.def&&(r=r.def),r.msg=e,r.state=2,r.chain.length>0&&t(n,r))}function a(t,e,n,r){for(var i=0;i=0&&(t._idleTimeoutId=setTimeout(function(){t._onTimeout&&t._onTimeout()},e))},e.setImmediate="function"==typeof t?t:function(t){var n=c++,r=arguments.length<2?!1:a.call(arguments,1);return u[n]=!0,o(function(){u[n]&&(r?t.apply(null,r):t.call(null),e.clearImmediate(n))}),n},e.clearImmediate="function"==typeof r?r:function(t){delete u[t]}}).call(e,n(13).setImmediate,n(13).clearImmediate)},function(t,e){function n(){c=!1,s.length?u=s.concat(u):h=-1,u.length&&r()}function r(){if(!c){var t=setTimeout(n);c=!0;for(var e=u.length;e;){for(s=u,u=[];++h1)for(var n=1;ne;e++)u.throwIf(this.validateListening(s[e]));for(e=0;h>e;e++)f.push(s[e].listen(o(e,l),this));return i(l),n={listenable:s},n.stop=r(n,f,this),this.subscriptions=(this.subscriptions||[]).concat(n),n}}},function(t,e,n){var r=n(10),i=n(6),o=n(18),s=n(19),a={preEmit:1,shouldEmit:1},u=n(20);t.exports=function(t){function e(){var e,n=0;if(this.subscriptions=[],this.emitter=new r.EventEmitter,this.eventLabel="change",u(this,t),this.init&&r.isFunction(this.init)&&this.init(),this.listenables)for(e=[].concat(this.listenables);n1&&(n.init=function(){var t=arguments;e.init.forEach(function(e){e.apply(this,t)},this)}),e.preEmit.length>1&&(n.preEmit=function(){return e.preEmit.reduce(function(t,e){var n=e.apply(this,t);return void 0===n?t:[n]}.bind(this),arguments)}),e.shouldEmit.length>1&&(n.shouldEmit=function(){var t=arguments;return!e.shouldEmit.some(function(e){return!e.apply(this,t)},this)}),Object.keys(e).forEach(function(t){1===e[t].length&&(n[t]=e[t][0])}),n}},function(t,e){t.exports=function(t,e){for(var n in e)if(Object.getOwnPropertyDescriptor&&Object.defineProperty){var r=Object.getOwnPropertyDescriptor(e,n);if(!r.value||"function"!=typeof r.value||!e.hasOwnProperty(n))continue;t[n]=e[n].bind(t)}else{var i=e[n];if("function"!=typeof i||!e.hasOwnProperty(n))continue;t[n]=i.bind(t)}return t}},function(t,e,n){var r=n(10);t.exports={preEmit:function(){},shouldEmit:function(){return!0},listen:function(t,e){e=e||this;var n=function(n){i||t.apply(e,n)},r=this,i=!1;return this.emitter.addListener(this.eventLabel,n),function(){i=!0,r.emitter.removeListener(r.eventLabel,n)}},promise:function(t){var e=this,n=this.children.indexOf("completed")>=0&&this.children.indexOf("failed")>=0;if(!n)throw new Error('Publisher must have "completed" and "failed" child publishers');t.then(function(t){return e.completed(t)},function(t){return e.failed(t)})},listenAndPromise:function(t,e){var n=this;e=e||this,this.willCallPromise=(this.willCallPromise||0)+1;var r=this.listen(function(){if(!t)throw new Error("Expected a function returning a promise but got "+t);var r=arguments,i=t.apply(e,r);return n.promise.call(n,i)},e);return function(){n.willCallPromise--,r.call(n)}},trigger:function(){var t=arguments,e=this.preEmit.apply(this,t);t=void 0===e?t:r.isArguments(e)?e:[].concat(e),this.shouldEmit.apply(this,t)&&this.emitter.emit(this.eventLabel,t)},triggerAsync:function(){var t=arguments,e=this;r.nextTick(function(){e.trigger.apply(e,t)})},triggerPromise:function(){var t=this,e=arguments,n=this.children.indexOf("completed")>=0&&this.children.indexOf("failed")>=0,i=r.createPromise(function(i,o){if(t.willCallPromise)return void r.nextTick(function(){var n=t.promise;t.promise=function(e){return e.then(i,o),t.promise=n,t.promise.apply(t,arguments)},t.trigger.apply(t,e)});if(n)var s=t.completed.listen(function(t){s(),a(),i(t)}),a=t.failed.listen(function(t){s(),a(),o(t)});t.triggerAsync.apply(t,e),n||i()});return i}}},function(t,e){t.exports={}},function(t,e,n){var r=n(10),i=n(6),o=n(18),s={preEmit:1,shouldEmit:1},a=function(t){t=t||{},r.isObject(t)||(t={actionName:t});for(var e in i.ActionMethods)if(!s[e]&&i.PublisherMethods[e])throw new Error("Cannot override API method "+e+" in Reflux.ActionMethods. Use another method name or override it on Reflux.PublisherMethods instead.");for(var n in t)if(!s[n]&&i.PublisherMethods[n])throw new Error("Cannot override API method "+n+" in action creation. Use another method name or override it on Reflux.PublisherMethods instead.");t.children=t.children||[],t.asyncResult&&(t.children=t.children.concat(["completed","failed"]));for(var u=0,c={};ur?1:-1:r>i?1:-1}}function s(t){return function(e){var n=!1;return Object.keys(e).forEach(function(r){n||(n=-1!==JSON.stringify(e[r]).toLowerCase().indexOf(t.toLowerCase()))}),n}}function a(t,e){var n=String(e).toLowerCase();return function(r){return void 0===e?!r[t]:-1!==String(r[t]).toLowerCase().indexOf(n)}}function u(t,e){Object.keys(e).forEach(function(n){var r=null;switch(e[n]){case null:break;default:r=a(n,e[n])}r&&t.applyWhere(r)})}var c=function(){function t(t,e){for(var n=0;nt}function e(t,e,n){return t===e?n?!0:!1:void 0===t?!1:void 0===e?!0:null===t?!1:null===e?!0:t>e}function r(n,r,i){return n===r?0:i?t(n,r)?1:-1:e(n,r)?1:-1}function i(t,e){return Array.isArray(t)?function(e){return-1!==t.indexOf(e)}:"string"==typeof t?function(e){return-1!==t.indexOf(e)}:t&&"object"==typeof t?function(e){return t.hasOwnProperty(e)}:void 0}function o(t,e){var n,r=e||"parse-stringify";return"parse-stringify"===r&&(n=JSON.parse(JSON.stringify(t))),n}function a(){try{return"localStorage"in window&&null!==window.localStorage}catch(t){return!1}}function u(){}function c(t,e){this.filename=t||"loki.db",this.collections=[],this.databaseVersion=1.1,this.engineVersion=1.1,this.autosave=!1,this.autosaveInterval=5e3,this.autosaveHandle=null,this.options={},this.persistenceMethod=null,this.persistenceAdapter=null,this.events={init:[],flushChanges:[],close:[],changes:[],warning:[]};var n=function(){return"undefined"==typeof window?"NODEJS":"undefined"!=typeof s&&s.window?"NODEJS":"undefined"!=typeof document?-1===document.URL.indexOf("http://")&&-1===document.URL.indexOf("https://")?"CORDOVA":"BROWSER":"CORDOVA"};e&&e.hasOwnProperty("env")?this.ENV=e.env:this.ENV=n(),"undefined"===this.ENV&&(this.ENV="NODEJS"),this.configureOptions(e,!0),this.on("init",this.clearChanges)}function h(){this.fs=n(33)}function l(){}function f(t,e,n,r){return this.collection=t,this.searchIsChained=!e&&!n,this.filteredrows=[],this.filterInitialized=!1,"undefined"!=typeof e&&null!==e?this.find(e,r):"undefined"!=typeof n&&null!==n?this.where(n):this}function p(t,e,n){this.collection=t,this.name=e,this.persistent=!1,"undefined"!=typeof n&&(this.persistent=n),this.resultset=new f(t),this.resultdata=[],this.resultsdirty=!1,this.cachedresultset=null,this.filterPipeline=[],this.sortFunction=null,this.sortCriteria=null,this.sortDirty=!1,this.events={rebuild:[]}}function d(t,e){function n(t,e,n){l.changes.push({name:t,operation:e,obj:JSON.parse(JSON.stringify(n))})}function r(){l.changes=[]}function i(t){t&&(t.meta||(t.meta={}),t.meta.created=(new Date).getTime(),t.meta.revision=0)}function o(t){t&&(t.meta.updated=(new Date).getTime(),t.meta.revision+=1)}function s(t){n(l.name,"I",t)}function a(t){n(l.name,"U",t)}function u(t){i(t),s(t)}function c(t){o(t),a(t)}function h(){d=l.disableChangesApi?i:u,y=l.disableChangesApi?o:c}this.name=t,this.data=[],this.idIndex=[],this.binaryIndices={},this.constraints={unique:{},exact:{}},this.objType=t,this.dirty=!0,this.cachedIndex=null,this.cachedBinaryIndex=null,this.cachedData=null;var l=this;e=e||{},e.hasOwnProperty("unique")&&(Array.isArray(e.unique)||(e.unique=[e.unique]),e.unique.forEach(function(t){l.constraints.unique[t]=new k(t)})),e.hasOwnProperty("exact")&&e.exact.forEach(function(t){l.constraints.exact[t]=new E(t)}),this.transactional=e.hasOwnProperty("transactional")?e.transactional:!1,this.cloneObjects=e.hasOwnProperty("clone")?e.clone:!1,this.asyncListeners=e.hasOwnProperty("asyncListeners")?e.asyncListeners:!1,this.disableChangesApi=e.hasOwnProperty("disableChangesApi")?e.disableChangesApi:!0,this.maxId=0,this.DynamicViews=[],this.events={insert:[],update:[],"pre-insert":[],"pre-update":[],close:[],flushbuffer:[],error:[],"delete":[],warning:[]},this.changes=[],this.ensureId();var f=[];if(e&&e.indices)if("[object Array]"===Object.prototype.toString.call(e.indices))f=e.indices;else{if("string"!=typeof e.indices)throw new TypeError("Indices needs to be a string or an array of strings");f=[e.indices]}for(var p=0;p0;)i=i[r.shift()];return i}function x(t,e,n){for(var r,i,o=0,s=t.length;s>o;){if(i=(o+s)/2|0,r=n.apply(null,[e,t[i]]),0===r)return{found:!0,index:i};0>r?s=i:o=i+1}return{found:!1,index:s}}function S(t){return function(e,n){return x(e,n,t)}}function I(){}function k(t){this.field=t,this.keyMap={},this.lokiMap={}}function E(t){this.index={},this.field=t}function j(t){this.field=t}var O={copyProperties:function(t,e){var n;for(n in t)e[n]=t[n]}},A={$eq:function(t,e){return t===e},$gt:function(t,n){return e(t,n)},$gte:function(t,n){return e(t,n,!0)},$lt:function(e,n){return t(e,n)},$lte:function(e,n){return t(e,n,!0)},$ne:function(t,e){return t!==e},$regex:function(t,e){return e.test(t)},$in:function(t,e){return e.indexOf(t)>-1},$containsAny:function(t,e){var n;return Array.isArray(e)||(e=[e]),n=i(t,e)||function(){return!1},e.reduce(function(t,e){return t?t:n(e)},!1)},$contains:function(t,e){var n;return Array.isArray(e)||(e=[e]),n=i(t,e)||function(){return!0},e.reduce(function(t,e){return t?n(e):t},!0)}},D={$eq:A.$eq,$gt:A.$gt,$gte:A.$gte,$lt:A.$lt,$lte:A.$lte,$ne:A.$ne,$regex:A.$regex,$in:A.$in,$contains:A.$contains,$containsAny:A.$containsAny};return u.prototype.events={},u.prototype.asyncListeners=!1,u.prototype.on=function(t,e){var n=this.events[t];return n||(n=this.events[t]=[]),n.push(e),e},u.prototype.emit=function(t,e){var n=this;if(!t||!this.events[t])throw new Error("No event "+t+" defined");this.events[t].forEach(function(t){n.asyncListeners?setTimeout(function(){t(e)},1):t(e)})},u.prototype.removeListener=function(t,e){if(this.events[t]){var n=this.events[t];n.splice(n.indexOf(e),1)}},c.prototype=new u,c.prototype.configureOptions=function(t,e){var n={NODEJS:"fs",BROWSER:"localStorage",CORDOVA:"localStorage"},r={fs:h,localStorage:l};if(this.options={},this.persistenceMethod=null,this.persistenceAdapter=null,"undefined"!=typeof t){if(this.options=t,this.options.hasOwnProperty("persistenceMethod")&&"function"==typeof r[t.persistenceMethod]&&(this.persistenceMethod=t.persistenceMethod,this.persistenceAdapter=new r[t.persistenceMethod]),this.options.hasOwnProperty("adapter")&&(this.persistenceMethod="adapter",this.persistenceAdapter=t.adapter),t.hasOwnProperty("autoload")&&"undefined"!=typeof e&&e){var i=this;setTimeout(function(){i.loadDatabase(t,t.autoloadCallback)},1)}this.options.hasOwnProperty("autosaveInterval")&&(this.autosaveDisable(),this.autosaveInterval=parseInt(this.options.autosaveInterval,10)),this.options.hasOwnProperty("autosave")&&this.options.autosave&&(this.autosaveDisable(),this.autosave=!0,this.autosaveEnable())}null===this.persistenceAdapter&&(this.persistenceMethod=n[this.ENV],this.persistenceMethod&&(this.persistenceAdapter=new r[this.persistenceMethod]))},c.prototype.anonym=function(t,e){var n=new d("anonym",e);return n.insert(t),n},c.prototype.addCollection=function(t,e){var n=new d(t,e);return this.collections.push(n),n},c.prototype.loadCollection=function(t){if(!t.name)throw new Error("Collection must be have a name property to be loaded");this.collections.push(t)},c.prototype.getCollection=function(t){var e,n=this.collections.length;for(e=0;n>e;e+=1)if(this.collections[e].name===t)return this.collections[e];return this.emit("warning","collection "+t+" not found"),null},c.prototype.listCollections=function(){for(var t=this.collections.length,e=[];t--;)e.push({name:this.collections[t].name,type:this.collections[t].objType,count:this.collections[t].data.length});return e},c.prototype.removeCollection=function(t){var e,n=this.collections.length;for(e=0;n>e;e+=1)if(this.collections[e].name===t)return void this.collections.splice(e,1)},c.prototype.getName=function(){return this.name},c.prototype.serializeReplacer=function(t,e){switch(t){case"autosaveHandle":case"persistenceAdapter":case"constraints":return null;default:return e}},c.prototype.serialize=function(){return JSON.stringify(this,this.serializeReplacer)},c.prototype.toJson=c.prototype.serialize,c.prototype.loadJSON=function(t,e){var n,r,i,o,s=JSON.parse(t),a=0,u=s.collections.length;for(this.name=s.name,this.databaseVersion=1,s.hasOwnProperty("databaseVersion")&&(this.databaseVersion=s.databaseVersion),this.collections=[],a;u>a;a+=1){if(n=s.collections[a],r=this.addCollection(n.name),i=n.data.length,o=0,e&&e.hasOwnProperty(n.name)){var c=e[n.name].inflate?e[n.name].inflate:O.copyProperties;for(o;i>o;o++){var h=new e[n.name].proto;c(n.data[o],h),r.data[o]=h}}else for(o;i>o;o++)r.data[o]=n.data[o];if(r.transactional=n.transactional,r.asyncListeners=n.asyncListeners,r.disableChangesApi=n.disableChangesApi,r.cloneObjects=n.cloneObjects,r.maxId=0===n.data.length?0:n.maxId,r.idIndex=n.idIndex,"undefined"!=typeof n.indices&&(r.idIndex=n.indices.id),"undefined"!=typeof n.binaryIndices&&(r.binaryIndices=n.binaryIndices),r.ensureId(),"undefined"!=typeof n.DynamicViews)for(var l=0;la;)c=Math.floor((a+u)/2),t(o[s[c]][r],i)?a=c+1:u=c;for(h=a,a=0,u=s.length-1;u>a;)c=Math.floor((a+u)/2),t(i,o[s[c]][r])?u=c:a=c+1;l=u;var d=o[s[h]][r],y=o[s[l]][r];switch(n){case"$eq":return d!==i?[0,-1]:(y!==i&&l--,[h,l]);case"$gt":return t(y,i,!0)?[0,-1]:[l,o.length-1];case"$gte":return t(d,i)?[0,-1]:[h,o.length-1];case"$lt":return 0===h&&t(d,i)?[0,0]:[0,h-1];case"$lte":return y!==i&&l--,0===l&&t(y,i)?[0,0]:[0,l];default:return[0,o.length-1]}},f.prototype.findOr=function(t){var e=0,n=0,r=null,i=[],o=null;if(this.filterInitialized){for(i=[],n=0;n1&&(this.filteredrows=this.filteredrows.slice(0,1)),this):(f=this.collection.chain().findAnd(h[o]).data(),e?0===f.length?[]:f[0]:f);if("$or"===o)return this.searchIsChained?(this.findOr(h[o]),e&&this.filteredrows.length>1&&(this.filteredrows=this.filteredrows.slice(0,1)),this):(f=this.collection.chain().findOr(h[o]).data(),e?0===f.length?[]:f[0]:f);if(-1!=o.indexOf(".")&&(y=!0),"object"!=typeof h[o])i="$eq",r=h[o];else{if("object"!=typeof h[o])throw"Do not know what you want to do.";for(s in h[o])h[o].hasOwnProperty(s)&&(i=s,r=h[o][s])}break}if("$regex"===i&&(r=new RegExp(r)),null===this.collection.data)throw new TypeError;if((!this.searchIsChained||this.searchIsChained&&!this.filterInitialized)&&"$ne"!==i&&"$regex"!==i&&"$contains"!==i&&"$containsAny"!==i&&"$in"!==i&&this.collection.binaryIndices.hasOwnProperty(n)&&(this.collection.ensureIndex(n),l=!0,p=this.collection.binaryIndices[n]),a=D[i],this.searchIsChained){if(this.filterInitialized){if(l)for(u=p,c=this.filteredrows.length;c--;)a(u[this.filteredrows[c]],r)&&f.push(this.filteredrows[c]);else if(u=this.collection.data,c=this.filteredrows.length,y)for(;c--;)this.dotSubScan(u[this.filteredrows[c]],n,a,r)&&f.push(this.filteredrows[c]);else for(;c--;)a(u[this.filteredrows[c]][n],r)&&f.push(this.filteredrows[c]);return this.filteredrows=f,this}if(l){u=this.collection.data;for(var v=this.calculateRange(i,n,r,this),g=v[0];g<=v[1];g++)f.push(p.values[g]);this.filteredrows=f}else if(u=this.collection.data,c=u.length,y)for(;c--;)this.dotSubScan(u[c],n,a,r)&&f.push(c);else for(;c--;)a(u[c][n],r)&&f.push(c);return this.filteredrows=f,this.filterInitialized=!0,this}if(l){u=this.collection.data;var m=this.calculateRange(i,n,r,this);if(e)return-1!==m[1]?u[p.values[m[0]]]:[];for(c=m[0];c<=m[1];c++)f.push(u[p.values[c]]);this.filteredrows=f}else{if(u=this.collection.data,c=u.length,e){for(;c--;)if(a(u[c][n],r))return u[c];return[]}if(y)for(;c--;)this.dotSubScan(u[c],n,a,r)&&f.push(u[c]);else for(;c--;)a(u[c][n],r)&&f.push(u[c])}return f},f.prototype.where=function(t){var e,n=[];if("function"!=typeof t)throw"Argument is not a stored view or a function";e=t;try{if(this.searchIsChained){if(this.filterInitialized){for(var r=this.filteredrows.length;r--;)e(this.collection.data[this.filteredrows[r]])===!0&&n.push(this.filteredrows[r]);return this.filteredrows=n,this}for(var i=this.collection.data.length;i--;)e(this.collection.data[i])===!0&&n.push(i);return this.filteredrows=n,this.filterInitialized=!0,this}for(var o=this.collection.data.length;o--;)e(this.collection.data[o])===!0&&n.push(this.collection.data[o]);return n}catch(s){throw s}},f.prototype.data=function(){var t=[];if(this.searchIsChained&&!this.filterInitialized){if(0===this.filteredrows.length)return this.collection.data;this.filterInitialized=!0}var e,n=this.collection.data,r=this.filteredrows,i=this.filteredrows.length;for(e=0;i>e;e++)t.push(n[r[e]]);return t},f.prototype.update=function(t){if("function"!=typeof t)throw"Argument is not a function";this.searchIsChained&&!this.filterInitialized&&0===this.filteredrows.length&&(this.filteredrows=Object.keys(this.collection.data));for(var e=this.filteredrows.length,n=this.collection.data,r=0;e>r;r++)t(n[this.filteredrows[r]]),this.collection.update(n[this.filteredrows[r]]);return this},f.prototype.remove=function(){this.searchIsChained&&!this.filterInitialized&&0===this.filteredrows.length&&(this.filteredrows=Object.keys(this.collection.data));for(var t=this.filteredrows.length,e=0;t>e;e++)this.collection.remove(this.filteredrows[e]);return this.filteredrows=[],this},f.prototype.mapReduce=function(t,e){try{return e(this.data().map(t))}catch(n){throw n}},f.prototype.eqJoin=function(t,e,n,r){var i,o,s,a=[],u=[],c=[],h="function"==typeof e,l="function"==typeof n,p={};if(a=this.data(),i=a.length,t instanceof f)u=t.data();else{if(!Array.isArray(t))throw new TypeError("joinData needs to be an array or result set");u=t}o=u.length;for(var y=0;o>y;y++)s=l?n(u[y]):u[y][n],p[s]=u[y];r||(r=function(t,e){return{left:t,right:e}});for(var v=0;i>v;v++)s=h?e(a[v]):a[v][e],c.push(r(a[v],p[s]||{}));return this.collection=new d("joinData"),this.collection.insert(c),this.filteredrows=[],this.filterInitialized=!1,this},f.prototype.map=function(t){var e=this.data().map(t);return this.collection=new d("mappedData"),this.collection.insert(e),this.filteredrows=[],this.filterInitialized=!1,this},p.prototype=new u,p.prototype.rematerialize=function(t){var e,n,r;if(t=t||{},this.resultdata=[],this.resultsdirty=!0,this.resultset=new f(this.collection),(this.sortFunction||this.sortCriteria)&&(this.sortDirty=!0),t.hasOwnProperty("removeWhereFilters"))for(e=this.filterPipeline.length,n=e;n--;)"where"===this.filterPipeline[n].type&&(n!==this.filterPipeline.length-1&&(this.filterPipeline[n]=this.filterPipeline[this.filterPipeline.length-1]),this.filterPipeline.length--);var i=this.filterPipeline;for(this.filterPipeline=[],e=i.length,r=0;e>r;r++)this.applyFind(i[r].val);return this.data(),this.emit("rebuild",this),this},p.prototype.branchResultset=function(){return this.resultset.copy()},p.prototype.toJSON=function(){var t=new p(this.collection,this.name,this.persistent);return t.resultset=this.resultset,t.resultdata=[],t.resultsdirty=!0,t.filterPipeline=this.filterPipeline,t.sortFunction=this.sortFunction,t.sortCriteria=this.sortCriteria,t.sortDirty=this.sortDirty,t.collection=null,t},p.prototype.applySort=function(t){return this.sortFunction=t,this.sortCriteria=null,this.queueSortPhase(),this},p.prototype.applySimpleSort=function(t,e){return"undefined"==typeof e&&(e=!1),this.sortCriteria=[[t,e]],this.sortFunction=null,this.queueSortPhase(),this},p.prototype.applySortCriteria=function(t){return this.sortCriterial=t,this.sortFunction=null,this.queueSortPhase(),this},p.prototype.startTransaction=function(){return this.cachedresultset=this.resultset.copy(),this},p.prototype.commit=function(){return this.cachedresultset=null,this},p.prototype.rollback=function(){return this.resultset=this.cachedresultset,this.persistent&&(this.resultdata=this.resultset.data(),this.emit("rebuild",this)),this},p.prototype.applyFind=function(t){return this.filterPipeline.push({type:"find",val:t}),this.resultset.find(t),(this.sortFunction||this.sortCriteria)&&(this.sortDirty=!0,this.queueSortPhase()),this.persistent&&(this.resultsdirty=!0,this.queueSortPhase()),this},p.prototype.applyWhere=function(t){return this.filterPipeline.push({type:"where",val:t}),this.resultset.where(t),(this.sortFunction||this.sortCriteria)&&(this.sortDirty=!0,this.queueSortPhase()),this.persistent&&(this.resultsdirty=!0,this.queueSortPhase()),this},p.prototype.data=function(){return(this.sortDirty||this.resultsdirty||!this.resultset.filterInitialized)&&this.performSortPhase(),this.persistent?this.resultdata:this.resultset.data()},p.prototype.queueSortPhase=function(){var t=this;this.sortDirty||(this.sortDirty=!0,setTimeout(function(){t.performSortPhase()},1))},p.prototype.performSortPhase=function(){if(this.sortDirty||this.resultsdirty||!this.resultset.filterInitialized){if(this.sortFunction&&this.resultset.sort(this.sortFunction),this.sortCriteria&&this.resultset.compoundsort(this.sortCriteria),!this.persistent)return void(this.sortDirty=!1);this.resultdata=this.resultset.data(),this.resultsdirty=!1,this.sortDirty=!1,this.emit("rebuild",this)}},p.prototype.evaluateDocument=function(t){var e=this.resultset.filteredrows,n=e.indexOf(t),r=e.length,i=new f(this.collection);i.filteredrows=[t],i.filterInitialized=!0;for(var o=0;on?(e[n]=e[r-1],e.length=r-1,this.persistent&&(this.resultdata[n]=this.resultdata[r-1],this.resultdata.length=r-1)):(e.length=r-1,this.persistent&&(this.resultdata.length=r-1)),void((this.sortFunction||this.sortCriteria)&&this.queueSortPhase())):-1!==n&&-1!==s?(this.persistent&&(this.resultdata[n]=this.collection.data[t]),void((this.sortFunction||this.sortCriteria)&&(this.sortDirty=!0))):void 0:void 0},p.prototype.removeDocument=function(t){var e,n=this.resultset.filteredrows,r=n.indexOf(t),i=n.length;for(-1!==r&&(i-1>r?(n[r]=n[i-1],n.length=i-1,this.persistent&&(this.resultdata[r]=this.resultdata[i-1],this.resultdata.length=i-1)):(n.length=i-1,this.persistent&&(this.resultdata.length=i-1)),(this.sortFunction||this.sortCriteria)&&this.queueSortPhase()),i=n.length,e=0;i>e;e++)n[e]>t&&n[e]--},p.prototype.mapReduce=function(t,e){try{return e(this.data().map(t))}catch(n){throw n}},d.prototype=new u,d.prototype.byExample=function(t){var e,n,r;r=[];for(e in t)t.hasOwnProperty(e)&&r.push((n={},n[e]=t[e],n));return{$and:r}},d.prototype.findObject=function(t){return this.findOne(this.byExample(t))},d.prototype.findObjects=function(t){return this.find(this.byExample(t))},d.prototype.ensureIndex=function(n,r){if("undefined"==typeof r&&(r=!1),null===n||void 0===n)throw"Attempting to set index without an associated property";if(!this.binaryIndices.hasOwnProperty(n)||r||this.binaryIndices[n].dirty){this.binaryIndices[n]={name:n,dirty:!0,values:[]};var i,o=this.data.length,s=0;for(i=this.binaryIndices[n],s;o>s;s+=1)i.values.push(s);var a=function(n,r){return function(i,o){var s=r.data[i],a=r.data[o];return s[n]===a[n]?0:e(s[n],a[n])?1:t(s[n],a[n])?-1:void 0}}(n,this);i.values.sort(a),i.dirty=!1,this.dirty=!0}},d.prototype.ensureUniqueIndex=function(t){var e=this.constraints.unique[t];e||(this.constraints.unique[t]=e=new k(t));return this.data.forEach(function(t){e.set(t)}),e},d.prototype.ensureAllIndexes=function(t){for(var e=Object.keys(this.binaryIndices),n=e.length;n--;)this.ensureIndex(e[n],t)},d.prototype.flagBinaryIndexesDirty=function(){for(var t=Object.keys(this.binaryIndices),e=t.length;e--;)this.binaryIndices[t[e]].dirty=!0},d.prototype.count=function(){return this.data.length},d.prototype.ensureId=function(){var t=this.data.length,e=0;for(this.idIndex=[],e;t>e;e+=1)this.idIndex.push(this.data[e].$loki)},d.prototype.ensureIdAsync=function(t){this.async(function(){this.ensureId()},t)},d.prototype.addDynamicView=function(t,e){var n=new p(this,t,e);return this.DynamicViews.push(n),n},d.prototype.removeDynamicView=function(t){for(var e=0;e0&&this.flagBinaryIndexesDirty(),Array.isArray(t)){var e=0,n=t.length;for(e;n>e;e+=1)this.update(t[e])}else{if(!t.hasOwnProperty("$loki"))throw"Trying to update unsynced document. Please save the document first by using insert() or addMany()";try{this.startTransaction();var r,i,o=this.get(t.$loki,!0),s=this;if(!o)throw new Error("Trying to update a document not in collection.");this.emit("pre-update",t),r=o[0],Object.keys(this.constraints.unique).forEach(function(t){s.constraints.unique[t].update(r)}),i=o[1],this.data[i]=t;for(var a=0;a0&&this.flagBinaryIndexesDirty(),"undefined"!=typeof t.$loki)throw"Document is already in collection, please use update()";try{this.startTransaction(),this.maxId++,isNaN(this.maxId)&&(this.maxId=this.data[this.data.length-1].$loki+1),t.$loki=this.maxId,t.meta.version=0,this.data.push(t);var n=this;Object.keys(this.constraints.unique).forEach(function(e){n.constraints.unique[e].set(t)});for(var r=0;e>r;r++)this.DynamicViews[r].evaluateDocument(this.data.length-1);return this.idIndex.push(t.$loki),this.commit(),this.dirty=!0,t}catch(i){this.rollback(),console.error(i.message)}},d.prototype.removeWhere=function(t){var e;e="function"==typeof t?this.data.filter(t):new f(this,t);for(var n=e.length;n--;)this.remove(e[n]);var r;for(r in this.DynamicViews)this.DynamicViews[r].rematerialize()},d.prototype.removeDataOnly=function(){this.removeWhere(function(t){return!0})},d.prototype.remove=function(t){if("number"==typeof t&&(t=this.get(t)),"object"!=typeof t)throw new Error("Parameter is not an object");if(Array.isArray(t)){var e=0,n=t.length;for(e;n>e;e+=1)this.remove(t[e])}else{if(!t.hasOwnProperty("$loki"))throw new Error("Object is not a document stored in the collection");Object.keys(this.binaryIndices).length>0&&this.flagBinaryIndexesDirty();try{this.startTransaction();var r=this.get(t.$loki,!0),i=r[1],o=this;Object.keys(this.constraints.unique).forEach(function(e){o.constraints.unique[e].remove(t)});for(var s=0;se;e+=1)i.push(b(this.data[e],t,r));return i},d.prototype.max=function(t){return Math.max.apply(null,this.extract(t))},d.prototype.min=function(t){return Math.min.apply(null,this.extract(t))},d.prototype.maxRecord=function(t){var e,n=0,r=this.data.length,i=y(t),o={index:0,value:void 0};for(n;r>n;n+=1)void 0!==e?en;n+=1)void 0!==e?e>b(this.data[n],t,i)&&(e=b(this.data[n],t,i),o.index=this.data[n].$loki):(e=b(this.data[n],t,i),o.index=this.data[n].$loki);return o.value=e,o},d.prototype.extractNumerical=function(t){return this.extract(t).map(v).filter(Number).filter(function(t){return!isNaN(t)})},d.prototype.avg=function(t){return _(this.extractNumerical(t))},d.prototype.stdDev=function(t){return w(this.extractNumerical(t))},d.prototype.mode=function(t){var e={},n=this.extract(t);n.forEach(function(t){e[t]?e[t]+=1:e[t]=1});var r,i,o;for(i in e)r?rt?-1:t>e?1:0},setSort:function(t){this.bs=new S(t)},bs:function(){return new S(this.sort)},set:function(t,e){var n=this.bs(this.keys,t);n.found?this.values[n.index]=e:(this.keys.splice(n.index,0,t),this.values.splice(n.index,0,e))},get:function(t){return this.values[x(this.keys,t,this.sort).index]}},k.prototype.keyMap={},k.prototype.lokiMap={},k.prototype.set=function(t){if(this.keyMap[t[this.field]])throw new Error("Duplicate key for property "+this.field+": "+t[this.field]);this.keyMap[t[this.field]]=t,this.lokiMap[t.$loki]=t[this.field]},k.prototype.get=function(t){return this.keyMap[t]},k.prototype.byId=function(t){return this.keyMap[this.lokiMap[t]]},k.prototype.update=function(t){if(this.lokiMap[t.$loki]!==t[this.field]){var e=this.lokiMap[t.$loki];this.set(t),this.keyMap[e]=void 0}else this.keyMap[t[this.field]]=t},k.prototype.remove=function(t){var e=this.keyMap[t];this.keyMap[t]=void 0,this.lokiMap[e.$loki]=void 0},k.prototype.clear=function(){this.keyMap={},this.lokiMap={}},E.prototype={set:function(t,e){this.index[t]?this.index[t].push(e):this.index[t]=[e]},remove:function(t,e){var n=this.index[t];for(var r in n)n[r]==e&&n.splice(r,1);n.length<1&&(this.index[t]=void 0)},get:function(t){return this.index[t]},clear:function(t){this.index={}}},j.prototype={keys:[],values:[],sort:function(t,e){return e>t?-1:t>e?1:0},bs:function(){return new S(this.sort)},setSort:function(t){this.bs=new S(t)},set:function(t,e){var n=x(this.keys,t,this.sort);n.found?this.values[n.index].push(e):(this.keys.splice(n.index,0,t),this.values.splice(n.index,0,[e]))},get:function(t){var e=x(this.keys,t,this.sort);return e.found?this.values[e.index]:[]},getLt:function(t){var e=x(this.keys,t,this.sort),n=e.index;return e.found&&n--,this.getAll(t,0,n)},getGt:function(t){var e=x(this.keys,t,this.sort),n=e.index;return e.found&&n++,this.getAll(t,n,this.keys.length)},getAll:function(t,e,n){for(var r=[],i=e;n>i;i++)r=r.concat(this.values[i]);return r},getPos:function(t){return x(this.keys,t,this.sort)},remove:function(t,e){var n=x(this.keys,t,this.sort).index,r=this.values[n];for(var i in r)r[i]==e&&r.splice(i,1);r.length<1&&(this.keys.splice(n,1),this.values.splice(n,1))},clear:function(t){this.keys=[],this.values=[]}},c.Collection=d,c.KeyValueStore=I,c}()})}).call(e,function(){return this}())},function(t,e){console.log("I'm `fs` modules")},function(t,e){"use strict";var n={v4:function(){var t=Math.round(1e6-5e5*Math.random());return t}};t.exports=n},function(t,e,n){"use strict";var r=n(5),i={},o=function(t){if(i[t])return i[t];var e=r.createActions(["add","update","destroy","filter","sort","search","registerView","resetView","reload","populate","onPopulateSuccess","destroyAll","setObject","setCollection"]);return t&&(i[t]=e),e};t.exports=o},function(t,e,n){"use strict";function r(t,e){return void 0===t&&(t=null),e}var i=n(5),o=n(3),s={registerStore:function(t,e,n){this.store=e,this.name=""+e.name+"Synchronizer",this.idAttribute=t.idAttribute,this.client=n,this.onError=t.onError,this.setDeserializer(),this.listenTo(e,this.onStoreChange),this.listenTo(e.listenables.populate,this.populate)},onStoreChange:function(t,e){var n=void 0===arguments[2]?!0:arguments[2],r=["add","update","destroy"];n&&o.contains(r,t)&&this[t](e)},setSerializer:function(t){this.serializer=t},setDeserializer:function(){var t=void 0===arguments[0]?r:arguments[0];this.deserializer=t},setClient:function(t){this.client=t},_logError:function(t,e){this.onError&&this.onError(this.name,t,e)},populate:function(t,e){var n=this;this.client.getAll(t,e).then(function(e){var r;e.constructor===Array?(r=e.map(n.deserializer.bind(null,t)),n.store.listenables.setCollection(r),setTimeout(function(){n.store.listenables.onPopulateSuccess()},1e3)):(r=n.deserializer(t,e),n.store.listenables.setObject(r)),n.trigger("populate",e)}).fail(function(t){n._logError("populate",t),console.error(t)})},reload:function(t){var e=this;this.client.get(t.id).then(function(n){e._updateSuccess(t,n)}).fail(function(t){e._logError("reload",t),console.error(t)})},update:function(t){var e=this;this.client.update(t,this.serializer).then(function(n){e._updateSuccess(t,n),e.store.flushChanges()}).fail(function(t){e._logError("update",t),console.error(t)})},_updateSuccess:function(t,e){var n=o.extend({},t,e);this.store.listenables.setObject(n),this.trigger("update",n)},destroy:function(t){var e=this;this.client.destroy(t).then(function(t){e.trigger("destroy",t),e.store.flushChanges()}).fail(function(t){e._logError("destroy",t),console.error(t)})},add:function(t){var e=this,n=o.clone(t);delete n.id,this.client.add(n,this.serializer).then(function(r){e.store.listenables.setObject(o.extend({},n,r)),e.store.flushChanges(),r.oldId=t.id,e.trigger("add",r)}).fail(function(t){e._logError("add",t),console.error(t)})}};t.exports=function(t,e,n){var r=i.createStore(s);return r.registerStore(t,e,n),r}},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var i=function(){function t(t,e){for(var n=0;n tag, or a module - // using CommonJS and NodeJS or RequireJS module formats. In - // Common/Node/RequireJS, the module exports the Q API and when - // executed as a simple