@angular-wave/angular.ts 0.0.28 → 0.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular-ts.esm.js +1 -1
- package/dist/angular-ts.umd.js +1 -1
- package/index.html +2 -2
- package/package.json +1 -1
- package/src/core/controller.js +3 -0
- package/src/directive/controller.js +0 -56
- package/src/directive/controller.md +46 -0
- package/src/router/common/trace.js +7 -7
- package/src/router/directives/state-directives.js +75 -75
- package/src/router/directives/view-directive.js +21 -21
- package/src/router/hooks/update-globals.js +1 -1
- package/src/router/index.js +12 -12
- package/src/router/injectables.js +11 -11
- package/src/router/resolve/resolve-context.js +1 -1
- package/src/router/router.js +8 -77
- package/src/router/services.js +5 -43
- package/src/router/state/state-builder.js +1 -0
- package/src/router/state/state-object.js +1 -1
- package/src/router/state/state-registry.js +56 -3
- package/src/router/state/state-service.js +16 -25
- package/src/router/state/target-state.js +1 -1
- package/src/router/state/views.js +5 -5
- package/src/router/state-filters.js +0 -2
- package/src/router/state-provider.js +0 -2
- package/src/router/template-factory.js +4 -4
- package/src/router/transition/transition-service.js +2 -3
- package/src/router/url/url-config.js +0 -2
- package/src/router/url/url-matcher-factory.js +0 -1
- package/src/router/url/url-matcher.js +0 -8
- package/src/router/url/url-router.js +4 -0
- package/src/router/url/url-service.js +6 -6
- package/src/router/view/view.js +67 -65
- package/src/services/browser.js +1 -5
- package/src/shared/common.js +1 -1
- package/test/core/pubsub.spec.js +73 -0
- package/test/module-test.html +5 -5
- package/test/original-test.html +3 -3
- package/test/router/services.spec.js +1 -1
- package/test/router/state-directives.spec.js +72 -80
- package/test/router/state-filter.spec.js +6 -4
- package/test/router/state.spec.js +15 -13
- package/test/router/template-factory.spec.js +4 -4
- package/test/router/url-matcher-factory.spec.js +2 -2
- package/test/router/view-directive.spec.js +165 -163
- package/test/router/view-hook.spec.js +2 -2
- package/test/router/view-scroll.spec.js +14 -14
- package/test/router/view.spec.js +2 -2
- package/types/router/core/common/coreservices.d.ts +2 -2
- package/types/router/core/common/trace.d.ts +7 -7
- package/types/router/core/globals.d.ts +2 -1
- package/types/router/core/interface.d.ts +3 -10
- package/types/router/core/params/interface.d.ts +3 -3
- package/types/router/core/resolve/resolveContext.d.ts +4 -4
- package/types/router/core/router.d.ts +5 -51
- package/types/router/core/state/interface.d.ts +12 -12
- package/types/router/core/state/stateObject.d.ts +1 -1
- package/types/router/core/state/stateQueueManager.d.ts +2 -2
- package/types/router/core/state/stateRegistry.d.ts +5 -4
- package/types/router/core/state/stateService.d.ts +13 -13
- package/types/router/core/state/targetState.d.ts +1 -1
- package/types/router/core/transition/interface.d.ts +2 -2
- package/types/router/core/transition/transition.d.ts +12 -12
- package/types/router/core/transition/transitionService.d.ts +5 -5
- package/types/router/core/url/interface.d.ts +3 -3
- package/types/router/core/url/urlConfig.d.ts +3 -3
- package/types/router/core/url/urlMatcherFactory.d.ts +3 -3
- package/types/router/core/url/urlRouter.d.ts +2 -2
- package/types/router/core/url/urlRule.d.ts +6 -6
- package/types/router/core/url/urlRules.d.ts +6 -6
- package/types/router/core/url/urlService.d.ts +8 -8
- package/types/router/core/view/interface.d.ts +3 -3
- package/types/router/core/view/view.d.ts +26 -26
- package/types/router/directives/viewDirective.d.ts +6 -6
- package/types/router/interface.d.ts +8 -8
- package/types/router/locationServices.d.ts +3 -3
- package/types/router/services.d.ts +1 -1
- package/types/router/stateProvider.d.ts +5 -5
- package/types/router/statebuilders/views.d.ts +1 -1
- package/types/router/templateFactory.d.ts +2 -2
- package/types/router/viewScroll.d.ts +2 -2
|
@@ -53,8 +53,10 @@ export class StateService {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
// Needs access to urlRouter, stateRegistry
|
|
56
|
-
constructor(
|
|
57
|
-
this.
|
|
56
|
+
constructor(globals, transitionService) {
|
|
57
|
+
this.stateRegistry = undefined;
|
|
58
|
+
this.urlRouter = undefined;
|
|
59
|
+
this.urlService = undefined;
|
|
58
60
|
this.globals = globals;
|
|
59
61
|
this.transitionService = transitionService;
|
|
60
62
|
this.invalidCallbacks = [];
|
|
@@ -96,10 +98,7 @@ export class StateService {
|
|
|
96
98
|
* @internal
|
|
97
99
|
*/
|
|
98
100
|
_handleInvalidTargetState(fromPath, toState) {
|
|
99
|
-
const fromState = PathUtils.makeTargetState(
|
|
100
|
-
this.router.stateRegistry,
|
|
101
|
-
fromPath,
|
|
102
|
-
);
|
|
101
|
+
const fromState = PathUtils.makeTargetState(this.stateRegistry, fromPath);
|
|
103
102
|
const globals = this.globals;
|
|
104
103
|
const latestThing = () => globals.transitionHistory.peekTail();
|
|
105
104
|
const latest = latestThing();
|
|
@@ -278,7 +277,7 @@ export class StateService {
|
|
|
278
277
|
// If we're reloading, find the state object to reload from
|
|
279
278
|
if (isObject(options.reload) && !options.reload.name)
|
|
280
279
|
throw new Error("Invalid reload state object");
|
|
281
|
-
const reg = this.
|
|
280
|
+
const reg = this.stateRegistry;
|
|
282
281
|
options.reloadState =
|
|
283
282
|
options.reload === true
|
|
284
283
|
? reg.root()
|
|
@@ -287,18 +286,13 @@ export class StateService {
|
|
|
287
286
|
throw new Error(
|
|
288
287
|
`No such reload state '${isString(options.reload) ? options.reload : options.reload.name}'`,
|
|
289
288
|
);
|
|
290
|
-
return new TargetState(
|
|
291
|
-
this.router.stateRegistry,
|
|
292
|
-
identifier,
|
|
293
|
-
params,
|
|
294
|
-
options,
|
|
295
|
-
);
|
|
289
|
+
return new TargetState(this.stateRegistry, identifier, params, options);
|
|
296
290
|
}
|
|
297
291
|
|
|
298
292
|
getCurrentPath() {
|
|
299
293
|
const globals = this.globals;
|
|
300
294
|
const latestSuccess = globals.successfulTransitions.peekTail();
|
|
301
|
-
const rootPath = () => [new PathNode(this.
|
|
295
|
+
const rootPath = () => [new PathNode(this.stateRegistry.root())];
|
|
302
296
|
return latestSuccess ? latestSuccess.treeChanges().to : rootPath();
|
|
303
297
|
}
|
|
304
298
|
/**
|
|
@@ -350,7 +344,7 @@ export class StateService {
|
|
|
350
344
|
if (error instanceof Rejection) {
|
|
351
345
|
const isLatest = this.globals.lastStartedTransitionId <= trans.$id;
|
|
352
346
|
if (error.type === RejectType.IGNORED) {
|
|
353
|
-
isLatest &&
|
|
347
|
+
isLatest && EventBus.publish("urlRouter.update");
|
|
354
348
|
// Consider ignored `Transition.run()` as a successful `transitionTo`
|
|
355
349
|
return services.$q.when(this.globals.current);
|
|
356
350
|
}
|
|
@@ -366,7 +360,7 @@ export class StateService {
|
|
|
366
360
|
return redirect.run().catch(rejectedTransitionHandler(redirect));
|
|
367
361
|
}
|
|
368
362
|
if (error.type === RejectType.ABORTED) {
|
|
369
|
-
isLatest &&
|
|
363
|
+
isLatest && EventBus.publish("urlRouter.update");
|
|
370
364
|
return services.$q.reject(error);
|
|
371
365
|
}
|
|
372
366
|
}
|
|
@@ -415,7 +409,7 @@ export class StateService {
|
|
|
415
409
|
*/
|
|
416
410
|
is(stateOrName, params, options) {
|
|
417
411
|
options = defaults(options, { relative: this.$current });
|
|
418
|
-
const state = this.
|
|
412
|
+
const state = this.stateRegistry.matcher.find(
|
|
419
413
|
stateOrName,
|
|
420
414
|
options.relative,
|
|
421
415
|
);
|
|
@@ -474,7 +468,7 @@ export class StateService {
|
|
|
474
468
|
if (!glob.matches(this.$current.name)) return false;
|
|
475
469
|
stateOrName = this.$current.name;
|
|
476
470
|
}
|
|
477
|
-
const state = this.
|
|
471
|
+
const state = this.stateRegistry.matcher.find(
|
|
478
472
|
stateOrName,
|
|
479
473
|
options.relative,
|
|
480
474
|
),
|
|
@@ -514,7 +508,7 @@ export class StateService {
|
|
|
514
508
|
};
|
|
515
509
|
options = defaults(options, defaultHrefOpts);
|
|
516
510
|
params = params || {};
|
|
517
|
-
const state = this.
|
|
511
|
+
const state = this.stateRegistry.matcher.find(
|
|
518
512
|
stateOrName,
|
|
519
513
|
options.relative,
|
|
520
514
|
);
|
|
@@ -525,7 +519,7 @@ export class StateService {
|
|
|
525
519
|
if (!nav || nav.url === undefined || nav.url === null) {
|
|
526
520
|
return null;
|
|
527
521
|
}
|
|
528
|
-
return this.
|
|
522
|
+
return this.urlRouter.href(nav.url, params, {
|
|
529
523
|
absolute: options.absolute,
|
|
530
524
|
});
|
|
531
525
|
}
|
|
@@ -557,7 +551,7 @@ export class StateService {
|
|
|
557
551
|
return (this._defaultErrorHandler = handler || this._defaultErrorHandler);
|
|
558
552
|
}
|
|
559
553
|
get(stateOrName, base) {
|
|
560
|
-
const reg = this.
|
|
554
|
+
const reg = this.stateRegistry;
|
|
561
555
|
if (arguments.length === 0) return reg.get();
|
|
562
556
|
return reg.get(stateOrName, base || this.$current);
|
|
563
557
|
}
|
|
@@ -578,10 +572,7 @@ export class StateService {
|
|
|
578
572
|
if (!state || !state.lazyLoad)
|
|
579
573
|
throw new Error("Can not lazy load " + stateOrName);
|
|
580
574
|
const currentPath = this.getCurrentPath();
|
|
581
|
-
const target = PathUtils.makeTargetState(
|
|
582
|
-
this.router.stateRegistry,
|
|
583
|
-
currentPath,
|
|
584
|
-
);
|
|
575
|
+
const target = PathUtils.makeTargetState(this.stateRegistry, currentPath);
|
|
585
576
|
transition =
|
|
586
577
|
transition || this.transitionService.create(currentPath, target);
|
|
587
578
|
return lazyLoadState(transition, state);
|
|
@@ -22,7 +22,7 @@ import { stringify } from "../../shared/strings";
|
|
|
22
22
|
* 3) and transition options
|
|
23
23
|
* 4) the registered state object (the [[StateDeclaration]])
|
|
24
24
|
*
|
|
25
|
-
* Many
|
|
25
|
+
* Many ng-router APIs such as [[StateService.go]] take a [[StateOrName]] argument which can
|
|
26
26
|
* either be a *state object* (a [[StateDeclaration]] or [[StateObject]]) or a *state name* (a string).
|
|
27
27
|
* The `TargetState` class normalizes those options.
|
|
28
28
|
*
|
|
@@ -11,7 +11,7 @@ export function getNg1ViewConfigFactory() {
|
|
|
11
11
|
let templateFactory = null;
|
|
12
12
|
return (path, view) => {
|
|
13
13
|
templateFactory =
|
|
14
|
-
templateFactory || services.$injector.get("$templateFactory");
|
|
14
|
+
templateFactory || services.$injector.get("$templateFactory"); // TODO: remove static injector
|
|
15
15
|
return [new Ng1ViewConfig(path, view, templateFactory)];
|
|
16
16
|
};
|
|
17
17
|
}
|
|
@@ -81,8 +81,8 @@ export function ng1ViewsBuilder(state) {
|
|
|
81
81
|
config.$context,
|
|
82
82
|
config.$name,
|
|
83
83
|
);
|
|
84
|
-
config.$
|
|
85
|
-
config.$
|
|
84
|
+
config.$ngViewName = normalized.ngViewName;
|
|
85
|
+
config.$ngViewContextAnchor = normalized.ngViewContextAnchor;
|
|
86
86
|
views[name] = config;
|
|
87
87
|
});
|
|
88
88
|
return views;
|
|
@@ -101,10 +101,10 @@ export class Ng1ViewConfig {
|
|
|
101
101
|
|
|
102
102
|
/** @type {Number} */ this.$id = id++;
|
|
103
103
|
this.loaded = false;
|
|
104
|
-
this.getTemplate = (
|
|
104
|
+
this.getTemplate = (ngView, context) =>
|
|
105
105
|
this.component
|
|
106
106
|
? this.factory.makeComponentTemplate(
|
|
107
|
-
|
|
107
|
+
ngView,
|
|
108
108
|
context,
|
|
109
109
|
this.component,
|
|
110
110
|
this.viewDecl.bindings,
|
|
@@ -172,13 +172,13 @@ export class TemplateFactory {
|
|
|
172
172
|
* It analyses the component's bindings, then constructs a template that instantiates the component.
|
|
173
173
|
* The template wires input and output bindings to resolves or from the parent component.
|
|
174
174
|
*
|
|
175
|
-
* @param {angular.IAugmentedJQuery}
|
|
175
|
+
* @param {angular.IAugmentedJQuery} ngView {object} The parent ui-view (for binding outputs to callbacks)
|
|
176
176
|
* @param {angular.ResolveContext} context The ResolveContext (for binding outputs to callbacks returned from resolves)
|
|
177
177
|
* @param {string} component {string} Component's name in camel case.
|
|
178
178
|
* @param {any} [bindings] An object defining the component's bindings: {foo: '<'}
|
|
179
179
|
* @return {string} The template as a string: "<component-name input1='::$resolve.foo'></component-name>".
|
|
180
180
|
*/
|
|
181
|
-
makeComponentTemplate(
|
|
181
|
+
makeComponentTemplate(ngView, context, component, bindings) {
|
|
182
182
|
bindings = bindings || {};
|
|
183
183
|
// Bind once prefix
|
|
184
184
|
const prefix = "::"; //angular.version.minor >= 3 ? "::" : "";
|
|
@@ -194,8 +194,8 @@ export class TemplateFactory {
|
|
|
194
194
|
// If the ui-view has an attribute which matches a binding on the routed component
|
|
195
195
|
// then pass that attribute through to the routed component template.
|
|
196
196
|
// Prefer ui-view wired mappings to resolve data, unless the resolve was explicitly bound using `bindings:`
|
|
197
|
-
if (
|
|
198
|
-
return `${attrName}='${
|
|
197
|
+
if (ngView.attr(attrName) && !bindings[name])
|
|
198
|
+
return `${attrName}='${ngView.attr(attrName)}'`;
|
|
199
199
|
const resolveName = bindings[name] || name;
|
|
200
200
|
// Pre-evaluate the expression for "@" bindings by enclosing in {{ }}
|
|
201
201
|
// some-attr="{{ ::$resolve.someResolveName }}"
|
|
@@ -57,9 +57,9 @@ export let defaultTransOpts = {
|
|
|
57
57
|
*/
|
|
58
58
|
export class TransitionService {
|
|
59
59
|
/**
|
|
60
|
-
* @param {import('../
|
|
60
|
+
* @param {import('../globals').UIRouterGlobals} globals
|
|
61
61
|
*/
|
|
62
|
-
constructor(
|
|
62
|
+
constructor(globals, viewService) {
|
|
63
63
|
this._transitionCount = 0;
|
|
64
64
|
/** The transition hook types, such as `onEnter`, `onStart`, etc */
|
|
65
65
|
this._eventTypes = [];
|
|
@@ -67,7 +67,6 @@ export class TransitionService {
|
|
|
67
67
|
this._registeredHooks = {};
|
|
68
68
|
/** The paths on a criteria object */
|
|
69
69
|
this._criteriaPaths = {};
|
|
70
|
-
this.router = router;
|
|
71
70
|
this.globals = globals;
|
|
72
71
|
this.$view = viewService;
|
|
73
72
|
this._deregisterHookFns = {};
|
|
@@ -18,8 +18,6 @@ export class UrlConfig {
|
|
|
18
18
|
/** @type {ParamTypes} */
|
|
19
19
|
this.paramTypes = new ParamTypes();
|
|
20
20
|
/** @type {boolean} */
|
|
21
|
-
this._decodeParams = true;
|
|
22
|
-
/** @type {boolean} */
|
|
23
21
|
this._isCaseInsensitive = false;
|
|
24
22
|
/** @type {boolean} */
|
|
25
23
|
this._isStrictMode = true;
|
|
@@ -39,7 +39,6 @@ const defaultConfig = {
|
|
|
39
39
|
state: { params: {} },
|
|
40
40
|
strict: true,
|
|
41
41
|
caseInsensitive: true,
|
|
42
|
-
decodeParams: true,
|
|
43
42
|
};
|
|
44
43
|
/**
|
|
45
44
|
* Matches URLs against patterns.
|
|
@@ -313,13 +312,6 @@ export class UrlMatcher {
|
|
|
313
312
|
}
|
|
314
313
|
_getDecodedParamValue(value, param) {
|
|
315
314
|
if (isDefined(value)) {
|
|
316
|
-
if (this.config.decodeParams && !param.type.raw) {
|
|
317
|
-
if (Array.isArray(value)) {
|
|
318
|
-
value = value.map((paramValue) => decodeURIComponent(paramValue));
|
|
319
|
-
} else {
|
|
320
|
-
value = decodeURIComponent(value);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
315
|
value = param.type.decode(value);
|
|
324
316
|
}
|
|
325
317
|
return param.value(value);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EventBus } from "../../core/pubsub";
|
|
1
2
|
import { stripLastPathElement } from "../../shared/strings";
|
|
2
3
|
|
|
3
4
|
function appendBasePath(url, isHtml5, absolute, baseHref) {
|
|
@@ -22,6 +23,9 @@ export class UrlRouter {
|
|
|
22
23
|
this.urlService = urlService;
|
|
23
24
|
this.urlRuleFactory = urlRuleFactory;
|
|
24
25
|
this.$locationProvider = $locationProvider;
|
|
26
|
+
EventBus.subscribe("$urlRouter:update", () => {
|
|
27
|
+
this.update();
|
|
28
|
+
});
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
update(read) {
|
|
@@ -213,9 +213,9 @@ export class UrlService {
|
|
|
213
213
|
* Starts or stops listening for URL changes
|
|
214
214
|
*
|
|
215
215
|
* Call this sometime after calling [[deferIntercept]] to start monitoring the url.
|
|
216
|
-
* This causes
|
|
216
|
+
* This causes ng-router to start listening for changes to the URL, if it wasn't already listening.
|
|
217
217
|
*
|
|
218
|
-
* If called with `false`,
|
|
218
|
+
* If called with `false`, ng-router will stop listening (call listen(true) to start listening again).
|
|
219
219
|
*
|
|
220
220
|
* #### Example:
|
|
221
221
|
* ```js
|
|
@@ -243,15 +243,15 @@ export class UrlService {
|
|
|
243
243
|
/**
|
|
244
244
|
* Disables monitoring of the URL.
|
|
245
245
|
*
|
|
246
|
-
* Call this method before
|
|
247
|
-
* It will stop
|
|
246
|
+
* Call this method before ng-router has bootstrapped.
|
|
247
|
+
* It will stop ng-router from performing the initial url sync.
|
|
248
248
|
*
|
|
249
249
|
* This can be useful to perform some asynchronous initialization before the router starts.
|
|
250
|
-
* Once the initialization is complete, call [[listen]] to tell
|
|
250
|
+
* Once the initialization is complete, call [[listen]] to tell ng-router to start watching and synchronizing the URL.
|
|
251
251
|
*
|
|
252
252
|
* #### Example:
|
|
253
253
|
* ```js
|
|
254
|
-
* // Prevent
|
|
254
|
+
* // Prevent ng-router from automatically intercepting URL changes when it starts;
|
|
255
255
|
* urlService.deferIntercept();
|
|
256
256
|
*
|
|
257
257
|
* fetch('/states.json').then(resp => resp.json()).then(data => {
|
package/src/router/view/view.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import { curry, prop } from "../../shared/hof";
|
|
9
9
|
import { isString } from "../../shared/utils";
|
|
10
10
|
import { trace } from "../common/trace";
|
|
11
|
+
import { getNg1ViewConfigFactory } from "../state/views";
|
|
11
12
|
/**
|
|
12
13
|
* The View service
|
|
13
14
|
*
|
|
@@ -29,7 +30,7 @@ export class ViewService {
|
|
|
29
30
|
* @param {number} $id
|
|
30
31
|
*/
|
|
31
32
|
constructor($id) {
|
|
32
|
-
this.
|
|
33
|
+
this._ngViews = [];
|
|
33
34
|
this._viewConfigs = [];
|
|
34
35
|
this._viewConfigFactories = {};
|
|
35
36
|
this._listeners = [];
|
|
@@ -37,59 +38,60 @@ export class ViewService {
|
|
|
37
38
|
_rootViewContext: this._rootViewContext.bind(this),
|
|
38
39
|
_viewConfigFactory: this._viewConfigFactory.bind(this),
|
|
39
40
|
_registeredUIView: (id) =>
|
|
40
|
-
find(this.
|
|
41
|
-
_registeredUIViews: () => this.
|
|
41
|
+
find(this._ngViews, (view) => `${$id}.${view.id}` === id),
|
|
42
|
+
_registeredUIViews: () => this._ngViews,
|
|
42
43
|
_activeViewConfigs: () => this._viewConfigs,
|
|
43
44
|
_onSync: (listener) => {
|
|
44
45
|
this._listeners.push(listener);
|
|
45
46
|
return () => removeFrom(this._listeners, listener);
|
|
46
47
|
},
|
|
47
48
|
};
|
|
49
|
+
this._pluginapi._viewConfigFactory("ng1", getNg1ViewConfigFactory());
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
/**
|
|
51
53
|
* Normalizes a view's name from a state.views configuration block.
|
|
52
54
|
*
|
|
53
55
|
* This should be used by a framework implementation to calculate the values for
|
|
54
|
-
* [[_ViewDeclaration.$
|
|
56
|
+
* [[_ViewDeclaration.$ngViewName]] and [[_ViewDeclaration.$ngViewContextAnchor]].
|
|
55
57
|
*
|
|
56
58
|
* @param context the context object (state declaration) that the view belongs to
|
|
57
59
|
* @param rawViewName the name of the view, as declared in the [[StateDeclaration.views]]
|
|
58
60
|
*
|
|
59
|
-
* @returns the normalized
|
|
61
|
+
* @returns the normalized ngViewName and ngViewContextAnchor that the view targets
|
|
60
62
|
*/
|
|
61
63
|
static normalizeUIViewTarget(context, rawViewName = "") {
|
|
62
64
|
// TODO: Validate incoming view name with a regexp to allow:
|
|
63
65
|
// ex: "view.name@foo.bar" , "^.^.view.name" , "view.name@^.^" , "" ,
|
|
64
66
|
// "@" , "$default@^" , "!$default.$default" , "!foo.bar"
|
|
65
67
|
const viewAtContext = rawViewName.split("@");
|
|
66
|
-
let
|
|
67
|
-
let
|
|
68
|
+
let ngViewName = viewAtContext[0] || "$default"; // default to unnamed view
|
|
69
|
+
let ngViewContextAnchor = isString(viewAtContext[1])
|
|
68
70
|
? viewAtContext[1]
|
|
69
71
|
: "^"; // default to parent context
|
|
70
72
|
// Handle relative view-name sugar syntax.
|
|
71
73
|
// Matches rawViewName "^.^.^.foo.bar" into array: ["^.^.^.foo.bar", "^.^.^", "foo.bar"],
|
|
72
|
-
const relativeViewNameSugar = /^(\^(?:\.\^)*)\.(.*$)/.exec(
|
|
74
|
+
const relativeViewNameSugar = /^(\^(?:\.\^)*)\.(.*$)/.exec(ngViewName);
|
|
73
75
|
if (relativeViewNameSugar) {
|
|
74
76
|
// Clobbers existing contextAnchor (rawViewName validation will fix this)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
ngViewContextAnchor = relativeViewNameSugar[1]; // set anchor to "^.^.^"
|
|
78
|
+
ngViewName = relativeViewNameSugar[2]; // set view-name to "foo.bar"
|
|
77
79
|
}
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
if (ngViewName.charAt(0) === "!") {
|
|
81
|
+
ngViewName = ngViewName.substr(1);
|
|
82
|
+
ngViewContextAnchor = ""; // target absolutely from root
|
|
81
83
|
}
|
|
82
84
|
// handle parent relative targeting "^.^.^"
|
|
83
85
|
const relativeMatch = /^(\^(?:\.\^)*)$/;
|
|
84
|
-
if (relativeMatch.exec(
|
|
85
|
-
const anchorState =
|
|
86
|
+
if (relativeMatch.exec(ngViewContextAnchor)) {
|
|
87
|
+
const anchorState = ngViewContextAnchor
|
|
86
88
|
.split(".")
|
|
87
89
|
.reduce((anchor, x) => anchor.parent, context);
|
|
88
|
-
|
|
89
|
-
} else if (
|
|
90
|
-
|
|
90
|
+
ngViewContextAnchor = anchorState.name;
|
|
91
|
+
} else if (ngViewContextAnchor === ".") {
|
|
92
|
+
ngViewContextAnchor = context.name;
|
|
91
93
|
}
|
|
92
|
-
return {
|
|
94
|
+
return { ngViewName, ngViewContextAnchor };
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
_rootViewContext(context) {
|
|
@@ -125,18 +127,18 @@ export class ViewService {
|
|
|
125
127
|
this._viewConfigs.push(viewConfig);
|
|
126
128
|
}
|
|
127
129
|
sync() {
|
|
128
|
-
const
|
|
130
|
+
const ngViewsByFqn = this._ngViews
|
|
129
131
|
.map((uiv) => [uiv.fqn, uiv])
|
|
130
132
|
.reduce(applyPairs, {});
|
|
131
|
-
// Return a weighted depth value for a
|
|
133
|
+
// Return a weighted depth value for a ngView.
|
|
132
134
|
// The depth is the nesting depth of ui-views (based on FQN; times 10,000)
|
|
133
|
-
// plus the depth of the state that is populating the
|
|
134
|
-
function
|
|
135
|
+
// plus the depth of the state that is populating the ngView
|
|
136
|
+
function ngViewDepth(ngView) {
|
|
135
137
|
const stateDepth = (context) =>
|
|
136
138
|
context && context.parent ? stateDepth(context.parent) + 1 : 1;
|
|
137
139
|
return (
|
|
138
|
-
|
|
139
|
-
stateDepth(
|
|
140
|
+
ngView.fqn.split(".").length * 10000 +
|
|
141
|
+
stateDepth(ngView.creationContext)
|
|
140
142
|
);
|
|
141
143
|
}
|
|
142
144
|
// Return the ViewConfig's context's depth in the context tree.
|
|
@@ -151,34 +153,34 @@ export class ViewService {
|
|
|
151
153
|
(depthFn, posNeg, left, right) =>
|
|
152
154
|
posNeg * (depthFn(left) - depthFn(right)),
|
|
153
155
|
);
|
|
154
|
-
const matchingConfigPair = (
|
|
156
|
+
const matchingConfigPair = (ngView) => {
|
|
155
157
|
const matchingConfigs = this._viewConfigs.filter(
|
|
156
|
-
ViewService.matches(
|
|
158
|
+
ViewService.matches(ngViewsByFqn, ngView),
|
|
157
159
|
);
|
|
158
160
|
if (matchingConfigs.length > 1) {
|
|
159
161
|
// This is OK. Child states can target a ui-view that the parent state also targets (the child wins)
|
|
160
162
|
// Sort by depth and return the match from the deepest child
|
|
161
|
-
// console.log(`Multiple matching view configs for ${
|
|
163
|
+
// console.log(`Multiple matching view configs for ${ngView.fqn}`, matchingConfigs);
|
|
162
164
|
matchingConfigs.sort(depthCompare(viewConfigDepth, -1)); // descending
|
|
163
165
|
}
|
|
164
|
-
return {
|
|
166
|
+
return { ngView, viewConfig: matchingConfigs[0] };
|
|
165
167
|
};
|
|
166
168
|
const configureUIView = (tuple) => {
|
|
167
169
|
// If a parent ui-view is reconfigured, it could destroy child ui-views.
|
|
168
|
-
// Before configuring a child ui-view, make sure it's still in the active
|
|
169
|
-
if (this.
|
|
170
|
-
tuple.
|
|
170
|
+
// Before configuring a child ui-view, make sure it's still in the active ngViews array.
|
|
171
|
+
if (this._ngViews.indexOf(tuple.ngView) !== -1)
|
|
172
|
+
tuple.ngView.configUpdated(tuple.viewConfig);
|
|
171
173
|
};
|
|
172
174
|
// Sort views by FQN and state depth. Process uiviews nearest the root first.
|
|
173
|
-
const
|
|
174
|
-
.sort(depthCompare(
|
|
175
|
+
const ngViewTuples = this._ngViews
|
|
176
|
+
.sort(depthCompare(ngViewDepth, 1))
|
|
175
177
|
.map(matchingConfigPair);
|
|
176
|
-
const matchedViewConfigs =
|
|
178
|
+
const matchedViewConfigs = ngViewTuples.map((tuple) => tuple.viewConfig);
|
|
177
179
|
const unmatchedConfigTuples = this._viewConfigs
|
|
178
180
|
.filter((config) => !inArray(matchedViewConfigs, config))
|
|
179
|
-
.map((viewConfig) => ({
|
|
180
|
-
|
|
181
|
-
const allTuples =
|
|
181
|
+
.map((viewConfig) => ({ ngView: undefined, viewConfig }));
|
|
182
|
+
ngViewTuples.forEach(configureUIView);
|
|
183
|
+
const allTuples = ngViewTuples.concat(unmatchedConfigTuples);
|
|
182
184
|
this._listeners.forEach((cb) => cb(allTuples));
|
|
183
185
|
trace.traceViewSync(allTuples);
|
|
184
186
|
}
|
|
@@ -194,29 +196,29 @@ export class ViewService {
|
|
|
194
196
|
* Note: There is no corresponding `deregisterUIView`.
|
|
195
197
|
* A `ui-view` should hang on to the return value of `registerUIView` and invoke it to deregister itself.
|
|
196
198
|
*
|
|
197
|
-
* @param
|
|
199
|
+
* @param ngView The metadata for a UIView
|
|
198
200
|
* @return a de-registration function used when the view is destroyed.
|
|
199
201
|
*/
|
|
200
|
-
registerUIView(
|
|
201
|
-
trace.traceViewServiceUIViewEvent("-> Registering",
|
|
202
|
-
const
|
|
202
|
+
registerUIView(ngView) {
|
|
203
|
+
trace.traceViewServiceUIViewEvent("-> Registering", ngView);
|
|
204
|
+
const ngViews = this._ngViews;
|
|
203
205
|
const fqnAndTypeMatches = (uiv) =>
|
|
204
|
-
uiv.fqn ===
|
|
205
|
-
if (
|
|
206
|
-
trace.traceViewServiceUIViewEvent("!!!! duplicate
|
|
207
|
-
|
|
206
|
+
uiv.fqn === ngView.fqn && uiv.$type === ngView.$type;
|
|
207
|
+
if (ngViews.filter(fqnAndTypeMatches).length)
|
|
208
|
+
trace.traceViewServiceUIViewEvent("!!!! duplicate ngView named:", ngView);
|
|
209
|
+
ngViews.push(ngView);
|
|
208
210
|
this.sync();
|
|
209
211
|
return () => {
|
|
210
|
-
const idx =
|
|
212
|
+
const idx = ngViews.indexOf(ngView);
|
|
211
213
|
if (idx === -1) {
|
|
212
214
|
trace.traceViewServiceUIViewEvent(
|
|
213
|
-
"Tried removing non-registered
|
|
214
|
-
|
|
215
|
+
"Tried removing non-registered ngView",
|
|
216
|
+
ngView,
|
|
215
217
|
);
|
|
216
218
|
return;
|
|
217
219
|
}
|
|
218
|
-
trace.traceViewServiceUIViewEvent("<- Deregistering",
|
|
219
|
-
removeFrom(
|
|
220
|
+
trace.traceViewServiceUIViewEvent("<- Deregistering", ngView);
|
|
221
|
+
removeFrom(ngViews)(ngView);
|
|
220
222
|
};
|
|
221
223
|
}
|
|
222
224
|
/**
|
|
@@ -225,7 +227,7 @@ export class ViewService {
|
|
|
225
227
|
* @return {Array} Returns an array of fully-qualified view names.
|
|
226
228
|
*/
|
|
227
229
|
available() {
|
|
228
|
-
return this.
|
|
230
|
+
return this._ngViews.map(prop("fqn"));
|
|
229
231
|
}
|
|
230
232
|
/**
|
|
231
233
|
* Returns the list of views on the page containing loaded content.
|
|
@@ -233,7 +235,7 @@ export class ViewService {
|
|
|
233
235
|
* @return {Array} Returns an array of fully-qualified view names.
|
|
234
236
|
*/
|
|
235
237
|
active() {
|
|
236
|
-
return this.
|
|
238
|
+
return this._ngViews.filter(prop("$config")).map(prop("name"));
|
|
237
239
|
}
|
|
238
240
|
}
|
|
239
241
|
/**
|
|
@@ -269,7 +271,7 @@ export class ViewService {
|
|
|
269
271
|
* </ui-view>
|
|
270
272
|
* </ui-view>
|
|
271
273
|
*
|
|
272
|
-
*
|
|
274
|
+
* ngViews: [
|
|
273
275
|
* { fqn: "$default", creationContext: { name: "" } },
|
|
274
276
|
* { fqn: "$default.foo", creationContext: { name: "A" } },
|
|
275
277
|
* { fqn: "$default.foo.$default", creationContext: { name: "A.B" } }
|
|
@@ -278,10 +280,10 @@ export class ViewService {
|
|
|
278
280
|
*
|
|
279
281
|
* These four view configs all match the ui-view with the fqn: "$default.foo.$default.bar":
|
|
280
282
|
*
|
|
281
|
-
* - ViewConfig1: {
|
|
282
|
-
* - ViewConfig2: {
|
|
283
|
-
* - ViewConfig3: {
|
|
284
|
-
* - ViewConfig4: {
|
|
283
|
+
* - ViewConfig1: { ngViewName: "bar", ngViewContextAnchor: "A.B.C" }
|
|
284
|
+
* - ViewConfig2: { ngViewName: "$default.bar", ngViewContextAnchor: "A.B" }
|
|
285
|
+
* - ViewConfig3: { ngViewName: "foo.$default.bar", ngViewContextAnchor: "A" }
|
|
286
|
+
* - ViewConfig4: { ngViewName: "$default.foo.$default.bar", ngViewContextAnchor: "" }
|
|
285
287
|
*
|
|
286
288
|
* Using ViewConfig3 as an example, it matches the ui-view with fqn "$default.foo.$default.bar" because:
|
|
287
289
|
* - The ViewConfig's segmented target name is: [ "foo", "$default", "bar" ]
|
|
@@ -293,13 +295,13 @@ export class ViewService {
|
|
|
293
295
|
*
|
|
294
296
|
* @internal
|
|
295
297
|
*/
|
|
296
|
-
ViewService.matches = (
|
|
298
|
+
ViewService.matches = (ngViewsByFqn, ngView) => (viewConfig) => {
|
|
297
299
|
// Don't supply an ng1 ui-view with an ng2 ViewConfig, etc
|
|
298
|
-
if (
|
|
299
|
-
// Split names apart from both viewConfig and
|
|
300
|
+
if (ngView.$type !== viewConfig.viewDecl.$type) return false;
|
|
301
|
+
// Split names apart from both viewConfig and ngView into segments
|
|
300
302
|
const vc = viewConfig.viewDecl;
|
|
301
|
-
const vcSegments = vc.$
|
|
302
|
-
const uivSegments =
|
|
303
|
+
const vcSegments = vc.$ngViewName.split(".");
|
|
304
|
+
const uivSegments = ngView.fqn.split(".");
|
|
303
305
|
// Check if the tails of the segment arrays match. ex, these arrays' tails match:
|
|
304
306
|
// vc: ["foo", "bar"], uiv fqn: ["$default", "foo", "bar"]
|
|
305
307
|
if (!equals(vcSegments, uivSegments.slice(0 - vcSegments.length)))
|
|
@@ -308,6 +310,6 @@ ViewService.matches = (uiViewsByFqn, uiView) => (viewConfig) => {
|
|
|
308
310
|
// ["$default", "foo"].join(".") == "$default.foo", does the ui-view $default.foo context match?
|
|
309
311
|
const negOffset = 1 - vcSegments.length || undefined;
|
|
310
312
|
const fqnToFirstSegment = uivSegments.slice(0, negOffset).join(".");
|
|
311
|
-
const
|
|
312
|
-
return vc.$
|
|
313
|
+
const ngViewContext = ngViewsByFqn[fqnToFirstSegment].creationContext;
|
|
314
|
+
return vc.$ngViewContextAnchor === (ngViewContext && ngViewContext.name);
|
|
313
315
|
};
|
package/src/services/browser.js
CHANGED
|
@@ -102,11 +102,7 @@ export function Browser($log, $$taskTrackerFactory) {
|
|
|
102
102
|
// lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
|
|
103
103
|
lastBrowserUrl = url;
|
|
104
104
|
lastHistoryState = state;
|
|
105
|
-
|
|
106
|
-
// due to a bug in IE10/IE11 which leads
|
|
107
|
-
// to not firing a `hashchange` nor `popstate` event
|
|
108
|
-
// in some cases (see #9143).
|
|
109
|
-
history[replace ? "replaceState" : "pushState"](state, "", url);
|
|
105
|
+
history.pushState(state, "", url);
|
|
110
106
|
cacheState();
|
|
111
107
|
return self;
|
|
112
108
|
// getter
|
package/src/shared/common.js
CHANGED