diff --git a/dist/grammar.js b/dist/grammar.js index 51fb856..15da8a4 100644 --- a/dist/grammar.js +++ b/dist/grammar.js @@ -80,7 +80,9 @@ define(["assert", 'route-recognizer'], function($__0,$__2) { return path; } }, {}); - Grammar.prototype.recognize.parameters = [[$traceurRuntime.type.string], []]; + Object.defineProperty(Grammar.prototype.recognize, "parameters", {get: function() { + return [[$traceurRuntime.type.string], []]; + }}); var CanonicalRecognizer = function CanonicalRecognizer(name) { this.name = name; this.rewrites = {}; @@ -195,3 +197,5 @@ define(["assert", 'route-recognizer'], function($__0,$__2) { __esModule: true }; }); + +//# sourceMappingURL=grammar.ats diff --git a/dist/pipeline.js b/dist/pipeline.js index ae2e2b3..bc1dd29 100644 --- a/dist/pipeline.js +++ b/dist/pipeline.js @@ -34,3 +34,5 @@ define([], function() { __esModule: true }; }); + +//# sourceMappingURL=pipeline.ats diff --git a/dist/router.es5.js b/dist/router.es5.js index e894e7e..09b6a8d 100644 --- a/dist/router.es5.js +++ b/dist/router.es5.js @@ -12,6 +12,7 @@ angular.module('ngNewRouter', []) .factory('$setupRoutersStep', setupRoutersStepFactory) .factory('$initLocalsStep', initLocalsStepFactory) .factory('$initControllersStep', initControllersStepFactory) + .factory('$bindRouteParamsForDirectiveStep', bindRouteParamsForDirectiveStepFactory) .factory('$runCanDeactivateHookStep', runCanDeactivateHookStepFactory) .factory('$runCanActivateHookStep', runCanActivateHookStepFactory) .factory('$loadTemplatesStep', loadTemplatesStepFactory) @@ -29,7 +30,9 @@ angular.module('ngNewRouter', []) */ angular.module('ng') .provider('$controllerIntrospector', $controllerIntrospectorProvider) - .config(controllerProviderDecorator); + .provider('$compileIntrospector', $compileIntrospectorProvider) + .config(controllerProviderDecorator) + .config(compileProviderDecorator); /* * decorates with routing info @@ -43,6 +46,15 @@ function controllerProviderDecorator($controllerProvider, $controllerIntrospecto } controllerProviderDecorator.$inject = ["$controllerProvider", "$controllerIntrospectorProvider"]; +function compileProviderDecorator($compileProvider, $compileIntrospectorProvider) { + var directive = $compileProvider.directive; + $compileProvider.directive = function (name, directiveFactory) { + $compileIntrospectorProvider.directive(name, directiveFactory); + return directive.apply(this, arguments); + }; +} +compileProviderDecorator.$inject = ["$compileProvider", "$compileIntrospectorProvider"]; + /* * private service that holds route mappings for each controller */ @@ -77,12 +89,50 @@ function $controllerIntrospectorProvider() { } } -function routerFactory($$rootRouter, $rootScope, $location, $$grammar, $controllerIntrospector) { + +/* + * private service that holds route mappings for each controller + */ +function $compileIntrospectorProvider() { + var directiveFactories = []; + var onDirectiveDefined = null; + return { + directive: function (name, directiveFactory) { + if (angular.isArray(directiveFactory)) { + directiveFactory = directiveFactory[directiveFactory.length - 1]; + } + if (directiveFactory.$routeConfig) { + if (onDirectiveDefined) { + onDirectiveDefined(name, directiveFactory.$routeConfig); + } else { + directiveFactories.push({name: name, config: directiveFactory.$routeConfig}); + } + } + }, + $get: ['$componentLoader', '$injector', function ($componentLoader, $injector) { + return function (newOnDirectiveDefined) { + onDirectiveDefined = function (name, config) { + return newOnDirectiveDefined(name, config); + }; + while(directiveFactories.length > 0) { + var rule = directiveFactories.pop(); + onDirectiveDefined(rule.name, rule.config); + } + } + }] + } +} + +function routerFactory($$rootRouter, $rootScope, $location, $$grammar, $controllerIntrospector, $compileIntrospector) { $controllerIntrospector(function (name, config) { $$grammar.config(name, config); }); + $compileIntrospector(function (name, config) { + $$grammar.config(name, config); + }); + $rootScope.$watch(function () { return $location.path(); }, function (newUrl) { @@ -100,7 +150,7 @@ function routerFactory($$rootRouter, $rootScope, $location, $$grammar, $controll return $$rootRouter; } -routerFactory.$inject = ["$$rootRouter", "$rootScope", "$location", "$$grammar", "$controllerIntrospector"]; +routerFactory.$inject = ["$$rootRouter", "$rootScope", "$location", "$$grammar", "$controllerIntrospector", "$compileIntrospector"]; /** * @name ngViewport @@ -189,7 +239,11 @@ function ngViewportDirective($animate, $injector, $q, $router) { }); var newController = instruction.controller; - newScope[componentName] = newController; + if (instruction.directive && instruction.directive.controllerAs) { + newScope[instruction.directive.controllerAs] = newController; + } else { + newScope[componentName] = newController; + } var result; if (currentController && currentController.deactivate) { @@ -372,23 +426,56 @@ function initLocalsStepFactory() { /* * $initControllersStep */ -function initControllersStepFactory($controller, $componentLoader) { +function initControllersStepFactory($controller, $componentLoader, $injector) { return function initControllers(instruction) { return instruction.router.traverseInstruction(instruction, function(instruction) { var controllerName = $componentLoader.controllerName(instruction.component); + var directiveName = $componentLoader.directiveName(instruction.component); var locals = instruction.locals; var ctrl; try { ctrl = $controller(controllerName, locals); } catch(e) { - console.warn && console.warn('Could not instantiate controller', controllerName); - ctrl = $controller(angular.noop, locals); + try { + var directives = $injector.get(directiveName); + // can't handle two names on the same directive yet + instruction.directive = directives[0]; + ctrl = $controller(instruction.directive.controller, locals); + } catch(e) { + console.warn && console.warn('Could not instantiate controller', controllerName); + ctrl = $controller(angular.noop, locals); + } } return instruction.controller = ctrl; }); } } -initControllersStepFactory.$inject = ["$controller", "$componentLoader"]; +initControllersStepFactory.$inject = ["$controller", "$componentLoader", "$injector"]; + +function bindRouteParamsForDirectiveStepFactory() { + return function bindRouteParamsForDirective(instruction) { + return instruction.router.traverseInstruction(instruction, function(instruction) { + if (instruction.directive && instruction.directive.bindToController) { + var bindings; + if (typeof instruction.directive.bindToController == 'object') { + // ng 1.4 object syntax + bindings = instruction.directive.$$bindings.bindToController; + } else if (instruction.directive.bindToController == true) { + // ng 1.3 syntax + bindings = instruction.directive.$$isolateBindings; + } + if (bindings) { + Object.keys(bindings).forEach(function(key) { + if (instruction.params[bindings[key].attrName]) { + instruction.controller[key] = instruction.params[bindings[key].attrName]; + } + }); + } + } + return true; + }); + }; +} function runCanDeactivateHookStepFactory() { return function runCanDeactivateHook(instruction) { @@ -416,7 +503,16 @@ runCanActivateHookStepFactory.$inject = ["$injector"]; function loadTemplatesStepFactory($componentLoader, $templateRequest) { return function loadTemplates(instruction) { return instruction.router.traverseInstruction(instruction, function(instruction) { - var componentTemplateUrl = $componentLoader.template(instruction.component); + var componentTemplateUrl; + if (instruction.directive) { + if (instruction.directive.template) { + return instruction.template = instruction.directive.template + } else { + componentTemplateUrl = instruction.directive.templateUrl; + } + } else { + componentTemplateUrl = $componentLoader.template(instruction.component); + } return $templateRequest(componentTemplateUrl).then(function (templateHtml) { return instruction.template = templateHtml; }); @@ -438,6 +534,7 @@ function pipelineProvider() { '$setupRoutersStep', '$initLocalsStep', '$initControllersStep', + '$bindRouteParamsForDirectiveStep', '$runCanDeactivateHookStep', '$runCanActivateHookStep', '$loadTemplatesStep', @@ -493,6 +590,7 @@ function pipelineProvider() { function $componentLoaderProvider() { var DEFAULT_SUFFIX = 'Controller'; + var DEFAULT_DIRECTIVE_SUFFIX = 'Directive'; var componentToCtrl = function componentToCtrlDefault(name) { return name[0].toUpperCase() + name.substr(1) + DEFAULT_SUFFIX; @@ -507,12 +605,22 @@ function $componentLoaderProvider() { return name[0].toLowerCase() + name.substr(1, name.length - DEFAULT_SUFFIX.length - 1); }; + var componentToDirective = function componentToDirectiveDefault(name) { + return name + DEFAULT_DIRECTIVE_SUFFIX; + }; + + var directiveToComponent = function directiveToComponent(name) { + return name.substr(0, name.length - DEFAULT_DIRECTIVE_SUFFIX.length); + }; + return { $get: function () { return { controllerName: componentToCtrl, template: componentToTemplate, - component: ctrlToComponent + component: ctrlToComponent, + directiveName: componentToDirective, + directiveToComponent: directiveToComponent }; }, @@ -541,6 +649,11 @@ function $componentLoaderProvider() { setTemplateMapping: function(newFn) { componentToTemplate = newFn; return this; + }, + + setDirectiveMapping: function(newFn) { + componentToDirective = newFn; + return this; } }; } diff --git a/dist/router.es5.min.js b/dist/router.es5.min.js index abeb48b..d9ab67d 100644 --- a/dist/router.es5.min.js +++ b/dist/router.es5.min.js @@ -1 +1 @@ -"use strict";function controllerProviderDecorator(t,e){var r=t.register;t.register=function(t,n){return e.register(t,n),r.apply(this,arguments)}}function $controllerIntrospectorProvider(){var t=[],e=null;return{register:function(r,n){angular.isArray(n)&&(n=n[n.length-1]),n.$routeConfig&&(e?e(r,n.$routeConfig):t.push({name:r,config:n.$routeConfig}))},$get:["$componentLoader",function(r){return function(n){for(e=function(t,e){return t=r.component(t),n(t,e)};t.length>0;){var o=t.pop();e(o.name,o.config)}}}]}}function routerFactory(t,e,r,n,o){o(function(t,e){n.config(t,e)}),e.$watch(function(){return r.path()},function(e){t.navigate(e)});var i=t.navigate;return t.navigate=function(t){return i.call(this,t).then(function(t){t&&r.path(t)})},t}function ngViewportDirective(t,e,r,n){function o(t,r,n){return e.invoke(t,r,n.locals)}function i(e,n,i,u,s){function p(){g&&(t.cancel(g),g=null),l&&(l.$destroy(),l=null),v&&(g=t.leave(v),g.then(function(){g=null}),v=null)}var l,f,h,v,g,d,m=i.ngViewport||"default",y=u[0],w=u[1],$=y&&y.$$router||c;$.registerViewport({canDeactivate:function(t){return h&&h.canDeactivate?o(h.canDeactivate,h,t):!0},activate:function(i){var c=a(i);if(c!==d){i.locals.$scope=f=e.$new(),w.$$router=i.router,w.$$template=i.template;var u=i.component,g=s(f,function(e){t.enter(e,null,v||n),p()}),m=i.controller;f[u]=m;var y;if(h&&h.deactivate&&(y=r.when(o(h.deactivate,h,i))),h=m,v=g,l=f,d=c,m.activate){var $=r.when(o(m.activate,m,i));return y?y.then($):$}return y}}},m)}function a(t){return JSON.stringify({path:t.path,component:t.component,params:Object.keys(t.params).reduce(function(e,r){return"childRoute"!==r&&(e[r]=t.params[r]),e},{})})}var c=n;return{restrict:"AE",transclude:"element",terminal:!0,priority:400,require:["?^^ngViewport","ngViewport"],link:i,controller:function(){},controllerAs:"$$ngViewport"}}function ngViewportFillContentDirective(t){return{restrict:"EA",priority:-400,require:"ngViewport",link:function(e,r,n,o){var i=o.$$template;r.html(i);var a=t(r.contents());a(e)}}}function makeComponentString(t){return['',""].join("")}function ngLinkDirective(t,e,r){function n(t,e,n,i){var a=i&&i.$$router||o;if(a){var c,u=n.ngLink||"",s=u.match(LINK_MICROSYNTAX_RE),p=s[1],l=s[2];if(l){var f=r(l);if(f.constant){var h=f();c="."+a.generate(p,h),e.attr("href",c)}else t.$watch(function(){return f(t)},function(t){c="."+a.generate(p,t),e.attr("href",c)},!0)}else c="."+a.generate(p),e.attr("href",c)}}var o=t;return{require:"?^^ngViewport",restrict:"A",link:n}}function anchorLinkDirective(t){return{restrict:"E",link:function(e,r){if("a"===r[0].nodeName.toLowerCase()){var n="[object SVGAnimatedString]"===Object.prototype.toString.call(r.prop("href"))?"xlink:href":"href";r.on("click",function(e){var o=r.attr(n);o||e.preventDefault(),t.recognize(o)&&(t.navigate(o),e.preventDefault())})}}}}function setupRoutersStepFactory(){return function(t){return t.router.makeDescendantRouters(t)}}function initLocalsStepFactory(){return function(t){return t.router.traverseInstruction(t,function(t){return t.locals={$router:t.router,$routeParams:t.params||{}}})}}function initControllersStepFactory(t,e){return function(r){return r.router.traverseInstruction(r,function(r){var n,o=e.controllerName(r.component),i=r.locals;try{n=t(o,i)}catch(a){console.warn&&console.warn("Could not instantiate controller",o),n=t(angular.noop,i)}return r.controller=n})}}function runCanDeactivateHookStepFactory(){return function(t){return t.router.canDeactivatePorts(t)}}function runCanActivateHookStepFactory(t){function e(e,r,n){return t.invoke(e,r,{$routeParams:n.params})}return function(t){return t.router.traverseInstruction(t,function(t){var r=t.controller;return!r.canActivate||e(r.canActivate,r,t)})}}function loadTemplatesStepFactory(t,e){return function(r){return r.router.traverseInstruction(r,function(r){var n=t.template(r.component);return e(n).then(function(t){return r.template=t})})}}function activateStepValue(t){return t.router.activatePorts(t)}function pipelineProvider(){var t,e=["$setupRoutersStep","$initLocalsStep","$initControllersStep","$runCanDeactivateHookStep","$runCanActivateHookStep","$loadTemplatesStep","$activateStep"];return{steps:e.slice(0),config:function(t){e=t},$get:["$injector","$q",function(r,n){return t=e.map(function(t){return r.get(t)}),{process:function(e){function r(t){if(0===o.length)return t;var i=o.shift();return n.when(i(e)).then(r)}var o=t.slice(0);return r()}}}]}}function $componentLoaderProvider(){var t="Controller",e=function(e){return e[0].toUpperCase()+e.substr(1)+t},r=function(t){var e=dashCase(t);return"./components/"+e+"/"+e+".html"},n=function(e){return e[0].toLowerCase()+e.substr(1,e.length-t.length-1)};return{$get:function(){return{controllerName:e,template:r,component:n}},setCtrlNameMapping:function(t){return e=t,this},setComponentFromCtrlMapping:function(t){return n=t,this},setTemplateMapping:function(t){return r=t,this}}}function privatePipelineFactory(t){return t}function dashCase(t){return t.replace(/([A-Z])/g,function(t){return"-"+t.toLowerCase()})}angular.module("ngNewRouter",[]).factory("$router",routerFactory).value("$routeParams",{}).provider("$componentLoader",$componentLoaderProvider).provider("$pipeline",pipelineProvider).factory("$$pipeline",privatePipelineFactory).factory("$setupRoutersStep",setupRoutersStepFactory).factory("$initLocalsStep",initLocalsStepFactory).factory("$initControllersStep",initControllersStepFactory).factory("$runCanDeactivateHookStep",runCanDeactivateHookStepFactory).factory("$runCanActivateHookStep",runCanActivateHookStepFactory).factory("$loadTemplatesStep",loadTemplatesStepFactory).value("$activateStep",activateStepValue).directive("ngViewport",ngViewportDirective).directive("ngViewport",ngViewportFillContentDirective).directive("ngLink",ngLinkDirective).directive("a",anchorLinkDirective),angular.module("ng").provider("$controllerIntrospector",$controllerIntrospectorProvider).config(controllerProviderDecorator),controllerProviderDecorator.$inject=["$controllerProvider","$controllerIntrospectorProvider"],routerFactory.$inject=["$$rootRouter","$rootScope","$location","$$grammar","$controllerIntrospector"],ngViewportDirective.$inject=["$animate","$injector","$q","$router"],ngViewportFillContentDirective.$inject=["$compile"];var LINK_MICROSYNTAX_RE=/^(.+?)(?:\((.*)\))?$/;ngLinkDirective.$inject=["$router","$location","$parse"],anchorLinkDirective.$inject=["$router"],initControllersStepFactory.$inject=["$controller","$componentLoader"],runCanActivateHookStepFactory.$inject=["$injector"],loadTemplatesStepFactory.$inject=["$componentLoader","$templateRequest"],privatePipelineFactory.$inject=["$pipeline"],angular.module("ngNewRouter").factory("$$rootRouter",["$q","$$grammar","$$pipeline",function(t,e,r){function n(t,e,r,n){return h(e,"constructor",{value:t,configurable:!0,enumerable:!1,writable:!0}),arguments.length>3?("function"==typeof n&&(t.__proto__=n),t.prototype=g(o(n),i(e))):t.prototype=e,h(t,"prototype",{configurable:!1,writable:!1}),v(t,i(r))}function o(t){if("function"==typeof t){var e=t.prototype;if(Object(e)===e||null===e)return t.prototype;throw new TypeError("super prototype must be an Object or null")}if(null===t)return null;throw new TypeError("Super expression must either be null or a function, not "+typeof t+".")}function i(t){for(var e={},r=m(t),n=0;n3?("function"==typeof i&&(t.__proto__=i),t.prototype=u(e(i),r(n))):t.prototype=n,a(t,"prototype",{configurable:!1,writable:!1}),c(t,r(o))}function e(t){if("function"==typeof t){var e=t.prototype;if(Object(e)===e||null===e)return t.prototype;throw new TypeError("super prototype must be an Object or null")}if(null===t)return null;throw new TypeError("Super expression must either be null or a function, not "+typeof t+".")}function r(t){for(var e={},r=p(t),n=0;ns;s++){var l,f=c[s];(l=f.match(/^:([^\/]+)$/))?(u.push(new r(l[1])),i.push(l[1]),a.dynamics++):(l=f.match(/^\*([^\/]+)$/))?(u.push(new n(l[1])),i.push(l[1]),a.stars++):""===f?u.push(new o):(u.push(new e(f)),a.statics++)}return u}function a(t){this.charSpec=t,this.nextStates=[]}function c(t){return t.sort(function(t,e){if(t.types.stars!==e.types.stars)return t.types.stars-e.types.stars;if(t.types.stars){if(t.types.statics!==e.types.statics)return e.types.statics-t.types.statics;if(t.types.dynamics!==e.types.dynamics)return e.types.dynamics-t.types.dynamics}return t.types.dynamics!==e.types.dynamics?t.types.dynamics-e.types.dynamics:t.types.statics!==e.types.statics?e.types.statics-t.types.statics:0})}function u(t,e){for(var r=[],n=0,o=t.length;o>n;n++){var i=t[n];r=r.concat(i.match(e))}return r}function s(t){this.queryParams=t||{}}function p(t,e,r){for(var n=t.handlers,o=t.regex,i=e.match(o),a=1,c=new s(r),u=0,p=n.length;p>u;u++){for(var l=n[u],f=l.names,h={},v=0,g=f.length;g>v;v++)h[f[v]]=i[a++];c.push({handler:l.handler,params:h,isDynamic:!!f.length})}return c}function l(t,e){return e.eachChar(function(e){t=t.put(e)}),t}var f=function(){function t(t,e,r){this.path=t,this.matcher=e,this.delegate=r}function e(t){this.routes={},this.children={},this.target=t}function r(e,n,o){return function(i,a){var c=e+i;return a?void a(r(c,n,o)):new t(e+i,n,o)}}function n(t,e,r){for(var n=0,o=0,i=t.length;i>o;o++)n+=t[o].path.length;e=e.substr(n);var a={path:e,handler:r};t.push(a)}function o(t,e,r,i){var a=e.routes;for(var c in a)if(a.hasOwnProperty(c)){var u=t.slice();n(u,c,a[c]),e.children[c]?o(u,e.children[c],r,i):r.call(i,u)}}return t.prototype={to:function(t,e){var r=this.delegate;if(r&&r.willAddRoute&&(t=r.willAddRoute(this.matcher.target,t)),this.matcher.add(this.path,t),e){if(0===e.length)throw new Error("You must have an argument in the function passed to `to`");this.matcher.addChild(this.path,t,e,this.delegate)}return this}},e.prototype={add:function(t,e){this.routes[t]=e},addChild:function(t,n,o,i){var a=new e(n);this.children[t]=a;var c=r(t,a,i);i&&i.contextEntered&&i.contextEntered(n,c),o(c)}},function(t,n){var i=new e;t(r("",i,this.delegate)),o([],i,function(t){n?n(this,t):this.add(t)},this)}}(),h=["/",".","*","+","?","|","(",")","[","]","{","}","\\"],v=new RegExp("(\\"+h.join("|\\")+")","g");e.prototype={eachChar:function(t){for(var e,r=this.string,n=0,o=r.length;o>n;n++)e=r.charAt(n),t({validChars:e})},regex:function(){return this.string.replace(v,"\\$1")},generate:function(){return this.string}},r.prototype={eachChar:function(t){t({invalidChars:"/",repeat:!0})},regex:function(){return"([^/]+)"},generate:function(t){return t[this.name]}},n.prototype={eachChar:function(t){t({invalidChars:"",repeat:!0})},regex:function(){return"(.+)"},generate:function(t){return t[this.name]}},o.prototype={eachChar:function(){},regex:function(){return""},generate:function(){return""}},a.prototype={get:function(t){for(var e=this.nextStates,r=0,n=e.length;n>r;r++){var o=e[r],i=o.charSpec.validChars===t.validChars;if(i=i&&o.charSpec.invalidChars===t.invalidChars)return o}},put:function(t){var e;return(e=this.get(t))?e:(e=new a(t),this.nextStates.push(e),t.repeat&&e.nextStates.push(e),e)},match:function(t){for(var e,r,n,o=this.nextStates,i=[],a=0,c=o.length;c>a;a++)e=o[a],r=e.charSpec,"undefined"!=typeof(n=r.validChars)?-1!==n.indexOf(t)&&i.push(e):"undefined"!=typeof(n=r.invalidChars)&&-1===n.indexOf(t)&&i.push(e);return i}};var g=Object.create||function(t){function e(){}return e.prototype=t,new e};s.prototype=g({splice:Array.prototype.splice,slice:Array.prototype.slice,push:Array.prototype.push,length:0,queryParams:null});var d=function(){this.rootState=new a,this.names={}};return d.prototype={add:function(t,e){for(var r,n=this.rootState,a="^",c={statics:0,dynamics:0,stars:0},u=[],s=[],p=!0,f=0,h=t.length;h>f;f++){var v=t[f],g=[],d=i(v.path,g,c);s=s.concat(d);for(var m=0,y=d.length;y>m;m++){var w=d[m];w instanceof o||(p=!1,n=n.put({validChars:"/"}),a+="/",n=l(n,w),a+=w.regex())}var $={handler:v.handler,names:g};u.push($)}p&&(n=n.put({validChars:"/"}),a+="/"),n.handlers=u,n.regex=new RegExp(a+"$"),n.types=c,(r=e&&e.as)&&(this.names[r]={segments:s,handlers:u})},handlersFor:function(t){var e=this.names[t],r=[];if(!e)throw new Error("There is no route named "+t);for(var n=0,o=e.handlers.length;o>n;n++)r.push(e.handlers[n]);return r},hasRoute:function(t){return!!this.names[t]},generate:function(t,e){var r=this.names[t],n="";if(!r)throw new Error("There is no route named "+t);for(var i=r.segments,a=0,c=i.length;c>a;a++){var u=i[a];u instanceof o||(n+="/",n+=u.generate(e))}return"/"!==n.charAt(0)&&(n="/"+n),e&&e.queryParams&&(n+=this.generateQueryString(e.queryParams,r.handlers)),n},generateQueryString:function(e){var r=[],n=[];for(var o in e)e.hasOwnProperty(o)&&n.push(o);n.sort();for(var i=0,a=n.length;a>i;i++){o=n[i];var c=e[o];if(null!=c){var u=encodeURIComponent(o);if(t(c))for(var s=0,p=c.length;p>s;s++){var l=o+"[]="+encodeURIComponent(c[s]);r.push(l)}else u+="="+encodeURIComponent(c),r.push(u)}}return 0===r.length?"":"?"+r.join("&")},parseQueryString:function(t){for(var e=t.split("&"),r={},n=0;n2&&"[]"===a.slice(c-2)&&(u=!0,a=a.slice(0,c-2),r[a]||(r[a]=[])),o=i[1]?decodeURIComponent(i[1]):""),u?r[a].push(o):r[a]=o}return r},recognize:function(t){var e,r,n,o,i=[this.rootState],a={},s=!1;if(o=t.indexOf("?"),-1!==o){var l=t.substr(o+1,t.length);t=t.substr(0,o),a=this.parseQueryString(l)}for(t=decodeURI(t),"/"!==t.charAt(0)&&(t="/"+t),e=t.length,e>1&&"/"===t.charAt(e-1)&&(t=t.substr(0,e-1),s=!0),r=0,n=t.length;n>r&&(i=u(i,t.charAt(r)),i.length);r++);var f=[];for(r=0,n=i.length;n>r;r++)i[r].handlers&&f.push(i[r]);i=c(f);var h=f[0];return h&&h.handlers?(s&&"(.+)$"===h.regex.source.slice(-5)&&(t+="/"),p(h,t,a)):void 0}},d.prototype.map=f,d.VERSION="VERSION_STRING_PLACEHOLDER",d}()),f="/*childRoute",h=function(){this.rules={}};t(h,{config:function(t,e){"app"===t&&(t="/"),this.rules[t]||(this.rules[t]=new v(t)),this.rules[t].config(e)},recognize:function(t){var e=void 0!==arguments[1]?arguments[1]:"/",r=this;if("undefined"!=typeof t){var n=this.rules[e];if(n){var i=n.recognize(t);if(i){var a=i[i.length-1],c=a.handler,u=a.params,s={viewports:{},params:u};if(u&&u.childRoute){var p="/"+u.childRoute;s.canonicalUrl=c.rewroteUrl.substr(0,c.rewroteUrl.length-(u.childRoute.length+1)),o(c.components,function(t,e){s.viewports[e]=r.recognize(p,t)}),s.canonicalUrl+=s.viewports[Object.keys(s.viewports)[0]].canonicalUrl}else s.canonicalUrl=c.rewroteUrl,o(c.components,function(t,e){s.viewports[e]={viewports:{}}});return o(s.viewports,function(t,e){t.component=c.components[e],t.params=u}),s}}}},generate:function(t,e){var r,n="";do{if(r=null,o(this.rules,function(o){o.hasRoute(t)&&(n=o.generate(t,e)+n,r=o)}),!r)return"";t=r.name}while("/"!==r.name);return n}},{}),Object.defineProperty(h.prototype.recognize,"parameters",{get:function(){return[[$traceurRuntime.type.string],[]]}});var v=function(t){this.name=t,this.rewrites={},this.recognizer=new l};return t(v,{config:function(t){var e=this;t instanceof Array?t.forEach(function(t){return e.configOne(t)}):this.configOne(t)},getCanonicalUrl:function(t){return"."===t[0]&&(t=t.substr(1)),(""===t||"/"!==t[0])&&(t="/"+t),o(this.rewrites,function(e,r){"/"===r?"/"===t&&(t=e):0===t.indexOf(r)&&(t=t.replace(r,e))}),t},configOne:function(t){var e=this;if(t.redirectTo){if(this.rewrites[t.path])throw new Error('"'+t.path+'" already maps to "'+this.rewrites[t.path]+'"');return void(this.rewrites[t.path]=t.redirectTo)}if(t.component){if(t.components)throw new Error('A route config should have either a "component" or "components" property, but not both.');t.components=t.component,delete t.component}"string"==typeof t.components&&(t.components={"default":t.components});var r;t.as?r=[t.as]:(r=i(t.components,function(t,e){return e+":"+t}),t.components["default"]&&r.push(t.components["default"])),r.forEach(function(r){return e.recognizer.add([{path:t.path,handler:t}],{as:r})});var o=n(t);o.path+=f,this.recognizer.add([{path:o.path,handler:o}])},recognize:function(t){var e=this.getCanonicalUrl(t),r=this.recognizer.recognize(e);return r&&(r[0].handler.rewroteUrl=e),r},generate:function(t,e){return this.recognizer.generate(t,e)},hasRoute:function(t){return this.recognizer.hasRoute(t)}},{}),new h}]); \ No newline at end of file +"use strict";function controllerProviderDecorator(t,e){var r=t.register;t.register=function(t,n){return e.register(t,n),r.apply(this,arguments)}}function compileProviderDecorator(t,e){var r=t.directive;t.directive=function(t,n){return e.directive(t,n),r.apply(this,arguments)}}function $controllerIntrospectorProvider(){var t=[],e=null;return{register:function(r,n){angular.isArray(n)&&(n=n[n.length-1]),n.$routeConfig&&(e?e(r,n.$routeConfig):t.push({name:r,config:n.$routeConfig}))},$get:["$componentLoader",function(r){return function(n){for(e=function(t,e){return t=r.component(t),n(t,e)};t.length>0;){var o=t.pop();e(o.name,o.config)}}}]}}function $compileIntrospectorProvider(){var t=[],e=null;return{directive:function(r,n){angular.isArray(n)&&(n=n[n.length-1]),n.$routeConfig&&(e?e(r,n.$routeConfig):t.push({name:r,config:n.$routeConfig}))},$get:["$componentLoader","$injector",function(){return function(r){for(e=function(t,e){return r(t,e)};t.length>0;){var n=t.pop();e(n.name,n.config)}}}]}}function routerFactory(t,e,r,n,o,i){o(function(t,e){n.config(t,e)}),i(function(t,e){n.config(t,e)}),e.$watch(function(){return r.path()},function(e){t.navigate(e)});var a=t.navigate;return t.navigate=function(t){return a.call(this,t).then(function(t){t&&r.path(t)})},t}function ngViewportDirective(t,e,r,n){function o(t,r,n){return e.invoke(t,r,n.locals)}function i(e,n,i,u,s){function p(){g&&(t.cancel(g),g=null),l&&(l.$destroy(),l=null),v&&(g=t.leave(v),g.then(function(){g=null}),v=null)}var l,f,h,v,g,d,m=i.ngViewport||"default",y=u[0],$=u[1],w=y&&y.$$router||c;w.registerViewport({canDeactivate:function(t){return h&&h.canDeactivate?o(h.canDeactivate,h,t):!0},activate:function(i){var c=a(i);if(c!==d){i.locals.$scope=f=e.$new(),$.$$router=i.router,$.$$template=i.template;var u=i.component,g=s(f,function(e){t.enter(e,null,v||n),p()}),m=i.controller;i.directive&&i.directive.controllerAs?f[i.directive.controllerAs]=m:f[u]=m;var y;if(h&&h.deactivate&&(y=r.when(o(h.deactivate,h,i))),h=m,v=g,l=f,d=c,m.activate){var w=r.when(o(m.activate,m,i));return y?y.then(w):w}return y}}},m)}function a(t){return JSON.stringify({path:t.path,component:t.component,params:Object.keys(t.params).reduce(function(e,r){return"childRoute"!==r&&(e[r]=t.params[r]),e},{})})}var c=n;return{restrict:"AE",transclude:"element",terminal:!0,priority:400,require:["?^^ngViewport","ngViewport"],link:i,controller:function(){},controllerAs:"$$ngViewport"}}function ngViewportFillContentDirective(t){return{restrict:"EA",priority:-400,require:"ngViewport",link:function(e,r,n,o){var i=o.$$template;r.html(i);var a=t(r.contents());a(e)}}}function makeComponentString(t){return['',""].join("")}function ngLinkDirective(t,e,r){function n(t,e,n,i){var a=i&&i.$$router||o;if(a){var c,u=n.ngLink||"",s=u.match(LINK_MICROSYNTAX_RE),p=s[1],l=s[2];if(l){var f=r(l);if(f.constant){var h=f();c="."+a.generate(p,h),e.attr("href",c)}else t.$watch(function(){return f(t)},function(t){c="."+a.generate(p,t),e.attr("href",c)},!0)}else c="."+a.generate(p),e.attr("href",c)}}var o=t;return{require:"?^^ngViewport",restrict:"A",link:n}}function anchorLinkDirective(t){return{restrict:"E",link:function(e,r){if("a"===r[0].nodeName.toLowerCase()){var n="[object SVGAnimatedString]"===Object.prototype.toString.call(r.prop("href"))?"xlink:href":"href";r.on("click",function(e){var o=r.attr(n);o||e.preventDefault(),t.recognize(o)&&(t.navigate(o),e.preventDefault())})}}}}function setupRoutersStepFactory(){return function(t){return t.router.makeDescendantRouters(t)}}function initLocalsStepFactory(){return function(t){return t.router.traverseInstruction(t,function(t){return t.locals={$router:t.router,$routeParams:t.params||{}}})}}function initControllersStepFactory(t,e,r){return function(n){return n.router.traverseInstruction(n,function(n){var o,i=e.controllerName(n.component),a=e.directiveName(n.component),c=n.locals;try{o=t(i,c)}catch(u){try{var s=r.get(a);n.directive=s[0],o=t(n.directive.controller,c)}catch(u){console.warn&&console.warn("Could not instantiate controller",i),o=t(angular.noop,c)}}return n.controller=o})}}function bindRouteParamsForDirectiveStepFactory(){return function(t){return t.router.traverseInstruction(t,function(t){if(t.directive&&t.directive.bindToController){var e;"object"==typeof t.directive.bindToController?e=t.directive.$$bindings.bindToController:1==t.directive.bindToController&&(e=t.directive.$$isolateBindings),e&&Object.keys(e).forEach(function(r){t.params[e[r].attrName]&&(t.controller[r]=t.params[e[r].attrName])})}return!0})}}function runCanDeactivateHookStepFactory(){return function(t){return t.router.canDeactivatePorts(t)}}function runCanActivateHookStepFactory(t){function e(e,r,n){return t.invoke(e,r,{$routeParams:n.params})}return function(t){return t.router.traverseInstruction(t,function(t){var r=t.controller;return!r.canActivate||e(r.canActivate,r,t)})}}function loadTemplatesStepFactory(t,e){return function(r){return r.router.traverseInstruction(r,function(r){var n;if(r.directive){if(r.directive.template)return r.template=r.directive.template;n=r.directive.templateUrl}else n=t.template(r.component);return e(n).then(function(t){return r.template=t})})}}function activateStepValue(t){return t.router.activatePorts(t)}function pipelineProvider(){var t,e=["$setupRoutersStep","$initLocalsStep","$initControllersStep","$bindRouteParamsForDirectiveStep","$runCanDeactivateHookStep","$runCanActivateHookStep","$loadTemplatesStep","$activateStep"];return{steps:e.slice(0),config:function(t){e=t},$get:["$injector","$q",function(r,n){return t=e.map(function(t){return r.get(t)}),{process:function(e){function r(t){if(0===o.length)return t;var i=o.shift();return n.when(i(e)).then(r)}var o=t.slice(0);return r()}}}]}}function $componentLoaderProvider(){var t="Controller",e="Directive",r=function(e){return e[0].toUpperCase()+e.substr(1)+t},n=function(t){var e=dashCase(t);return"./components/"+e+"/"+e+".html"},o=function(e){return e[0].toLowerCase()+e.substr(1,e.length-t.length-1)},i=function(t){return t+e},a=function(t){return t.substr(0,t.length-e.length)};return{$get:function(){return{controllerName:r,template:n,component:o,directiveName:i,directiveToComponent:a}},setCtrlNameMapping:function(t){return r=t,this},setComponentFromCtrlMapping:function(t){return o=t,this},setTemplateMapping:function(t){return n=t,this},setDirectiveMapping:function(t){return i=t,this}}}function privatePipelineFactory(t){return t}function dashCase(t){return t.replace(/([A-Z])/g,function(t){return"-"+t.toLowerCase()})}angular.module("ngNewRouter",[]).factory("$router",routerFactory).value("$routeParams",{}).provider("$componentLoader",$componentLoaderProvider).provider("$pipeline",pipelineProvider).factory("$$pipeline",privatePipelineFactory).factory("$setupRoutersStep",setupRoutersStepFactory).factory("$initLocalsStep",initLocalsStepFactory).factory("$initControllersStep",initControllersStepFactory).factory("$bindRouteParamsForDirectiveStep",bindRouteParamsForDirectiveStepFactory).factory("$runCanDeactivateHookStep",runCanDeactivateHookStepFactory).factory("$runCanActivateHookStep",runCanActivateHookStepFactory).factory("$loadTemplatesStep",loadTemplatesStepFactory).value("$activateStep",activateStepValue).directive("ngViewport",ngViewportDirective).directive("ngViewport",ngViewportFillContentDirective).directive("ngLink",ngLinkDirective).directive("a",anchorLinkDirective),angular.module("ng").provider("$controllerIntrospector",$controllerIntrospectorProvider).provider("$compileIntrospector",$compileIntrospectorProvider).config(controllerProviderDecorator).config(compileProviderDecorator),controllerProviderDecorator.$inject=["$controllerProvider","$controllerIntrospectorProvider"],compileProviderDecorator.$inject=["$compileProvider","$compileIntrospectorProvider"],routerFactory.$inject=["$$rootRouter","$rootScope","$location","$$grammar","$controllerIntrospector","$compileIntrospector"],ngViewportDirective.$inject=["$animate","$injector","$q","$router"],ngViewportFillContentDirective.$inject=["$compile"];var LINK_MICROSYNTAX_RE=/^(.+?)(?:\((.*)\))?$/;ngLinkDirective.$inject=["$router","$location","$parse"],anchorLinkDirective.$inject=["$router"],initControllersStepFactory.$inject=["$controller","$componentLoader","$injector"],runCanActivateHookStepFactory.$inject=["$injector"],loadTemplatesStepFactory.$inject=["$componentLoader","$templateRequest"],privatePipelineFactory.$inject=["$pipeline"],angular.module("ngNewRouter").factory("$$rootRouter",["$q","$$grammar","$$pipeline",function(t,e,r){function n(t,e,r,n){return h(e,"constructor",{value:t,configurable:!0,enumerable:!1,writable:!0}),arguments.length>3?("function"==typeof n&&(t.__proto__=n),t.prototype=g(o(n),i(e))):t.prototype=e,h(t,"prototype",{configurable:!1,writable:!1}),v(t,i(r))}function o(t){if("function"==typeof t){var e=t.prototype;if(Object(e)===e||null===e)return t.prototype;throw new TypeError("super prototype must be an Object or null")}if(null===t)return null;throw new TypeError("Super expression must either be null or a function, not "+typeof t+".")}function i(t){for(var e={},r=m(t),n=0;n3?("function"==typeof i&&(t.__proto__=i),t.prototype=u(e(i),r(n))):t.prototype=n,a(t,"prototype",{configurable:!1,writable:!1}),c(t,r(o))}function e(t){if("function"==typeof t){var e=t.prototype;if(Object(e)===e||null===e)return t.prototype;throw new TypeError("super prototype must be an Object or null")}if(null===t)return null;throw new TypeError("Super expression must either be null or a function, not "+typeof t+".")}function r(t){for(var e={},r=p(t),n=0;ns;s++){var l,f=c[s];(l=f.match(/^:([^\/]+)$/))?(u.push(new r(l[1])),i.push(l[1]),a.dynamics++):(l=f.match(/^\*([^\/]+)$/))?(u.push(new n(l[1])),i.push(l[1]),a.stars++):""===f?u.push(new o):(u.push(new e(f)),a.statics++)}return u}function a(t){this.charSpec=t,this.nextStates=[]}function c(t){return t.sort(function(t,e){if(t.types.stars!==e.types.stars)return t.types.stars-e.types.stars;if(t.types.stars){if(t.types.statics!==e.types.statics)return e.types.statics-t.types.statics;if(t.types.dynamics!==e.types.dynamics)return e.types.dynamics-t.types.dynamics}return t.types.dynamics!==e.types.dynamics?t.types.dynamics-e.types.dynamics:t.types.statics!==e.types.statics?e.types.statics-t.types.statics:0})}function u(t,e){for(var r=[],n=0,o=t.length;o>n;n++){var i=t[n];r=r.concat(i.match(e))}return r}function s(t){this.queryParams=t||{}}function p(t,e,r){for(var n=t.handlers,o=t.regex,i=e.match(o),a=1,c=new s(r),u=0,p=n.length;p>u;u++){for(var l=n[u],f=l.names,h={},v=0,g=f.length;g>v;v++)h[f[v]]=i[a++];c.push({handler:l.handler,params:h,isDynamic:!!f.length})}return c}function l(t,e){return e.eachChar(function(e){t=t.put(e)}),t}var f=function(){function t(t,e,r){this.path=t,this.matcher=e,this.delegate=r}function e(t){this.routes={},this.children={},this.target=t}function r(e,n,o){return function(i,a){var c=e+i;return a?void a(r(c,n,o)):new t(e+i,n,o)}}function n(t,e,r){for(var n=0,o=0,i=t.length;i>o;o++)n+=t[o].path.length;e=e.substr(n);var a={path:e,handler:r};t.push(a)}function o(t,e,r,i){var a=e.routes;for(var c in a)if(a.hasOwnProperty(c)){var u=t.slice();n(u,c,a[c]),e.children[c]?o(u,e.children[c],r,i):r.call(i,u)}}return t.prototype={to:function(t,e){var r=this.delegate;if(r&&r.willAddRoute&&(t=r.willAddRoute(this.matcher.target,t)),this.matcher.add(this.path,t),e){if(0===e.length)throw new Error("You must have an argument in the function passed to `to`");this.matcher.addChild(this.path,t,e,this.delegate)}return this}},e.prototype={add:function(t,e){this.routes[t]=e},addChild:function(t,n,o,i){var a=new e(n);this.children[t]=a;var c=r(t,a,i);i&&i.contextEntered&&i.contextEntered(n,c),o(c)}},function(t,n){var i=new e;t(r("",i,this.delegate)),o([],i,function(t){n?n(this,t):this.add(t)},this)}}(),h=["/",".","*","+","?","|","(",")","[","]","{","}","\\"],v=new RegExp("(\\"+h.join("|\\")+")","g");e.prototype={eachChar:function(t){for(var e,r=this.string,n=0,o=r.length;o>n;n++)e=r.charAt(n),t({validChars:e})},regex:function(){return this.string.replace(v,"\\$1")},generate:function(){return this.string}},r.prototype={eachChar:function(t){t({invalidChars:"/",repeat:!0})},regex:function(){return"([^/]+)"},generate:function(t){return t[this.name]}},n.prototype={eachChar:function(t){t({invalidChars:"",repeat:!0})},regex:function(){return"(.+)"},generate:function(t){return t[this.name]}},o.prototype={eachChar:function(){},regex:function(){return""},generate:function(){return""}},a.prototype={get:function(t){for(var e=this.nextStates,r=0,n=e.length;n>r;r++){var o=e[r],i=o.charSpec.validChars===t.validChars;if(i=i&&o.charSpec.invalidChars===t.invalidChars)return o}},put:function(t){var e;return(e=this.get(t))?e:(e=new a(t),this.nextStates.push(e),t.repeat&&e.nextStates.push(e),e)},match:function(t){for(var e,r,n,o=this.nextStates,i=[],a=0,c=o.length;c>a;a++)e=o[a],r=e.charSpec,"undefined"!=typeof(n=r.validChars)?-1!==n.indexOf(t)&&i.push(e):"undefined"!=typeof(n=r.invalidChars)&&-1===n.indexOf(t)&&i.push(e);return i}};var g=Object.create||function(t){function e(){}return e.prototype=t,new e};s.prototype=g({splice:Array.prototype.splice,slice:Array.prototype.slice,push:Array.prototype.push,length:0,queryParams:null});var d=function(){this.rootState=new a,this.names={}};return d.prototype={add:function(t,e){for(var r,n=this.rootState,a="^",c={statics:0,dynamics:0,stars:0},u=[],s=[],p=!0,f=0,h=t.length;h>f;f++){var v=t[f],g=[],d=i(v.path,g,c);s=s.concat(d);for(var m=0,y=d.length;y>m;m++){var $=d[m];$ instanceof o||(p=!1,n=n.put({validChars:"/"}),a+="/",n=l(n,$),a+=$.regex())}var w={handler:v.handler,names:g};u.push(w)}p&&(n=n.put({validChars:"/"}),a+="/"),n.handlers=u,n.regex=new RegExp(a+"$"),n.types=c,(r=e&&e.as)&&(this.names[r]={segments:s,handlers:u})},handlersFor:function(t){var e=this.names[t],r=[];if(!e)throw new Error("There is no route named "+t);for(var n=0,o=e.handlers.length;o>n;n++)r.push(e.handlers[n]);return r},hasRoute:function(t){return!!this.names[t]},generate:function(t,e){var r=this.names[t],n="";if(!r)throw new Error("There is no route named "+t);for(var i=r.segments,a=0,c=i.length;c>a;a++){var u=i[a];u instanceof o||(n+="/",n+=u.generate(e))}return"/"!==n.charAt(0)&&(n="/"+n),e&&e.queryParams&&(n+=this.generateQueryString(e.queryParams,r.handlers)),n},generateQueryString:function(e){var r=[],n=[];for(var o in e)e.hasOwnProperty(o)&&n.push(o);n.sort();for(var i=0,a=n.length;a>i;i++){o=n[i];var c=e[o];if(null!=c){var u=encodeURIComponent(o);if(t(c))for(var s=0,p=c.length;p>s;s++){var l=o+"[]="+encodeURIComponent(c[s]);r.push(l)}else u+="="+encodeURIComponent(c),r.push(u)}}return 0===r.length?"":"?"+r.join("&")},parseQueryString:function(t){for(var e=t.split("&"),r={},n=0;n2&&"[]"===a.slice(c-2)&&(u=!0,a=a.slice(0,c-2),r[a]||(r[a]=[])),o=i[1]?decodeURIComponent(i[1]):""),u?r[a].push(o):r[a]=o}return r},recognize:function(t){var e,r,n,o,i=[this.rootState],a={},s=!1;if(o=t.indexOf("?"),-1!==o){var l=t.substr(o+1,t.length);t=t.substr(0,o),a=this.parseQueryString(l)}for(t=decodeURI(t),"/"!==t.charAt(0)&&(t="/"+t),e=t.length,e>1&&"/"===t.charAt(e-1)&&(t=t.substr(0,e-1),s=!0),r=0,n=t.length;n>r&&(i=u(i,t.charAt(r)),i.length);r++);var f=[];for(r=0,n=i.length;n>r;r++)i[r].handlers&&f.push(i[r]);i=c(f);var h=f[0];return h&&h.handlers?(s&&"(.+)$"===h.regex.source.slice(-5)&&(t+="/"),p(h,t,a)):void 0}},d.prototype.map=f,d.VERSION="VERSION_STRING_PLACEHOLDER",d}()),f="/*childRoute",h=function(){this.rules={}};t(h,{config:function(t,e){"app"===t&&(t="/"),this.rules[t]||(this.rules[t]=new v(t)),this.rules[t].config(e)},recognize:function(t){var e=void 0!==arguments[1]?arguments[1]:"/",r=this;if("undefined"!=typeof t){var n=this.rules[e];if(n){var i=n.recognize(t);if(i){var a=i[i.length-1],c=a.handler,u=a.params,s={viewports:{},params:u};if(u&&u.childRoute){var p="/"+u.childRoute;s.canonicalUrl=c.rewroteUrl.substr(0,c.rewroteUrl.length-(u.childRoute.length+1)),o(c.components,function(t,e){s.viewports[e]=r.recognize(p,t)}),s.canonicalUrl+=s.viewports[Object.keys(s.viewports)[0]].canonicalUrl}else s.canonicalUrl=c.rewroteUrl,o(c.components,function(t,e){s.viewports[e]={viewports:{}}});return o(s.viewports,function(t,e){t.component=c.components[e],t.params=u}),s}}}},generate:function(t,e){var r,n="";do{if(r=null,o(this.rules,function(o){o.hasRoute(t)&&(n=o.generate(t,e)+n,r=o)}),!r)return"";t=r.name}while("/"!==r.name);return n}},{}),Object.defineProperty(h.prototype.recognize,"parameters",{get:function(){return[[$traceurRuntime.type.string],[]]}});var v=function(t){this.name=t,this.rewrites={},this.recognizer=new l};return t(v,{config:function(t){var e=this;t instanceof Array?t.forEach(function(t){return e.configOne(t)}):this.configOne(t)},getCanonicalUrl:function(t){return"."===t[0]&&(t=t.substr(1)),(""===t||"/"!==t[0])&&(t="/"+t),o(this.rewrites,function(e,r){"/"===r?"/"===t&&(t=e):0===t.indexOf(r)&&(t=t.replace(r,e))}),t},configOne:function(t){var e=this;if(t.redirectTo){if(this.rewrites[t.path])throw new Error('"'+t.path+'" already maps to "'+this.rewrites[t.path]+'"');return void(this.rewrites[t.path]=t.redirectTo)}if(t.component){if(t.components)throw new Error('A route config should have either a "component" or "components" property, but not both.');t.components=t.component,delete t.component}"string"==typeof t.components&&(t.components={"default":t.components});var r;t.as?r=[t.as]:(r=i(t.components,function(t,e){return e+":"+t}),t.components["default"]&&r.push(t.components["default"])),r.forEach(function(r){return e.recognizer.add([{path:t.path,handler:t}],{as:r})});var o=n(t);o.path+=f,this.recognizer.add([{path:o.path,handler:o}])},recognize:function(t){var e=this.getCanonicalUrl(t),r=this.recognizer.recognize(e);return r&&(r[0].handler.rewroteUrl=e),r},generate:function(t,e){return this.recognizer.generate(t,e)},hasRoute:function(t){return this.recognizer.hasRoute(t)}},{}),new h}]); \ No newline at end of file diff --git a/dist/router.js b/dist/router.js index 870237b..ab5dfb8 100644 --- a/dist/router.js +++ b/dist/router.js @@ -129,15 +129,21 @@ define(["assert", './grammar', './pipeline'], function($__0,$__2,$__4) { return this.registry.generate(name, params); } }, {}); - Router.parameters = [[Grammar], [Pipeline], [], []]; - Router.prototype.generate.parameters = [[$traceurRuntime.type.string], []]; + Object.defineProperty(Router, "parameters", {get: function() { + return [[Grammar], [Pipeline], [], []]; + }}); + Object.defineProperty(Router.prototype.generate, "parameters", {get: function() { + return [[$traceurRuntime.type.string], []]; + }}); var RootRouter = function RootRouter(grammar, pipeline) { assert.argumentTypes(grammar, Grammar, pipeline, Pipeline); $traceurRuntime.superCall(this, $RootRouter.prototype, "constructor", [grammar, pipeline, null, '/']); }; var $RootRouter = RootRouter; ($traceurRuntime.createClass)(RootRouter, {}, {}, Router); - RootRouter.parameters = [[Grammar], [Pipeline]]; + Object.defineProperty(RootRouter, "parameters", {get: function() { + return [[Grammar], [Pipeline]]; + }}); var ChildRouter = function ChildRouter(parent, name) { $traceurRuntime.superCall(this, $ChildRouter.prototype, "constructor", [parent.registry, parent.pipeline, parent, name]); this.parent = parent; @@ -169,3 +175,5 @@ define(["assert", './grammar', './pipeline'], function($__0,$__2,$__4) { __esModule: true }; }); + +//# sourceMappingURL=router.ats diff --git a/src/router-directive.es5.js b/src/router-directive.es5.js index e85180d..39e3259 100644 --- a/src/router-directive.es5.js +++ b/src/router-directive.es5.js @@ -12,6 +12,7 @@ angular.module('ngNewRouter', []) .factory('$setupRoutersStep', setupRoutersStepFactory) .factory('$initLocalsStep', initLocalsStepFactory) .factory('$initControllersStep', initControllersStepFactory) + .factory('$bindRouteParamsForDirectiveStep', bindRouteParamsForDirectiveStepFactory) .factory('$runCanDeactivateHookStep', runCanDeactivateHookStepFactory) .factory('$runCanActivateHookStep', runCanActivateHookStepFactory) .factory('$loadTemplatesStep', loadTemplatesStepFactory) @@ -29,7 +30,9 @@ angular.module('ngNewRouter', []) */ angular.module('ng') .provider('$controllerIntrospector', $controllerIntrospectorProvider) - .config(controllerProviderDecorator); + .provider('$compileIntrospector', $compileIntrospectorProvider) + .config(controllerProviderDecorator) + .config(compileProviderDecorator); /* * decorates with routing info @@ -42,6 +45,14 @@ function controllerProviderDecorator($controllerProvider, $controllerIntrospecto }; } +function compileProviderDecorator($compileProvider, $compileIntrospectorProvider) { + var directive = $compileProvider.directive; + $compileProvider.directive = function (name, directiveFactory) { + $compileIntrospectorProvider.directive(name, directiveFactory); + return directive.apply(this, arguments); + }; +} + /* * private service that holds route mappings for each controller */ @@ -76,12 +87,50 @@ function $controllerIntrospectorProvider() { } } -function routerFactory($$rootRouter, $rootScope, $location, $$grammar, $controllerIntrospector) { + +/* + * private service that holds route mappings for each controller + */ +function $compileIntrospectorProvider() { + var directiveFactories = []; + var onDirectiveDefined = null; + return { + directive: function (name, directiveFactory) { + if (angular.isArray(directiveFactory)) { + directiveFactory = directiveFactory[directiveFactory.length - 1]; + } + if (directiveFactory.$routeConfig) { + if (onDirectiveDefined) { + onDirectiveDefined(name, directiveFactory.$routeConfig); + } else { + directiveFactories.push({name: name, config: directiveFactory.$routeConfig}); + } + } + }, + $get: ['$componentLoader', '$injector', function ($componentLoader, $injector) { + return function (newOnDirectiveDefined) { + onDirectiveDefined = function (name, config) { + return newOnDirectiveDefined(name, config); + }; + while(directiveFactories.length > 0) { + var rule = directiveFactories.pop(); + onDirectiveDefined(rule.name, rule.config); + } + } + }] + } +} + +function routerFactory($$rootRouter, $rootScope, $location, $$grammar, $controllerIntrospector, $compileIntrospector) { $controllerIntrospector(function (name, config) { $$grammar.config(name, config); }); + $compileIntrospector(function (name, config) { + $$grammar.config(name, config); + }); + $rootScope.$watch(function () { return $location.path(); }, function (newUrl) { @@ -187,7 +236,11 @@ function ngViewportDirective($animate, $injector, $q, $router) { }); var newController = instruction.controller; - newScope[componentName] = newController; + if (instruction.directive && instruction.directive.controllerAs) { + newScope[instruction.directive.controllerAs] = newController; + } else { + newScope[componentName] = newController; + } var result; if (currentController && currentController.deactivate) { @@ -366,23 +419,56 @@ function initLocalsStepFactory() { /* * $initControllersStep */ -function initControllersStepFactory($controller, $componentLoader) { +function initControllersStepFactory($controller, $componentLoader, $injector) { return function initControllers(instruction) { return instruction.router.traverseInstruction(instruction, function(instruction) { var controllerName = $componentLoader.controllerName(instruction.component); + var directiveName = $componentLoader.directiveName(instruction.component); var locals = instruction.locals; var ctrl; try { ctrl = $controller(controllerName, locals); } catch(e) { - console.warn && console.warn('Could not instantiate controller', controllerName); - ctrl = $controller(angular.noop, locals); + try { + var directives = $injector.get(directiveName); + // can't handle two names on the same directive yet + instruction.directive = directives[0]; + ctrl = $controller(instruction.directive.controller, locals); + } catch(e) { + console.warn && console.warn('Could not instantiate controller', controllerName); + ctrl = $controller(angular.noop, locals); + } } return instruction.controller = ctrl; }); } } +function bindRouteParamsForDirectiveStepFactory() { + return function bindRouteParamsForDirective(instruction) { + return instruction.router.traverseInstruction(instruction, function(instruction) { + if (instruction.directive && instruction.directive.bindToController) { + var bindings; + if (typeof instruction.directive.bindToController == 'object') { + // ng 1.4 object syntax + bindings = instruction.directive.$$bindings.bindToController; + } else if (instruction.directive.bindToController == true) { + // ng 1.3 syntax + bindings = instruction.directive.$$isolateBindings; + } + if (bindings) { + Object.keys(bindings).forEach(function(key) { + if (instruction.params[bindings[key].attrName]) { + instruction.controller[key] = instruction.params[bindings[key].attrName]; + } + }); + } + } + return true; + }); + }; +} + function runCanDeactivateHookStepFactory() { return function runCanDeactivateHook(instruction) { return instruction.router.canDeactivatePorts(instruction); @@ -408,7 +494,16 @@ function runCanActivateHookStepFactory($injector) { function loadTemplatesStepFactory($componentLoader, $templateRequest) { return function loadTemplates(instruction) { return instruction.router.traverseInstruction(instruction, function(instruction) { - var componentTemplateUrl = $componentLoader.template(instruction.component); + var componentTemplateUrl; + if (instruction.directive) { + if (instruction.directive.template) { + return instruction.template = instruction.directive.template + } else { + componentTemplateUrl = instruction.directive.templateUrl; + } + } else { + componentTemplateUrl = $componentLoader.template(instruction.component); + } return $templateRequest(componentTemplateUrl).then(function (templateHtml) { return instruction.template = templateHtml; }); @@ -429,6 +524,7 @@ function pipelineProvider() { '$setupRoutersStep', '$initLocalsStep', '$initControllersStep', + '$bindRouteParamsForDirectiveStep', '$runCanDeactivateHookStep', '$runCanActivateHookStep', '$loadTemplatesStep', @@ -484,6 +580,7 @@ function pipelineProvider() { function $componentLoaderProvider() { var DEFAULT_SUFFIX = 'Controller'; + var DEFAULT_DIRECTIVE_SUFFIX = 'Directive'; var componentToCtrl = function componentToCtrlDefault(name) { return name[0].toUpperCase() + name.substr(1) + DEFAULT_SUFFIX; @@ -498,12 +595,22 @@ function $componentLoaderProvider() { return name[0].toLowerCase() + name.substr(1, name.length - DEFAULT_SUFFIX.length - 1); }; + var componentToDirective = function componentToDirectiveDefault(name) { + return name + DEFAULT_DIRECTIVE_SUFFIX; + }; + + var directiveToComponent = function directiveToComponent(name) { + return name.substr(0, name.length - DEFAULT_DIRECTIVE_SUFFIX.length); + }; + return { $get: function () { return { controllerName: componentToCtrl, template: componentToTemplate, - component: ctrlToComponent + component: ctrlToComponent, + directiveName: componentToDirective, + directiveToComponent: directiveToComponent }; }, @@ -532,6 +639,11 @@ function $componentLoaderProvider() { setTemplateMapping: function(newFn) { componentToTemplate = newFn; return this; + }, + + setDirectiveMapping: function(newFn) { + componentToDirective = newFn; + return this; } }; } diff --git a/test/compile-introspector.es5.spec.js b/test/compile-introspector.es5.spec.js new file mode 100644 index 0000000..1c67b70 --- /dev/null +++ b/test/compile-introspector.es5.spec.js @@ -0,0 +1,40 @@ +describe('$compileIntrospector', function () { + + var $compileProvider; + + beforeEach(function() { + module('ng'); + module('ngNewRouter'); + module(function(_$compileProvider_) { + $compileProvider = _$compileProvider_; + }); + }); + + it('should call the introspector function whenever a controller is registered', inject(function ($compileIntrospector) { + var spy = jasmine.createSpy(); + $compileIntrospector(spy); + var DirectiveFactory = function() { + return { + template: "awesome", + controller: function() {} + }; + } + DirectiveFactory.$routeConfig = [{ path: '/', component: 'example' }]; + $compileProvider.directive('some', DirectiveFactory); + expect(spy).toHaveBeenCalledWith('some', [{ path: '/', component: 'example' }]); + })); + + it('should call the introspector function whenever a controller is registered with array annotations', inject(function ($compileIntrospector) { + var spy = jasmine.createSpy(); + $compileIntrospector(spy); + var DirectiveFactory = function(foo) { + return { + template: "awesome", + controller: function() {} + }; + } + DirectiveFactory.$routeConfig = [{ path: '/', component: 'example' }]; + $compileProvider.directive('some', ['foo', DirectiveFactory]); + expect(spy).toHaveBeenCalledWith('some', [{ path: '/', component: 'example' }]); + })); +}); diff --git a/test/component-loader.es5.spec.js b/test/component-loader.es5.spec.js index 42ed6ab..c82cda0 100644 --- a/test/component-loader.es5.spec.js +++ b/test/component-loader.es5.spec.js @@ -13,4 +13,12 @@ describe('$componentLoader', function () { it('should convert a component name to a template URL', inject(function ($componentLoader) { expect($componentLoader.template('foo')).toBe('./components/foo/foo.html'); })); + + it('should convert a component name to a potential directive', inject(function ($componentLoader) { + expect($componentLoader.directiveName('foo')).toBe('fooDirective'); + })); + + it('should convert a directive name to a component name', inject(function ($componentLoader) { + expect($componentLoader.directiveToComponent('fooDirective')).toBe('foo'); + })); }); diff --git a/test/router-viewport.es5.spec.js b/test/router-viewport.es5.spec.js index 20044c5..42ae74d 100644 --- a/test/router-viewport.es5.spec.js +++ b/test/router-viewport.es5.spec.js @@ -7,7 +7,8 @@ describe('ngViewport', function () { $rootScope, $router, $templateCache, - $controllerProvider; + $controllerProvider, + $compileProvider; beforeEach(function() { @@ -17,6 +18,9 @@ describe('ngViewport', function () { $controllerProvider = _$controllerProvider_; }); + module(function(_$compileProvider_) { + $compileProvider = _$compileProvider_; + }); inject(function(_$compile_, _$rootScope_, _$router_, _$templateCache_) { $compile = _$compile_; $rootScope = _$rootScope_; @@ -45,7 +49,6 @@ describe('ngViewport', function () { expect(elt.text()).toBe('one'); }); - // See https://github.com/angular/router/issues/105 it('should warn when instantiating a component with no controller', function () { put('noController', '
{{ 2 + 2 }}
'); @@ -647,6 +650,60 @@ describe('ngViewport', function () { expect($router.navigating).toBe(false); }); + describe("with directives", function() { + beforeEach(function() { + registerDirectiveComponent('three', '
{{three.number}}
', boringController('number', 'three')); + registerDirectiveComponent('otherUser', '
hello {{otherUser.myName}}
', function() {}, { + bindToController: true, + scope: { myName: "=name" } + }); + registerDirectiveComponent('customControllerAs', '
{{cheese.number}}', boringController("number", "three"), + { + controllerAs: 'cheese' + }) + }); + + it('should work in a simple case using a directive', function () { + compile(''); + + $router.config([ + { path: '/', component: 'three' } + ]); + + $router.navigate('/'); + $rootScope.$digest(); + + expect(elt.text()).toBe('three'); + }); + + it('should bind parameters if bindToController is set', function () { + $router.config([ + { path: '/user/:name', component: 'otherUser' } + ]); + compile(''); + + $router.navigate('/user/brian'); + $rootScope.$digest(); + expect(elt.text()).toBe('hello brian'); + + $router.navigate('/user/igor'); + $rootScope.$digest(); + expect(elt.text()).toBe('hello igor'); + }); + + it("should respect the directives controllerAs attribute", function() { + compile(''); + + $router.config([ + { path: '/', component: 'customControllerAs' } + ]); + + $router.navigate('/'); + $rootScope.$digest(); + + expect(elt.text()).toBe('three'); + }); + }); function registerComponent(name, template, config) { if (!template) { @@ -668,6 +725,32 @@ describe('ngViewport', function () { put(name, template); } + function registerDirectiveComponent(name, template, config, ddoOptions) { + var ddo = {}; + if (!template) { + template = ''; + } + ddo.template = template; + var ctrl; + if (!config) { + ctrl = function () {}; + } else if (angular.isArray(config)) { + ctrl = function () {}; + ctrl.$routeConfig = config; + } else if (typeof config === 'function') { + ctrl = config; + } else { + ctrl = function () {}; + ctrl.prototype = config; + } + ddo.controller = ctrl; + // using ng 1.3 for now + ddo = angular.extend(ddo, ddoOptions) + $compileProvider.directive(name, function() { + return ddo; + }); + } + function boringController (model, value) { return function () { this[model] = value; @@ -764,4 +847,5 @@ describe('ngViewport animations', function () { $rootScope.$digest(); return elt; } + }); diff --git a/test/util.es5.js b/test/util.es5.js index c12ed8d..458b8c7 100644 --- a/test/util.es5.js +++ b/test/util.es5.js @@ -29,13 +29,17 @@ function provideHelpers(fn, preInject) { $rootScope, $router, $templateCache, - $controllerProvider; + $controllerProvider, + $compileProvider; module('ng'); module('ngNewRouter'); module(function(_$controllerProvider_) { $controllerProvider = _$controllerProvider_; }); + module(function(_$compileProvider_) { + $compileProvider = _$compileProvider_; + }); inject(function(_$compile_, _$rootScope_, _$router_, _$templateCache_) { $compile = _$compile_; @@ -64,6 +68,32 @@ function provideHelpers(fn, preInject) { put(name, template); } + function registerDirectiveComponent(name, template, config, ddoOptions) { + var ddo = {}; + if (!template) { + template = ''; + } + ddo.template = template; + var ctrl; + if (!config) { + ctrl = function () {}; + } else if (angular.isArray(config)) { + ctrl = function () {}; + ctrl.$routeConfig = config; + } else if (typeof config === 'function') { + ctrl = config; + } else { + ctrl = function () {}; + ctrl.prototype = config; + } + ddo.controller = ctrl; + // using ng 1.3 for now + ddo = angular.extend(ddo, ddoOptions) + $compileProvider.directive(name, function() { + return ddo; + }); + } + function put (name, template) { $templateCache.put(componentTemplatePath(name), [200, template, {}]); @@ -77,6 +107,7 @@ function provideHelpers(fn, preInject) { fn({ registerComponent: registerComponent, + registerDirectiveComponent: registerDirectiveComponent, $router: $router, put: put, compile: compile