Skip to content

Commit

Permalink
feat(justjs): provide naive implementation of most of the coreservice…
Browse files Browse the repository at this point in the history
…s api

refactor(TransitionManager): remove $q .finally() call
refactor(common): simplify fnToString
refactor(urlRouter): provide $stateParams to avoid internally depending on ng1 DI
  • Loading branch information
christopherthielen committed Jan 9, 2016
1 parent f8e5f67 commit 426f134
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 24 deletions.
6 changes: 3 additions & 3 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ module.exports = function (grunt) {
]
},
core: {
entry: files.coreCommonJsEntrypoint,
entry: files.justjsCommonJsEntrypoint,
output: {
path: '<%= builddir %>',
filename: 'ui-router.js',
library: 'ui-router-core',
filename: 'ui-router-justjs.js',
library: 'uiRouter',
libraryTarget: 'umd'
},
module: {
Expand Down
5 changes: 3 additions & 2 deletions files.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
routerFiles = {
ng1CommonJsEntrypoint: ['./build/es5/ng1.js'],
coreCommonJsEntrypoint: ['./build/es5/ui-router.js'],
es6Entrypoint: ['./build/es6/ng1.js'],
justjsCommonJsEntrypoint: ['./build/es5/justjs.js'],
// es6Entrypoint: ['./build/es6/ng1.js'],

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

Expand Down
6 changes: 1 addition & 5 deletions src/common/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,11 +467,7 @@ export function applyPairs(memo: TypedMap<any>, keyValTuple: any[]) {
}

export function fnToString(fn: IInjectable) {
let _fn = pattern([
[isArray, arr => arr.slice(-1)[0]],
[val(true), identity]
])(fn);

let _fn = isArray(fn) ? fn.slice(-1)[0] : fn;
return _fn && _fn.toString() || "undefined";
}

Expand Down
89 changes: 89 additions & 0 deletions src/justjs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/// <reference path="../node_modules/typescript/lib/lib.es6.d.ts"/>

export * from "./ui-router";
import {services} from "./common/coreservices";
import {isDefined, isFunction, isArray, isObject, isInjectable} from "./common/predicates";
import {extend, assertPredicate, forEach} from "./common/common";

/** $q-like promise api */
services.$q = (executor: (resolve, reject) => void) => new Promise(executor);
services.$q.when = (val) => new Promise((resolve, reject) => resolve(val));
services.$q.reject = (val) => new Promise((resolve, reject) => { reject(val); });
services.$q.defer = function() {
let deferred: any = {};
deferred.promise = new Promise((resolve, reject) => {
deferred.resolve = resolve;
deferred.reject = reject;
});

return deferred;
};

services.$q.all = function (promises: { [key: string]: Promise<any> } | Promise<any>[]) {
if (isArray(promises)) {
return new Promise((resolve, reject) => {
let results = [];
promises.reduce((memo, promise) => {
if (!isDefined(memo)) return promise;
return memo.then(val => results.push(val)).then(() => promise);
}).then(() => resolve(results), reject);
});
}

if (isObject(promises)) {
let results = {};
return new Promise((resolve, reject) => {
let chain = services.$q.when();
forEach(promises, (promise: Promise<any>, key: string) => {
promise.then(val => results[key] = val);
chain = chain.then(() => promise);
});
chain.then(resolve, reject);
});
}
};





// angular1-like injector api

// globally available injectables
let globals = { };
services.$injector = { };

services.$injector.get = name => globals[name];
services.$injector.has = (name) => services.$injector.get(name) != null;
services.$injector.invoke = function(fn, context?, locals?) {
let all = extend({}, globals, locals || {});
let params = services.$injector.annotate(fn);
let ensureExist = assertPredicate(key => all.hasOwnProperty(key), key => `DI can't find injectable: '${key}'`);
let args = params.filter(ensureExist).map(x => all[x]);
if (isFunction(fn)) return fn.apply(context, args);
return fn.slice(-1)[0].apply(context, args);
};

let STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
let ARGUMENT_NAMES = /([^\s,]+)/g;
// http://stackoverflow.com/questions/1007981
services.$injector.annotate = function(fn) {
if (!isInjectable(fn)) throw new Error(`Not an injectable function: ${fn}`);
if (fn && fn.$inject) return fn.$inject;
if (isArray(fn)) return fn.slice(0, -1);
let fnStr = fn.toString().replace(STRIP_COMMENTS, '');
let result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
return result || [];
};

let loc = <any> services.location;

loc.hash = () => "";
loc.path = () => location.hash.replace(/^#/, "");
loc.search = () => location.search;
loc.url = (url) => { if (url) location.hash = url; return loc.path(); };
loc.replace = () => { console.log(new Error("not impl")); };
loc.onChange = (cb) => {
window.addEventListener("hashchange", cb, false);
};

6 changes: 3 additions & 3 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ import {StateService} from "./state/stateService";
*/
class Router {

stateParams = stateParamsFactory();

urlMatcherFactory: UrlMatcherFactory = new UrlMatcherFactory();

urlRouterProvider: UrlRouterProvider = new UrlRouterProvider(this.urlMatcherFactory);
urlRouterProvider: UrlRouterProvider = new UrlRouterProvider(this.urlMatcherFactory, this.stateParams);

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

Expand All @@ -32,8 +34,6 @@ class Router {

viewService = new ViewService(this.templateFactory);

stateParams = stateParamsFactory();

stateRegistry: StateRegistry = new StateRegistry(this.urlMatcherFactory, this.urlRouterProvider, () => this.stateService.$current);

// TODO: move this to ng1.ts
Expand Down
10 changes: 7 additions & 3 deletions src/state/hooks/transitionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,14 @@ export class TransitionManager {
runTransition(): IPromise<any> {
this.activeTransQ.clear(); // TODO: nuke this
this.activeTransQ.enqueue(this.transition);
return this.transition.run()
let promise = this.transition.run()
.then((trans: Transition) => trans.to()) // resolve to the final state (TODO: good? bad?)
.catch(error => this.transRejected(error)) // if rejected, handle dynamic and redirect
.finally(() => this.activeTransQ.remove(this.transition));
.catch(error => this.transRejected(error)); // if rejected, handle dynamic and redirect

let always = () => this.activeTransQ.remove(this.transition);
promise.then(always, always);

return promise;

This comment has been minimized.

Copy link
@christopherthielen

christopherthielen Jul 27, 2016

Author Contributor

@elboman
Here I removed .finally for .then(always, always).

}

registerUpdateGlobalState() {
Expand Down
3 changes: 2 additions & 1 deletion src/transition/transition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import {StateDeclaration, StateOrName} from "../state/interface";
import {TransitionOptions, TransitionHookOptions, TreeChanges, IHookRegistry, IHookRegistration, IHookGetter} from "./interface";

import {TransitionHook, HookRegistry, matchState, HookBuilder, RejectFactory} from "./module";
import {Node, PathFactory} from "../path/module";
import {Node} from "../path/node";
import {PathFactory} from "../path/pathFactory";
import {State, TargetState} from "../state/module";
import {Param} from "../params/module";
import {Resolvable} from "../resolve/module";
Expand Down
2 changes: 1 addition & 1 deletion src/transition/transitionHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class TransitionHook {
// Transition is no longer current
[this.isSuperseded, () => REJECT.superseded(this.options.current())],
// If the hook returns false, abort the current Transition
[eq(false), val(REJECT.aborted("Hook aborted transition"))],
[eq(false), () => REJECT.aborted("Hook aborted transition")],
// If the hook returns a Transition, halt the current Transition and redirect to that Transition.
[is(TargetState), (target) => REJECT.redirected(target)],
// A promise was returned, wait for the promise and then chain another hookHandler
Expand Down
1 change: 1 addition & 0 deletions src/ui-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ import * as url from "./url/module";
import * as view from "./view/module";

export { common, params, path, resolve, state, transition, url, view };
export {Router} from "./router";
13 changes: 7 additions & 6 deletions src/url/urlRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {isFunction, isString, isDefined, isArray} from "../common/predicates";
import {UrlMatcher} from "./module";
import {services} from "../common/coreservices";
import {UrlMatcherFactory} from "./urlMatcherFactory";
import {StateParams} from "../params/stateParams";

let $location = services.location;

Expand All @@ -21,9 +22,9 @@ function interpolate(pattern, match) {
});
}

function handleIfMatch($injector, handler, match) {
function handleIfMatch($injector, $stateParams, handler, match) {
if (!match) return false;
let result = $injector.invoke(handler, handler, { $match: match });
let result = $injector.invoke(handler, handler, { $match: match, $stateParams: $stateParams });
return isDefined(result) ? result : true;
}

Expand Down Expand Up @@ -80,7 +81,7 @@ export class UrlRouterProvider {
otherwiseFn: Function = null;
private interceptDeferred = false;

constructor(private $urlMatcherFactory: UrlMatcherFactory) {
constructor(private $urlMatcherFactory: UrlMatcherFactory, private $stateParams: StateParams) {

}

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

// @todo Queue this
Expand All @@ -214,7 +215,7 @@ export class UrlRouterProvider {
_handler = ['$match', redirect.format.bind(redirect)];
}
return extend(function () {
return handleIfMatch(services.$injector, _handler, _what.exec($location.path(), $location.search(), $location.hash()));
return handleIfMatch(services.$injector, $stateParams, _handler, _what.exec($location.path(), $location.search(), $location.hash()));
}, {
prefix: isString(_what.prefix) ? _what.prefix : ''
});
Expand All @@ -227,7 +228,7 @@ export class UrlRouterProvider {
_handler = ['$match', ($match) => interpolate(redirect, $match)];
}
return extend(function () {
return handleIfMatch(services.$injector, _handler, _what.exec($location.path()));
return handleIfMatch(services.$injector, $stateParams, _handler, _what.exec($location.path()));
}, {
prefix: regExpPrefix(_what)
});
Expand Down

0 comments on commit 426f134

Please sign in to comment.