Skip to content

Commit fcb15c5

Browse files
feat(ng2.uiSrefActive): Implement uiSrefStatus, uiSrefActive, uiSrefActiveEq
1 parent 0eb7406 commit fcb15c5

File tree

7 files changed

+135
-62
lines changed

7 files changed

+135
-62
lines changed

src/globals.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export class UIRouterGlobals {
6363

6464
const clearCurrentTransition = () => { if (this.transition === $transition$) this.transition = null; };
6565

66-
$transition$.promise.finally(clearCurrentTransition)
66+
$transition$.promise.then(clearCurrentTransition, clearCurrentTransition);
6767

6868
};
6969

src/ng2/directives.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
21
import {UiSref} from "../ng2/uiSref";
3-
import {UiSrefClass} from "../ng2/uiSrefActive";
2+
import {UiSrefActive} from "../ng2/uiSrefActive";
43
import {UiView} from "../ng2/uiView";
4+
import {UiSrefStatus} from "./uiSrefStatus";
5+
6+
export * from "./uiView";
57
export * from "./uiSref";
8+
export * from "./uiSrefStatus";
69
export * from "./uiSrefActive";
7-
export * from "./uiView";
810

9-
export let UIROUTER_DIRECTIVES = [UiSref, UiSrefClass, UiView];
11+
export let UIROUTER_DIRECTIVES = [UiSref, UiView, UiSrefActive, UiSrefStatus];

src/ng2/providers.ts

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {UiView} from "./uiView";
1111
import {ng2ViewsBuilder, Ng2ViewConfig} from "./viewsBuilder";
1212
import {Ng2ViewDeclaration} from "./interface";
1313
import {UIRouterConfig} from "./uiRouterConfig";
14+
import {UIRouterGlobals} from "../globals";
1415

