diff options
Diffstat (limited to 'src/service/route.js')
| -rw-r--r-- | src/service/route.js | 473 | 
1 files changed, 238 insertions, 235 deletions
| diff --git a/src/service/route.js b/src/service/route.js index 3918c251..f2ecbd2a 100644 --- a/src/service/route.js +++ b/src/service/route.js @@ -62,264 +62,267 @@        </doc:scenario>      </doc:example>   */ -angularServiceInject('$route', function($rootScope, $location, $routeParams) { -  /** -   * @ngdoc event -   * @name angular.service.$route#$beforeRouteChange -   * @eventOf angular.service.$route -   * @eventType broadcast on root scope -   * @description -   * Broadcasted before a route change. -   * -   * @param {Route} next Future route information. -   * @param {Route} current Current route information. -   * -   * The `Route` object extends the route definition with the following properties. -   * -   *    * `scope` - The instance of the route controller. -   *    * `params` - The current {@link angular.service.$routeParams params}. -   * -   */ +function $RouteProvider(){ +  this.$get = ['$rootScope', '$location', '$routeParams', +      function( $rootScope,  $location,  $routeParams) { +    /** +     * @ngdoc event +     * @name angular.service.$route#$beforeRouteChange +     * @eventOf angular.service.$route +     * @eventType broadcast on root scope +     * @description +     * Broadcasted before a route change. +     * +     * @param {Route} next Future route information. +     * @param {Route} current Current route information. +     * +     * The `Route` object extends the route definition with the following properties. +     * +     *    * `scope` - The instance of the route controller. +     *    * `params` - The current {@link angular.service.$routeParams params}. +     * +     */ -  /** -   * @ngdoc event -   * @name angular.service.$route#$afterRouteChange -   * @eventOf angular.service.$route -   * @eventType broadcast on root scope -   * @description -   * Broadcasted after a route change. -   * -   * @param {Route} current Current route information. -   * @param {Route} previous Previous route information. -   * -   * The `Route` object extends the route definition with the following properties. -   * -   *    * `scope` - The instance of the route controller. -   *    * `params` - The current {@link angular.service.$routeParams params}. -   * -   */ +    /** +     * @ngdoc event +     * @name angular.service.$route#$afterRouteChange +     * @eventOf angular.service.$route +     * @eventType broadcast on root scope +     * @description +     * Broadcasted after a route change. +     * +     * @param {Route} current Current route information. +     * @param {Route} previous Previous route information. +     * +     * The `Route` object extends the route definition with the following properties. +     * +     *    * `scope` - The instance of the route controller. +     *    * `params` - The current {@link angular.service.$routeParams params}. +     * +     */ -  /** -   * @ngdoc event -   * @name angular.service.$route#$routeUpdate -   * @eventOf angular.service.$route -   * @eventType emit on the current route scope -   * @description -   * -   * The `reloadOnSearch` property has been set to false, and we are reusing the same -   * instance of the Controller. -   */ +    /** +     * @ngdoc event +     * @name angular.service.$route#$routeUpdate +     * @eventOf angular.service.$route +     * @eventType emit on the current route scope +     * @description +     * +     * The `reloadOnSearch` property has been set to false, and we are reusing the same +     * instance of the Controller. +     */ -  var routes = {}, -      matcher = switchRouteMatcher, -      parentScope = $rootScope, -      dirty = 0, -      forceReload = false, -      $route = { -        routes: routes, +    var routes = {}, +        matcher = switchRouteMatcher, +        parentScope = $rootScope, +        dirty = 0, +        forceReload = false, +        $route = { +          routes: routes, -        /** -         * @ngdoc method -         * @name angular.service.$route#parent -         * @methodOf angular.service.$route -         * -         * @param {Scope} [scope=rootScope] Scope to be used as parent for newly created -         *    `$route.current.scope` scopes. -         * -         * @description -         * Sets a scope to be used as the parent scope for scopes created on route change. If not -         * set, defaults to the root scope. -         */ -        parent: function(scope) { -          if (scope) parentScope = scope; -        }, +          /** +           * @ngdoc method +           * @name angular.service.$route#parent +           * @methodOf angular.service.$route +           * +           * @param {Scope} [scope=rootScope] Scope to be used as parent for newly created +           *    `$route.current.scope` scopes. +           * +           * @description +           * Sets a scope to be used as the parent scope for scopes created on route change. If not +           * set, defaults to the root scope. +           */ +          parent: function(scope) { +            if (scope) parentScope = scope; +          }, -        /** -         * @ngdoc method -         * @name angular.service.$route#when -         * @methodOf angular.service.$route -         * -         * @param {string} path Route path (matched against `$location.hash`) -         * @param {Object} route Mapping information to be assigned to `$route.current` on route -         *    match. -         * -         *    Object properties: -         * -         *    - `controller` – `{function()=}` – Controller fn that should be associated with newly -         *      created scope. -         *    - `template` – `{string=}` – path to an html template that should be used by -         *      {@link angular.widget.ng:view ng:view} or -         *      {@link angular.widget.ng:include ng:include} widgets. -         *    - `redirectTo` – {(string|function())=} – value to update -         *      {@link angular.service.$location $location} path with and trigger route redirection. -         * -         *      If `redirectTo` is a function, it will be called with the following parameters: -         * -         *      - `{Object.<string>}` - route parameters extracted from the current -         *        `$location.path()` by applying the current route template. -         *      - `{string}` - current `$location.path()` -         *      - `{Object}` - current `$location.search()` -         * -         *      The custom `redirectTo` function is expected to return a string which will be used -         *      to update `$location.path()` and `$location.search()`. -         * -         *    - `[reloadOnSearch=true]` - {boolean=} - reload route when only $location.search() -         *    changes. -         * -         *      If the option is set to false and url in the browser changes, then -         *      $routeUpdate event is emited on the current route scope. You can use this event to -         *      react to {@link angular.service.$routeParams} changes: -         * -         *            function MyCtrl($route, $routeParams) { -         *              this.$on('$routeUpdate', function() { -         *                // do stuff with $routeParams -         *              }); -         *            } -         * -         * @returns {Object} route object -         * -         * @description -         * Adds a new route definition to the `$route` service. -         */ -        when: function(path, route) { -          var routeDef = routes[path]; -          if (!routeDef) routeDef = routes[path] = {reloadOnSearch: true}; -          if (route) extend(routeDef, route); // TODO(im): what the heck? merge two route definitions? -          dirty++; -          return routeDef; -        }, +          /** +           * @ngdoc method +           * @name angular.service.$route#when +           * @methodOf angular.service.$route +           * +           * @param {string} path Route path (matched against `$location.hash`) +           * @param {Object} route Mapping information to be assigned to `$route.current` on route +           *    match. +           * +           *    Object properties: +           * +           *    - `controller` – `{function()=}` – Controller fn that should be associated with newly +           *      created scope. +           *    - `template` – `{string=}` – path to an html template that should be used by +           *      {@link angular.widget.ng:view ng:view} or +           *      {@link angular.widget.ng:include ng:include} widgets. +           *    - `redirectTo` – {(string|function())=} – value to update +           *      {@link angular.service.$location $location} path with and trigger route redirection. +           * +           *      If `redirectTo` is a function, it will be called with the following parameters: +           * +           *      - `{Object.<string>}` - route parameters extracted from the current +           *        `$location.path()` by applying the current route template. +           *      - `{string}` - current `$location.path()` +           *      - `{Object}` - current `$location.search()` +           * +           *      The custom `redirectTo` function is expected to return a string which will be used +           *      to update `$location.path()` and `$location.search()`. +           * +           *    - `[reloadOnSearch=true]` - {boolean=} - reload route when only $location.search() +           *    changes. +           * +           *      If the option is set to false and url in the browser changes, then +           *      $routeUpdate event is emited on the current route scope. You can use this event to +           *      react to {@link angular.service.$routeParams} changes: +           * +           *            function MyCtrl($route, $routeParams) { +           *              this.$on('$routeUpdate', function() { +           *                // do stuff with $routeParams +           *              }); +           *            } +           * +           * @returns {Object} route object +           * +           * @description +           * Adds a new route definition to the `$route` service. +           */ +          when: function(path, route) { +            var routeDef = routes[path]; +            if (!routeDef) routeDef = routes[path] = {reloadOnSearch: true}; +            if (route) extend(routeDef, route); // TODO(im): what the heck? merge two route definitions? +            dirty++; +            return routeDef; +          }, -        /** -         * @ngdoc method -         * @name angular.service.$route#otherwise -         * @methodOf angular.service.$route -         * -         * @description -         * Sets route definition that will be used on route change when no other route definition -         * is matched. -         * -         * @param {Object} params Mapping information to be assigned to `$route.current`. -         */ -        otherwise: function(params) { -          $route.when(null, params); -        }, +          /** +           * @ngdoc method +           * @name angular.service.$route#otherwise +           * @methodOf angular.service.$route +           * +           * @description +           * Sets route definition that will be used on route change when no other route definition +           * is matched. +           * +           * @param {Object} params Mapping information to be assigned to `$route.current`. +           */ +          otherwise: function(params) { +            $route.when(null, params); +          }, -        /** -         * @ngdoc method -         * @name angular.service.$route#reload -         * @methodOf angular.service.$route -         * -         * @description -         * Causes `$route` service to reload (and recreate the `$route.current` scope) upon the next -         * eval even if {@link angular.service.$location $location} hasn't changed. -         */ -        reload: function() { -          dirty++; -          forceReload = true; -        } -      }; +          /** +           * @ngdoc method +           * @name angular.service.$route#reload +           * @methodOf angular.service.$route +           * +           * @description +           * Causes `$route` service to reload (and recreate the `$route.current` scope) upon the next +           * eval even if {@link angular.service.$location $location} hasn't changed. +           */ +          reload: function() { +            dirty++; +            forceReload = true; +          } +        }; -  $rootScope.$watch(function() { return dirty + $location.url(); }, updateRoute); +    $rootScope.$watch(function() { return dirty + $location.url(); }, updateRoute); -  return $route; +    return $route; -  ///////////////////////////////////////////////////// +    ///////////////////////////////////////////////////// -  function switchRouteMatcher(on, when) { -    // TODO(i): this code is convoluted and inefficient, we should construct the route matching -    //   regex only once and then reuse it -    var regex = '^' + when.replace(/([\.\\\(\)\^\$])/g, "\\$1") + '$', -        params = [], -        dst = {}; -    forEach(when.split(/\W/), function(param) { -      if (param) { -        var paramRegExp = new RegExp(":" + param + "([\\W])"); -        if (regex.match(paramRegExp)) { -          regex = regex.replace(paramRegExp, "([^\\/]*)$1"); -          params.push(param); +    function switchRouteMatcher(on, when) { +      // TODO(i): this code is convoluted and inefficient, we should construct the route matching +      //   regex only once and then reuse it +      var regex = '^' + when.replace(/([\.\\\(\)\^\$])/g, "\\$1") + '$', +          params = [], +          dst = {}; +      forEach(when.split(/\W/), function(param) { +        if (param) { +          var paramRegExp = new RegExp(":" + param + "([\\W])"); +          if (regex.match(paramRegExp)) { +            regex = regex.replace(paramRegExp, "([^\\/]*)$1"); +            params.push(param); +          }          } -      } -    }); -    var match = on.match(new RegExp(regex)); -    if (match) { -      forEach(params, function(name, index) { -        dst[name] = match[index + 1];        }); +      var match = on.match(new RegExp(regex)); +      if (match) { +        forEach(params, function(name, index) { +          dst[name] = match[index + 1]; +        }); +      } +      return match ? dst : null;      } -    return match ? dst : null; -  } -  function updateRoute() { -    var next = parseRoute(), -        last = $route.current, -        Controller; +    function updateRoute() { +      var next = parseRoute(), +          last = $route.current, +          Controller; -    if (next && last && next.$route === last.$route -        && equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) { -      $route.current = next; -      copy(next.params, $routeParams); -      last.scope && last.scope.$emit('$routeUpdate'); -    } else { -      forceReload = false; -      $rootScope.$broadcast('$beforeRouteChange', next, last); -      last && last.scope && last.scope.$destroy(); -      $route.current = next; -      if (next) { -        if (next.redirectTo) { -          if (isString(next.redirectTo)) { -            $location.path(interpolate(next.redirectTo, next.params)).search(next.params) -                     .replace(); +      if (next && last && next.$route === last.$route +          && equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) { +        $route.current = next; +        copy(next.params, $routeParams); +        last.scope && last.scope.$emit('$routeUpdate'); +      } else { +        forceReload = false; +        $rootScope.$broadcast('$beforeRouteChange', next, last); +        last && last.scope && last.scope.$destroy(); +        $route.current = next; +        if (next) { +          if (next.redirectTo) { +            if (isString(next.redirectTo)) { +              $location.path(interpolate(next.redirectTo, next.params)).search(next.params) +                       .replace(); +            } else { +              $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search())) +                       .replace(); +            }            } else { -            $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search())) -                     .replace(); +            copy(next.params, $routeParams); +            (Controller = next.controller) && inferInjectionArgs(Controller); +            next.scope = parentScope.$new(Controller);            } -        } else { -          copy(next.params, $routeParams); -          (Controller = next.controller) && inferInjectionArgs(Controller); -          next.scope = parentScope.$new(Controller);          } +        $rootScope.$broadcast('$afterRouteChange', next, last);        } -      $rootScope.$broadcast('$afterRouteChange', next, last);      } -  } -  /** -   * @returns the current active route, by matching it against the URL -   */ -  function parseRoute() { -    // Match a route -    var params, match; -    forEach(routes, function(route, path) { -      if (!match && (params = matcher($location.path(), path))) { -        match = inherit(route, { -          params: extend({}, $location.search(), params), -          pathParams: params}); -        match.$route = route; -      } -    }); -    // No route matched; fallback to "otherwise" route -    return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}}); -  } +    /** +     * @returns the current active route, by matching it against the URL +     */ +    function parseRoute() { +      // Match a route +      var params, match; +      forEach(routes, function(route, path) { +        if (!match && (params = matcher($location.path(), path))) { +          match = inherit(route, { +            params: extend({}, $location.search(), params), +            pathParams: params}); +          match.$route = route; +        } +      }); +      // No route matched; fallback to "otherwise" route +      return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}}); +    } -  /** -   * @returns interpolation of the redirect path with the parametrs -   */ -  function interpolate(string, params) { -    var result = []; -    forEach((string||'').split(':'), function(segment, i) { -      if (i == 0) { -        result.push(segment); -      } else { -        var segmentMatch = segment.match(/(\w+)(.*)/); -        var key = segmentMatch[1]; -        result.push(params[key]); -        result.push(segmentMatch[2] || ''); -        delete params[key]; -      } -    }); -    return result.join(''); -  } +    /** +     * @returns interpolation of the redirect path with the parametrs +     */ +    function interpolate(string, params) { +      var result = []; +      forEach((string||'').split(':'), function(segment, i) { +        if (i == 0) { +          result.push(segment); +        } else { +          var segmentMatch = segment.match(/(\w+)(.*)/); +          var key = segmentMatch[1]; +          result.push(params[key]); +          result.push(segmentMatch[2] || ''); +          delete params[key]; +        } +      }); +      return result.join(''); +    } -}, ['$rootScope', '$location', '$routeParams']); +  }]; +} | 
