UNPKG

10.3 kBJavaScriptView Raw
1/** @publicapi @module view */ /** */
2import { ng as angular } from './angular';
3import { isArray, isDefined, isFunction, isObject, services, tail, kebobString, unnestR, Resolvable, } from '@uirouter/core';
4/**
5 * Service which manages loading of templates from a ViewConfig.
6 */
7var TemplateFactory = /** @class */ (function () {
8 function TemplateFactory() {
9 var _this = this;
10 /** @hidden */ this._useHttp = angular.version.minor < 3;
11 /** @hidden */ this.$get = [
12 '$http',
13 '$templateCache',
14 '$injector',
15 function ($http, $templateCache, $injector) {
16 _this.$templateRequest = $injector.has && $injector.has('$templateRequest') && $injector.get('$templateRequest');
17 _this.$http = $http;
18 _this.$templateCache = $templateCache;
19 return _this;
20 },
21 ];
22 }
23 /** @hidden */
24 TemplateFactory.prototype.useHttpService = function (value) {
25 this._useHttp = value;
26 };
27 /**
28 * Creates a template from a configuration object.
29 *
30 * @param config Configuration object for which to load a template.
31 * The following properties are search in the specified order, and the first one
32 * that is defined is used to create the template:
33 *
34 * @param params Parameters to pass to the template function.
35 * @param context The resolve context associated with the template's view
36 *
37 * @return {string|object} The template html as a string, or a promise for
38 * that string,or `null` if no template is configured.
39 */
40 TemplateFactory.prototype.fromConfig = function (config, params, context) {
41 var defaultTemplate = '<ui-view></ui-view>';
42 var asTemplate = function (result) { return services.$q.when(result).then(function (str) { return ({ template: str }); }); };
43 var asComponent = function (result) { return services.$q.when(result).then(function (str) { return ({ component: str }); }); };
44 return isDefined(config.template)
45 ? asTemplate(this.fromString(config.template, params))
46 : isDefined(config.templateUrl)
47 ? asTemplate(this.fromUrl(config.templateUrl, params))
48 : isDefined(config.templateProvider)
49 ? asTemplate(this.fromProvider(config.templateProvider, params, context))
50 : isDefined(config.component)
51 ? asComponent(config.component)
52 : isDefined(config.componentProvider)
53 ? asComponent(this.fromComponentProvider(config.componentProvider, params, context))
54 : asTemplate(defaultTemplate);
55 };
56 /**
57 * Creates a template from a string or a function returning a string.
58 *
59 * @param template html template as a string or function that returns an html template as a string.
60 * @param params Parameters to pass to the template function.
61 *
62 * @return {string|object} The template html as a string, or a promise for that
63 * string.
64 */
65 TemplateFactory.prototype.fromString = function (template, params) {
66 return isFunction(template) ? template(params) : template;
67 };
68 /**
69 * Loads a template from the a URL via `$http` and `$templateCache`.
70 *
71 * @param {string|Function} url url of the template to load, or a function
72 * that returns a url.
73 * @param {Object} params Parameters to pass to the url function.
74 * @return {string|Promise.<string>} The template html as a string, or a promise
75 * for that string.
76 */
77 TemplateFactory.prototype.fromUrl = function (url, params) {
78 if (isFunction(url))
79 url = url(params);
80 if (url == null)
81 return null;
82 if (this._useHttp) {
83 return this.$http
84 .get(url, { cache: this.$templateCache, headers: { Accept: 'text/html' } })
85 .then(function (response) {
86 return response.data;
87 });
88 }
89 return this.$templateRequest(url);
90 };
91 /**
92 * Creates a template by invoking an injectable provider function.
93 *
94 * @param provider Function to invoke via `locals`
95 * @param {Function} injectFn a function used to invoke the template provider
96 * @return {string|Promise.<string>} The template html as a string, or a promise
97 * for that string.
98 */
99 TemplateFactory.prototype.fromProvider = function (provider, params, context) {
100 var deps = services.$injector.annotate(provider);
101 var providerFn = isArray(provider) ? tail(provider) : provider;
102 var resolvable = new Resolvable('', providerFn, deps);
103 return resolvable.get(context);
104 };
105 /**
106 * Creates a component's template by invoking an injectable provider function.
107 *
108 * @param provider Function to invoke via `locals`
109 * @param {Function} injectFn a function used to invoke the template provider
110 * @return {string} The template html as a string: "<component-name input1='::$resolve.foo'></component-name>".
111 */
112 TemplateFactory.prototype.fromComponentProvider = function (provider, params, context) {
113 var deps = services.$injector.annotate(provider);
114 var providerFn = isArray(provider) ? tail(provider) : provider;
115 var resolvable = new Resolvable('', providerFn, deps);
116 return resolvable.get(context);
117 };
118 /**
119 * Creates a template from a component's name
120 *
121 * This implements route-to-component.
122 * It works by retrieving the component (directive) metadata from the injector.
123 * It analyses the component's bindings, then constructs a template that instantiates the component.
124 * The template wires input and output bindings to resolves or from the parent component.
125 *
126 * @param uiView {object} The parent ui-view (for binding outputs to callbacks)
127 * @param context The ResolveContext (for binding outputs to callbacks returned from resolves)
128 * @param component {string} Component's name in camel case.
129 * @param bindings An object defining the component's bindings: {foo: '<'}
130 * @return {string} The template as a string: "<component-name input1='::$resolve.foo'></component-name>".
131 */
132 TemplateFactory.prototype.makeComponentTemplate = function (uiView, context, component, bindings) {
133 bindings = bindings || {};
134 // Bind once prefix
135 var prefix = angular.version.minor >= 3 ? '::' : '';
136 // Convert to kebob name. Add x- prefix if the string starts with `x-` or `data-`
137 var kebob = function (camelCase) {
138 var kebobed = kebobString(camelCase);
139 return /^(x|data)-/.exec(kebobed) ? "x-" + kebobed : kebobed;
140 };
141 var attributeTpl = function (input) {
142 var name = input.name, type = input.type;
143 var attrName = kebob(name);
144 // If the ui-view has an attribute which matches a binding on the routed component
145 // then pass that attribute through to the routed component template.
146 // Prefer ui-view wired mappings to resolve data, unless the resolve was explicitly bound using `bindings:`
147 if (uiView.attr(attrName) && !bindings[name])
148 return attrName + "='" + uiView.attr(attrName) + "'";
149 var resolveName = bindings[name] || name;
150 // Pre-evaluate the expression for "@" bindings by enclosing in {{ }}
151 // some-attr="{{ ::$resolve.someResolveName }}"
152 if (type === '@')
153 return attrName + "='{{" + prefix + "$resolve." + resolveName + "}}'";
154 // Wire "&" callbacks to resolves that return a callback function
155 // Get the result of the resolve (should be a function) and annotate it to get its arguments.
156 // some-attr="$resolve.someResolveResultName(foo, bar)"
157 if (type === '&') {
158 var res = context.getResolvable(resolveName);
159 var fn = res && res.data;
160 var args = (fn && services.$injector.annotate(fn)) || [];
161 // account for array style injection, i.e., ['foo', function(foo) {}]
162 var arrayIdxStr = isArray(fn) ? "[" + (fn.length - 1) + "]" : '';
163 return attrName + "='$resolve." + resolveName + arrayIdxStr + "(" + args.join(',') + ")'";
164 }
165 // some-attr="::$resolve.someResolveName"
166 return attrName + "='" + prefix + "$resolve." + resolveName + "'";
167 };
168 var attrs = getComponentBindings(component).map(attributeTpl).join(' ');
169 var kebobName = kebob(component);
170 return "<" + kebobName + " " + attrs + "></" + kebobName + ">";
171 };
172 return TemplateFactory;
173}());
174export { TemplateFactory };
175// Gets all the directive(s)' inputs ('@', '=', and '<') and outputs ('&')
176function getComponentBindings(name) {
177 var cmpDefs = services.$injector.get(name + 'Directive'); // could be multiple
178 if (!cmpDefs || !cmpDefs.length)
179 throw new Error("Unable to find component named '" + name + "'");
180 return cmpDefs.map(getBindings).reduce(unnestR, []);
181}
182// Given a directive definition, find its object input attributes
183// Use different properties, depending on the type of directive (component, bindToController, normal)
184var getBindings = function (def) {
185 if (isObject(def.bindToController))
186 return scopeBindings(def.bindToController);
187 return scopeBindings(def.scope);
188};
189// for ng 1.2 style, process the scope: { input: "=foo" }
190// for ng 1.3 through ng 1.5, process the component's bindToController: { input: "=foo" } object
191var scopeBindings = function (bindingsObj) {
192 return Object.keys(bindingsObj || {})
193 // [ 'input', [ '=foo', '=', 'foo' ] ]
194 .map(function (key) { return [key, /^([=<@&])[?]?(.*)/.exec(bindingsObj[key])]; })
195 // skip malformed values
196 .filter(function (tuple) { return isDefined(tuple) && isArray(tuple[1]); })
197 // { name: ('foo' || 'input'), type: '=' }
198 .map(function (tuple) { return ({ name: tuple[1][2] || tuple[0], type: tuple[1][1] }); });
199};
200//# sourceMappingURL=templateFactory.js.map
\No newline at end of file