templateFactory.js 9.9 KB

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