1516
let uiRouterFactory = (routerConfig: UIRouterConfig) => {
1617
let router = new UIRouter();
@@ -46,6 +47,8 @@ export const UIROUTER_PROVIDERS: Provider[] = [
4647

4748
provide(StateRegistry, { useFactory: (r: UIRouter) => { return r.stateRegistry; }, deps: [UIRouter]}),
4849

50+
provide(UIRouterGlobals, { useFactory: (r: UIRouter) => { return r.globals; }, deps: [UIRouter]}),
51+
4952
provide(UiView.INJECT.context, { useFactory: (r: StateRegistry) => { console.log(r); return r.root(); }, deps: [StateRegistry]} ),
5053

5154
provide(UiView.INJECT.fqn, { useValue: null })

src/ng2/uiSref.ts

-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ export class UiSref {
2929
@Optional() private _anchorUiSref: AnchorUiSref
3030
) { }
3131

32-
set "ui-sref"(val) { this.state = val; this.update(); }
3332
set "uiSref"(val) { this.state = val; this.update(); }
3433
set "uiParams"(val) { this.params = val; this.update(); }
3534
set "uiOptions"(val) { this.options = val; this.update(); }
@@ -42,7 +41,6 @@ export class UiSref {
4241
if (this._anchorUiSref) {
4342
this._anchorUiSref.update(this._router.stateService.href(this.state, this.params));
4443
}
45-
// TODO: process ui-sref-active
4644
}
4745

4846
go() {

src/ng2/uiSrefActive.ts

+13-45
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,20 @@
1-
/** @module ng2 */ /** */
2-
import {UIRouter} from "../router";
3-
import {Directive} from "angular2/core";
4-
import {UiSref} from "./uiSref";
51

6-
@Directive({
7-
selector: '[uiSrefClass]',
8-
inputs: ['uiSrefClass']
9-
})
10-
export class UiSrefClass {
11-
// current statuses of the bound uiSref directive
12-
active = false;
13-
exact = false;
14-
entering = false;
15-
exiting = false;
16-
inactive = true;
2+
import {Directive, Input, ElementRef, Host, Renderer} from "angular2/core";
3+
import {UiSrefStatus, SrefStatus} from "./uiSrefStatus";
174

18-
patterns: any;
19-
classes: string;
20-
sref: UiSref;
5+
@Directive({ selector: '[uiSrefActive],[uiSrefActiveEq]' })
6+
export class UiSrefActive {
7+
private _classes: string[] = [];
8+
@Input('uiSrefActive') set active(val) { this._classes = val.split("\s+")};
219

22-
//constructor($transitions: TransitionService, public router: UIRouter) {
23-
constructor(public router: UIRouter) {
24-
this.ngOnDestroy = <any> router.transitionService.onSuccess({}, this._update.bind(this));
25-
}
26-
27-
ngOnDestroy() {}
28-
29-
/**
30-
* e.g.
31-
* {
32-
* active: 'active && !exiting',
33-
* loading: 'entering',
34-
* active: matches('admin.*')
35-
* }
36-
*/
37-
set uiSrefClass(val) {
38-
console.log(val); // [uiSrefClass]="{active: isActive}" logs as "{active: undefined}"
39-
this.patterns = val;
40-
}
41-
42-
public provideUiSref(sref: UiSref) {
43-
this.sref = sref;
44-
this._update();
45-
}
10+
private _classesEq: string[] = [];
11+
@Input('uiSrefActiveEq') set activeEq(val) { this._classesEq = val.split("\s+")};
4612

47-
private _update() {
48-
if (!this.sref) return;
49-
// update classes
13+
constructor(uiSrefStatus: UiSrefStatus, rnd: Renderer, @Host() host: ElementRef) {
14+
uiSrefStatus.uiSrefStatus.subscribe((next: SrefStatus) => {
15+
this._classes.forEach(cls => rnd.setElementClass(host.nativeElement, cls, next.active));
16+
this._classesEq.forEach(cls => rnd.setElementClass(host.nativeElement, cls, next.exact));
17+
});
5018
}
5119
}
5220

src/ng2/uiSrefStatus.ts

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import {Directive, Output, EventEmitter} from "angular2/core";
2+
import {StateService} from "../state/stateService";
3+
import {UiSref} from "./uiSref";
4+
import {UIRouter} from "../router";
5+
import {Node} from "../path/node";
6+
import {TransitionService} from "../transition/transitionService";
7+
import {Transition} from "../transition/transition";
8+
import {TargetState} from "../state/targetState";
9+
import {TreeChanges} from "../transition/interface";
10+
import {State} from "../state/stateObject";
11+
import {anyTrueR, tail} from "../common/common";
12+
import {UIRouterGlobals} from "../globals";
13+
14+
export interface SrefStatus {
15+
active: boolean;
16+
exact: boolean;
17+
entering: boolean;
18+
exiting: boolean;
19+
}
20+
21+
/**
22+
* Emits events when the uiSref status changes
23+
*
24+
* This API is subject to change.
25+
*/
26+
@Directive({ selector: '[uiSrefStatus],[uiSrefActive],[uiSrefActiveEq]' })
27+
export class UiSrefStatus {
28+
private _deregisterHook;
29+
30+
// current statuses of the state/params the uiSref directive is linking to
31+
@Output("uiSrefStatus") uiSrefStatus = new EventEmitter<SrefStatus>();
32+
33+
status: SrefStatus = {
34+
active: false,
35+
exact: false,
36+
entering: false,
37+
exiting: false
38+
};
39+
40+
constructor(transitionService: TransitionService,
41+
private _globals: UIRouterGlobals,
42+
private _stateService: StateService,
43+
public sref: UiSref) {
44+
this._deregisterHook = transitionService.onStart({}, ($transition$) => this._transition($transition$));
45+
}
46+
47+
ngOnInit() {
48+
let lastTrans = this._globals.transitionHistory.peekTail();
49+
if (lastTrans != null) {
50+
this._transition(lastTrans);
51+
}
52+
}
53+
54+
ngOnDestroy() {
55+
this._deregisterHook()
56+
}
57+
58+
private _setStatus(status: SrefStatus) {
59+
this.status = status;
60+
this.uiSrefStatus.emit(status);
61+
}
62+
63+
private _transition($transition$: Transition) {
64+
let sref = this.sref;
65+
66+
let status: SrefStatus = <any> {
67+
active: false,
68+
exact: false,
69+
entering: false,
70+
exiting: false
71+
};
72+
73+
let srefTarget: TargetState = this._stateService.target(sref.state, sref.params, sref.options);
74+
if (!srefTarget.exists()) {
75+
return this._setStatus(status);
76+
}
77+
78+
let tc: TreeChanges = $transition$.treeChanges();
79+
let state: State = srefTarget.$state();
80+
const isTarget = (node: Node) => node.state === state;
81+
82+
status.active = tc.from.map(isTarget).reduce(anyTrueR, false);
83+
status.exact = tail(tc.from.map(isTarget)) === true;
84+
status.entering = tc.entering.map(isTarget).reduce(anyTrueR, false);
85+
status.exiting = tc.exiting.map(isTarget).reduce(anyTrueR, false);
86+
87+
if ($transition$.isActive()) {
88+
this._setStatus(status);
89+
}
90+
91+
let update = (currentPath: Node[]) => () => {
92+
if (!$transition$.isActive()) return; // superseded
93+
status.active = currentPath.map(isTarget).reduce(anyTrueR, false);
94+
status.exact = tail(currentPath.map(isTarget)) === true;
95+
status.entering = status.exiting = false;
96+
this._setStatus(status);
97+
};
98+
99+
$transition$.promise.then(update(tc.to), update(tc.from));
100+
}
101+
}

src/ng2/uiView.ts

+11-10
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,17 @@ const getProviders = (injector) => {
3030
color: grey;
3131
}`
3232
],
33-
template: `
34-
<div style="padding: 1em; border: 1px solid lightgrey;">
35-
36-
<div #content style="color: lightgrey; font-size: smaller;">
37-
<div>ui-view #{{uiViewData.id}} created by '{{ parentContext.name || "(root)" }}' state</div>
38-
<div>name: (absolute) '{{uiViewData.fqn}}' (contextual) '{{uiViewData.name}}@{{parentContext.name}}' </div>
39-
<div>currently filled by: '{{(uiViewData.config && uiViewData.config.context) || 'empty...'}}'</div>
40-
</div>
41-
42-
</div>`
33+
template: `<div #content></div>`,
34+
// debugtemplate: `
35+
// <div style="padding: 1em; border: 1px solid lightgrey;">
36+
//
37+
// <div #content style="color: lightgrey; font-size: smaller;">
38+
// <div>ui-view #{{uiViewData.id}} created by '{{ parentContext.name || "(root)" }}' state</div>
39+
// <div>name: (absolute) '{{uiViewData.fqn}}' (contextual) '{{uiViewData.name}}@{{parentContext.name}}' </div>
40+
// <div>currently filled by: '{{(uiViewData.config && uiViewData.config.context) || 'empty...'}}'</div>
41+
// </div>
42+
//
43+
// </div>`
4344
})
4445
export class UiView {
4546
@Input() name: string;

0 commit comments

Comments
 (0)