Skip to content

Commit

Permalink
feat(plugin): Create plugin API
Browse files Browse the repository at this point in the history
Closes #7
  • Loading branch information
christopherthielen committed Nov 29, 2016
1 parent 5c5f7eb commit 36a5215
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

// Need to import or export at least one concrete something
import {noop} from "./common/common";
import {UIRouter} from "./router";

/**
* An interface for getting values from dependency injection.
Expand Down Expand Up @@ -81,3 +82,7 @@ export interface UIInjector {
getNative(token: any): any;
getNative<T>(token: any): T;
}

export abstract class UIRouterPlugin {
abstract name(): string;
}
63 changes: 62 additions & 1 deletion src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {ViewService} from "./view/view";
import {StateRegistry} from "./state/stateRegistry";
import {StateService} from "./state/stateService";
import {UIRouterGlobals, Globals} from "./globals";
import {UIRouterPlugin} from "./interface";

/**
* The master class used to instantiate an instance of UI-Router.
Expand Down Expand Up @@ -41,5 +42,65 @@ export class UIRouter {
this.globals.$current = this.stateRegistry.root();
this.globals.current = this.globals.$current.self;
}
}

private _plugins: { [key: string]: UIRouterPlugin } = {};

/**
* Adds a plugin to UI-Router
*
* This method adds a UI-Router Plugin.
* A plugin can enhance or change UI-Router behavior using any public API.
*
* #### Example:
* ```js
* import { MyCoolPlugin } from "ui-router-cool-plugin";
*
* var plugin = router.addPlugin(MyCoolPlugin);
* ```
*
* ### Plugin authoring
*
* A plugin is simply a class (or constructor function) which accepts a [[UIRouter]] instance and (optionally) an options object.
*
* The plugin can implement its functionality using any of the public APIs of [[UIRouter]].
* For example, it may configure router options or add a Transition Hook.
*
* The plugin can then be published as a separate module.
*
* #### Example:
* ```js
* export class MyAuthPlugin {
* constructor(router: UIRouter, options: any) {
* let $transitions = router.transitionService;
* let $state = router.stateService;
*
* let authCriteria = {
* to: (state) => state.data && state.data.requiresAuth
* };
*
* function authHook(transition: Transition) {
* let authService = transition.injector().get('AuthService');
* if (!authService.isAuthenticated()) {
* return $state.target('login');
* }
* }
*
* $transitions.onStart(authCriteria, authHook);
* }
* }
* ```
*
* @param PluginClass a UI-Router Plugin class (or constructor function).
* @param options options to pass to the plugin
* @returns {T}
*/
addPlugin<T extends UIRouterPlugin>(PluginClass: { new(router: UIRouter, options?: any): T }, options: any = {}): T {
let pluginInstance = new PluginClass(this, options);
var pluginName = pluginInstance.name();
return this._plugins[pluginName] = pluginInstance;
}

getPlugin(pluginName: string): UIRouterPlugin {
return this._plugins[pluginName];
}
}
63 changes: 63 additions & 0 deletions test/pluginSpec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { UIRouter, TransitionService, StateService } from "../src/index";
import "../src/justjs";
import { StateRegistry } from "../src/state/stateRegistry";
import { UrlRouter } from "../src/url/urlRouter";
import {UIRouterPlugin} from "../src/interface";

describe('plugin api', function () {
let router: UIRouter;
let $registry: StateRegistry;
let $transitions: TransitionService;
let $state: StateService;
let $urlRouter: UrlRouter;

beforeEach(() => {
router = new UIRouter();
$registry = router.stateRegistry;
$state = router.stateService;
$transitions = router.transitionService;
$urlRouter = router.urlRouter;
router.stateRegistry.stateQueue.autoFlush($state);
});

class FancyPlugin extends UIRouterPlugin {
constructor(public router: UIRouter) {
super();

}
name() { return "fancyplugin" }
}

describe('initialization', () => {
it('should return an instance of the plugin', () => {
let plugin = router.addPlugin(FancyPlugin);
expect(plugin instanceof FancyPlugin).toBeTruthy();
});

it('should pass the router instance to the plugin constructor', () => {
let pluginRouterInstance = undefined;
function Plugin(router) {
pluginRouterInstance = router;
this.name = () => "plugin";
}

router.addPlugin(<any> Plugin);
expect(pluginRouterInstance).toBe(router);
});

it('should throw if the plugin constructor returns an object without name() getter', () => {
function Plugin(router) {
}

expect(() => router.addPlugin(<any> Plugin)).toThrow()
});
});

describe('getPlugin', () => {
it('should return the plugin instance', () => {
router.addPlugin(FancyPlugin);
let plugin = router.getPlugin('fancyplugin');
expect(plugin instanceof FancyPlugin).toBeTruthy();
});
})
});

0 comments on commit 36a5215

Please sign in to comment.