diff --git a/Gruntfile.js b/Gruntfile.js index 7af87827b..3cbd82b80 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -106,7 +106,7 @@ module.exports = function (grunt) { grunt.registerTask('jsdoc', 'Generate documentation', function () { promising(this, - system('node_modules/jsdoc/jsdoc -c config/jsdoc.js -d \'' + grunt.config('builddir') + '\'/doc src') + system('\"./node_modules/jsdoc/jsdoc\" -c ./config/jsdoc.js -d \"./' + grunt.config('builddir') + '/doc\" src') ); }); @@ -150,10 +150,10 @@ module.exports = function (grunt) { var version = grunt.config('pkg.version'), releasedir = grunt.config('builddir'); promising(this, - system('git add \'' + releasedir + '\'').then(function () { + system('git add \"' + releasedir + '\"').then(function () { return system('git commit -m \'release ' + version + '\''); }).then(function () { - return system('git tag \'' + version + '\''); + return system('git tag \"' + version + '\"'); }) ); }); diff --git a/bower.json b/bower.json index 73b6ff0ee..f19776ced 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "angular-ui-router", - "version": "0.2.0", + "version": "0.2.1", "main": "./release/angular-ui-router.min.js", "dependencies": { "angular": ">= 1.0.6" diff --git a/component.json b/component.json index 4f23115ba..151f9576e 100644 --- a/component.json +++ b/component.json @@ -1,6 +1,6 @@ { "name": "angular-ui-router", - "version": "0.2.0", + "version": "0.2.1", "description": "State-based routing for AngularJS", "keywords": [ "angular", diff --git a/package.json b/package.json index afb8ebf78..3149ad136 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "angular-ui-router", "description": "State-based routing for AngularJS", - "version": "0.2.0", + "version": "0.2.1", "homepage": "http://angular-ui.github.com/", "author": { "name": "Karsten Sperling", diff --git a/release/angular-ui-router.js b/release/angular-ui-router.js index feb17c7ce..db2cf24b9 100644 --- a/release/angular-ui-router.js +++ b/release/angular-ui-router.js @@ -1,9 +1,15 @@ /** * State-based routing for AngularJS - * @version v0.2.0 + * @version v0.2.1 * @link http://angular-ui.github.com/ * @license MIT License, http://www.opensource.org/licenses/MIT */ + +/* commonjs package manager support (eg componentjs) */ +if (module && exports && module.exports === exports){ + module.exports = 'ui.router'; +} + (function (window, angular, undefined) { /*jshint globalstrict:true*/ /*global angular:false*/ @@ -127,7 +133,7 @@ function $Resolve( $q, $injector) { visited[key] = VISIT_IN_PROGRESS; if (isString(value)) { - plan.push(key, [ function() { return $injector.get(key); }], NO_DEPENDENCIES); + plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES); } else { var params = $injector.annotate(value); forEach(params, function (param) { @@ -214,7 +220,7 @@ function $Resolve( $q, $injector) { } // Wait for any parameter that we have a promise for (either from parent or from this // resolve; in that case study() will have made sure it's ordered before us in the plan). - params.forEach(function (dep) { + forEach(params, function (dep) { if (promises.hasOwnProperty(dep) && !locals.hasOwnProperty(dep)) { waitParams++; promises[dep].then(function (result) { @@ -448,7 +454,8 @@ function UrlMatcher(pattern) { var placeholder = /([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g, names = {}, compiled = '^', last = 0, m, segments = this.segments = [], - params = this.params = []; + params = this.params = [], + typeMap = this.typeMap = {}; function addParameter(id) { if (!/^\w+(-+\w+)*$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'"); @@ -469,6 +476,10 @@ function UrlMatcher(pattern) { while ((m = placeholder.exec(pattern))) { id = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null regexp = m[4] || (m[1] == '*' ? '.*' : '[^/]*'); + if (isDefined(this.types[regexp])) { + this.typeMap[id] = regexp; + regexp = this.types[regexp].pattern; // use the regexp defined for this type instead + } segment = pattern.substring(last, m.index); if (segment.indexOf('?') >= 0) break; // we're into the search part compiled += quoteRegExp(segment) + '(' + regexp + ')'; @@ -543,7 +554,10 @@ UrlMatcher.prototype.toString = function () { * @return {Object} The captured parameter values. */ UrlMatcher.prototype.exec = function (path, searchParams) { - var m = this.regexp.exec(path); + var m = this.regexp.exec(path), + types = this.types, + typeMap = this.typeMap; + if (!m) return null; var params = this.params, nTotal = params.length, @@ -555,7 +569,17 @@ UrlMatcher.prototype.exec = function (path, searchParams) { for (i=0; i=0||(s.push(a[c]),u[a[c]]=r[a[c]])}return P({},u,t)}function u(r,t){var n=1,o=2,i={},u=[],s=i,l=P(r.when(i),{$$promises:i,$$values:i});this.study=function(i){function c(r,e){if(v[e]!==o){if(p.push(e),v[e]===n)throw p.splice(0,p.indexOf(e)),Error("Cyclic dependency: "+p.join(" -> "));if(v[e]=n,b(r))h.push(e,[function(){return t.get(e)}],u);else{var a=t.annotate(r);y(a,function(r){r!==e&&i.hasOwnProperty(r)&&c(i[r],r)}),h.push(e,r,a)}p.pop(),v[e]=o}}function f(r){return E(r)&&r.then&&r.$$promises}if(!E(i))throw Error("'invocables' must be an object");var h=[],p=[],v={};return y(i,c),i=p=v=null,function(n,o,i){function u(){--w||(b||a(d,o.$$values),$.$$values=d,$.$$promises=!0,v.resolve(d))}function c(r){$.$$failure=r,v.reject(r)}function p(e,a,o){function s(r){f.reject(r),c(r)}function l(){if(!g($.$$failure))try{f.resolve(t.invoke(a,i,d)),f.promise.then(function(r){d[e]=r,u()},s)}catch(r){s(r)}}var f=r.defer(),h=0;o.forEach(function(r){m.hasOwnProperty(r)&&!n.hasOwnProperty(r)&&(h++,m[r].then(function(t){d[r]=t,--h||l()},s))}),h||l(),m[e]=f.promise}if(f(n)&&i===e&&(i=o,o=n,n=null),n){if(!E(n))throw Error("'locals' must be an object")}else n=s;if(o){if(!f(o))throw Error("'parent' must be a promise returned by $resolve.resolve()")}else o=l;var v=r.defer(),$=v.promise,m=$.$$promises={},d=P({},n),w=1+h.length/3,b=!1;if(g(o.$$failure))return c(o.$$failure),$;o.$$values?(b=a(d,o.$$values),u()):(P(m,o.$$promises),o.then(u,c));for(var x=0,y=h.length;y>x;x+=3)n.hasOwnProperty(h[x])?u():p(h[x],h[x+1],h[x+2]);return $}},this.resolve=function(r,t,e,n){return this.study(r)(t,e,n)}}function s(r,t,e){this.fromConfig=function(r,t,e){return g(r.template)?this.fromString(r.template,t):g(r.templateUrl)?this.fromUrl(r.templateUrl,t):g(r.templateProvider)?this.fromProvider(r.templateProvider,t,e):null},this.fromString=function(r,t){return w(r)?r(t):r},this.fromUrl=function(e,n){return w(e)&&(e=e(n)),null==e?null:r.get(e,{cache:t}).then(function(r){return r.data})},this.fromProvider=function(r,t,n){return e.invoke(r,null,n||{params:t})}}function l(r){function t(t){if(!/^\w+(-+\w+)*$/.test(t))throw Error("Invalid parameter name '"+t+"' in pattern '"+r+"'");if(o[t])throw Error("Duplicate parameter name '"+t+"' in pattern '"+r+"'");o[t]=!0,l.push(t)}function e(r){return r.replace(/[\\\[\]\^$*+?.()|{}]/g,"\\$&")}var n,a=/([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,o={},i="^",u=0,s=this.segments=[],l=this.params=[];this.source=r;for(var c,f,h;(n=a.exec(r))&&(c=n[2]||n[3],f=n[4]||("*"==n[1]?".*":"[^/]*"),h=r.substring(u,n.index),!(h.indexOf("?")>=0));)i+=e(h)+"("+f+")",t(c),s.push(h),u=a.lastIndex;h=r.substring(u);var p=h.indexOf("?");if(p>=0){var v=this.sourceSearch=h.substring(p);h=h.substring(0,p),this.sourcePath=r.substring(0,u+p),y(v.substring(1).split(/[&?]/),t)}else this.sourcePath=r,this.sourceSearch="";i+=e(h)+"$",s.push(h),this.regexp=RegExp(i),this.prefix=s[0]}function c(){this.compile=function(r){return new l(r)},this.isMatcher=function(r){return E(r)&&w(r.exec)&&w(r.format)&&w(r.concat)},this.$get=function(){return this}}function f(r){function t(r){var t=/^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(r.source);return null!=t?t[1].replace(/\\(.)/g,"$1"):""}function e(r,t){return r.replace(/\$(\$|\d{1,2})/,function(r,e){return t["$"===e?0:Number(e)]})}function n(r,t,e){if(!e)return!1;var n=r.invoke(t,t,{$match:e});return g(n)?n:!0}var a=[],o=null;this.rule=function(r){if(!w(r))throw Error("'rule' must be a function");return a.push(r),this},this.otherwise=function(r){if(b(r)){var t=r;r=function(){return t}}else if(!w(r))throw Error("'rule' must be a function");return o=r,this},this.when=function(a,o){var i,u=b(o);if(b(a)&&(a=r.compile(a)),!u&&!w(o)&&!x(o))throw Error("invalid 'handler' in when()");var s={matcher:function(t,e){return u&&(i=r.compile(e),e=["$match",function(r){return i.format(r)}]),P(function(r,a){return n(r,e,t.exec(a.path(),a.search()))},{prefix:b(t.prefix)?t.prefix:""})},regex:function(r,a){if(r.global||r.sticky)throw Error("when() RegExp must not be global or sticky");return u&&(i=a,a=["$match",function(r){return e(i,r)}]),P(function(t,e){return n(t,a,r.exec(e.path()))},{prefix:t(r)})}},l={matcher:r.isMatcher(a),regex:a instanceof RegExp};for(var c in l)if(l[c])return this.rule(s[c](a,o));throw Error("invalid 'what' in when()")},this.$get=["$location","$rootScope","$injector",function(r,t,e){function n(){function t(t){var n=t(e,r);return n?(b(n)&&r.replace().url(n),!0):!1}var n,i=a.length;for(n=0;i>n;n++)if(t(a[n]))return;o&&t(o)}return t.$on("$locationChangeSuccess",n),{}}]}function h(r,a,o){function u(r,t){var n=b(r),a=n?r:r.name,o=0===a.indexOf(".")||0===a.indexOf("^");if(o){if(!t)throw Error("No reference point given for path '"+a+"'");for(var i=a.split("."),u=0,s=i.length,l=t;s>u;u++)if(""!==i[u]||0!==u){if("^"!==i[u])break;if(!l.parent)throw Error("Path '"+a+"' not valid for state '"+t.name+"'");l=l.parent}else l=t;i=i.slice(u).join("."),a=l.name+(l.name&&i?".":"")+i}var c=m[a];return!c||!n&&(n||c!==r&&c.self!==r)?e:c}function s(t){t=n(t,{self:t,resolve:t.resolve||{},toString:function(){return this.name}});var e=t.name;if(!b(e)||e.indexOf("@")>=0)throw Error("State must have a valid name");if(m[e])throw Error("State '"+e+"'' is already defined");for(var a in d)t[a]=d[a](t);return m[e]=t,!t["abstract"]&&t.url&&r.when(t.url,["$match","$stateParams",function(r,e){$.$current.navigable==t&&h(r,e)||$.transitionTo(t,r,!1)}]),t}function l(r,t){return E(r)?t=r:t.name=r,s(t),this}function c(r,t,a,s,l,c,m){function d(r,e,n,o,i){var u=n?e:p(r.params,e),s={$stateParams:u};i.resolve=l.resolve(r.resolve,s,i.resolve,r);var c=[i.resolve.then(function(r){i.globals=r})];return o&&c.push(o),y(r.views,function(t,e){var n=t.resolve&&t.resolve!==r.resolve?t.resolve:{};n.$template=[function(){return a.load(e,{view:t,locals:s,params:u,notify:!1})||""}],c.push(l.resolve(n,s,i.resolve,r).then(function(n){n.$$controller=t.controller,n.$$state=r,i[e]=n}))}),t.all(c).then(function(){return i})}var w=t.reject(Error("transition superseded")),b=t.reject(Error("transition prevented"));return v.locals={resolve:null,globals:{$stateParams:{}}},$={params:{},current:v.self,$current:v,transition:null},$.go=function(r,t,e){return this.transitionTo(r,t,P({inherit:!0,relative:$.$current},e))},$.transitionTo=function(e,a,o){g(o)||(o=o===!0||o===!1?{location:o}:{}),a=a||{},o=P({location:!0,inherit:!1,relative:null},o);var l=u(e,o.relative);if(!g(l))throw Error("No such state "+l);if(l["abstract"])throw Error("Cannot transition to abstract state '"+e+"'");o.inherit&&(a=i(c,a||{},$.$current,l)),e=l;var p,E,x=e.path,y=$.$current,C=$.params,S=y.path,O=v.locals,k=[];for(p=0,E=x[p];E&&E===S[p]&&h(a,C,E.ownParams);p++,E=x[p])O=k[p]=E.locals;if(e===y&&O===y.locals)return $.transition=null,t.when($.current);a=f(e.params,a||{});var R=r.$broadcast("$stateChangeStart",e.self,a,y.self,C);if(R.defaultPrevented)return b;for(var I=t.when(O),M=p;x.length>M;M++,E=x[M])O=k[M]=n(O),I=d(E,a,E===e,I,O);var U=$.transition=I.then(function(){var t,n,i;if($.transition!==U)return w;for(t=S.length-1;t>=p;t--)i=S[t],i.self.onExit&&s.invoke(i.self.onExit,i.self,i.locals.globals),i.locals=null;for(t=p;x.length>t;t++)n=x[t],n.locals=k[t],n.self.onEnter&&s.invoke(n.self.onEnter,n.self,n.locals.globals);$.$current=e,$.current=e.self,$.params=a,j($.params,c),$.transition=null;var u=e.navigable;return o.location&&u&&m.url(u.url.format(u.locals.globals.$stateParams)),r.$broadcast("$stateChangeSuccess",e.self,a,y.self,C),$.current},function(n){return $.transition!==U?w:($.transition=null,r.$broadcast("$stateChangeError",e.self,a,y.self,C,n),t.reject(n))});return U},$.is=function(r){var t=u(r);return g(t)?$.$current===t:e},$.includes=function(r){var t=u(r);return g(t)?g($.$current.includes[t.name]):e},$.href=function(r,t,e){e=P({lossy:!0,inherit:!1,relative:$.$current},e||{});var n=u(r,e.relative);if(!g(n))return null;t=i(c,t||{},$.$current,n);var a=n&&e.lossy?n.navigable:n,s=a&&a.url?a.url.format(f(n.params,t||{})):null;return!o.html5Mode()&&s?"#"+s:s},$.get=function(r){var t=u(r);return t&&t.self?t.self:null},$}function f(r,t){var e={};return y(r,function(r){var n=t[r];e[r]=null!=n?n+"":null}),e}function h(r,t,e){if(!e){e=[];for(var n in r)e.push(n)}for(var a=0;e.length>a;a++){var o=e[a];if(r[o]!=t[o])return!1}return!0}function p(r,t){var e={};return y(r,function(r){e[r]=t[r]}),e}var v,$,m={},d={parent:function(r){if(g(r.parent)&&r.parent)return u(r.parent);var t=/^(.+)\.[^.]+$/.exec(r.name);return t?u(t[1]):v},data:function(r){return r.parent&&r.parent.data&&(r.data=r.self.data=t.extend({},r.parent.data,r.data)),r.data},url:function(r){var t=r.url;if(b(t))return"^"==t.charAt(0)?a.compile(t.substring(1)):(r.parent.navigable||v).url.concat(t);if(a.isMatcher(t)||null==t)return t;throw Error("Invalid url '"+t+"' in state '"+r+"'")},navigable:function(r){return r.url?r:r.parent?r.parent.navigable:null},params:function(r){if(!r.params)return r.url?r.url.parameters():r.parent.params;if(!x(r.params))throw Error("Invalid params in state '"+r+"'");if(r.url)throw Error("Both params and url specicified in state '"+r+"'");return r.params},views:function(r){var t={};return y(g(r.views)?r.views:{"":r},function(e,n){0>n.indexOf("@")&&(n+="@"+r.parent.name),t[n]=e}),t},ownParams:function(r){if(!r.parent)return r.params;var t={};y(r.params,function(r){t[r]=!0}),y(r.parent.params,function(e){if(!t[e])throw Error("Missing required parameter '"+e+"' in state '"+r.name+"'");t[e]=!1});var e=[];return y(t,function(r,t){r&&e.push(t)}),e},path:function(r){return r.parent?r.parent.path.concat(r):[]},includes:function(r){var t=r.parent?P({},r.parent.includes):{};return t[r.name]=!0,t}};v=s({name:"",url:"^",views:null,"abstract":!0}),v.navigable=null,this.state=l,this.$get=c,c.$inject=["$rootScope","$q","$view","$injector","$resolve","$stateParams","$location","$urlRouter"]}function p(){function r(r,t){return{load:function(e,n){var a,o={template:null,controller:null,view:null,locals:null,notify:!0,async:!0,params:{}};return n=P(o,n),n.view&&(a=t.fromConfig(n.view,n.params,n.locals)),a&&n.notify&&r.$broadcast("$viewContentLoading",n),a}}}this.$get=r,r.$inject=["$rootScope","$templateFactory"]}function v(r,e,n,a,o){var i;try{i=a.get("$animator")}catch(u){}var s=!1,l={restrict:"ECA",terminal:!0,transclude:!0,compile:function(a,u,c){return function(a,u,f){function h(t){var i=r.$current&&r.$current.locals[$];if(i!==v){var s=w(d&&t);if(s.remove(u),p&&(p.$destroy(),p=null),!i)return v=null,E.state=null,s.restore(c(a),u);v=i,E.state=i.$$state;var l=e(s.populate(i.$template,u));if(p=a.$new(),i.$$controller){i.$scope=p;var f=n(i.$$controller,i);u.children().data("$ngControllerController",f)}l(p),p.$emit("$viewContentLoaded"),m&&p.$eval(m),o()}}var p,v,$=f[l.name]||f.name||"",m=f.onload||"",d=g(i)&&i(a,f),w=function(r){return{"true":{remove:function(r){d.leave(r.contents(),r)},restore:function(r,t){d.enter(r,t)},populate:function(r,e){var n=t.element("
").html(r).contents();return d.enter(n,e),n}},"false":{remove:function(r){r.html("")},restore:function(r,t){t.append(r)},populate:function(r,t){return t.html(r),t.contents()}}}[""+r]};u.append(c(a));var b=u.parent().inheritedData("$uiView");0>$.indexOf("@")&&($=$+"@"+(b?b.state.name:""));var E={name:$,state:null};u.data("$uiView",E);var x=function(){if(!s){s=!0;try{h(!0)}catch(r){throw s=!1,r}s=!1}};a.$on("$stateChangeSuccess",x),a.$on("$viewContentLoading",x),h(!1)}}};return l}function $(r){var t=r.match(/^([^(]+?)\s*(\((.*)\))?$/);if(!t||4!==t.length)throw Error("Invalid state ref '"+r+"'");return{state:t[1],paramExpr:t[3]||null}}function m(r){return{restrict:"A",link:function(t,n,a){var o=$(a.uiSref),i=null,u=r.$current,s="FORM"===n[0].nodeName,l=s?"action":"href",c=!0,f=n.parent().inheritedData("$uiView");f&&f.state&&f.state.name&&(u=f.state);var h=function(t){if(t&&(i=t),c){var a=r.href(o.state,i,{relative:u});return a?(n[0][l]=a,e):(c=!1,!1)}};o.paramExpr&&(t.$watch(o.paramExpr,function(r,t){r!==t&&h(r)},!0),i=t.$eval(o.paramExpr)),h(),s||n.bind("click",function(e){1!=e.which||e.ctrlKey||e.metaKey||e.shiftKey||(r.go(o.state,i,{relative:u}),t.$apply(),e.preventDefault())})}}}function d(r,t){function a(r){this.locals=r.locals.globals,this.params=this.locals.$stateParams}function o(){this.locals=null,this.params=null}function i(e,i){if(null!=i.redirectTo){var u,l=i.redirectTo;if(b(l))u=l;else{if(!w(l))throw Error("Invalid 'redirectTo' in when()");u=function(r,t){return l(r,t.path(),t.search())}}t.when(e,u)}else r.state(n(i,{parent:null,name:"route:"+encodeURIComponent(e),url:e,onEnter:a,onExit:o}));return s.push(i),this}function u(r,t,n){function a(r){return""!==r.name?r:e}var o={routes:s,params:n,current:e};return t.$on("$stateChangeStart",function(r,e,n,o){t.$broadcast("$routeChangeStart",a(e),a(o))}),t.$on("$stateChangeSuccess",function(r,e,n,i){o.current=a(e),t.$broadcast("$routeChangeSuccess",a(e),a(i)),j(n,o.params)}),t.$on("$stateChangeError",function(r,e,n,o,i,u){t.$broadcast("$routeChangeError",a(e),a(o),u)}),o}var s=[];a.$inject=["$$state"],this.when=i,this.$get=u,u.$inject=["$state","$rootScope","$routeParams"]}var g=t.isDefined,w=t.isFunction,b=t.isString,E=t.isObject,x=t.isArray,y=t.forEach,P=t.extend,j=t.copy;t.module("ui.router.util",["ng"]),t.module("ui.router.router",["ui.router.util"]),t.module("ui.router.state",["ui.router.router","ui.router.util"]),t.module("ui.router",["ui.router.state"]),t.module("ui.router.compat",["ui.router"]),u.$inject=["$q","$injector"],t.module("ui.router.util").service("$resolve",u),s.$inject=["$http","$templateCache","$injector"],t.module("ui.router.util").service("$templateFactory",s),l.prototype.concat=function(r){return new l(this.sourcePath+r+this.sourceSearch)},l.prototype.toString=function(){return this.source},l.prototype.exec=function(r,t){var e=this.regexp.exec(r);if(!e)return null;var n,a=this.params,o=a.length,i=this.segments.length-1,u={};if(i!==e.length-1)throw Error("Unbalanced capture group in route '"+this.source+"'");for(n=0;i>n;n++)u[a[n]]=e[n+1];for(;o>n;n++)u[a[n]]=t[a[n]];return u},l.prototype.parameters=function(){return this.params},l.prototype.format=function(r){var t=this.segments,e=this.params;if(!r)return t.join("");var n,a,o,i=t.length-1,u=e.length,s=t[0];for(n=0;i>n;n++)o=r[e[n]],null!=o&&(s+=encodeURIComponent(o)),s+=t[n+1];for(;u>n;n++)o=r[e[n]],null!=o&&(s+=(a?"&":"?")+e[n]+"="+encodeURIComponent(o),a=!0);return s},t.module("ui.router.util").provider("$urlMatcherFactory",c),f.$inject=["$urlMatcherFactoryProvider"],t.module("ui.router.router").provider("$urlRouter",f),h.$inject=["$urlRouterProvider","$urlMatcherFactoryProvider","$locationProvider"],t.module("ui.router.state").value("$stateParams",{}).provider("$state",h),p.$inject=[],t.module("ui.router.state").provider("$view",p),v.$inject=["$state","$compile","$controller","$injector","$anchorScroll"],t.module("ui.router.state").directive("uiView",v),m.$inject=["$state"],t.module("ui.router.state").directive("uiSref",m),d.$inject=["$stateProvider","$urlRouterProvider"],t.module("ui.router.compat").provider("$route",d).directive("ngView",v)})(window,window.angular); \ No newline at end of file +module&&exports&&module.exports===exports&&(module.exports="ui.router"),function(a,b,c){"use strict";function d(a,b){return y(new(y(function(){},{prototype:a})),b)}function e(a){return x(arguments,function(b){b!==a&&x(b,function(b,c){a.hasOwnProperty(c)||(a[c]=b)})}),a}function f(a,b){var c=[];for(var d in a.path)if(""!==a.path[d]){if(!b.path[d])break;c.push(a.path[d])}return c}function g(a,b,c,d){var e,g=f(c,d),h={},i=[];for(var j in g)if(g[j].params&&g[j].params.length){e=g[j].params;for(var k in e)i.indexOf(e[k])>=0||(i.push(e[k]),h[e[k]]=a[e[k]])}return y({},h,b)}function h(a,b){var d=1,f=2,g={},h=[],i=g,j=y(a.when(g),{$$promises:g,$$values:g});this.study=function(g){function k(a,c){if(o[c]!==f){if(n.push(c),o[c]===d)throw n.splice(0,n.indexOf(c)),new Error("Cyclic dependency: "+n.join(" -> "));if(o[c]=d,u(a))m.push(c,[function(){return b.get(a)}],h);else{var e=b.annotate(a);x(e,function(a){a!==c&&g.hasOwnProperty(a)&&k(g[a],a)}),m.push(c,a,e)}n.pop(),o[c]=f}}function l(a){return v(a)&&a.then&&a.$$promises}if(!v(g))throw new Error("'invocables' must be an object");var m=[],n=[],o={};return x(g,k),g=n=o=null,function(d,f,g){function h(){--t||(u||e(r,f.$$values),p.$$values=r,p.$$promises=!0,o.resolve(r))}function k(a){p.$$failure=a,o.reject(a)}function n(c,e,f){function i(a){l.reject(a),k(a)}function j(){if(!s(p.$$failure))try{l.resolve(b.invoke(e,g,r)),l.promise.then(function(a){r[c]=a,h()},i)}catch(a){i(a)}}var l=a.defer(),m=0;x(f,function(a){q.hasOwnProperty(a)&&!d.hasOwnProperty(a)&&(m++,q[a].then(function(b){r[a]=b,--m||j()},i))}),m||j(),q[c]=l.promise}if(l(d)&&g===c&&(g=f,f=d,d=null),d){if(!v(d))throw new Error("'locals' must be an object")}else d=i;if(f){if(!l(f))throw new Error("'parent' must be a promise returned by $resolve.resolve()")}else f=j;var o=a.defer(),p=o.promise,q=p.$$promises={},r=y({},d),t=1+m.length/3,u=!1;if(s(f.$$failure))return k(f.$$failure),p;f.$$values?(u=e(r,f.$$values),h()):(y(q,f.$$promises),f.then(h,k));for(var w=0,z=m.length;z>w;w+=3)d.hasOwnProperty(m[w])?h():n(m[w],m[w+1],m[w+2]);return p}},this.resolve=function(a,b,c,d){return this.study(a)(b,c,d)}}function i(a,b,c){this.fromConfig=function(a,b,c){return s(a.template)?this.fromString(a.template,b):s(a.templateUrl)?this.fromUrl(a.templateUrl,b):s(a.templateProvider)?this.fromProvider(a.templateProvider,b,c):null},this.fromString=function(a,b){return t(a)?a(b):a},this.fromUrl=function(c,d){return t(c)&&(c=c(d)),null==c?null:a.get(c,{cache:b}).then(function(a){return a.data})},this.fromProvider=function(a,b,d){return c.invoke(a,null,d||{params:b})}}function j(a){function b(b){if(!/^\w+(-+\w+)*$/.test(b))throw new Error("Invalid parameter name '"+b+"' in pattern '"+a+"'");if(f[b])throw new Error("Duplicate parameter name '"+b+"' in pattern '"+a+"'");f[b]=!0,j.push(b)}function c(a){return a.replace(/[\\\[\]\^$*+?.()|{}]/g,"\\$&")}var d,e=/([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,f={},g="^",h=0,i=this.segments=[],j=this.params=[];this.typeMap={},this.source=a;for(var k,l,m;(d=e.exec(a))&&(k=d[2]||d[3],l=d[4]||("*"==d[1]?".*":"[^/]*"),s(this.types[l])&&(this.typeMap[k]=l,l=this.types[l].pattern),m=a.substring(h,d.index),!(m.indexOf("?")>=0));)g+=c(m)+"("+l+")",b(k),i.push(m),h=e.lastIndex;m=a.substring(h);var n=m.indexOf("?");if(n>=0){var o=this.sourceSearch=m.substring(n);m=m.substring(0,n),this.sourcePath=a.substring(0,h+n),x(o.substring(1).split(/[&?]/),b)}else this.sourcePath=a,this.sourceSearch="";g+=c(m)+"$",i.push(m),this.regexp=new RegExp(g),this.prefix=i[0]}function k(){this.compile=function(a){return new j(a)},this.isMatcher=function(a){return v(a)&&t(a.exec)&&t(a.format)&&t(a.concat)},this.type=function(a,b){return j.prototype.type(a,b)},this.$get=function(){return this}}function l(a){function b(a){var b=/^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(a.source);return null!=b?b[1].replace(/\\(.)/g,"$1"):""}function c(a,b){return a.replace(/\$(\$|\d{1,2})/,function(a,c){return b["$"===c?0:Number(c)]})}function d(a,b,c){if(!c)return!1;var d=a.invoke(b,b,{$match:c});return s(d)?d:!0}var e=[],f=null;this.rule=function(a){if(!t(a))throw new Error("'rule' must be a function");return e.push(a),this},this.otherwise=function(a){if(u(a)){var b=a;a=function(){return b}}else if(!t(a))throw new Error("'rule' must be a function");return f=a,this},this.when=function(e,f){var g,h=u(f);if(u(e)&&(e=a.compile(e)),!h&&!t(f)&&!w(f))throw new Error("invalid 'handler' in when()");var i={matcher:function(b,c){return h&&(g=a.compile(c),c=["$match",function(a){return g.format(a)}]),y(function(a,e){return d(a,c,b.exec(e.path(),e.search()))},{prefix:u(b.prefix)?b.prefix:""})},regex:function(a,e){if(a.global||a.sticky)throw new Error("when() RegExp must not be global or sticky");return h&&(g=e,e=["$match",function(a){return c(g,a)}]),y(function(b,c){return d(b,e,a.exec(c.path()))},{prefix:b(a)})}},j={matcher:a.isMatcher(e),regex:e instanceof RegExp};for(var k in j)if(j[k])return this.rule(i[k](e,f));throw new Error("invalid 'what' in when()")},this.$get=["$location","$rootScope","$injector",function(a,b,c){function d(){function b(b){var d=b(c,a);return d?(u(d)&&a.replace().url(d),!0):!1}var d,g=e.length;for(d=0;g>d;d++)if(b(e[d]))return;f&&b(f)}return b.$on("$locationChangeSuccess",d),{}}]}function m(a,e,f){function h(a){return 0===a.indexOf(".")||0===a.indexOf("^")}function i(a,b){var d=u(a),e=d?a:a.name,f=h(e);if(f){if(!b)throw new Error("No reference point given for path '"+e+"'");for(var g=e.split("."),i=0,j=g.length,k=b;j>i;i++)if(""!==g[i]||0!==i){if("^"!==g[i])break;if(!k.parent)throw new Error("Path '"+e+"' not valid for state '"+b.name+"'");k=k.parent}else k=b;g=g.slice(i).join("."),e=k.name+(k.name&&g?".":"")+g}var l=A[e];return!l||!d&&(d||l!==a&&l.self!==a)?c:l}function j(b){b=d(b,{self:b,resolve:b.resolve||{},toString:function(){return this.name}});var c=b.name;if(!u(c)||c.indexOf("@")>=0)throw new Error("State must have a valid name");if(A[c])throw new Error("State '"+c+"'' is already defined");for(var e in B)t(B[e])&&(b[e]=B[e](b,B.$delegates[e]));return A[c]=b,!b["abstract"]&&b.url&&a.when(b.url,["$match","$stateParams",function(a,c){r.$current.navigable==b&&o(b,a,c)||r.transitionTo(b,a,!1)}]),b}function k(a,b){return u(a)&&!s(b)?B[a]:t(b)&&u(a)?(B[a]&&!B.$delegates[a]&&(B.$delegates[a]=B[a]),B[a]=b,this):this}function l(a,b){return v(a)?b=a:b.name=a,j(b),this}function m(a,e,h,j,k,l,m){function t(a,b,c,d,f){var g=c?b:p(a.params,b),i={$stateParams:g};f.resolve=k.resolve(a.resolve,i,f.resolve,a);var j=[f.resolve.then(function(a){f.globals=a})];return d&&j.push(d),x(a.views,function(b,c){var d=b.resolve&&b.resolve!==a.resolve?b.resolve:{};d.$template=[function(){return h.load(c,{view:b,locals:i,params:g,notify:!1})||""}],j.push(k.resolve(d,i,f.resolve,a).then(function(d){d.$$controller=b.controller,d.$$state=a,f[c]=d}))}),e.all(j).then(function(){return f})}var u=e.reject(new Error("transition superseded")),v=e.reject(new Error("transition prevented")),w=e.reject(new Error("transition aborted")),B=e.reject(new Error("transition failed"));return q.locals={resolve:null,globals:{$stateParams:{}}},r={params:{},current:q.self,$current:q,transition:null},r.go=function(a,b,c){return this.transitionTo(a,b,y({inherit:!0,relative:r.$current},c))},r.transitionTo=function(b,c,f){s(f)||(f=f===!0||f===!1?{location:f}:{}),c=c||{},f=y({location:!0,inherit:!1,relative:null,broadcastStateChangeSuccess:!0,$retry:!1},f);var h,k=r.$current,p=r.params,x=k.path,A=i(b,f.relative);if(!s(A)){var C={to:b,toParams:c,options:f};if(h=a.$broadcast("$stateNotFound",C,k.self,p),h.defaultPrevented)return w;if(h.retry){if(f.$retry)return B;var D=r.transition=e.when(h.retry);return D.then(function(){return D!==r.transition?u:(C.options.$retry=!0,r.transitionTo(C.to,C.toParams,C.options))},function(){return w}),D}if(b=C.to,c=C.toParams,f=C.options,A=i(b,f.relative),!s(A)){if(f.relative)throw new Error("Could not resolve '"+b+"' from state '"+f.relative+"'");throw new Error("No such state '"+b+"'")}}if(A["abstract"])throw new Error("Cannot transition to abstract state '"+b+"'");f.inherit&&(c=g(l,c||{},r.$current,A)),b=A;var E,F,G=b.path,H=q.locals,I=[];for(E=0,F=G[E];F&&F===x[E]&&o(F,c,p,F.ownParams);E++,F=G[E])H=I[E]=F.locals;if(b===k&&H===k.locals)return r.transition=null,e.when(r.current);if(c=n(b.params,c||{}),h=a.$broadcast("$stateChangeStart",b.self,c,k.self,p),h.defaultPrevented)return v;for(var J=e.when(H),K=E;K=E;d--)g=x[d],g.self.onExit&&j.invoke(g.self.onExit,g.self,g.locals.globals),g.locals=null;for(d=E;d").html(a).contents();return r.enter(d,c),d}},"false":{remove:function(a){a.html("")},restore:function(a,b){b.append(a)},populate:function(a,b){return b.html(a),b.contents()}}}[a.toString()]};h.append(k(e));var u=h.parent().inheritedData("$uiView");p.indexOf("@")<0&&(p=p+"@"+(u?u.state.name:""));var v={name:p,state:null};h.data("$uiView",v);var w=function(){if(!i){i=!0;try{m(!0)}catch(a){throw i=!1,a}i=!1}};e.$on("$stateChangeSuccess",w),e.$on("$viewContentLoading",w),m(!1)}}};return j}function p(a){var b=a.match(/^([^(]+?)\s*(\((.*)\))?$/);if(!b||4!==b.length)throw new Error("Invalid state ref '"+a+"'");return{state:b[1],paramExpr:b[3]||null}}function q(a){return{restrict:"A",link:function(b,c,d){var e=p(d.uiSref),f=null,g=a.$current,h="FORM"===c[0].nodeName,i=h?"action":"href",j=!0,k=c.parent().inheritedData("$uiView");k&&k.state&&k.state.name&&(g=k.state);var l=function(b){if(b&&(f=b),j){var d=a.href(e.state,f,{relative:g});return d?(c[0][i]=d,void 0):(j=!1,!1)}};e.paramExpr&&(b.$watch(e.paramExpr,function(a){a!==f&&l(a)},!0),f=b.$eval(e.paramExpr)),l(),h||c.bind("click",function(c){var d=c.which||c.button;1!=d||c.ctrlKey||c.metaKey||c.shiftKey||(a.go(e.state,f,{relative:g}),b.$apply(),c.preventDefault())})}}}function r(a,b){function e(a){this.locals=a.locals.globals,this.params=this.locals.$stateParams}function f(){this.locals=null,this.params=null}function g(c,g){if(null!=g.redirectTo){var h,j=g.redirectTo;if(u(j))h=j;else{if(!t(j))throw new Error("Invalid 'redirectTo' in when()");h=function(a,b){return j(a,b.path(),b.search())}}b.when(c,h)}else a.state(d(g,{parent:null,name:"route:"+encodeURIComponent(c),url:c,onEnter:e,onExit:f}));return i.push(g),this}function h(a,b,d){function e(a){return""!==a.name?a:c}var f={routes:i,params:d,current:c};return b.$on("$stateChangeStart",function(a,c,d,f){b.$broadcast("$routeChangeStart",e(c),e(f))}),b.$on("$stateChangeSuccess",function(a,c,d,g){f.current=e(c),b.$broadcast("$routeChangeSuccess",e(c),e(g)),z(d,f.params)}),b.$on("$stateChangeError",function(a,c,d,f,g,h){b.$broadcast("$routeChangeError",e(c),e(f),h)}),f}var i=[];e.$inject=["$$state"],this.when=g,this.$get=h,h.$inject=["$state","$rootScope","$routeParams"]}var s=b.isDefined,t=b.isFunction,u=b.isString,v=b.isObject,w=b.isArray,x=b.forEach,y=b.extend,z=b.copy;b.module("ui.router.util",["ng"]),b.module("ui.router.router",["ui.router.util"]),b.module("ui.router.state",["ui.router.router","ui.router.util"]),b.module("ui.router",["ui.router.state"]),b.module("ui.router.compat",["ui.router"]),h.$inject=["$q","$injector"],b.module("ui.router.util").service("$resolve",h),i.$inject=["$http","$templateCache","$injector"],b.module("ui.router.util").service("$templateFactory",i),j.prototype.concat=function(a){return new j(this.sourcePath+a+this.sourceSearch)},j.prototype.toString=function(){return this.source},j.prototype.exec=function(a,b){var c=this.regexp.exec(a),d=this.types,e=this.typeMap;if(!c)return null;var f,g=this.params,h=g.length,i=this.segments.length-1,j={};if(i!==c.length-1)throw new Error("Unbalanced capture group in route '"+this.source+"'");for(f=0;i>f;f++)j[g[f]]=c[f+1];for(;h>f;f++)j[g[f]]=b[g[f]];var k={};return x(j,function(a,b){k[b]=s(e[b])?d[e[b]].decode(a):a}),k},j.prototype.parameters=function(){return this.params},j.prototype.format=function(a){var b=this.segments,c=this.params,d=this.types,e=this.typeMap;if(!a)return b.join("");var f,g,h,i=b.length-1,j=c.length,k=b[0],l={};for(x(a,function(a,b){if(s(e[b])){var c=d[e[b]];c.is(a)&&(l[b]=c.encode(a))}else l[b]=a}),f=0;i>f;f++)h=l[c[f]],null!=h&&(k+=encodeURIComponent(h)),k+=b[f+1];for(;j>f;f++)h=l[c[f]],null!=h&&(k+=(g?"&":"?")+c[f]+"="+encodeURIComponent(h),g=!0);return k},j.prototype.types={"boolean":{pattern:"true|false",is:function(a){return a===!0||a===!1},equals:function(a,b){return this.is(a)&&this.is(b)?a===b:!1},encode:function(a){return a.toString().toLowerCase()},decode:function(a){return a&&"true"===a.toLowerCase()?!0:a&&"false"===a.toLowerCase()?!1:c}},integer:{pattern:"[0-9]+",is:function(a){return"number"==typeof a&&0===a%1},equals:function(a,b){return this.is(a)&&this.is(b)?a===b:!1},encode:function(a){return a.toString()},decode:function(a){return parseInt(a,10)}}},j.prototype.type=function(a,b){if(!b&&j.prototype.types[a])return j.prototype.types[a];if(!(u(a)&&v(b)&&t(b.decode)&&t(b.encode)))throw new Error("Invalid type '"+a+"'");u(b.pattern)||(b.pattern=".*"),t(b.is)||(b.is=function(a){return JSON.stringify(b.decode(b.encode(a)))===JSON.stringify(a)}),t(b.equals)||(b.equals=function(a,c){return b.is(a)&&b.is(c)?b.encode(a)===b.encode(c):!1}),j.prototype.types[a]=b},b.module("ui.router.util").provider("$urlMatcherFactory",k),l.$inject=["$urlMatcherFactoryProvider"],b.module("ui.router.router").provider("$urlRouter",l),m.$inject=["$urlRouterProvider","$urlMatcherFactoryProvider","$locationProvider"],b.module("ui.router.state").value("$stateParams",{}).provider("$state",m),n.$inject=[],b.module("ui.router.state").provider("$view",n),o.$inject=["$state","$compile","$controller","$injector","$anchorScroll"],b.module("ui.router.state").directive("uiView",o),q.$inject=["$state"],b.module("ui.router.state").directive("uiSref",q),r.$inject=["$stateProvider","$urlRouterProvider"],b.module("ui.router.compat").provider("$route",r).directive("ngView",o)}(window,window.angular); \ No newline at end of file diff --git a/release/doc/$resolve.html b/release/doc/$resolve.html index 224845b81..b224c56ac 100644 --- a/release/doc/$resolve.html +++ b/release/doc/$resolve.html @@ -118,40 +118,32 @@

resolve$q promise. If a promise is returned it will be resolved and the resulting value will be used instead. Dependencies of invocables are resolved (in this order of precedence)

-
  • from the specified locals
  • from another invocable that is part of this $resolve call
  • from an invocable that is inherited from a parent call to $resolve (or recursively from any ancestor $resolve of that parent).
-

The return value of $resolve is a promise for an object that contains (in this order of precedence)

-
  • any locals (if specified)
  • the resolved return values of all injectables
  • any values inherited from a parent call to $resolve (if specified)
-

The promise will resolve after the parent promise (if any) and all promises returned by injectables have been resolved. If any invocable (or $injector.invoke) throws an exception, or if a promise returned by an invocable is rejected, the $resolve promise is immediately rejected with the same error. A rejection of a parent promise (if specified) will likewise be propagated immediately. Once the $resolve promise has been rejected, no further invocables will be called.

-

Cyclic dependencies between invocables are not permitted and will caues $resolve to throw an error. As a special case, an injectable can depend on a parameter with the same name as the injectable, which will be fulfilled from the parent injectable of the same name. This allows inherited values to be decorated. Note that in this case any other injectable in the same $resolve with the same dependency would see the decorated value, not the inherited value.

-

Note that missing dependencies -- unlike cyclic dependencies -- will cause an (asynchronous) rejection of the $resolve promise rather than a (synchronous) exception.

-

Invocables are invoked eagerly as soon as all dependencies are available. This is true even for dependencies inherited from a parent call to $resolve.

-

As a special case, an invocable can be a string, in which case it is taken to be a service name to be passed to $injector.get(). This is supported primarily for backwards-compatibility with the resolve property of $routeProvider routes.

@@ -196,10 +188,7 @@
Parameters:
-Object.<string, Function -| - -string> +Object.<string, (Function|string)> @@ -210,6 +199,8 @@
Parameters:
+ + @@ -241,6 +232,8 @@
Parameters:
+ + @@ -272,6 +265,8 @@
Parameters:
+ + @@ -303,6 +298,8 @@
Parameters:
+ + @@ -352,6 +349,10 @@
Parameters:
+ + + + @@ -493,6 +494,10 @@
Parameters:
+ + + + @@ -541,9 +546,10 @@

Index

Modules

  • + - + \ No newline at end of file diff --git a/release/doc/$templateFactory.html b/release/doc/$templateFactory.html index f45308105..ab0b572a6 100644 --- a/release/doc/$templateFactory.html +++ b/release/doc/$templateFactory.html @@ -93,6 +93,10 @@

    new $ + + + + @@ -193,6 +197,8 @@

    Parameters:
    + + @@ -327,6 +333,8 @@
    Properties
    + + @@ -358,6 +366,8 @@
    Properties
    + + @@ -408,6 +418,10 @@
    Properties
    + + + + @@ -574,6 +588,10 @@
    Parameters:
    + + + + @@ -738,6 +756,10 @@
    Parameters:
    + + + + @@ -835,6 +857,8 @@
    Parameters:
    + + @@ -864,6 +888,8 @@
    Parameters:
    + + @@ -895,6 +921,8 @@
    Parameters:
    + + @@ -944,6 +972,10 @@
    Parameters:
    + + + + @@ -999,9 +1031,10 @@

    Index

    Modules

    • + - + \ No newline at end of file diff --git a/release/doc/$urlMatcherFactory.html b/release/doc/$urlMatcherFactory.html index f4fcf4cf5..5fd556a22 100644 --- a/release/doc/$urlMatcherFactory.html +++ b/release/doc/$urlMatcherFactory.html @@ -81,7 +81,7 @@

      new
      Source:
      • - urlMatcherFactory.js, line 219 + urlMatcherFactory.js, line 349
      @@ -94,6 +94,10 @@

      new + + + + @@ -212,7 +216,7 @@

      Parameters:
      Source:
      • - urlMatcherFactory.js, line 226 + urlMatcherFactory.js, line 356
      @@ -225,6 +229,10 @@
      Parameters:
      + + + + @@ -347,7 +355,7 @@
      Parameters:
      Source:
      • - urlMatcherFactory.js, line 238 + urlMatcherFactory.js, line 368
      @@ -360,6 +368,10 @@
      Parameters:
      + + + + @@ -408,9 +420,10 @@

      Index

      Modules

      • + - + \ No newline at end of file diff --git a/release/doc/UrlMatcher.html b/release/doc/UrlMatcher.html index 3c2faf125..caadec077 100644 --- a/release/doc/UrlMatcher.html +++ b/release/doc/UrlMatcher.html @@ -52,10 +52,8 @@

        new UrlMatc of search parameters. Multiple search parameter names are separated by '&'. Search parameters do not influence whether or not a URL is matched, but their values are passed through into the matched parameters returned by exec.

        -

        Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace syntax, which optionally allows a regular expression for the parameter to be specified:

        -
        • ':' name - colon placeholder
        • '*' name - catch-all placeholder
        • @@ -63,15 +61,12 @@

          new UrlMatc
        • '{' name ':' regexp '}' - curly placeholder with regexp. Should the regexp itself contain curly braces, they must be in matched pairs or escaped with a backslash.
        -

        Parameter names may contain only word characters (latin letters, digits, and underscore) and must be unique within the pattern (across both path and search parameters). For colon placeholders or curly placeholders without an explicit regexp, a path parameter matches any number of characters other than '/'. For catch-all placeholders the path parameter matches any number of characters.

        -

        Examples

        -
        • '/hello/' - Matches only if the path is exactly '/hello/'. There is no special treatment for trailing slashes, and patterns have to match the entire path, not just a prefix.
        • @@ -231,6 +226,10 @@
          Properties:
          + + + + @@ -272,14 +271,10 @@

          concat -

          Example

          -

          The following two matchers are equivalent:

          - -
          new UrlMatcher('/user/{id}?q').concat('/details?date');
          -new UrlMatcher('/user/{id}/details?q&date');
          -
          +
          new UrlMatcher('/user/{id}?q').concat('/details?date');
          +new UrlMatcher('/user/{id}/details?q&date');
          @@ -360,7 +355,7 @@
          Parameters:
          Source:
          • - urlMatcherFactory.js, line 128 + urlMatcherFactory.js, line 133
          @@ -373,6 +368,10 @@
          Parameters:
          + + + + @@ -419,12 +418,9 @@

          exec
          new UrlMatcher('/user/{id}?q&r').exec('/user/bob', { x:'1', q:'hello' });
          -// returns { id:'bob', q:'hello', r:null }
          -
          +
          new UrlMatcher('/user/{id}?q&r').exec('/user/bob', { x:'1', q:'hello' });
          +// returns { id:'bob', q:'hello', r:null }
          @@ -528,7 +524,7 @@
          Parameters:
          Source:
          • - urlMatcherFactory.js, line 156 + urlMatcherFactory.js, line 161
          @@ -541,6 +537,10 @@
          Parameters:
          + + + + @@ -585,12 +585,9 @@

          formatCreates a URL that matches this pattern by substituting the specified values for the path and search parameters. Null values for path parameters are treated as empty strings.

          -

          Example

          - -
          new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
          -// returns '/user/bob?q=yes'
          -
          +
          new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
          +// returns '/user/bob?q=yes'
          @@ -671,7 +668,7 @@
          Parameters:
          Source:
          • - urlMatcherFactory.js, line 195 + urlMatcherFactory.js, line 213
          @@ -684,6 +681,10 @@
          Parameters:
          + + + + @@ -758,7 +759,7 @@

          parameters<
          Source:
          • - urlMatcherFactory.js, line 177 + urlMatcherFactory.js, line 195
          @@ -771,6 +772,10 @@

          parameters< + + + + @@ -800,6 +805,182 @@

          Returns:
          + + + + +
          +

          type(name, handler) → {Object}

          + + +
          +
          + + +
          +

          Registers a custom type for parameters or gets a handler for a registered type. +A handler object must include a decode function that decodes a string value +from the URL into the type, and a encode function that encodes the type into +a string value for the URL.

          +

          Example

          +
          // Register myType
          +.type('myType', {
          +   pattern: "[0-9]+",                       // (Optional) Regex pattern used to match the URL to this type.
          +   is : function (typeObj) {},              // (Optional) Determines if a param is of this type when saving to the URL.
          +   equals: function (typeObj, otherObj) {}, // (Optional) Determines if two objects of this type are equal.
          +   encode: function (typeObj) {},           // (Required) Encode this type to the URL.
          +   decode: function (value) {}              // (Required) Decode the URL segment to this type.
          + });
          +// Get myType
          +.type('myType');
          +
          + + + + + + + +
          Parameters:
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          NameTypeDescription
          name + + +string + + + +

          the name of the type to register or get.

          handler + + +Object + + + +

          the handler object with functions of working with this type.

          + + + +
          + + + + + + + + + + + + + + + + + + + +
          Source:
          +
          • + urlMatcherFactory.js, line 318 +
          + + + + + + + +
          + + + + + + + + + + + +
          Returns:
          + + +
          +

          the handler object.

          +
          + + + +
          +
          + Type +
          +
          + +Object + + +
          +
          + + + +
          @@ -824,9 +1005,10 @@

          Index

          Modules

          • + - + \ No newline at end of file diff --git a/release/doc/global.html b/release/doc/global.html index 2dd9004bd..e0c1d4398 100644 --- a/release/doc/global.html +++ b/release/doc/global.html @@ -216,6 +216,10 @@
            Parameters:
            + + + + @@ -421,6 +425,10 @@
            Parameters:
            + + + + @@ -451,9 +459,10 @@

            Index

            Modules

            • + - + \ No newline at end of file diff --git a/release/doc/index.html b/release/doc/index.html index 351a274a5..7f06bf759 100644 --- a/release/doc/index.html +++ b/release/doc/index.html @@ -54,9 +54,10 @@

              Index

              Modules

              • + - + \ No newline at end of file diff --git a/release/doc/scripts/linenumber.js b/release/doc/scripts/linenumber.js new file mode 100644 index 000000000..a0c570d5d --- /dev/null +++ b/release/doc/scripts/linenumber.js @@ -0,0 +1,17 @@ +(function() { + var counter = 0; + var numbered; + var source = document.getElementsByClassName('prettyprint source'); + + if (source && source[0]) { + source = source[0].getElementsByTagName('code')[0]; + + numbered = source.innerHTML.split('\n'); + numbered = numbered.map(function(item) { + counter++; + return '' + item; + }); + + source.innerHTML = numbered.join('\n'); + } +})(); diff --git a/sample/states.js b/sample/states.js index 276b765cb..4ce69a5da 100644 --- a/sample/states.js +++ b/sample/states.js @@ -27,6 +27,33 @@ angular.module('uiRouterSample') // Use $stateProvider to configure your states. $stateProvider + ///////////////////// + // Parameter Types // + ///////////////////// + // contact id is formatted like ##-####, as dependent on some backend system. + .type("myCustomId", { + pattern: "[0-9]{2}[\-][0-9]{4}", + is: function (typeObj) { + return (angular.isObject(typeObj) && typeObj.firstPart && typeObj.secondPart); + }, + equals: function (typeObj, otherObj) { + if (this.is(typeObj) && this.is(otherObj)) { + return (typeObj.firstPart === otherObj.firstPart && typeObj.secondPart === otherObj.secondPart); + } + return false; + }, + decode: function (value) { + var tokens = value.split("-"); + return { + firstPart: tokens[0], + secondPart: tokens[1] + }; + }, + encode: function (typeObj) { + return typeObj.firstPart + "-" + typeObj.secondPart; + } + }) + ////////// // Home // ////////// @@ -139,7 +166,7 @@ angular.module('uiRouterSample') // So its url will end up being '/contacts/{contactId:[0-9]{1,8}}'. When the // url becomes something like '/contacts/42' then this state becomes active // and the $stateParams object becomes { contactId: 42 }. - url: '/{contactId:[0-9]{1,4}}', + url: '/{contactId:myCustomId}', // If there is more than a single ui-view in the parent template, or you would // like to target a ui-view from even higher up the state tree, you can use the @@ -157,6 +184,7 @@ angular.module('uiRouterSample') templateUrl: 'contacts.detail.html', controller: ['$scope', '$stateParams', 'utils', function ( $scope, $stateParams, utils) { + console.log($stateParams.contactId); $scope.contact = utils.findById($scope.contacts, $stateParams.contactId); }] }, diff --git a/src/resolve.js b/src/resolve.js index 4f1a4cfcf..45cf6cf88 100644 --- a/src/resolve.js +++ b/src/resolve.js @@ -42,7 +42,7 @@ function $Resolve( $q, $injector) { visited[key] = VISIT_IN_PROGRESS; if (isString(value)) { - plan.push(key, [ function() { return $injector.get(key); }], NO_DEPENDENCIES); + plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES); } else { var params = $injector.annotate(value); forEach(params, function (param) { diff --git a/src/state.js b/src/state.js index 464771c6a..76cf4f142 100644 --- a/src/state.js +++ b/src/state.js @@ -107,6 +107,12 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ $delegates: {} }; + // Create a proxy through to the Type registration on the UrlMatcherFactory + this.type = function (name, handler) { + $urlMatcherFactory.type(name, handler); + return this; + }; + function isRelative(stateName) { return stateName.indexOf(".") === 0 || stateName.indexOf("^") === 0; } @@ -164,7 +170,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ // Register the state in the global state list and with $urlRouter if necessary. if (!state['abstract'] && state.url) { $urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) { - if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) { + if ($state.$current.navigable != state || !equalForKeys(state, $match, $stateParams)) { $state.transitionTo(state, $match, false); } }]); @@ -239,7 +245,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ $state.transitionTo = function transitionTo(to, toParams, options) { if (!isDefined(options)) options = (options === true || options === false) ? { location: options } : {}; toParams = toParams || {}; - options = extend({ location: true, inherit: false, relative: null, $retry: false }, options); + options = extend({ location: true, inherit: false, relative: null, broadcastStateChangeSuccess : true, $retry: false }, options); var from = $state.$current, fromParams = $state.params, fromPath = from.path; @@ -288,7 +294,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ // Starting from the root of the path, keep all levels that haven't changed var keep, state, locals = root.locals, toLocals = []; for (keep = 0, state = toPath[keep]; - state && state === fromPath[keep] && equalForKeys(toParams, fromParams, state.ownParams); + state && state === fromPath[keep] && equalForKeys(state, toParams, fromParams, state.ownParams); keep++, state = toPath[keep]) { locals = toLocals[keep] = state.locals; } @@ -329,6 +335,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ var transition = $state.transition = resolved.then(function () { var l, entering, exiting; + if ($state.transition !== transition) return TransitionSuperseded; // Exit 'from' states not kept @@ -362,7 +369,10 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ $location.url(toNav.url.format(toNav.locals.globals.$stateParams)); } - $rootScope.$broadcast('$stateChangeSuccess', to.self, toParams, from.self, fromParams); + if(options.broadcastStateChangeSuccess){ + $rootScope.$broadcast('$stateChangeSuccess', to.self, toParams, from.self, fromParams); + } + return $state.current; }, function (error) { @@ -479,21 +489,30 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ forEach(keys, function (name) { var value = values[name]; - normalized[name] = (value != null) ? String(value) : null; + //normalized[name] = (value != null) ? String(value) : null; + normalized[name] = (value != null) ? value : null; }); return normalized; } - function equalForKeys(a, b, keys) { + function equalForKeys(state, aParams, bParams, keys) { + var url = state.url || {}, + types = url.types || {}, + typeMap = url.typeMap || {}; + // If keys not provided, assume keys from object 'a' if (!keys) { keys = []; - for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility + for (var n in aParams) keys.push(n); // Used instead of Object.keys() for IE8 compatibility } for (var i=0; i= 0) break; // we're into the search part compiled += quoteRegExp(segment) + '(' + regexp + ')'; @@ -97,7 +111,23 @@ function UrlMatcher(pattern) { this.sourcePath = pattern.substring(0, last+i); // Allow parameters to be separated by '?' as well as '&' to make concat() easier - forEach(search.substring(1).split(/[&?]/), addParameter); + var searchParams = search.substring(1).split(/[&?]/), j; + for(j=0;j