From 831f4964aa498d69a835666a9c2a3f1ae3477bfe Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 22 Nov 2013 01:19:09 +0200 Subject: [PATCH] fix build and tests, add missing methods to lodash build --- build.js | 2 +- js/lib/lodash.js | 1031 +++++++++++++++++++++++------------- test/spec/behavior/hash.js | 6 + 3 files changed, 671 insertions(+), 368 deletions(-) diff --git a/build.js b/build.js index e1b0de2b2..36b604fcf 100644 --- a/build.js +++ b/build.js @@ -122,7 +122,7 @@ function generatePresets() { }); fs.writeFileSync('data/presets/presets.json', stringify(presets)); - fs.writeFileSync('js/id/core/area_keys.js', '/* jshint -W109 */\niD.Way.areaKeys = ' + stringify(areaKeys) + ';'); + fs.writeFileSync('js/id/core/area_keys.js', '/* jshint -W109 */\niD.areaKeys = ' + stringify(areaKeys) + ';'); var presetsYaml = _.cloneDeep(translations); _.forEach(presetsYaml.presets, function(preset) { diff --git a/js/lib/lodash.js b/js/lib/lodash.js index c21dfda8f..cda72370c 100644 --- a/js/lib/lodash.js +++ b/js/lib/lodash.js @@ -1,7 +1,7 @@ /** * @license * Lo-Dash 2.3.0 (Custom Build) - * Build: `lodash include="any,assign,bind,clone,compact,contains,debounce,difference,each,every,extend,filter,find,first,forEach,groupBy,indexOf,intersection,isEmpty,isEqual,isFunction,keys,last,map,omit,pairs,pluck,reject,some,throttle,union,uniq,unique,values,without,chain,flatten,value" exports="global"` + * Build: `lodash include="any,assign,bind,clone,compact,contains,debounce,difference,each,every,extend,filter,find,first,forEach,groupBy,indexOf,intersection,isEmpty,isEqual,isFunction,keys,last,map,omit,pairs,pluck,reject,some,throttle,union,uniq,unique,values,without,flatten,value,chain,cloneDeep,merge" exports="global,node"` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors @@ -106,6 +106,15 @@ /** Used as a reference to the global object */ var root = (objectTypes[typeof window] && window) || this; + /** Detect free variable `exports` */ + var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; + + /** Detect free variable `module` */ + var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; + + /** Detect the popular CommonJS extension `module.exports` */ + var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; + /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */ var freeGlobal = objectTypes[typeof global] && global; if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) { @@ -126,11 +135,11 @@ */ function baseIndexOf(array, value, fromIndex) { var index = (fromIndex || 0) - 1, - length = array ? array.length : 0; + length = array ? array.length : 0; while (++index < length) { if (array[index] === value) { - return index; + return index; } } return -1; @@ -171,21 +180,21 @@ */ function cachePush(value) { var cache = this.cache, - type = typeof value; + type = typeof value; if (type == 'boolean' || value == null) { cache[value] = true; } else { if (type != 'number' && type != 'string') { - type = 'object'; + type = 'object'; } var key = type == 'number' ? value : keyPrefix + value, - typeCache = cache[type] || (cache[type] = {}); + typeCache = cache[type] || (cache[type] = {}); if (type == 'object') { - (typeCache[key] || (typeCache[key] = [])).push(value); + (typeCache[key] || (typeCache[key] = [])).push(value); } else { - typeCache[key] = true; + typeCache[key] = true; } } } @@ -199,13 +208,13 @@ */ function createCache(array) { var index = -1, - length = array.length, - first = array[0], - mid = array[(length / 2) | 0], - last = array[length - 1]; + length = array.length, + first = array[0], + mid = array[(length / 2) | 0], + last = array[length - 1]; if (first && typeof first == 'object' && - mid && typeof mid == 'object' && last && typeof last == 'object') { + mid && typeof mid == 'object' && last && typeof last == 'object') { return false; } var cache = getObject(); @@ -351,6 +360,7 @@ /** Native method shortcuts */ var fnToString = Function.prototype.toString, + getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, hasOwnProperty = objectProto.hasOwnProperty, now = reNative.test(now = Date.now) && now || function() { return +new Date; }, push = arrayRef.push, @@ -361,8 +371,8 @@ // IE 8 only accepts DOM elements try { var o = {}, - func = reNative.test(func = Object.defineProperty) && func, - result = func(o, o, o) && func; + func = reNative.test(func = Object.defineProperty) && func, + result = func(o, o, o) && func; } catch(e) { } return result; }()); @@ -397,9 +407,9 @@ while (length--) { var key = shadowedProps[length]; for (var className in nonEnumProps) { - if (hasOwnProperty.call(nonEnumProps, className) && !hasOwnProperty.call(nonEnumProps[className], key)) { - nonEnumProps[className][key] = false; - } + if (hasOwnProperty.call(nonEnumProps, className) && !hasOwnProperty.call(nonEnumProps[className], key)) { + nonEnumProps[className][key] = false; + } } } }()); @@ -504,8 +514,8 @@ (function() { var ctor = function() { this.x = 1; }, - object = { '0': 1, 'length': 1 }, - props = []; + object = { '0': 1, 'length': 1 }, + props = []; ctor.prototype = { 'valueOf': 1, 'y': 1 }; for (var key in new ctor) { props.push(key); } @@ -586,6 +596,14 @@ */ support.nonEnumShadows = !/valueOf/.test(props); + /** + * Detect if own properties are iterated after inherited properties (all but IE < 9). + * + * @memberOf _.support + * @type boolean + */ + support.ownLast = props[0] != 'x'; + /** * Detect if `Array#shift` and `Array#splice` augment array-like objects correctly. * @@ -668,11 +686,11 @@ __p += '\n var skipErrorProps = iterable === errorProto || iterable instanceof Error;\n '; } - var conditions = []; if (support.enumPrototypes) { conditions.push('!(skipProto && index == "prototype")'); } if (support.enumErrorProps) { conditions.push('!(skipErrorProps && (index == "message" || index == "name"))'); } + var conditions = []; if (support.enumPrototypes) { conditions.push('!(skipProto && index == "prototype")'); } if (support.enumErrorProps) { conditions.push('!(skipErrorProps && (index == "message" || index == "name"))'); } if (obj.useHas && obj.keys) { __p += '\n var ownIndex = -1,\n ownProps = objectTypes[typeof iterable] && keys(iterable),\n length = ownProps ? ownProps.length : 0;\n\n while (++ownIndex < length) {\n index = ownProps[ownIndex];\n'; - if (conditions.length) { + if (conditions.length) { __p += ' if (' + (conditions.join(' && ')) + ') {\n '; @@ -686,7 +704,7 @@ __p += '\n } '; } else { __p += '\n for (index in iterable) {\n'; - if (obj.useHas) { conditions.push("hasOwnProperty.call(iterable, index)"); } if (conditions.length) { + if (obj.useHas) { conditions.push("hasOwnProperty.call(iterable, index)"); } if (conditions.length) { __p += ' if (' + (conditions.join(' && ')) + ') {\n '; @@ -704,7 +722,7 @@ __p += '\n index = \'' + (obj.shadowedProps[k]) + '\';\n if ((!(isProto && nonEnum[index]) && hasOwnProperty.call(iterable, index))'; - if (!obj.useHas) { + if (!obj.useHas) { __p += ' || (!nonEnum[index] && iterable[index] !== objectProto[index])'; } __p += ') {\n ' + @@ -738,23 +756,23 @@ */ function baseBind(bindData) { var func = bindData[0], - partialArgs = bindData[2], - thisArg = bindData[4]; + partialArgs = bindData[2], + thisArg = bindData[4]; function bound() { // `Function#bind` spec // http://es5.github.io/#x15.3.4.5 if (partialArgs) { - var args = partialArgs.slice(); - push.apply(args, arguments); + var args = partialArgs.slice(); + push.apply(args, arguments); } // mimic the constructor's `return` behavior // http://es5.github.io/#x13.2.2 if (this instanceof bound) { - // ensure `new bound` is an instance of `func` - var thisBinding = baseCreate(func.prototype), - result = func.apply(thisBinding, args || arguments); - return isObject(result) ? result : thisBinding; + // ensure `new bound` is an instance of `func` + var thisBinding = baseCreate(func.prototype), + result = func.apply(thisBinding, args || arguments); + return isObject(result) ? result : thisBinding; } return func.apply(thisArg, args || arguments); } @@ -778,7 +796,7 @@ if (callback) { var result = callback(value); if (typeof result != 'undefined') { - return result; + return result; } } // inspect [[Class]] @@ -790,18 +808,18 @@ } var ctor = ctorByClass[className]; switch (className) { - case boolClass: - case dateClass: - return new ctor(+value); + case boolClass: + case dateClass: + return new ctor(+value); - case numberClass: - case stringClass: - return new ctor(value); + case numberClass: + case stringClass: + return new ctor(value); - case regexpClass: - result = ctor(value.source, reFlags.exec(value)); - result.lastIndex = value.lastIndex; - return result; + case regexpClass: + result = ctor(value.source, reFlags.exec(value)); + result.lastIndex = value.lastIndex; + return result; } } else { return value; @@ -815,9 +833,9 @@ var length = stackA.length; while (length--) { - if (stackA[length] == value) { - return stackB[length]; - } + if (stackA[length] == value) { + return stackB[length]; + } } result = isArr ? ctor(value.length) : {}; } @@ -827,10 +845,10 @@ // add array properties assigned by `RegExp#exec` if (isArr) { if (hasOwnProperty.call(value, 'index')) { - result.index = value.index; + result.index = value.index; } if (hasOwnProperty.call(value, 'input')) { - result.input = value.input; + result.input = value.input; } } // exit for shallow clone @@ -870,12 +888,12 @@ baseCreate = (function() { function Object() {} return function(prototype) { - if (isObject(prototype)) { - Object.prototype = prototype; - var result = new Object; - Object.prototype = null; - } - return result || root.Object(); + if (isObject(prototype)) { + Object.prototype = prototype; + var result = new Object; + Object.prototype = null; + } + return result || root.Object(); }; }()); } @@ -901,19 +919,19 @@ var bindData = func.__bindData__; if (typeof bindData == 'undefined') { if (support.funcNames) { - bindData = !func.name; + bindData = !func.name; } bindData = bindData || !support.funcDecomp; if (!bindData) { - var source = fnToString.call(func); - if (!support.funcNames) { - bindData = !reFuncName.test(source); - } - if (!bindData) { - // checks if `func` references the `this` keyword and stores the result - bindData = reThis.test(source); - setBindData(func, bindData); - } + var source = fnToString.call(func); + if (!support.funcNames) { + bindData = !reFuncName.test(source); + } + if (!bindData) { + // checks if `func` references the `this` keyword and stores the result + bindData = reThis.test(source); + setBindData(func, bindData); + } } } // exit early if there are no `this` references or `func` is bound @@ -922,16 +940,16 @@ } switch (argCount) { case 1: return function(value) { - return func.call(thisArg, value); + return func.call(thisArg, value); }; case 2: return function(a, b) { - return func.call(thisArg, a, b); + return func.call(thisArg, a, b); }; case 3: return function(value, index, collection) { - return func.call(thisArg, value, index, collection); + return func.call(thisArg, value, index, collection); }; case 4: return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); + return func.call(thisArg, accumulator, value, index, collection); }; } return bind(func, thisArg); @@ -947,42 +965,42 @@ */ function baseCreateWrapper(bindData) { var func = bindData[0], - bitmask = bindData[1], - partialArgs = bindData[2], - partialRightArgs = bindData[3], - thisArg = bindData[4], - arity = bindData[5]; + bitmask = bindData[1], + partialArgs = bindData[2], + partialRightArgs = bindData[3], + thisArg = bindData[4], + arity = bindData[5]; var isBind = bitmask & 1, - isBindKey = bitmask & 2, - isCurry = bitmask & 4, - isCurryBound = bitmask & 8, - key = func; + isBindKey = bitmask & 2, + isCurry = bitmask & 4, + isCurryBound = bitmask & 8, + key = func; function bound() { var thisBinding = isBind ? thisArg : this; if (partialArgs) { - var args = partialArgs.slice(); - push.apply(args, arguments); + var args = partialArgs.slice(); + push.apply(args, arguments); } if (partialRightArgs || isCurry) { - args || (args = slice(arguments)); - if (partialRightArgs) { - push.apply(args, partialRightArgs); - } - if (isCurry && args.length < arity) { - bitmask |= 16 & ~32; - return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]); - } + args || (args = slice(arguments)); + if (partialRightArgs) { + push.apply(args, partialRightArgs); + } + if (isCurry && args.length < arity) { + bitmask |= 16 & ~32; + return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]); + } } args || (args = arguments); if (isBindKey) { - func = thisBinding[key]; + func = thisBinding[key]; } if (this instanceof bound) { - thisBinding = baseCreate(func.prototype); - var result = func.apply(thisBinding, args); - return isObject(result) ? result : thisBinding; + thisBinding = baseCreate(func.prototype); + var result = func.apply(thisBinding, args); + return isObject(result) ? result : thisBinding; } return func.apply(thisBinding, args); } @@ -1001,24 +1019,24 @@ */ function baseDifference(array, values) { var index = -1, - indexOf = getIndexOf(), - length = array ? array.length : 0, - isLarge = length >= largeArraySize && indexOf === baseIndexOf, - result = []; + indexOf = getIndexOf(), + length = array ? array.length : 0, + isLarge = length >= largeArraySize && indexOf === baseIndexOf, + result = []; if (isLarge) { var cache = createCache(values); if (cache) { - indexOf = cacheIndexOf; - values = cache; + indexOf = cacheIndexOf; + values = cache; } else { - isLarge = false; + isLarge = false; } } while (++index < length) { var value = array[index]; if (indexOf(values, value) < 0) { - result.push(value); + result.push(value); } } if (isLarge) { @@ -1040,28 +1058,28 @@ */ function baseFlatten(array, isShallow, isStrict, fromIndex) { var index = (fromIndex || 0) - 1, - length = array ? array.length : 0, - result = []; + length = array ? array.length : 0, + result = []; while (++index < length) { var value = array[index]; if (value && typeof value == 'object' && typeof value.length == 'number' - && (isArray(value) || isArguments(value))) { - // recursively flatten arrays (susceptible to call stack limits) - if (!isShallow) { - value = baseFlatten(value, isShallow, isStrict); - } - var valIndex = -1, - valLength = value.length, - resIndex = result.length; + && (isArray(value) || isArguments(value))) { + // recursively flatten arrays (susceptible to call stack limits) + if (!isShallow) { + value = baseFlatten(value, isShallow, isStrict); + } + var valIndex = -1, + valLength = value.length, + resIndex = result.length; - result.length += valLength; - while (++valIndex < valLength) { - result[resIndex++] = value[valIndex]; - } + result.length += valLength; + while (++valIndex < valLength) { + result[resIndex++] = value[valIndex]; + } } else if (!isStrict) { - result.push(value); + result.push(value); } } return result; @@ -1085,7 +1103,7 @@ if (callback) { var result = callback(a, b); if (typeof result != 'undefined') { - return !!result; + return !!result; } } // exit early for identical values @@ -1094,12 +1112,12 @@ return a !== 0 || (1 / a == 1 / b); } var type = typeof a, - otherType = typeof b; + otherType = typeof b; // exit early for unlike primitive values if (a === a && - !(a && objectTypes[type]) && - !(b && objectTypes[otherType])) { + !(a && objectTypes[type]) && + !(b && objectTypes[otherType])) { return false; } // exit early for `null` and `undefined` avoiding ES3's Function#call behavior @@ -1109,7 +1127,7 @@ } // compare [[Class]] names var className = toString.call(a), - otherClass = toString.call(b); + otherClass = toString.call(b); if (className == argsClass) { className = objectClass; @@ -1124,30 +1142,30 @@ case boolClass: case dateClass: // coerce dates and booleans to numbers, dates to milliseconds and booleans - // to `1` or `0` treating invalid dates coerced to `NaN` as not equal + // to `1` or `0` treating invalid dates coerced to `NaN` as not equal return +a == +b; case numberClass: // treat `NaN` vs. `NaN` as equal - return (a != +a) + return (a != +a) ? b != +b // but treat `+0` vs. `-0` as not equal : (a == 0 ? (1 / a == 1 / b) : a == +b); case regexpClass: case stringClass: - // coerce regexes to strings (http://es5.github.io/#x15.10.6.4) + // coerce regexes to strings (http://es5.github.io/#x15.10.6.4) // treat string primitives and their corresponding object instances as equal - return a == String(b); + return a == String(b); } var isArr = className == arrayClass; if (!isArr) { // unwrap any `lodash` wrapped values var aWrapped = hasOwnProperty.call(a, '__wrapped__'), - bWrapped = hasOwnProperty.call(b, '__wrapped__'); + bWrapped = hasOwnProperty.call(b, '__wrapped__'); if (aWrapped || bWrapped) { - return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB); + return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB); } // exit for functions and DOM nodes if (className != objectClass || (!support.nodeClass && (isNode(a) || isNode(b)))) { @@ -1155,13 +1173,13 @@ } // in older versions of Opera, `arguments` objects have `Array` constructors var ctorA = !support.argsObject && isArguments(a) ? Object : a.constructor, - ctorB = !support.argsObject && isArguments(b) ? Object : b.constructor; + ctorB = !support.argsObject && isArguments(b) ? Object : b.constructor; // non `Object` object instances with different constructors are not equal if (ctorA != ctorB && - !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) && - ('constructor' in a && 'constructor' in b) - ) { + !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) && + ('constructor' in a && 'constructor' in b) + ) { return false; } } @@ -1193,21 +1211,21 @@ // compare lengths to determine if a deep comparison is necessary result = size == a.length; if (!result && !isWhere) { - return result; + return result; } // deep compare the contents, ignoring non-numeric properties while (size--) { - var index = length, - value = b[size]; + var index = length, + value = b[size]; - if (isWhere) { - while (index--) { - if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) { - break; - } + if (isWhere) { + while (index--) { + if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) { + break; + } } - } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) { - break; + } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) { + break; } } return result; @@ -1216,20 +1234,20 @@ // which, in this case, is more costly forIn(b, function(value, key, b) { if (hasOwnProperty.call(b, key)) { - // count the number of properties. - size++; - // deep compare each property value. - return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB)); + // count the number of properties. + size++; + // deep compare each property value. + return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB)); } }); if (result && !isWhere) { // ensure both objects have the same number of properties forIn(a, function(value, key, a) { - if (hasOwnProperty.call(a, key)) { - // `size` will be `-1` if `a` has more properties than `b` - return (result = --size > -1); - } + if (hasOwnProperty.call(a, key)) { + // `size` will be `-1` if `a` has more properties than `b` + return (result = --size > -1); + } }); } if (initedStack) { @@ -1239,6 +1257,71 @@ return result; } + /** + * The base implementation of `_.merge` without argument juggling or support + * for `thisArg` binding. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {Function} [callback] The function to customize merging properties. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates values with source counterparts. + */ + function baseMerge(object, source, callback, stackA, stackB) { + (isArray(source) ? forEach : forOwn)(source, function(source, key) { + var found, + isArr, + result = source, + value = object[key]; + + if (source && ((isArr = isArray(source)) || isPlainObject(source))) { + // avoid merging previously merged cyclic sources + var stackLength = stackA.length; + while (stackLength--) { + if ((found = stackA[stackLength] == source)) { + value = stackB[stackLength]; + break; + } + } + if (!found) { + var isShallow; + if (callback) { + result = callback(value, source); + if ((isShallow = typeof result != 'undefined')) { + value = result; + } + } + if (!isShallow) { + value = isArr + ? (isArray(value) ? value : []) + : (isPlainObject(value) ? value : {}); + } + // add `source` and associated `value` to the stack of traversed objects + stackA.push(source); + stackB.push(value); + + // recursively merge objects and arrays (susceptible to call stack limits) + if (!isShallow) { + baseMerge(value, source, callback, stackA, stackB); + } + } + } + else { + if (callback) { + result = callback(value, source); + if (typeof result == 'undefined') { + result = source; + } + } + if (typeof result != 'undefined') { + value = result; + } + } + object[key] = value; + }); + } + /** * The base implementation of `_.uniq` without support for callback shorthands * or `thisArg` binding. @@ -1251,35 +1334,35 @@ */ function baseUniq(array, isSorted, callback) { var index = -1, - indexOf = getIndexOf(), - length = array ? array.length : 0, - result = []; + indexOf = getIndexOf(), + length = array ? array.length : 0, + result = []; var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf, - seen = (callback || isLarge) ? getArray() : result; + seen = (callback || isLarge) ? getArray() : result; if (isLarge) { var cache = createCache(seen); if (cache) { - indexOf = cacheIndexOf; - seen = cache; + indexOf = cacheIndexOf; + seen = cache; } else { - isLarge = false; - seen = callback ? seen : (releaseArray(seen), result); + isLarge = false; + seen = callback ? seen : (releaseArray(seen), result); } } while (++index < length) { var value = array[index], - computed = callback ? callback(value, index, array) : value; + computed = callback ? callback(value, index, array) : value; if (isSorted - ? !index || seen[seen.length - 1] !== computed - : indexOf(seen, computed) < 0 - ) { - if (callback || isLarge) { - seen.push(computed); - } - result.push(value); + ? !index || seen[seen.length - 1] !== computed + : indexOf(seen, computed) < 0 + ) { + if (callback || isLarge) { + seen.push(computed); + } + result.push(value); } } if (isLarge) { @@ -1307,17 +1390,17 @@ callback = lodash.createCallback(callback, thisArg, 3); if (isArray(collection)) { - var index = -1, - length = collection.length; + var index = -1, + length = collection.length; - while (++index < length) { - var value = collection[index]; - setter(result, value, callback(value, index, collection), collection); - } + while (++index < length) { + var value = collection[index]; + setter(result, value, callback(value, index, collection), collection); + } } else { - baseEach(collection, function(value, key, collection) { - setter(result, value, callback(value, key, collection), collection); - }); + baseEach(collection, function(value, key, collection) { + setter(result, value, callback(value, key, collection), collection); + }); } return result; }; @@ -1347,11 +1430,11 @@ */ function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) { var isBind = bitmask & 1, - isBindKey = bitmask & 2, - isCurry = bitmask & 4, - isCurryBound = bitmask & 8, - isPartial = bitmask & 16, - isPartialRight = bitmask & 32; + isBindKey = bitmask & 2, + isCurry = bitmask & 4, + isCurryBound = bitmask & 8, + isPartial = bitmask & 16, + isPartialRight = bitmask & 32; if (!isBindKey && !isFunction(func)) { throw new TypeError; @@ -1370,23 +1453,23 @@ // set `thisBinding` is not previously bound if (isBind && !(bindData[1] & 1)) { - bindData[4] = thisArg; + bindData[4] = thisArg; } // set if previously bound but not currently (subsequent curried functions) if (!isBind && bindData[1] & 1) { - bitmask |= 8; + bitmask |= 8; } // set curried arity if not yet set if (isCurry && !(bindData[1] & 4)) { - bindData[5] = arity; + bindData[5] = arity; } // append partial left arguments if (isPartial) { - push.apply(bindData[2] || (bindData[2] = []), partialArgs); + push.apply(bindData[2] || (bindData[2] = []), partialArgs); } // append partial right arguments if (isPartialRight) { - push.apply(bindData[3] || (bindData[3] = []), partialRightArgs); + push.apply(bindData[3] || (bindData[3] = []), partialRightArgs); } // merge flags bindData[1] |= bitmask; @@ -1423,7 +1506,7 @@ // merge options into a template data object for (var object, index = 0; object = arguments[index]; index++) { for (var key in object) { - iteratorData[key] = object[key]; + iteratorData[key] = object[key]; } } var args = iteratorData.args; @@ -1431,9 +1514,9 @@ // create the function factory var factory = Function( - 'baseCreateCallback, errorClass, errorProto, hasOwnProperty, ' + - 'indicatorObject, isArguments, isArray, isString, keys, objectProto, ' + - 'objectTypes, nonEnumProps, stringClass, stringProto, toString', + 'baseCreateCallback, errorClass, errorProto, hasOwnProperty, ' + + 'indicatorObject, isArguments, isArray, isString, keys, objectProto, ' + + 'objectTypes, nonEnumProps, stringClass, stringProto, toString', 'return function(' + args + ') {\n' + iteratorTemplate(iteratorData) + '\n}' ); @@ -1470,6 +1553,46 @@ defineProperty(func, '__bindData__', descriptor); }; + /** + * A fallback implementation of `isPlainObject` which checks if a given value + * is an object created by the `Object` constructor, assuming objects created + * by the `Object` constructor have no inherited enumerable properties and that + * there are no `Object.prototype` extensions. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + */ + function shimIsPlainObject(value) { + var ctor, + result; + + // avoid non Object objects, `arguments` objects, and DOM elements + if (!(value && toString.call(value) == objectClass) || + (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor)) || + (!support.argsClass && isArguments(value)) || + (!support.nodeClass && isNode(value))) { + return false; + } + // IE < 9 iterates inherited properties before own properties. If the first + // iterated property is an object's own property then there are no inherited + // enumerable properties. + if (support.ownLast) { + forIn(value, function(value, key, object) { + result = hasOwnProperty.call(object, key); + return false; + }); + return result !== false; + } + // In most environments an object's own properties are iterated before + // its inherited properties. If the last iterated property is an object's + // own property then there are no inherited enumerable properties. + forIn(value, function(value, key) { + result = key; + }); + return typeof result == 'undefined' || hasOwnProperty.call(value, result); + } + /*--------------------------------------------------------------------------*/ /** @@ -1496,7 +1619,7 @@ if (!support.argsClass) { isArguments = function(value) { return value && typeof value == 'object' && typeof value.length == 'number' && - hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee') || false; + hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee') || false; }; } @@ -1556,7 +1679,7 @@ return []; } if ((support.enumPrototypes && typeof object == 'function') || - (support.nonEnumArgs && object.length && isArguments(object))) { + (support.nonEnumArgs && object.length && isArguments(object))) { return shimKeys(object); } return nativeKeys(object); @@ -1643,12 +1766,12 @@ var assign = createIterator(defaultsIteratorOptions, { 'top': defaultsIteratorOptions.top.replace(';', - ';\n' + - "if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {\n" + - ' var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);\n' + - "} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {\n" + - ' callback = args[--argsLength];\n' + - '}' + ';\n' + + "if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {\n" + + ' var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);\n' + + "} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {\n" + + ' callback = args[--argsLength];\n' + + '}' ), 'loop': 'result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]' }); @@ -1704,6 +1827,51 @@ return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1)); } + /** + * Creates a deep clone of `value`. If a callback is provided it will be + * executed to produce the cloned values. If the callback returns `undefined` + * cloning will be handled by the method instead. The callback is bound to + * `thisArg` and invoked with one argument; (value). + * + * Note: This method is loosely based on the structured clone algorithm. Functions + * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and + * objects created by constructors other than `Object` are cloned to plain `Object` objects. + * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to deep clone. + * @param {Function} [callback] The function to customize cloning values. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {*} Returns the deep cloned value. + * @example + * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } + * ]; + * + * var deep = _.cloneDeep(characters); + * deep[0] === characters[0]; + * // => false + * + * var view = { + * 'label': 'docs', + * 'node': element + * }; + * + * var clone = _.cloneDeep(view, function(value) { + * return _.isElement(value) ? value.cloneNode(true) : undefined; + * }); + * + * clone.node == view.node; + * // => false + */ + function cloneDeep(value, callback, thisArg) { + return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1)); + } + /** * Iterates over own and inherited enumerable properties of an object, * executing the callback for each property. The callback is bound to `thisArg` @@ -1781,7 +1949,7 @@ var result = []; forIn(object, function(value, key) { if (isFunction(value)) { - result.push(key); + result.push(key); } }); return result.sort(); @@ -1814,11 +1982,11 @@ return result; } var className = toString.call(value), - length = value.length; + length = value.length; if ((className == arrayClass || className == stringClass || - (support.argsClass ? className == argsClass : isArguments(value))) || - (className == objectClass && typeof length == 'number' && isFunction(value.splice))) { + (support.argsClass ? className == argsClass : isArguments(value))) || + (className == objectClass && typeof length == 'number' && isFunction(value.splice))) { return !length; } forOwn(value, function() { @@ -1920,6 +2088,42 @@ return !!(value && objectTypes[typeof value]); } + /** + * Checks if `value` is an object created by the `Object` constructor. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * _.isPlainObject(new Shape); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + */ + var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { + if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) { + return false; + } + var valueOf = value.valueOf, + objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); + + return objProto + ? (value == objProto || getPrototypeOf(value) == objProto) + : shimIsPlainObject(value); + }; + /** * Checks if `value` is a string. * @@ -1938,6 +2142,88 @@ value && typeof value == 'object' && toString.call(value) == stringClass || false; } + /** + * Recursively merges own enumerable properties of the source object(s), that + * don't resolve to `undefined` into the destination object. Subsequent sources + * will overwrite property assignments of previous sources. If a callback is + * provided it will be executed to produce the merged values of the destination + * and source properties. If the callback returns `undefined` merging will + * be handled by the method instead. The callback is bound to `thisArg` and + * invoked with two arguments; (objectValue, sourceValue). + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The destination object. + * @param {...Object} [source] The source objects. + * @param {Function} [callback] The function to customize merging properties. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns the destination object. + * @example + * + * var names = { + * 'characters': [ + * { 'name': 'barney' }, + * { 'name': 'fred' } + * ] + * }; + * + * var ages = { + * 'characters': [ + * { 'age': 36 }, + * { 'age': 40 } + * ] + * }; + * + * _.merge(names, ages); + * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] } + * + * var food = { + * 'fruits': ['apple'], + * 'vegetables': ['beet'] + * }; + * + * var otherFood = { + * 'fruits': ['banana'], + * 'vegetables': ['carrot'] + * }; + * + * _.merge(food, otherFood, function(a, b) { + * return _.isArray(a) ? a.concat(b) : undefined; + * }); + * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] } + */ + function merge(object) { + var args = arguments, + length = 2; + + if (!isObject(object)) { + return object; + } + + // allows working with `_.reduce` and `_.reduceRight` without using + // their `index` and `collection` arguments + if (typeof args[2] != 'number') { + length = args.length; + } + if (length > 3 && typeof args[length - 2] == 'function') { + var callback = baseCreateCallback(args[--length - 1], args[length--], 2); + } else if (length > 2 && typeof args[length - 1] == 'function') { + callback = args[--length]; + } + var sources = slice(arguments, 1, length), + index = -1, + stackA = getArray(), + stackB = getArray(); + + while (++index < length) { + baseMerge(object, sources[index], callback, stackA, stackB); + } + releaseArray(stackA); + releaseArray(stackB); + return object; + } + /** * Creates a shallow clone of `object` excluding the specified properties. * Property names may be specified as individual arguments or as arrays of @@ -1969,23 +2255,23 @@ if (typeof callback != 'function') { var props = []; forIn(object, function(value, key) { - props.push(key); + props.push(key); }); props = baseDifference(props, baseFlatten(arguments, true, false, 1)); var index = -1, - length = props.length; + length = props.length; while (++index < length) { - var key = props[index]; - result[key] = object[key]; + var key = props[index]; + result[key] = object[key]; } } else { callback = lodash.createCallback(callback, thisArg, 3); forIn(object, function(value, key, object) { - if (!callback(value, key, object)) { - result[key] = value; - } + if (!callback(value, key, object)) { + result[key] = value; + } }); } return result; @@ -2007,9 +2293,9 @@ */ function pairs(object) { var index = -1, - props = keys(object), - length = props.length, - result = Array(length); + props = keys(object), + length = props.length, + result = Array(length); while (++index < length) { var key = props[index]; @@ -2033,9 +2319,9 @@ */ function values(object) { var index = -1, - props = keys(object), - length = props.length, - result = Array(length); + props = keys(object), + length = props.length, + result = Array(length); while (++index < length) { result[index] = object[props[index]]; @@ -2074,9 +2360,9 @@ */ function contains(collection, target, fromIndex) { var index = -1, - indexOf = getIndexOf(), - length = collection ? collection.length : 0, - result = false; + indexOf = getIndexOf(), + length = collection ? collection.length : 0, + result = false; fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; if (isArray(collection)) { @@ -2085,9 +2371,9 @@ result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1; } else { baseEach(collection, function(value) { - if (++index >= fromIndex) { - return !(result = value === target); - } + if (++index >= fromIndex) { + return !(result = value === target); + } }); } return result; @@ -2140,16 +2426,16 @@ if (isArray(collection)) { var index = -1, - length = collection.length; + length = collection.length; while (++index < length) { - if (!(result = !!callback(collection[index], index, collection))) { - break; - } + if (!(result = !!callback(collection[index], index, collection))) { + break; + } } } else { baseEach(collection, function(value, index, collection) { - return (result = !!callback(value, index, collection)); + return (result = !!callback(value, index, collection)); }); } return result; @@ -2201,19 +2487,19 @@ if (isArray(collection)) { var index = -1, - length = collection.length; + length = collection.length; while (++index < length) { - var value = collection[index]; - if (callback(value, index, collection)) { - result.push(value); + var value = collection[index]; + if (callback(value, index, collection)) { + result.push(value); } } } else { baseEach(collection, function(value, index, collection) { - if (callback(value, index, collection)) { - result.push(value); - } + if (callback(value, index, collection)) { + result.push(value); + } }); } return result; @@ -2267,21 +2553,21 @@ if (isArray(collection)) { var index = -1, - length = collection.length; + length = collection.length; while (++index < length) { - var value = collection[index]; - if (callback(value, index, collection)) { - return value; - } + var value = collection[index]; + if (callback(value, index, collection)) { + return value; + } } } else { var result; baseEach(collection, function(value, index, collection) { - if (callback(value, index, collection)) { - result = value; - return false; - } + if (callback(value, index, collection)) { + result = value; + return false; + } }); return result; } @@ -2316,12 +2602,12 @@ function forEach(collection, callback, thisArg) { if (callback && typeof thisArg == 'undefined' && isArray(collection)) { var index = -1, - length = collection.length; + length = collection.length; while (++index < length) { - if (callback(collection[index], index, collection) === false) { - break; - } + if (callback(collection[index], index, collection) === false) { + break; + } } } else { baseEach(collection, callback, thisArg); @@ -2409,17 +2695,17 @@ */ function map(collection, callback, thisArg) { var index = -1, - length = collection ? collection.length : 0, - result = Array(typeof length == 'number' ? length : 0); + length = collection ? collection.length : 0, + result = Array(typeof length == 'number' ? length : 0); callback = lodash.createCallback(callback, thisArg, 3); if (isArray(collection)) { while (++index < length) { - result[index] = callback(collection[index], index, collection); + result[index] = callback(collection[index], index, collection); } } else { baseEach(collection, function(value, key, collection) { - result[++index] = callback(value, key, collection); + result[++index] = callback(value, key, collection); }); } return result; @@ -2540,16 +2826,16 @@ if (isArray(collection)) { var index = -1, - length = collection.length; + length = collection.length; while (++index < length) { - if ((result = callback(collection[index], index, collection))) { - break; + if ((result = callback(collection[index], index, collection))) { + break; } } } else { baseEach(collection, function(value, index, collection) { - return !(result = callback(value, index, collection)); + return !(result = callback(value, index, collection)); }); } return !!result; @@ -2657,18 +2943,18 @@ */ function first(array, callback, thisArg) { var n = 0, - length = array ? array.length : 0; + length = array ? array.length : 0; if (typeof callback != 'number' && callback != null) { var index = -1; callback = lodash.createCallback(callback, thisArg, 3); while (++index < length && callback(array[index], index, array)) { - n++; + n++; } } else { n = callback; if (n == null || thisArg) { - return array ? array[0] : undefined; + return array ? array[0] : undefined; } } return slice(array, 0, nativeMin(nativeMax(0, n), length)); @@ -2779,20 +3065,20 @@ */ function intersection(array) { var args = arguments, - argsLength = args.length, - argsIndex = -1, - caches = getArray(), - index = -1, - indexOf = getIndexOf(), - length = array ? array.length : 0, - result = [], - seen = getArray(); + argsLength = args.length, + argsIndex = -1, + caches = getArray(), + index = -1, + indexOf = getIndexOf(), + length = array ? array.length : 0, + result = [], + seen = getArray(); while (++argsIndex < argsLength) { var value = args[argsIndex]; caches[argsIndex] = indexOf === baseIndexOf && - (value ? value.length : 0) >= largeArraySize && - createCache(argsIndex ? args[argsIndex] : seen); + (value ? value.length : 0) >= largeArraySize && + createCache(argsIndex ? args[argsIndex] : seen); } outer: while (++index < length) { @@ -2800,21 +3086,21 @@ value = array[index]; if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) { - argsIndex = argsLength; - (cache || seen).push(value); - while (--argsIndex) { - cache = caches[argsIndex]; - if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) { - continue outer; - } - } - result.push(value); + argsIndex = argsLength; + (cache || seen).push(value); + while (--argsIndex) { + cache = caches[argsIndex]; + if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) { + continue outer; + } + } + result.push(value); } } while (argsLength--) { cache = caches[argsLength]; if (cache) { - releaseObject(cache); + releaseObject(cache); } } releaseArray(caches); @@ -2874,18 +3160,18 @@ */ function last(array, callback, thisArg) { var n = 0, - length = array ? array.length : 0; + length = array ? array.length : 0; if (typeof callback != 'number' && callback != null) { var index = length; callback = lodash.createCallback(callback, thisArg, 3); while (index-- && callback(array[index], index, array)) { - n++; + n++; } } else { n = callback; if (n == null || thisArg) { - return array ? array[length - 1] : undefined; + return array ? array[length - 1] : undefined; } } return slice(array, nativeMax(0, length - n)); @@ -2941,7 +3227,7 @@ */ function sortedIndex(array, value, callback, thisArg) { var low = 0, - high = array ? array.length : low; + high = array ? array.length : low; // explicitly reference `identity` for better inlining in Firefox callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity; @@ -2950,8 +3236,8 @@ while (low < high) { var mid = (low + high) >>> 1; (callback(array[mid]) < value) - ? low = mid + 1 - : high = mid; + ? low = mid + 1 + : high = mid; } return low; } @@ -3119,30 +3405,30 @@ // handle "_.pluck" style callback shorthands if (type != 'object') { return function(object) { - return object[func]; + return object[func]; }; } var props = keys(func), - key = props[0], - a = func[key]; + key = props[0], + a = func[key]; // handle "_.where" style callback shorthands if (props.length == 1 && a === a && !isObject(a)) { // fast path the common case of providing an object with a single // property containing a primitive value return function(object) { - var b = object[key]; - return a === b && (a !== 0 || (1 / a == 1 / b)); + var b = object[key]; + return a === b && (a !== 0 || (1 / a == 1 / b)); }; } return function(object) { var length = props.length, - result = false; + result = false; while (length--) { - if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) { - break; - } + if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) { + break; + } } return result; }; @@ -3189,15 +3475,15 @@ */ function debounce(func, wait, options) { var args, - maxTimeoutId, + maxTimeoutId, result, - stamp, + stamp, thisArg, timeoutId, - trailingCall, - lastCalled = 0, - maxWait = false, - trailing = true; + trailingCall, + lastCalled = 0, + maxWait = false, + trailing = true; if (!isFunction(func)) { throw new TypeError; @@ -3214,34 +3500,34 @@ var delayed = function() { var remaining = wait - (now() - stamp); if (remaining <= 0) { - if (maxTimeoutId) { - clearTimeout(maxTimeoutId); - } - var isCalled = trailingCall; - maxTimeoutId = timeoutId = trailingCall = undefined; - if (isCalled) { - lastCalled = now(); - result = func.apply(thisArg, args); - if (!timeoutId && !maxTimeoutId) { - args = thisArg = null; - } - } + if (maxTimeoutId) { + clearTimeout(maxTimeoutId); + } + var isCalled = trailingCall; + maxTimeoutId = timeoutId = trailingCall = undefined; + if (isCalled) { + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + } } else { - timeoutId = setTimeout(delayed, remaining); + timeoutId = setTimeout(delayed, remaining); } }; var maxDelayed = function() { if (timeoutId) { - clearTimeout(timeoutId); + clearTimeout(timeoutId); } maxTimeoutId = timeoutId = trailingCall = undefined; if (trailing || (maxWait !== wait)) { - lastCalled = now(); - result = func.apply(thisArg, args); - if (!timeoutId && !maxTimeoutId) { - args = thisArg = null; - } + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = null; + } } }; @@ -3252,37 +3538,37 @@ trailingCall = trailing && (timeoutId || !leading); if (maxWait === false) { - var leadingCall = leading && !timeoutId; + var leadingCall = leading && !timeoutId; } else { - if (!maxTimeoutId && !leading) { - lastCalled = stamp; - } - var remaining = maxWait - (stamp - lastCalled), - isCalled = remaining <= 0; + if (!maxTimeoutId && !leading) { + lastCalled = stamp; + } + var remaining = maxWait - (stamp - lastCalled), + isCalled = remaining <= 0; - if (isCalled) { - if (maxTimeoutId) { - maxTimeoutId = clearTimeout(maxTimeoutId); - } - lastCalled = stamp; - result = func.apply(thisArg, args); - } - else if (!maxTimeoutId) { - maxTimeoutId = setTimeout(maxDelayed, remaining); - } + if (isCalled) { + if (maxTimeoutId) { + maxTimeoutId = clearTimeout(maxTimeoutId); + } + lastCalled = stamp; + result = func.apply(thisArg, args); + } + else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); + } } if (isCalled && timeoutId) { - timeoutId = clearTimeout(timeoutId); + timeoutId = clearTimeout(timeoutId); } else if (!timeoutId && wait !== maxWait) { - timeoutId = setTimeout(delayed, wait); + timeoutId = setTimeout(delayed, wait); } if (leadingCall) { - isCalled = true; + isCalled = true; result = func.apply(thisArg, args); } if (isCalled && !timeoutId && !maxTimeoutId) { - args = thisArg = null; + args = thisArg = null; } return result; }; @@ -3321,7 +3607,7 @@ */ function throttle(func, wait, options) { var leading = true, - trailing = true; + trailing = true; if (!isFunction(func)) { throw new TypeError; @@ -3384,7 +3670,7 @@ */ function mixin(object, source) { var ctor = object, - isFunc = !source || isFunction(ctor); + isFunc = !source || isFunction(ctor); if (!source) { ctor = lodashWrapper; @@ -3394,19 +3680,19 @@ forEach(functions(source), function(methodName) { var func = object[methodName] = source[methodName]; if (isFunc) { - ctor.prototype[methodName] = function() { - var value = this.__wrapped__, - args = [value]; + ctor.prototype[methodName] = function() { + var value = this.__wrapped__, + args = [value]; - push.apply(args, arguments); - var result = func.apply(object, args); - if (value && typeof value == 'object' && value === result) { - return this; - } - result = new ctor(result); - result.__chain__ = this.__chain__; - return result; - }; + push.apply(args, arguments); + var result = func.apply(object, args); + if (value && typeof value == 'object' && value === result) { + return this; + } + result = new ctor(result); + result.__chain__ = this.__chain__; + return result; + }; } }); } @@ -3541,6 +3827,7 @@ lodash.intersection = intersection; lodash.keys = keys; lodash.map = map; + lodash.merge = merge; lodash.omit = omit; lodash.pairs = pairs; lodash.pluck = pluck; @@ -3566,6 +3853,7 @@ // add functions that return unwrapped values when chaining lodash.clone = clone; + lodash.cloneDeep = cloneDeep; lodash.contains = contains; lodash.every = every; lodash.find = find; @@ -3577,6 +3865,7 @@ lodash.isEqual = isEqual; lodash.isFunction = isFunction; lodash.isObject = isObject; + lodash.isPlainObject = isPlainObject; lodash.isString = isString; lodash.mixin = mixin; lodash.noop = noop; @@ -3593,14 +3882,14 @@ forOwn(lodash, function(func, methodName) { if (!lodash.prototype[methodName]) { lodash.prototype[methodName] = function() { - var args = [this.__wrapped__], - chainAll = this.__chain__; + var args = [this.__wrapped__], + chainAll = this.__chain__; push.apply(args, arguments); - var result = func.apply(lodash, args); - return chainAll - ? new lodashWrapper(result, chainAll) - : result; + var result = func.apply(lodash, args); + return chainAll + ? new lodashWrapper(result, chainAll) + : result; }; } }); @@ -3619,12 +3908,12 @@ var callbackable = methodName !== 'sample'; if (!lodash.prototype[methodName]) { lodash.prototype[methodName]= function(n, guard) { - var chainAll = this.__chain__, - result = func(this.__wrapped__, n, guard); + var chainAll = this.__chain__, + result = func(this.__wrapped__, n, guard); - return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function'))) - ? result - : new lodashWrapper(result, chainAll); + return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function'))) + ? result + : new lodashWrapper(result, chainAll); }; } }); @@ -3651,11 +3940,11 @@ var func = arrayRef[methodName]; lodash.prototype[methodName] = function() { var chainAll = this.__chain__, - result = func.apply(this.__wrapped__, arguments); + result = func.apply(this.__wrapped__, arguments); return chainAll - ? new lodashWrapper(result, chainAll) - : result; + ? new lodashWrapper(result, chainAll) + : result; }; }); @@ -3684,23 +3973,31 @@ isSplice = methodName == 'splice'; lodash.prototype[methodName] = function() { - var chainAll = this.__chain__, - value = this.__wrapped__, + var chainAll = this.__chain__, + value = this.__wrapped__, result = func.apply(value, arguments); if (value.length === 0) { delete value[0]; } - return (chainAll || isSplice) - ? new lodashWrapper(result, chainAll) - : result; + return (chainAll || isSplice) + ? new lodashWrapper(result, chainAll) + : result; }; }); } /*--------------------------------------------------------------------------*/ + if (freeExports && freeModule) { + // in Node.js or RingoJS + if (moduleExports) { + (freeModule.exports = lodash)._ = lodash; + } + + } + else { // in a browser or Rhino root._ = lodash; - + } }.call(this)); diff --git a/test/spec/behavior/hash.js b/test/spec/behavior/hash.js index cf4ccf6e9..82177f034 100644 --- a/test/spec/behavior/hash.js +++ b/test/spec/behavior/hash.js @@ -56,9 +56,15 @@ describe('iD.behavior.Hash', function () { hash(); + var clock = sinon.useFakeTimers(); + context.map().center([38.9, -77.0]); context.map().zoom(2.0); + clock.tick(500); + expect(location.hash).to.equal('#map=2.00/38.9/-77.0'); + + clock.restore(); }); });