Skip to content

Commit 426f134

Browse files
feat(justjs): provide naive implementation of most of the coreservices api
refactor(TransitionManager): remove $q .finally() call refactor(common): simplify fnToString refactor(urlRouter): provide $stateParams to avoid internally depending on ng1 DI
1 parent f8e5f67 commit 426f134

File tree

10 files changed

+117
-24
lines changed

10 files changed

+117
-24
lines changed

Gruntfile.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ module.exports = function (grunt) {
6868
]
6969
},
7070
core: {
71-
entry: files.coreCommonJsEntrypoint,
71+
entry: files.justjsCommonJsEntrypoint,
7272
output: {
7373
path: '<%= builddir %>',
74-
filename: 'ui-router.js',
75-
library: 'ui-router-core',
74+
filename: 'ui-router-justjs.js',
75+
library: 'uiRouter',
7676
libraryTarget: 'umd'
7777
},
7878
module: {

files.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
routerFiles = {
22
ng1CommonJsEntrypoint: ['./build/es5/ng1.js'],
3-
coreCommonJsEntrypoint: ['./build/es5/ui-router.js'],
4-
es6Entrypoint: ['./build/es6/ng1.js'],
3+
justjsCommonJsEntrypoint: ['./build/es5/justjs.js'],
4+
// es6Entrypoint: ['./build/es6/ng1.js'],
55

66
src: [
77
'src/ui-router.ts', // Main UI-Router module (re-exports all other core modules)
88
'src/ng1.ts', // UI-Router angular1 module (re-exports ui-router and ng1 modules)
9+
'src/justjs.ts', // UI-Router plain ol js module (re-exports ui-router)
910
'src/ng1/stateEvents.ts' // There might be a better approach to compiling this file
1011
],
1112

src/common/common.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -467,11 +467,7 @@ export function applyPairs(memo: TypedMap<any>, keyValTuple: any[]) {
467467
}
468468

469469
export function fnToString(fn: IInjectable) {
470-
let _fn = pattern([
471-
[isArray, arr => arr.slice(-1)[0]],
472-
[val(true), identity]
473-
])(fn);
474-
470+
let _fn = isArray(fn) ? fn.slice(-1)[0] : fn;
475471
return _fn && _fn.toString() || "undefined";
476472
}
477473

src/justjs.ts

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/// <reference path="../node_modules/typescript/lib/lib.es6.d.ts"/>
2+
3+
export * from "./ui-router";
4+
import {services} from "./common/coreservices";
5+
import {isDefined, isFunction, isArray, isObject, isInjectable} from "./common/predicates";
6+
import {extend, assertPredicate, forEach} from "./common/common";
7+
8+
/** $q-like promise api */
9+
services.$q = (executor: (resolve, reject) => void) => new Promise(executor);
10+
services.$q.when = (val) => new Promise((resolve, reject) => resolve(val));
11+
services.$q.reject = (val) => new Promise((resolve, reject) => { reject(val); });
12+
services.$q.defer = function() {
13+
let deferred: any = {};
14+
deferred.promise = new Promise((resolve, reject) => {
15+
deferred.resolve = resolve;
16+
deferred.reject = reject;
17+
});
18+
19+
return deferred;
20+
};
21+
22+
services.$q.all = function (promises: { [key: string]: Promise<any> } | Promise<any>[]) {
23+
if (isArray(promises)) {
24+
return new Promise((resolve, reject) => {
25+
let results = [];
26+
promises.reduce((memo, promise) => {
27+
if (!isDefined(memo)) return promise;
28+
return memo.then(val => results.push(val)).then(() => promise);
29+
}).then(() => resolve(results), reject);
30+
});
31+
}
32+
33+
if (isObject(promises)) {
34+
let results = {};
35+
return new Promise((resolve, reject) => {
36+
let chain = services.$q.when();
37+
forEach(promises, (promise: Promise<any>, key: string) => {
38+
promise.then(val => results[key] = val);
39+
chain = chain.then(() => promise);
40+
});
41+
chain.then(resolve, reject);
42+
});
43+
}
44+
};
45+
46+
47+
48+
49+
50+
// angular1-like injector api
51+
52+
// globally available injectables
53+
let globals = { };
54+
services.$injector = { };
55+
56+
services.$injector.get = name => globals[name];
57+
services.$injector.has = (name) => services.$injector.get(name) != null;
58+
services.$injector.invoke = function(fn, context?, locals?) {
59+
let all = extend({}, globals, locals || {});
60+
let params = services.$injector.annotate(fn);
61+
let ensureExist = assertPredicate(key => all.hasOwnProperty(key), key => `DI can't find injectable: '${key}'`);
62+
let args = params.filter(ensureExist).map(x => all[x]);
63+
if (isFunction(fn)) return fn.apply(context, args);
64+
return fn.slice(-1)[0].apply(context, args);
65+
};
66+
67+
let STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
68+
let ARGUMENT_NAMES = /([^\s,]+)/g;
69+
// http://stackoverflow.com/questions/1007981
70+
services.$injector.annotate = function(fn) {
71+
if (!isInjectable(fn)) throw new Error(`Not an injectable function: ${fn}`);
72+
if (fn && fn.$inject) return fn.$inject;
73+
if (isArray(fn)) return fn.slice(0, -1);
74+
let fnStr = fn.toString().replace(STRIP_COMMENTS, '');
75+
let result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
76+
return result || [];
77+
};
78+
79+
let loc = <any> services.location;
80+
81+
loc.hash = () => "";
82+
loc.path = () => location.hash.replace(/^#/, "");
83+
loc.search = () => location.search;
84+
loc.url = (url) => { if (url) location.hash = url; return loc.path(); };
85+
loc.replace = () => { console.log(new Error("not impl")); };
86+
loc.onChange = (cb) => {
87+
window.addEventListener("hashchange", cb, false);
88+
};
89+

src/router.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ import {StateService} from "./state/stateService";
2020
*/
2121
class Router {
2222

23+
stateParams = stateParamsFactory();
24+
2325
urlMatcherFactory: UrlMatcherFactory = new UrlMatcherFactory();
2426

25-
urlRouterProvider: UrlRouterProvider = new UrlRouterProvider(this.urlMatcherFactory);
27+
urlRouterProvider: UrlRouterProvider = new UrlRouterProvider(this.urlMatcherFactory, this.stateParams);
2628

2729
urlRouter: UrlRouter = new UrlRouter(this.urlRouterProvider);
2830

@@ -32,8 +34,6 @@ class Router {
3234

3335
viewService = new ViewService(this.templateFactory);
3436

35-
stateParams = stateParamsFactory();
36-
3737
stateRegistry: StateRegistry = new StateRegistry(this.urlMatcherFactory, this.urlRouterProvider, () => this.stateService.$current);
3838

3939
// TODO: move this to ng1.ts

src/state/hooks/transitionManager.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,14 @@ export class TransitionManager {
6464
runTransition(): IPromise<any> {
6565
this.activeTransQ.clear(); // TODO: nuke this
6666
this.activeTransQ.enqueue(this.transition);
67-
return this.transition.run()
67+
let promise = this.transition.run()
6868
.then((trans: Transition) => trans.to()) // resolve to the final state (TODO: good? bad?)
69-
.catch(error => this.transRejected(error)) // if rejected, handle dynamic and redirect
70-
.finally(() => this.activeTransQ.remove(this.transition));
69+
.catch(error => this.transRejected(error)); // if rejected, handle dynamic and redirect
70+
71+
let always = () => this.activeTransQ.remove(this.transition);
72+
promise.then(always, always);
73+
74+
return promise;
7175
}
7276

7377
registerUpdateGlobalState() {

src/transition/transition.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import {StateDeclaration, StateOrName} from "../state/interface";
1414
import {TransitionOptions, TransitionHookOptions, TreeChanges, IHookRegistry, IHookRegistration, IHookGetter} from "./interface";
1515

1616
import {TransitionHook, HookRegistry, matchState, HookBuilder, RejectFactory} from "./module";
17-
import {Node, PathFactory} from "../path/module";
17+
import {Node} from "../path/node";
18+
import {PathFactory} from "../path/pathFactory";
1819
import {State, TargetState} from "../state/module";
1920
import {Param} from "../params/module";
2021
import {Resolvable} from "../resolve/module";

src/transition/transitionHook.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class TransitionHook {
4040
// Transition is no longer current
4141
[this.isSuperseded, () => REJECT.superseded(this.options.current())],
4242
// If the hook returns false, abort the current Transition
43-
[eq(false), val(REJECT.aborted("Hook aborted transition"))],
43+
[eq(false), () => REJECT.aborted("Hook aborted transition")],
4444
// If the hook returns a Transition, halt the current Transition and redirect to that Transition.
4545
[is(TargetState), (target) => REJECT.redirected(target)],
4646
// A promise was returned, wait for the promise and then chain another hookHandler

src/ui-router.ts

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ import * as url from "./url/module";
88
import * as view from "./view/module";
99

1010
export { common, params, path, resolve, state, transition, url, view };
11+
export {Router} from "./router";

src/url/urlRouter.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {isFunction, isString, isDefined, isArray} from "../common/predicates";
55
import {UrlMatcher} from "./module";
66
import {services} from "../common/coreservices";
77
import {UrlMatcherFactory} from "./urlMatcherFactory";
8+
import {StateParams} from "../params/stateParams";
89

910
let $location = services.location;
1011

@@ -21,9 +22,9 @@ function interpolate(pattern, match) {
2122
});
2223
}
2324

24-
function handleIfMatch($injector, handler, match) {
25+
function handleIfMatch($injector, $stateParams, handler, match) {
2526
if (!match) return false;
26-
let result = $injector.invoke(handler, handler, { $match: match });
27+
let result = $injector.invoke(handler, handler, { $match: match, $stateParams: $stateParams });
2728
return isDefined(result) ? result : true;
2829
}
2930

@@ -80,7 +81,7 @@ export class UrlRouterProvider {
8081
otherwiseFn: Function = null;
8182
private interceptDeferred = false;
8283

83-
constructor(private $urlMatcherFactory: UrlMatcherFactory) {
84+
constructor(private $urlMatcherFactory: UrlMatcherFactory, private $stateParams: StateParams) {
8485

8586
}
8687

@@ -198,7 +199,7 @@ export class UrlRouterProvider {
198199
* @param {string|function} handler The path you want to redirect your user to.
199200
*/
200201
when(what, handler) {
201-
let {$urlMatcherFactory} = this;
202+
let {$urlMatcherFactory, $stateParams} = this;
202203
let redirect, handlerIsString = isString(handler);
203204

204205
// @todo Queue this
@@ -214,7 +215,7 @@ export class UrlRouterProvider {
214215
_handler = ['$match', redirect.format.bind(redirect)];
215216
}
216217
return extend(function () {
217-
return handleIfMatch(services.$injector, _handler, _what.exec($location.path(), $location.search(), $location.hash()));
218+
return handleIfMatch(services.$injector, $stateParams, _handler, _what.exec($location.path(), $location.search(), $location.hash()));
218219
}, {
219220
prefix: isString(_what.prefix) ? _what.prefix : ''
220221
});
@@ -227,7 +228,7 @@ export class UrlRouterProvider {
227228
_handler = ['$match', ($match) => interpolate(redirect, $match)];
228229
}
229230
return extend(function () {
230-
return handleIfMatch(services.$injector, _handler, _what.exec($location.path()));
231+
return handleIfMatch(services.$injector, $stateParams, _handler, _what.exec($location.path()));
231232
}, {
232233
prefix: regExpPrefix(_what)
233234
});

0 commit comments

Comments
 (0)