Skip to content

Commit

Permalink
release 0.2.13
Browse files Browse the repository at this point in the history
  • Loading branch information
christopherthielen committed Nov 21, 2014
1 parent ca6bc65 commit c3d543a
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 75 deletions.
181 changes: 108 additions & 73 deletions release/angular-ui-router.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* State-based routing for AngularJS
* @version v0.2.12
* @version v0.2.13
* @link http://angular-ui.github.com/
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
Expand Down Expand Up @@ -187,7 +187,7 @@ 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];
if (indexOf(keys, key) == -1) copy[key] = obj[key];
}
return copy;
}
Expand All @@ -202,10 +202,12 @@ function pluck(collection, key) {
}

function filter(collection, callback) {
var result = isArray(collection) ? [] : {};
var array = isArray(collection);
var result = array ? [] : {};
forEach(collection, function(val, i) {
if (callback(val, i))
result[i] = val;
if (callback(val, i)) {
result[array ? result.length : i] = val;
}
});
return result;
}
Expand Down Expand Up @@ -754,9 +756,11 @@ function UrlMatcher(pattern, config, parentMatcher) {
compiled = '^', last = 0, m,
segments = this.segments = [],
parentParams = parentMatcher ? parentMatcher.params : {},
params = this.params = parentMatcher ? parentMatcher.params.$$new() : new $$UMFP.ParamSet();
params = this.params = parentMatcher ? parentMatcher.params.$$new() : new $$UMFP.ParamSet(),
paramNames = [];

function addParameter(id, type, config, location) {
paramNames.push(id);
if (parentParams[id]) return parentParams[id];
if (!/^\w+(-+\w+)*(?:\[\])?$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
if (params[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'");
Expand Down Expand Up @@ -830,6 +834,7 @@ function UrlMatcher(pattern, config, parentMatcher) {

this.regexp = new RegExp(compiled, config.caseInsensitive ? 'i' : undefined);
this.prefix = segments[0];
this.$$paramNames = paramNames;
}

/**
Expand Down Expand Up @@ -945,7 +950,7 @@ UrlMatcher.prototype.exec = function (path, searchParams) {
* pattern has no parameters, an empty array is returned.
*/
UrlMatcher.prototype.parameters = function (param) {
if (!isDefined(param)) return this.params.$$keys();
if (!isDefined(param)) return this.$$paramNames;
return this.params[param] || null;
};

Expand Down Expand Up @@ -1161,28 +1166,51 @@ Type.prototype.$asArray = function(mode, isSearch) {
return new ArrayType(this, mode);

function ArrayType(type, mode) {
function bindTo(thisObj, callback) {
function bindTo(type, callbackName) {
return function() {
return callback.apply(thisObj, arguments);
return type[callbackName].apply(type, arguments);
};
}

function arrayHandler(callback, reducefn) {
// Wraps type functions to operate on each value of an array
// Wrap non-array value as array
function arrayWrap(val) { return isArray(val) ? val : (isDefined(val) ? [ val ] : []); }
// Unwrap array value for "auto" mode. Return undefined for empty array.
function arrayUnwrap(val) {
switch(val.length) {
case 0: return undefined;
case 1: return mode === "auto" ? val[0] : val;
default: return val;
}
}
function falsey(val) { return !val; }

// Wraps type (.is/.encode/.decode) functions to operate on each value of an array
function arrayHandler(callback, allTruthyMode) {
return function handleArray(val) {
if (!isArray(val)) val = [ val ];
val = arrayWrap(val);
var result = map(val, callback);
if (reducefn)
return result.reduce(reducefn, true);
return (result && result.length == 1 && mode === "auto") ? result[0] : result;
if (allTruthyMode === true)
return filter(result, falsey).length === 0;
return arrayUnwrap(result);
};
}

// Wraps type (.equals) functions to operate on each value of an array
function arrayEqualsHandler(callback) {
return function handleArray(val1, val2) {
var left = arrayWrap(val1), right = arrayWrap(val2);
if (left.length !== right.length) return false;
for (var i = 0; i < left.length; i++) {
if (!callback(left[i], right[i])) return false;
}
return true;
};
}

function alltruthy(val, memo) { return val && memo; }
this.encode = arrayHandler(bindTo(this, type.encode));
this.decode = arrayHandler(bindTo(this, type.decode));
this.equals = arrayHandler(bindTo(this, type.equals), alltruthy);
this.is = arrayHandler(bindTo(this, type.is), alltruthy);
this.encode = arrayHandler(bindTo(type, 'encode'));
this.decode = arrayHandler(bindTo(type, 'decode'));
this.is = arrayHandler(bindTo(type, 'is'), true);
this.equals = arrayEqualsHandler(bindTo(type, 'equals'));
this.pattern = type.pattern;
this.$arrayMode = mode;
}
Expand All @@ -1203,9 +1231,8 @@ function $UrlMatcherFactory() {

var isCaseInsensitive = false, isStrictMode = true, defaultSquashPolicy = false;

function valToString(val) { return val != null ? val.toString().replace("/", "%2F") : val; }
function valFromString(val) { return val != null ? val.toString().replace("%2F", "/") : val; }
function angularEquals(left, right) { return angular.equals(left, right); }
function valToString(val) { return val != null ? val.toString().replace(/\//g, "%2F") : val; }
function valFromString(val) { return val != null ? val.toString().replace(/%2F/g, "/") : val; }
// TODO: in 1.0, make string .is() return false if value is undefined by default.
// function regexpMatches(val) { /*jshint validthis:true */ return isDefined(val) && this.pattern.test(val); }
function regexpMatches(val) { /*jshint validthis:true */ return this.pattern.test(val); }
Expand All @@ -1230,16 +1257,37 @@ function $UrlMatcherFactory() {
pattern: /0|1/
},
date: {
encode: function (val) { return [
val.getFullYear(),
encode: function (val) {
if (!this.is(val))
return undefined;
return [ val.getFullYear(),
('0' + (val.getMonth() + 1)).slice(-2),
('0' + val.getDate()).slice(-2)
].join("-");
},
decode: function (val) { return new Date(val); },
decode: function (val) {
if (this.is(val)) return val;
var match = this.capture.exec(val);
return match ? new Date(match[1], match[2] - 1, match[3]) : undefined;
},
is: function(val) { return val instanceof Date && !isNaN(val.valueOf()); },
equals: function (a, b) { return a.toISOString() === b.toISOString(); },
pattern: /[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/
equals: function (a, b) { return this.is(a) && this.is(b) && a.toISOString() === b.toISOString(); },
pattern: /[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/,
capture: /([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/
},
json: {
encode: angular.toJson,
decode: angular.fromJson,
is: angular.isObject,
equals: angular.equals,
pattern: /[^/]*/
},
any: { // does not encode/decode
encode: angular.identity,
decode: angular.identity,
is: angular.identity,
equals: angular.equals,
pattern: /.*/
}
};

Expand Down Expand Up @@ -1506,33 +1554,29 @@ function $UrlMatcherFactory() {

this.Param = function Param(id, type, config, location) {
var self = this;
var defaultValueConfig = getDefaultValueConfig(config);
config = config || {};
type = getType(config, type);
config = unwrapShorthand(config);
type = getType(config, type, location);
var arrayMode = getArrayMode();
type = arrayMode ? type.$asArray(arrayMode, location === "search") : type;
if (type.name === "string" && !arrayMode && location === "path" && defaultValueConfig.value === undefined)
defaultValueConfig.value = ""; // for 0.2.x; in 0.3.0+ do not automatically default to ""
var isOptional = defaultValueConfig.value !== undefined;
if (type.name === "string" && !arrayMode && location === "path" && config.value === undefined)
config.value = ""; // for 0.2.x; in 0.3.0+ do not automatically default to ""
var isOptional = config.value !== undefined;
var squash = getSquashPolicy(config, isOptional);
var replace = getReplace(config, arrayMode, isOptional, squash);

function getDefaultValueConfig(config) {
function unwrapShorthand(config) {
var keys = isObject(config) ? objectKeys(config) : [];
var isShorthand = indexOf(keys, "value") === -1 && indexOf(keys, "type") === -1 &&
indexOf(keys, "squash") === -1 && indexOf(keys, "array") === -1;
var configValue = isShorthand ? config : config.value;
var result = {
fn: isInjectable(configValue) ? configValue : function () { return result.value; },
value: configValue
};
return result;
if (isShorthand) config = { value: config };
config.$$fn = isInjectable(config.value) ? config.value : function () { return config.value; };
return config;
}

function getType(config, urlType) {
function getType(config, urlType, location) {
if (config.type && urlType) throw new Error("Param '"+id+"' has two type configurations.");
if (urlType) return urlType;
if (!config.type) return $types.string;
if (!config.type) return (location === "config" ? $types.any : $types.string);
return config.type instanceof Type ? config.type : new Type(config.type);
}

Expand Down Expand Up @@ -1571,7 +1615,7 @@ function $UrlMatcherFactory() {
*/
function $$getDefaultValue() {
if (!injector) throw new Error("Injectable functions cannot be called at configuration time");
return injector.invoke(defaultValueConfig.fn);
return injector.invoke(config.$$fn);
}

/**
Expand All @@ -1593,13 +1637,14 @@ function $UrlMatcherFactory() {
extend(this, {
id: id,
type: type,
location: location,
array: arrayMode,
config: config,
squash: squash,
replace: replace,
isOptional: isOptional,
dynamic: undefined,
value: $value,
dynamic: undefined,
config: config,
toString: toString
});
};
Expand Down Expand Up @@ -1646,7 +1691,7 @@ function $UrlMatcherFactory() {
param = self[key];
val = paramValues[key];
isOptional = !val && param.isOptional;
result = result && (isOptional || param.type.is(val));
result = result && (isOptional || !!param.type.is(val));
});
return result;
},
Expand Down Expand Up @@ -1927,7 +1972,7 @@ function $UrlRouterProvider( $locationProvider, $urlMatcherFactory) {
$get.$inject = ['$location', '$rootScope', '$injector', '$browser'];
function $get( $location, $rootScope, $injector, $browser) {

var baseHref = $browser.baseHref(), location = $location.url();
var baseHref = $browser.baseHref(), location = $location.url(), lastPushedUrl;

function appendBasePath(url, isHtml5, absolute) {
if (baseHref === '/') return url;
Expand All @@ -1939,6 +1984,9 @@ function $UrlRouterProvider( $locationProvider, $urlMatcherFactory) {
// TODO: Optimize groups of rules with non-empty prefix into some sort of decision tree
function update(evt) {
if (evt && evt.defaultPrevented) return;
var ignoreUpdate = lastPushedUrl && $location.url() === lastPushedUrl;
lastPushedUrl = undefined;
if (ignoreUpdate) return true;

function check(rule) {
var handled = rule($injector, $location);
Expand Down Expand Up @@ -2011,6 +2059,7 @@ function $UrlRouterProvider( $locationProvider, $urlMatcherFactory) {

push: function(urlMatcher, params, options) {
$location.url(urlMatcher.format(params || {}));
lastPushedUrl = options && options.$$avoidResync ? $location.url() : undefined;
if (options && options.replace) $location.replace();
},

Expand Down Expand Up @@ -2140,7 +2189,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
ownParams: function(state) {
var params = state.url && state.url.params || new $$UMFP.ParamSet();
forEach(state.params || {}, function(config, id) {
if (!params[id]) params[id] = new $$UMFP.Param(id, null, config);
if (!params[id]) params[id] = new $$UMFP.Param(id, null, config, "config");
});
return params;
},
Expand Down Expand Up @@ -2266,7 +2315,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
if (!state[abstractKey] && state.url) {
$urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) {
if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) {
$state.transitionTo(state, $match, { location: false });
$state.transitionTo(state, $match, { inherit: true, location: false });
}
}]);
}
Expand Down Expand Up @@ -3147,7 +3196,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {

if (options.location && to.navigable) {
$urlRouter.push(to.navigable.url, to.navigable.locals.globals.$stateParams, {
replace: options.location === 'replace'
$$avoidResync: true, replace: options.location === 'replace'
});
}

Expand Down Expand Up @@ -3243,15 +3292,9 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
options = extend({ relative: $state.$current }, options || {});
var state = findState(stateOrName, options.relative);

if (!isDefined(state)) {
return undefined;
}

if ($state.$current !== state) {
return false;
}

return isDefined(params) && params !== null ? angular.equals($stateParams, params) : true;
if (!isDefined(state)) { return undefined; }
if ($state.$current !== state) { return false; }
return params ? equalForKeys(state.params.$$values(params), $stateParams) : true;
};

/**
Expand Down Expand Up @@ -3315,13 +3358,9 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
}

var state = findState(stateOrName, options.relative);
if (!isDefined(state)) {
return undefined;
}
if (!isDefined($state.$current.includes[state.name])) {
return false;
}
return equalForKeys(params, $stateParams);
if (!isDefined(state)) { return undefined; }
if (!isDefined($state.$current.includes[state.name])) { return false; }
return params ? equalForKeys(state.params.$$values(params), $stateParams, objectKeys(params)) : true;
};


Expand Down Expand Up @@ -4137,15 +4176,11 @@ function $StateRefActiveDirective($state, $stateParams, $interpolate) {

function isMatch() {
if (typeof $attrs.uiSrefActiveEq !== 'undefined') {
return $state.$current.self === state && matchesParams();
return state && $state.is(state.name, params);
} else {
return state && $state.includes(state.name) && matchesParams();
return state && $state.includes(state.name, params);
}
}

function matchesParams() {
return !params || equalForKeys(params, $stateParams);
}
}]
};
}
Expand Down
Loading

0 comments on commit c3d543a

Please sign in to comment.