@angular-wave/angular.ts 0.0.11 → 0.0.12
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/package.json +4 -1
- package/src/exts/messages.md +30 -30
- package/src/public.js +2 -0
- package/src/router/adapter/directives/stateDirectives.js +695 -0
- package/src/router/adapter/directives/viewDirective.js +514 -0
- package/src/router/adapter/injectables.js +314 -0
- package/src/router/adapter/interface.js +1 -0
- package/src/router/adapter/locationServices.js +86 -0
- package/src/router/adapter/services.js +132 -0
- package/src/router/adapter/stateFilters.js +43 -0
- package/src/router/adapter/stateProvider.js +137 -0
- package/src/router/adapter/statebuilders/onEnterExitRetain.js +30 -0
- package/src/router/adapter/statebuilders/views.js +146 -0
- package/src/router/adapter/templateFactory.js +218 -0
- package/src/router/adapter/urlRouterProvider.js +196 -0
- package/src/router/adapter/viewScroll.js +31 -0
- package/src/router/core/common/common.js +506 -0
- package/src/router/core/common/coreservices.js +15 -0
- package/src/router/core/common/glob.js +75 -0
- package/src/router/core/common/hof.js +194 -0
- package/src/router/core/common/predicates.js +44 -0
- package/src/router/core/common/queue.js +41 -0
- package/src/router/core/common/safeConsole.js +38 -0
- package/src/router/core/common/strings.js +141 -0
- package/src/router/core/common/trace.js +232 -0
- package/src/router/core/globals.js +29 -0
- package/src/router/core/hooks/coreResolvables.js +33 -0
- package/src/router/core/hooks/ignoredTransition.js +25 -0
- package/src/router/core/hooks/invalidTransition.js +14 -0
- package/src/router/core/hooks/lazyLoad.js +102 -0
- package/src/router/core/hooks/onEnterExitRetain.js +55 -0
- package/src/router/core/hooks/redirectTo.js +36 -0
- package/src/router/core/hooks/resolve.js +57 -0
- package/src/router/core/hooks/updateGlobals.js +30 -0
- package/src/router/core/hooks/url.js +25 -0
- package/src/router/core/hooks/views.js +39 -0
- package/src/router/core/interface.js +3 -0
- package/src/router/core/params/README.md +8 -0
- package/src/router/core/params/param.js +232 -0
- package/src/router/core/params/paramType.js +139 -0
- package/src/router/core/params/paramTypes.js +163 -0
- package/src/router/core/params/stateParams.js +35 -0
- package/src/router/core/path/pathNode.js +77 -0
- package/src/router/core/path/pathUtils.js +200 -0
- package/src/router/core/resolve/interface.js +10 -0
- package/src/router/core/resolve/resolvable.js +124 -0
- package/src/router/core/resolve/resolveContext.js +211 -0
- package/src/router/core/router.js +201 -0
- package/src/router/core/state/README.md +21 -0
- package/src/router/core/state/stateBuilder.js +333 -0
- package/src/router/core/state/stateMatcher.js +66 -0
- package/src/router/core/state/stateObject.js +116 -0
- package/src/router/core/state/stateQueueManager.js +89 -0
- package/src/router/core/state/stateRegistry.js +175 -0
- package/src/router/core/state/stateService.js +592 -0
- package/src/router/core/state/targetState.js +159 -0
- package/src/router/core/transition/hookBuilder.js +127 -0
- package/src/router/core/transition/hookRegistry.js +182 -0
- package/src/router/core/transition/interface.js +14 -0
- package/src/router/core/transition/rejectFactory.js +122 -0
- package/src/router/core/transition/transition.js +739 -0
- package/src/router/core/transition/transitionEventType.js +27 -0
- package/src/router/core/transition/transitionHook.js +199 -0
- package/src/router/core/transition/transitionService.js +311 -0
- package/src/router/core/url/interface.js +1 -0
- package/src/router/core/url/urlConfig.js +165 -0
- package/src/router/core/url/urlMatcher.js +548 -0
- package/src/router/core/url/urlMatcherFactory.js +123 -0
- package/src/router/core/url/urlRouter.js +115 -0
- package/src/router/core/url/urlRule.js +202 -0
- package/src/router/core/url/urlRules.js +348 -0
- package/src/router/core/url/urlService.js +268 -0
- package/src/router/core/vanilla/baseLocationService.js +31 -0
- package/src/router/core/vanilla/browserLocationConfig.js +42 -0
- package/src/router/core/vanilla/hashLocationService.js +19 -0
- package/src/router/core/vanilla/injector.js +98 -0
- package/src/router/core/vanilla/interface.js +1 -0
- package/src/router/core/vanilla/memoryLocationConfig.js +20 -0
- package/src/router/core/vanilla/memoryLocationService.js +13 -0
- package/src/router/core/vanilla/plugins.js +35 -0
- package/src/router/core/vanilla/pushStateLocationService.js +69 -0
- package/src/router/core/vanilla/q.js +54 -0
- package/src/router/core/vanilla/utils.js +63 -0
- package/src/router/core/view/interface.js +1 -0
- package/src/router/core/view/view.js +312 -0
- package/src/router/router.js +52 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/** @publicapi @module ng1 */ /** */
|
|
2
|
+
|
|
3
|
+
import { val } from "../core/common/hof";
|
|
4
|
+
import { createProxyFunctions } from "../core/common/common";
|
|
5
|
+
import { isObject } from "../../core/utils";
|
|
6
|
+
/**
|
|
7
|
+
* The Angular 1 `StateProvider`
|
|
8
|
+
*
|
|
9
|
+
* The `$stateProvider` works similar to Angular's v1 router, but it focuses purely
|
|
10
|
+
* on state.
|
|
11
|
+
*
|
|
12
|
+
* A state corresponds to a "place" in the application in terms of the overall UI and
|
|
13
|
+
* navigation. A state describes (via the controller / template / view properties) what
|
|
14
|
+
* the UI looks like and does at that place.
|
|
15
|
+
*
|
|
16
|
+
* States often have things in common, and the primary way of factoring out these
|
|
17
|
+
* commonalities in this model is via the state hierarchy, i.e. parent/child states aka
|
|
18
|
+
* nested states.
|
|
19
|
+
*
|
|
20
|
+
* The `$stateProvider` provides interfaces to declare these states for your app.
|
|
21
|
+
*/
|
|
22
|
+
export class StateProvider {
|
|
23
|
+
constructor(stateRegistry, stateService) {
|
|
24
|
+
this.stateRegistry = stateRegistry;
|
|
25
|
+
this.stateService = stateService;
|
|
26
|
+
createProxyFunctions(val(StateProvider.prototype), this, val(this));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Decorates states when they are registered
|
|
30
|
+
*
|
|
31
|
+
* Allows you to extend (carefully) or override (at your own peril) the
|
|
32
|
+
* `stateBuilder` object used internally by [[StateRegistry]].
|
|
33
|
+
* This can be used to add custom functionality to ui-router,
|
|
34
|
+
* for example inferring templateUrl based on the state name.
|
|
35
|
+
*
|
|
36
|
+
* When passing only a name, it returns the current (original or decorated) builder
|
|
37
|
+
* function that matches `name`.
|
|
38
|
+
*
|
|
39
|
+
* The builder functions that can be decorated are listed below. Though not all
|
|
40
|
+
* necessarily have a good use case for decoration, that is up to you to decide.
|
|
41
|
+
*
|
|
42
|
+
* In addition, users can attach custom decorators, which will generate new
|
|
43
|
+
* properties within the state's internal definition. There is currently no clear
|
|
44
|
+
* use-case for this beyond accessing internal states (i.e. $state.$current),
|
|
45
|
+
* however, expect this to become increasingly relevant as we introduce additional
|
|
46
|
+
* meta-programming features.
|
|
47
|
+
*
|
|
48
|
+
* **Warning**: Decorators should not be interdependent because the order of
|
|
49
|
+
* execution of the builder functions in non-deterministic. Builder functions
|
|
50
|
+
* should only be dependent on the state definition object and super function.
|
|
51
|
+
*
|
|
52
|
+
*
|
|
53
|
+
* Existing builder functions and current return values:
|
|
54
|
+
*
|
|
55
|
+
* - **parent** `{object}` - returns the parent state object.
|
|
56
|
+
* - **data** `{object}` - returns state data, including any inherited data that is not
|
|
57
|
+
* overridden by own values (if any).
|
|
58
|
+
* - **url** `{object}` - returns a {@link ui.router.util.type:UrlMatcher UrlMatcher}
|
|
59
|
+
* or `null`.
|
|
60
|
+
* - **navigable** `{object}` - returns closest ancestor state that has a URL (aka is
|
|
61
|
+
* navigable).
|
|
62
|
+
* - **params** `{object}` - returns an array of state params that are ensured to
|
|
63
|
+
* be a super-set of parent's params.
|
|
64
|
+
* - **views** `{object}` - returns a views object where each key is an absolute view
|
|
65
|
+
* name (i.e. "viewName@stateName") and each value is the config object
|
|
66
|
+
* (template, controller) for the view. Even when you don't use the views object
|
|
67
|
+
* explicitly on a state config, one is still created for you internally.
|
|
68
|
+
* So by decorating this builder function you have access to decorating template
|
|
69
|
+
* and controller properties.
|
|
70
|
+
* - **ownParams** `{object}` - returns an array of params that belong to the state,
|
|
71
|
+
* not including any params defined by ancestor states.
|
|
72
|
+
* - **path** `{string}` - returns the full path from the root down to this state.
|
|
73
|
+
* Needed for state activation.
|
|
74
|
+
* - **includes** `{object}` - returns an object that includes every state that
|
|
75
|
+
* would pass a `$state.includes()` test.
|
|
76
|
+
*
|
|
77
|
+
* #### Example:
|
|
78
|
+
* Override the internal 'views' builder with a function that takes the state
|
|
79
|
+
* definition, and a reference to the internal function being overridden:
|
|
80
|
+
* ```js
|
|
81
|
+
* $stateProvider.decorator('views', function (state, parent) {
|
|
82
|
+
* let result = {},
|
|
83
|
+
* views = parent(state);
|
|
84
|
+
*
|
|
85
|
+
* angular.forEach(views, function (config, name) {
|
|
86
|
+
* let autoName = (state.name + '.' + name).replace('.', '/');
|
|
87
|
+
* config.templateUrl = config.templateUrl || '/partials/' + autoName + '.html';
|
|
88
|
+
* result[name] = config;
|
|
89
|
+
* });
|
|
90
|
+
* return result;
|
|
91
|
+
* });
|
|
92
|
+
*
|
|
93
|
+
* $stateProvider.state('home', {
|
|
94
|
+
* views: {
|
|
95
|
+
* 'contact.list': { controller: 'ListController' },
|
|
96
|
+
* 'contact.item': { controller: 'ItemController' }
|
|
97
|
+
* }
|
|
98
|
+
* });
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
*
|
|
102
|
+
* ```js
|
|
103
|
+
* // Auto-populates list and item views with /partials/home/contact/list.html,
|
|
104
|
+
* // and /partials/home/contact/item.html, respectively.
|
|
105
|
+
* $state.go('home');
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* @param {string} name The name of the builder function to decorate.
|
|
109
|
+
* @param {object} func A function that is responsible for decorating the original
|
|
110
|
+
* builder function. The function receives two parameters:
|
|
111
|
+
*
|
|
112
|
+
* - `{object}` - state - The state config object.
|
|
113
|
+
* - `{object}` - super - The original builder function.
|
|
114
|
+
*
|
|
115
|
+
* @return {object} $stateProvider - $stateProvider instance
|
|
116
|
+
*/
|
|
117
|
+
decorator(name, func) {
|
|
118
|
+
return this.stateRegistry.decorator(name, func) || this;
|
|
119
|
+
}
|
|
120
|
+
state(name, definition) {
|
|
121
|
+
if (isObject(name)) {
|
|
122
|
+
definition = name;
|
|
123
|
+
} else {
|
|
124
|
+
definition.name = name;
|
|
125
|
+
}
|
|
126
|
+
this.stateRegistry.register(definition);
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Registers an invalid state handler
|
|
131
|
+
*
|
|
132
|
+
* This is a passthrough to [[StateService.onInvalid]] for ng1.
|
|
133
|
+
*/
|
|
134
|
+
onInvalid(callback) {
|
|
135
|
+
return this.stateService.onInvalid(callback);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** @publicapi @module ng1 */ /** */
|
|
2
|
+
import { getLocals } from "../services";
|
|
3
|
+
import { services } from "../../core/common/coreservices";
|
|
4
|
+
import { extend } from "../../../core/utils";
|
|
5
|
+
import { ResolveContext } from "../../core/resolve/resolveContext";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* This is a [[StateBuilder.builder]] function for angular1 `onEnter`, `onExit`,
|
|
9
|
+
* `onRetain` callback hooks on a [[Ng1StateDeclaration]].
|
|
10
|
+
*
|
|
11
|
+
* When the [[StateBuilder]] builds a [[StateObject]] object from a raw [[StateDeclaration]], this builder
|
|
12
|
+
* ensures that those hooks are injectable for @uirouter/angularjs (ng1).
|
|
13
|
+
*
|
|
14
|
+
* @internalapi
|
|
15
|
+
*/
|
|
16
|
+
export const getStateHookBuilder = (hookName) =>
|
|
17
|
+
function stateHookBuilder(stateObject) {
|
|
18
|
+
const hook = stateObject[hookName];
|
|
19
|
+
const pathname = hookName === "onExit" ? "from" : "to";
|
|
20
|
+
function decoratedNg1Hook(trans, state) {
|
|
21
|
+
const resolveContext = new ResolveContext(trans.treeChanges(pathname));
|
|
22
|
+
const subContext = resolveContext.subContext(state.$$state());
|
|
23
|
+
const locals = extend(getLocals(subContext), {
|
|
24
|
+
$state$: state,
|
|
25
|
+
$transition$: trans,
|
|
26
|
+
});
|
|
27
|
+
return services.$injector.invoke(hook, this, locals);
|
|
28
|
+
}
|
|
29
|
+
return hook ? decoratedNg1Hook : undefined;
|
|
30
|
+
};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/** @publicapi @module ng1 */ /** */
|
|
2
|
+
import { pick, forEach, tail, extend } from "../../core/common/common";
|
|
3
|
+
import { isArray, isDefined, isString } from "../../../core/utils";
|
|
4
|
+
import { isInjectable } from "../../core/common/predicates";
|
|
5
|
+
import { services } from "../../core/common/coreservices";
|
|
6
|
+
import { trace } from "../../core/common/trace";
|
|
7
|
+
import { ViewService } from "../../core/view/view";
|
|
8
|
+
import { ResolveContext } from "../../core/resolve/resolveContext";
|
|
9
|
+
import { Resolvable } from "../../core/resolve/resolvable";
|
|
10
|
+
|
|
11
|
+
/** @internalapi */
|
|
12
|
+
export function getNg1ViewConfigFactory() {
|
|
13
|
+
let templateFactory = null;
|
|
14
|
+
return (path, view) => {
|
|
15
|
+
templateFactory =
|
|
16
|
+
templateFactory || services.$injector.get("$templateFactory");
|
|
17
|
+
return [new Ng1ViewConfig(path, view, templateFactory)];
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** @internalapi */
|
|
21
|
+
const hasAnyKey = (keys, obj) =>
|
|
22
|
+
keys.reduce((acc, key) => acc || isDefined(obj[key]), false);
|
|
23
|
+
/**
|
|
24
|
+
* This is a [[StateBuilder.builder]] function for angular1 `views`.
|
|
25
|
+
*
|
|
26
|
+
* When the [[StateBuilder]] builds a [[StateObject]] object from a raw [[StateDeclaration]], this builder
|
|
27
|
+
* handles the `views` property with logic specific to @uirouter/angularjs (ng1).
|
|
28
|
+
*
|
|
29
|
+
* If no `views: {}` property exists on the [[StateDeclaration]], then it creates the `views` object
|
|
30
|
+
* and applies the state-level configuration to a view named `$default`.
|
|
31
|
+
*
|
|
32
|
+
* @internalapi
|
|
33
|
+
*/
|
|
34
|
+
export function ng1ViewsBuilder(state) {
|
|
35
|
+
// Do not process root state
|
|
36
|
+
if (!state.parent) return {};
|
|
37
|
+
const tplKeys = [
|
|
38
|
+
"templateProvider",
|
|
39
|
+
"templateUrl",
|
|
40
|
+
"template",
|
|
41
|
+
"notify",
|
|
42
|
+
"async",
|
|
43
|
+
],
|
|
44
|
+
ctrlKeys = [
|
|
45
|
+
"controller",
|
|
46
|
+
"controllerProvider",
|
|
47
|
+
"controllerAs",
|
|
48
|
+
"resolveAs",
|
|
49
|
+
],
|
|
50
|
+
compKeys = ["component", "bindings", "componentProvider"],
|
|
51
|
+
nonCompKeys = tplKeys.concat(ctrlKeys),
|
|
52
|
+
allViewKeys = compKeys.concat(nonCompKeys);
|
|
53
|
+
// Do not allow a state to have both state-level props and also a `views: {}` property.
|
|
54
|
+
// A state without a `views: {}` property can declare properties for the `$default` view as properties of the state.
|
|
55
|
+
// However, the `$default` approach should not be mixed with a separate `views: ` block.
|
|
56
|
+
if (isDefined(state.views) && hasAnyKey(allViewKeys, state)) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`State '${state.name}' has a 'views' object. ` +
|
|
59
|
+
`It cannot also have "view properties" at the state level. ` +
|
|
60
|
+
`Move the following properties into a view (in the 'views' object): ` +
|
|
61
|
+
` ${allViewKeys.filter((key) => isDefined(state[key])).join(", ")}`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
const views = {},
|
|
65
|
+
viewsObject = state.views || { $default: pick(state, allViewKeys) };
|
|
66
|
+
forEach(viewsObject, function (config, name) {
|
|
67
|
+
// Account for views: { "": { template... } }
|
|
68
|
+
name = name || "$default";
|
|
69
|
+
// Account for views: { header: "headerComponent" }
|
|
70
|
+
if (isString(config)) config = { component: config };
|
|
71
|
+
// Make a shallow copy of the config object
|
|
72
|
+
config = extend({}, config);
|
|
73
|
+
// Do not allow a view to mix props for component-style view with props for template/controller-style view
|
|
74
|
+
if (hasAnyKey(compKeys, config) && hasAnyKey(nonCompKeys, config)) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Cannot combine: ${compKeys.join("|")} with: ${nonCompKeys.join("|")} in stateview: '${name}@${state.name}'`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
config.resolveAs = config.resolveAs || "$resolve";
|
|
80
|
+
config.$type = "ng1";
|
|
81
|
+
config.$context = state;
|
|
82
|
+
config.$name = name;
|
|
83
|
+
const normalized = ViewService.normalizeUIViewTarget(
|
|
84
|
+
config.$context,
|
|
85
|
+
config.$name,
|
|
86
|
+
);
|
|
87
|
+
config.$uiViewName = normalized.uiViewName;
|
|
88
|
+
config.$uiViewContextAnchor = normalized.uiViewContextAnchor;
|
|
89
|
+
views[name] = config;
|
|
90
|
+
});
|
|
91
|
+
return views;
|
|
92
|
+
}
|
|
93
|
+
/** @hidden */
|
|
94
|
+
let id = 0;
|
|
95
|
+
/** @internalapi */
|
|
96
|
+
export class Ng1ViewConfig {
|
|
97
|
+
constructor(path, viewDecl, factory) {
|
|
98
|
+
this.path = path;
|
|
99
|
+
this.viewDecl = viewDecl;
|
|
100
|
+
this.factory = factory;
|
|
101
|
+
this.$id = id++;
|
|
102
|
+
this.loaded = false;
|
|
103
|
+
this.getTemplate = (uiView, context) =>
|
|
104
|
+
this.component
|
|
105
|
+
? this.factory.makeComponentTemplate(
|
|
106
|
+
uiView,
|
|
107
|
+
context,
|
|
108
|
+
this.component,
|
|
109
|
+
this.viewDecl.bindings,
|
|
110
|
+
)
|
|
111
|
+
: this.template;
|
|
112
|
+
}
|
|
113
|
+
load() {
|
|
114
|
+
const $q = services.$q;
|
|
115
|
+
const context = new ResolveContext(this.path);
|
|
116
|
+
const params = this.path.reduce(
|
|
117
|
+
(acc, node) => extend(acc, node.paramValues),
|
|
118
|
+
{},
|
|
119
|
+
);
|
|
120
|
+
const promises = {
|
|
121
|
+
template: $q.when(
|
|
122
|
+
this.factory.fromConfig(this.viewDecl, params, context),
|
|
123
|
+
),
|
|
124
|
+
controller: $q.when(this.getController(context)),
|
|
125
|
+
};
|
|
126
|
+
return $q.all(promises).then((results) => {
|
|
127
|
+
trace.traceViewServiceEvent("Loaded", this);
|
|
128
|
+
this.controller = results.controller;
|
|
129
|
+
extend(this, results.template); // Either { template: "tpl" } or { component: "cmpName" }
|
|
130
|
+
return this;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Gets the controller for a view configuration.
|
|
135
|
+
*
|
|
136
|
+
* @returns {Function|Promise.<Function>} Returns a controller, or a promise that resolves to a controller.
|
|
137
|
+
*/
|
|
138
|
+
getController(context) {
|
|
139
|
+
const provider = this.viewDecl.controllerProvider;
|
|
140
|
+
if (!isInjectable(provider)) return this.viewDecl.controller;
|
|
141
|
+
const deps = services.$injector.annotate(provider);
|
|
142
|
+
const providerFn = isArray(provider) ? tail(provider) : provider;
|
|
143
|
+
const resolvable = new Resolvable("", providerFn, deps);
|
|
144
|
+
return resolvable.get(context);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/** @publicapi @module view */ /** */
|
|
2
|
+
import {
|
|
3
|
+
isArray,
|
|
4
|
+
isDefined,
|
|
5
|
+
isFunction,
|
|
6
|
+
isObject,
|
|
7
|
+
} from "../core/common/predicates";
|
|
8
|
+
import { services } from "../core/common/coreservices";
|
|
9
|
+
import { tail, unnestR } from "../core/common/common";
|
|
10
|
+
import { Resolvable } from "../core/resolve/resolvable";
|
|
11
|
+
import { kebobString } from "../core/common/strings";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Service which manages loading of templates from a ViewConfig.
|
|
15
|
+
*/
|
|
16
|
+
export class TemplateFactory {
|
|
17
|
+
constructor() {
|
|
18
|
+
/** @hidden */ this._useHttp = true; // TODO investigate
|
|
19
|
+
/** @hidden */ this.$get = [
|
|
20
|
+
"$http",
|
|
21
|
+
"$templateCache",
|
|
22
|
+
"$injector",
|
|
23
|
+
($http, $templateCache, $injector) => {
|
|
24
|
+
this.$templateRequest =
|
|
25
|
+
$injector.has &&
|
|
26
|
+
$injector.has("$templateRequest") &&
|
|
27
|
+
$injector.get("$templateRequest");
|
|
28
|
+
this.$http = $http;
|
|
29
|
+
this.$templateCache = $templateCache;
|
|
30
|
+
return this;
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
/** @hidden */
|
|
35
|
+
useHttpService(value) {
|
|
36
|
+
this._useHttp = value;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Creates a template from a configuration object.
|
|
40
|
+
*
|
|
41
|
+
* @param config Configuration object for which to load a template.
|
|
42
|
+
* The following properties are search in the specified order, and the first one
|
|
43
|
+
* that is defined is used to create the template:
|
|
44
|
+
*
|
|
45
|
+
* @param params Parameters to pass to the template function.
|
|
46
|
+
* @param context The resolve context associated with the template's view
|
|
47
|
+
*
|
|
48
|
+
* @return {string|object} The template html as a string, or a promise for
|
|
49
|
+
* that string,or `null` if no template is configured.
|
|
50
|
+
*/
|
|
51
|
+
fromConfig(config, params, context) {
|
|
52
|
+
const defaultTemplate = "<ui-view></ui-view>";
|
|
53
|
+
const asTemplate = (result) =>
|
|
54
|
+
services.$q.when(result).then((str) => ({ template: str }));
|
|
55
|
+
const asComponent = (result) =>
|
|
56
|
+
services.$q.when(result).then((str) => ({ component: str }));
|
|
57
|
+
return isDefined(config.template)
|
|
58
|
+
? asTemplate(this.fromString(config.template, params))
|
|
59
|
+
: isDefined(config.templateUrl)
|
|
60
|
+
? asTemplate(this.fromUrl(config.templateUrl, params))
|
|
61
|
+
: isDefined(config.templateProvider)
|
|
62
|
+
? asTemplate(
|
|
63
|
+
this.fromProvider(config.templateProvider, params, context),
|
|
64
|
+
)
|
|
65
|
+
: isDefined(config.component)
|
|
66
|
+
? asComponent(config.component)
|
|
67
|
+
: isDefined(config.componentProvider)
|
|
68
|
+
? asComponent(
|
|
69
|
+
this.fromComponentProvider(
|
|
70
|
+
config.componentProvider,
|
|
71
|
+
params,
|
|
72
|
+
context,
|
|
73
|
+
),
|
|
74
|
+
)
|
|
75
|
+
: asTemplate(defaultTemplate);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Creates a template from a string or a function returning a string.
|
|
79
|
+
*
|
|
80
|
+
* @param template html template as a string or function that returns an html template as a string.
|
|
81
|
+
* @param params Parameters to pass to the template function.
|
|
82
|
+
*
|
|
83
|
+
* @return {string|object} The template html as a string, or a promise for that
|
|
84
|
+
* string.
|
|
85
|
+
*/
|
|
86
|
+
fromString(template, params) {
|
|
87
|
+
return isFunction(template) ? template(params) : template;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Loads a template from the a URL via `$http` and `$templateCache`.
|
|
91
|
+
*
|
|
92
|
+
* @param {string|Function} url url of the template to load, or a function
|
|
93
|
+
* that returns a url.
|
|
94
|
+
* @param {Object} params Parameters to pass to the url function.
|
|
95
|
+
* @return {string|Promise.<string>} The template html as a string, or a promise
|
|
96
|
+
* for that string.
|
|
97
|
+
*/
|
|
98
|
+
fromUrl(url, params) {
|
|
99
|
+
if (isFunction(url)) url = url(params);
|
|
100
|
+
if (url == null) return null;
|
|
101
|
+
if (this._useHttp) {
|
|
102
|
+
return this.$http
|
|
103
|
+
.get(url, {
|
|
104
|
+
cache: this.$templateCache,
|
|
105
|
+
headers: { Accept: "text/html" },
|
|
106
|
+
})
|
|
107
|
+
.then(function (response) {
|
|
108
|
+
return response.data;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return this.$templateRequest(url);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Creates a template by invoking an injectable provider function.
|
|
115
|
+
*
|
|
116
|
+
* @param provider Function to invoke via `locals`
|
|
117
|
+
* @param {Function} injectFn a function used to invoke the template provider
|
|
118
|
+
* @return {string|Promise.<string>} The template html as a string, or a promise
|
|
119
|
+
* for that string.
|
|
120
|
+
*/
|
|
121
|
+
fromProvider(provider, params, context) {
|
|
122
|
+
const deps = services.$injector.annotate(provider);
|
|
123
|
+
const providerFn = isArray(provider) ? tail(provider) : provider;
|
|
124
|
+
const resolvable = new Resolvable("", providerFn, deps);
|
|
125
|
+
return resolvable.get(context);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Creates a component's template by invoking an injectable provider function.
|
|
129
|
+
*
|
|
130
|
+
* @param provider Function to invoke via `locals`
|
|
131
|
+
* @param {Function} injectFn a function used to invoke the template provider
|
|
132
|
+
* @return {string} The template html as a string: "<component-name input1='::$resolve.foo'></component-name>".
|
|
133
|
+
*/
|
|
134
|
+
fromComponentProvider(provider, params, context) {
|
|
135
|
+
const deps = services.$injector.annotate(provider);
|
|
136
|
+
const providerFn = isArray(provider) ? tail(provider) : provider;
|
|
137
|
+
const resolvable = new Resolvable("", providerFn, deps);
|
|
138
|
+
return resolvable.get(context);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Creates a template from a component's name
|
|
142
|
+
*
|
|
143
|
+
* This implements route-to-component.
|
|
144
|
+
* It works by retrieving the component (directive) metadata from the injector.
|
|
145
|
+
* It analyses the component's bindings, then constructs a template that instantiates the component.
|
|
146
|
+
* The template wires input and output bindings to resolves or from the parent component.
|
|
147
|
+
*
|
|
148
|
+
* @param uiView {object} The parent ui-view (for binding outputs to callbacks)
|
|
149
|
+
* @param context The ResolveContext (for binding outputs to callbacks returned from resolves)
|
|
150
|
+
* @param component {string} Component's name in camel case.
|
|
151
|
+
* @param bindings An object defining the component's bindings: {foo: '<'}
|
|
152
|
+
* @return {string} The template as a string: "<component-name input1='::$resolve.foo'></component-name>".
|
|
153
|
+
*/
|
|
154
|
+
makeComponentTemplate(uiView, context, component, bindings) {
|
|
155
|
+
bindings = bindings || {};
|
|
156
|
+
// Bind once prefix
|
|
157
|
+
const prefix = angular.version.minor >= 3 ? "::" : "";
|
|
158
|
+
// Convert to kebob name. Add x- prefix if the string starts with `x-` or `data-`
|
|
159
|
+
const kebob = (camelCase) => {
|
|
160
|
+
const kebobed = kebobString(camelCase);
|
|
161
|
+
return /^(x|data)-/.exec(kebobed) ? `x-${kebobed}` : kebobed;
|
|
162
|
+
};
|
|
163
|
+
const attributeTpl = (input) => {
|
|
164
|
+
const { name, type } = input;
|
|
165
|
+
const attrName = kebob(name);
|
|
166
|
+
// If the ui-view has an attribute which matches a binding on the routed component
|
|
167
|
+
// then pass that attribute through to the routed component template.
|
|
168
|
+
// Prefer ui-view wired mappings to resolve data, unless the resolve was explicitly bound using `bindings:`
|
|
169
|
+
if (uiView.attr(attrName) && !bindings[name])
|
|
170
|
+
return `${attrName}='${uiView.attr(attrName)}'`;
|
|
171
|
+
const resolveName = bindings[name] || name;
|
|
172
|
+
// Pre-evaluate the expression for "@" bindings by enclosing in {{ }}
|
|
173
|
+
// some-attr="{{ ::$resolve.someResolveName }}"
|
|
174
|
+
if (type === "@")
|
|
175
|
+
return `${attrName}='{{${prefix}$resolve.${resolveName}}}'`;
|
|
176
|
+
// Wire "&" callbacks to resolves that return a callback function
|
|
177
|
+
// Get the result of the resolve (should be a function) and annotate it to get its arguments.
|
|
178
|
+
// some-attr="$resolve.someResolveResultName(foo, bar)"
|
|
179
|
+
if (type === "&") {
|
|
180
|
+
const res = context.getResolvable(resolveName);
|
|
181
|
+
const fn = res && res.data;
|
|
182
|
+
const args = (fn && services.$injector.annotate(fn)) || [];
|
|
183
|
+
// account for array style injection, i.e., ['foo', function(foo) {}]
|
|
184
|
+
const arrayIdxStr = isArray(fn) ? `[${fn.length - 1}]` : "";
|
|
185
|
+
return `${attrName}='$resolve.${resolveName}${arrayIdxStr}(${args.join(",")})'`;
|
|
186
|
+
}
|
|
187
|
+
// some-attr="::$resolve.someResolveName"
|
|
188
|
+
return `${attrName}='${prefix}$resolve.${resolveName}'`;
|
|
189
|
+
};
|
|
190
|
+
const attrs = getComponentBindings(component).map(attributeTpl).join(" ");
|
|
191
|
+
const kebobName = kebob(component);
|
|
192
|
+
return `<${kebobName} ${attrs}></${kebobName}>`;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Gets all the directive(s)' inputs ('@', '=', and '<') and outputs ('&')
|
|
196
|
+
function getComponentBindings(name) {
|
|
197
|
+
const cmpDefs = services.$injector.get(name + "Directive"); // could be multiple
|
|
198
|
+
if (!cmpDefs || !cmpDefs.length)
|
|
199
|
+
throw new Error(`Unable to find component named '${name}'`);
|
|
200
|
+
return cmpDefs.map(getBindings).reduce(unnestR, []);
|
|
201
|
+
}
|
|
202
|
+
// Given a directive definition, find its object input attributes
|
|
203
|
+
// Use different properties, depending on the type of directive (component, bindToController, normal)
|
|
204
|
+
const getBindings = (def) => {
|
|
205
|
+
if (isObject(def.bindToController))
|
|
206
|
+
return scopeBindings(def.bindToController);
|
|
207
|
+
return scopeBindings(def.scope);
|
|
208
|
+
};
|
|
209
|
+
// for ng 1.2 style, process the scope: { input: "=foo" }
|
|
210
|
+
// for ng 1.3 through ng 1.5, process the component's bindToController: { input: "=foo" } object
|
|
211
|
+
const scopeBindings = (bindingsObj) =>
|
|
212
|
+
Object.keys(bindingsObj || {})
|
|
213
|
+
// [ 'input', [ '=foo', '=', 'foo' ] ]
|
|
214
|
+
.map((key) => [key, /^([=<@&])[?]?(.*)/.exec(bindingsObj[key])])
|
|
215
|
+
// skip malformed values
|
|
216
|
+
.filter((tuple) => isDefined(tuple) && isArray(tuple[1]))
|
|
217
|
+
// { name: ('foo' || 'input'), type: '=' }
|
|
218
|
+
.map((tuple) => ({ name: tuple[1][2] || tuple[0], type: tuple[1][1] }));
|