diff --git a/src/common.js b/src/common.js index f3010ccd5..c7f853c99 100644 --- a/src/common.js +++ b/src/common.js @@ -61,20 +61,6 @@ function objectKeys(object) { return result; } -/** - * like objectKeys, but includes keys from prototype chain. - * @param object the object whose prototypal keys will be returned - * @param ignoreKeys an array of keys to ignore - */ -function protoKeys(object, ignoreKeys) { - var result = []; - for (var key in object) { - if (!ignoreKeys || ignoreKeys.indexOf(key) === -1) - result.push(key); - } - return result; -} - /** * IE8-safe wrapper for `Array.prototype.indexOf()`. * @@ -82,7 +68,7 @@ function protoKeys(object, ignoreKeys) { * @param {*} value A value to search the array for. * @return {Number} Returns the array index value of `value`, or `-1` if not present. */ -function arraySearch(array, value) { +function indexOf(array, value) { if (Array.prototype.indexOf) { return array.indexOf(value, Number(arguments[2]) || 0); } @@ -115,7 +101,7 @@ function inheritParams(currentParams, newParams, $current, $to) { if (!parentParams.length) continue; for (var j in parentParams) { - if (arraySearch(inheritList, parentParams[j]) >= 0) continue; + if (indexOf(inheritList, parentParams[j]) >= 0) continue; inheritList.push(parentParams[j]); inherited[parentParams[j]] = currentParams[parentParams[j]]; } @@ -160,6 +146,66 @@ function filterByKeys(keys, values) { }); return filtered; } + +// like _.indexBy +// when you know that your index values will be unique, or you want last-one-in to win +function indexBy(array, propName) { + var result = {}; + forEach(array, function(item) { + result[item[propName]] = item; + }); + return result; +} + +// extracted from underscore.js +// Return a copy of the object only containing the whitelisted properties. +function pick(obj) { + var copy = {}; + var keys = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1)); + forEach(keys, function(key) { + if (key in obj) copy[key] = obj[key]; + }); + return copy; +} + +// extracted from underscore.js +// Return a copy of the object omitting the blacklisted properties. +function omit(obj) { + var copy = {}; + var keys = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1)); + for (var key in obj) { + if (keys.indexOf(key) == -1) copy[key] = obj[key]; + } + return copy; +} + +function pluck(collection, key) { + var result = isArray(collection) ? [] : {}; + + forEach(collection, function(val, i) { + result[i] = isFunction(key) ? key(val) : val[key]; + }); + return result; +} + +function filter(collection, callback) { + var result = isArray(collection) ? [] : {}; + forEach(collection, function(val, i) { + if (callback(val, i)) + result[i] = val; + }); + return result; +} + +function map(collection, callback) { + var result = isArray(collection) ? [] : {}; + + forEach(collection, function(val, i) { + result[i] = callback(val, i); + }); + return result; +} + /** * @ngdoc overview * @name ui.router.util diff --git a/src/resolve.js b/src/resolve.js index e1d07c8e6..f1c179009 100644 --- a/src/resolve.js +++ b/src/resolve.js @@ -41,7 +41,7 @@ function $Resolve( $q, $injector) { */ this.study = function (invocables) { if (!isObject(invocables)) throw new Error("'invocables' must be an object"); - var invocableKeys = Object.keys(invocables || {}); + var invocableKeys = objectKeys(invocables || {}); // Perform a topological sort of invocables to build an ordered plan var plan = [], cycle = [], visited = {}; @@ -50,7 +50,7 @@ function $Resolve( $q, $injector) { cycle.push(key); if (visited[key] === VISIT_IN_PROGRESS) { - cycle.splice(0, cycle.indexOf(key)); + cycle.splice(0, indexOf(cycle, key)); throw new Error("Cyclic dependency: " + cycle.join(" -> ")); } visited[key] = VISIT_IN_PROGRESS; @@ -113,14 +113,6 @@ function $Resolve( $q, $injector) { resolution.reject(reason); } - // TODO: Remove this when we merge in 'new' branch - function omit(obj) { - var copy = {}, keys = angular.isArray(arguments[1]) ? arguments[1] : arguments.slice(1); - for (var key in obj) - if (keys.indexOf(key) == -1) copy[key] = obj[key]; - return copy; - } - // Short-circuit if parent has already failed if (isDefined(parent.$$failure)) { fail(parent.$$failure); diff --git a/src/state.js b/src/state.js index 69cf08a75..0ac905225 100644 --- a/src/state.js +++ b/src/state.js @@ -217,12 +217,12 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { //match greedy starts if (globSegments[0] === '**') { - segments = segments.slice(segments.indexOf(globSegments[1])); + segments = segments.slice(indexOf(segments, globSegments[1])); segments.unshift('**'); } //match greedy ends if (globSegments[globSegments.length - 1] === '**') { - segments.splice(segments.indexOf(globSegments[globSegments.length - 2]) + 1, Number.MAX_VALUE); + segments.splice(indexOf(segments, globSegments[globSegments.length - 2]) + 1, Number.MAX_VALUE); segments.push('**'); } @@ -1143,7 +1143,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { * @returns {Object|Array} State configuration object or array of all objects. */ $state.get = function (stateOrName, context) { - if (arguments.length === 0) return objectKeys(states).map(function(name) { return states[name].self; }); + if (arguments.length === 0) return map(objectKeys(states), function(name) { return states[name].self; }); var state = findState(stateOrName, context || $state.$current); return (state && state.self) ? state.self : null; }; diff --git a/src/urlMatcherFactory.js b/src/urlMatcherFactory.js index 8baf3f4be..5052c5802 100644 --- a/src/urlMatcherFactory.js +++ b/src/urlMatcherFactory.js @@ -238,7 +238,10 @@ UrlMatcher.prototype.exec = function (path, searchParams) { function decodePathArray(string) { function reverseString(str) { return str.split("").reverse().join(""); } function unquoteDashes(str) { return str.replace(/\\-/, "-"); } - return reverseString(string).split(/-(?!\\)/).map(reverseString).map(unquoteDashes).reverse(); + + var split = reverseString(string).split(/-(?!\\)/); + var allReversed = map(split, reverseString); + return map(allReversed, unquoteDashes).reverse(); } for (i = 0; i < nPath; i++) { @@ -334,7 +337,7 @@ UrlMatcher.prototype.format = function (values) { if (squash === false) { if (encoded != null) { if (isArray(encoded)) { - result += encoded.map(encodeDashes).join("-"); + result += map(encoded, encodeDashes).join("-"); } else { result += encodeURIComponent(encoded); } @@ -349,7 +352,7 @@ UrlMatcher.prototype.format = function (values) { } else { if (encoded == null || (isDefaultValue && squash !== false)) continue; if (!isArray(encoded)) encoded = [ encoded ]; - encoded = encoded.map(encodeURIComponent).join('&' + name + '='); + encoded = map(encoded, encodeURIComponent).join('&' + name + '='); result += (search ? '&' : '?') + (name + '=' + encoded); search = true; } @@ -498,7 +501,7 @@ Type.prototype.$asArray = function(mode, isSearch) { // Wraps type functions to operate on each value of an array return function handleArray(val) { if (!isArray(val)) val = [ val ]; - var result = val.map(callback); + var result = map(val, callback); if (reducefn) return result.reduce(reducefn, true); return (result && result.length == 1 && mode === "auto") ? result[0] : result; @@ -844,8 +847,8 @@ function $UrlMatcherFactory() { function getDefaultValueConfig(config) { var keys = isObject(config) ? objectKeys(config) : []; - var isShorthand = keys.indexOf("value") === -1 && keys.indexOf("type") === -1 && - keys.indexOf("squash") === -1 && keys.indexOf("array") === -1; + var isShorthand = indexOf(keys, "value") === -1 && indexOf(keys, "type") === -1 && + indexOf(keys, "squash") === -1 && indexOf(keys, "array") === -1; var configValue = isShorthand ? config : config.value; return { fn: isInjectable(configValue) ? configValue : function () { return configValue; }, @@ -886,8 +889,8 @@ function $UrlMatcherFactory() { replace = isArray(config.replace) ? config.replace : []; if (isString(squash)) replace.push({ from: squash, to: undefined }); - configuredKeys = replace.map(function(item) { return item.from; } ); - return defaultPolicy.filter(function(item) { return configuredKeys.indexOf(item.from) === -1; }).concat(replace); + configuredKeys = map(replace, function(item) { return item.from; } ); + return filter(defaultPolicy, function(item) { return indexOf(configuredKeys, item.from) === -1; }).concat(replace); } /** @@ -905,7 +908,7 @@ function $UrlMatcherFactory() { function $value(value) { function hasReplaceVal(val) { return function(obj) { return obj.from === val; }; } function $replace(value) { - var replacement = self.replace.filter(hasReplaceVal(value)).map(function(obj) { return obj.to; }); + var replacement = map(filter(self.replace, hasReplaceVal(value)), function(obj) { return obj.to; }); return replacement.length ? replacement[0] : value; } value = $replace(value); @@ -943,7 +946,7 @@ function $UrlMatcherFactory() { chain.reverse(); forEach(chain, function(paramset) { forEach(objectKeys(paramset), function(key) { - if (keys.indexOf(key) === -1 && ignore.indexOf(key) === -1) keys.push(key); + if (indexOf(keys, key) === -1 && indexOf(ignore, key) === -1) keys.push(key); }); }); return keys;