Skip to content

Commit

Permalink
feat(urlRouter): Allow a rule to be deleted.
Browse files Browse the repository at this point in the history
feat(urlRouter): Provide the new `rule` created by `.when()` to a callback fn
test(urlRouter): convert to typescript
  • Loading branch information
christopherthielen committed Aug 31, 2016
1 parent a94117d commit 55f3d3d
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 29 deletions.
2 changes: 2 additions & 0 deletions src/state/stateObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export class State {
public resolvables: Resolvable[];
public resolvePolicy: any;
public url: UrlMatcher;
/** @hidden temporary place to put the rule registered with $urlRouter.when() */
public _urlRule: any;
public params: { [key: string]: Param };
public views: { [key: string]: _ViewDeclaration; };
public self: StateDeclaration;
Expand Down
2 changes: 1 addition & 1 deletion src/state/stateQueueManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,6 @@ export class StateQueueManager {
if ($state.$current.navigable !== state || !equalForKeys($match, $stateParams)) {
$state.transitionTo(state, $match, { inherit: true, location: false, source: "url" });
}
}]);
}], (rule) => state._urlRule = rule);
}
}
4 changes: 2 additions & 2 deletions src/state/stateRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class StateRegistry {

listeners: StateRegistryListener[] = [];

constructor(urlMatcherFactory: UrlMatcherFactory, urlRouterProvider: UrlRouterProvider) {
constructor(urlMatcherFactory: UrlMatcherFactory, private urlRouterProvider: UrlRouterProvider) {
this.matcher = new StateMatcher(this.states);
this.builder = new StateBuilder(this.matcher, urlMatcherFactory);
this.stateQueue = new StateQueueManager(this.states, this.builder, urlRouterProvider, this.listeners);
Expand Down Expand Up @@ -130,7 +130,7 @@ export class StateRegistry {
let deregistered = [state].concat(children).reverse();

deregistered.forEach(state => {
state.url && state.url.config.$$removeRule();
this.urlRouterProvider.removeRule(state._urlRule);
delete this.states[state.name];
});

Expand Down
10 changes: 4 additions & 6 deletions src/url/urlMatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,11 @@ export class UrlMatcher {

/**
* @param pattern The pattern to compile into a matcher.
* @param config A configuration object hash
* * `caseInsensitive` - `true` if URL matching should be case insensitive, otherwise `false`, the default value (for backward compatibility) is `false`.
* * `strict` - `false` if matching against a URL with a trailing slash should be treated as equivalent to a URL without a trailing slash, the default value is `true`.
*
* @property {string} pattern The pattern that was passed into the constructor
* @param config A configuration object
* - `caseInsensitive` - `true` if URL matching should be case insensitive, otherwise `false`, the default value (for backward compatibility) is `false`.
* - `strict` - `false` if matching against a URL with a trailing slash should be treated as equivalent to a URL without a trailing slash, the default value is `true`.
*/
constructor(pattern: string, public config: any) {
constructor(pattern: string, public config?: any) {
this.pattern = pattern;
this.config = defaults(this.config, {
params: {},
Expand Down
24 changes: 12 additions & 12 deletions src/url/urlRouter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @module url */ /** for typedoc */
import {extend, bindFunctions, IInjectable} from "../common/common";
import {extend, bindFunctions, IInjectable, removeFrom} from "../common/common";
import {isFunction, isString, isDefined, isArray} from "../common/predicates";
import {UrlMatcher} from "./urlMatcher";
import {services, $InjectorLike, LocationServices} from "../common/coreservices";
Expand Down Expand Up @@ -125,13 +125,14 @@ export class UrlRouterProvider {
return this;
};

/** @hidden */
private $$removeRule(rule) {
let idx = this.rules.indexOf(rule);
if (idx !== -1) {
this.rules.splice(idx, 1);
}
return (idx !== -1);
/**
* Remove a rule previously registered
*
* @param rule the matcher rule that was previously registered using [[rule]]
* @return true if the rule was found (and removed)
*/
removeRule(rule): boolean {
return this.rules.length !== removeFrom(this.rules, rule).length;
}

/**
Expand Down Expand Up @@ -202,10 +203,11 @@ export class UrlRouterProvider {
*
* @param what A pattern string to match, compiled as a [[UrlMatcher]].
* @param handler The path (or function that returns a path) that you want to redirect your user to.
* @param ruleCallback [optional] A callback that receives the `rule` registered with [[UrlMatcher.rule]]
*
* Note: the handler may also invoke arbitrary code, such as `$state.go()`
*/
when(what: (RegExp|UrlMatcher|string), handler: string|IInjectable) {
when(what: (RegExp|UrlMatcher|string), handler: string|IInjectable, ruleCallback = function(rule) {}) {
let {$urlMatcherFactory, $stateParams} = this;
let redirect, handlerIsString = isString(handler);

Expand Down Expand Up @@ -250,9 +252,7 @@ export class UrlRouterProvider {
for (var n in check) {
if (check[n]) {
let rule = strategies[n](what, handler);
if (check.matcher && what['config']) {
what['config'].$$removeRule = () => this.$$removeRule(rule);
}
ruleCallback(rule);
return this.rule(rule);
}
}
Expand Down
48 changes: 40 additions & 8 deletions test/ng1/urlRouterSpec.js → test/ng1/urlRouterSpec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import ILocationService = angular.ILocationService;
declare var html5Compat;
import {UrlMatcher, services, UrlRouterProvider, UrlRouter, StateService} from "../../src/ng1";
import ILocationProvider = angular.ILocationProvider;

var module = angular.mock.module;
var uiRouter = require("angular-ui-router");
var UrlMatcher = uiRouter.UrlMatcher;
var services = uiRouter.services;

describe("UrlRouter", function () {

var $urp, $lp, $s, $ur, location, match, scope;
var $urp: UrlRouterProvider, $lp: ILocationProvider,
$s: StateService, $ur: UrlRouter, location: ILocationService, match, scope;

describe("provider", function () {

Expand All @@ -20,7 +23,7 @@ describe("UrlRouter", function () {
inject(function($rootScope, $location, $injector) {
scope = $rootScope.$new();
location = $location;
$ur = $injector.invoke($urp.$get, $urp);
$ur = $injector.invoke($urp['$get'], $urp);
});
});

Expand Down Expand Up @@ -71,9 +74,9 @@ describe("UrlRouter", function () {
inject(function($rootScope, $location, $injector) {
scope = $rootScope.$new();
location = $location;
$ur = $injector.invoke($urp.$get, $urp);
$ur = $injector.invoke($urp['$get'], $urp);
$s = $injector.get('$sniffer');
$s.history = true;
$s['history'] = true;
});
});

Expand Down Expand Up @@ -155,6 +158,35 @@ describe("UrlRouter", function () {
expect(called).toBeTruthy();
expect(location.path()).toBe("/b4z");
}));


it('removeRule should remove a previously registered rule', function() {
var count = 0, rule = function ($injector, $location) { count++; };
$urp.rule(rule);

$ur.sync();
expect(count).toBe(1);
$ur.sync();
expect(count).toBe(2);

$urp.removeRule(rule);
$ur.sync();
expect(count).toBe(2);
});

it('when should provide the new rule to the callback argument', function() {
var _rule, calls = 0;
location.url('/foo');
$urp.when('/foo', function() { calls++; }, function(rule) { _rule = rule; });
expect(typeof _rule).toBe('function');

$ur.sync();
expect(calls).toBe(1);

$urp.removeRule(_rule);
$ur.sync();
expect(calls).toBe(1);
});

describe("location updates", function() {
it('can push location changes', inject(function($urlRouter) {
Expand Down Expand Up @@ -248,7 +280,7 @@ describe("UrlRouter", function () {

it('should return URLs with #fragments when html5Mode is true & browser does not support pushState', inject(function($urlRouter) {
$lp.html5Mode(true);
$s.history = false;
$s['history'] = false;
expect(html5Compat($lp.html5Mode())).toBe(true);
expect($urlRouter.href(new UrlMatcher('/hello/:name'), {name: 'world', '#': 'frag'})).toBe('#/hello/world#frag');
}));
Expand Down

0 comments on commit 55f3d3d

Please sign in to comment.