UNPKG

@polymer/polymer

Version:

The Polymer library makes it easy to create your own web components. Give your element some markup and properties, and then use it on a site. Polymer provides features like dynamic templates and data binding to reduce the amount of boilerplate you need to

177 lines (169 loc) 6.32 kB
/** @license Copyright (c) 2017 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */ import './boot.js'; /** * Our TrustedTypePolicy for HTML which is declared using the Polymer html * template tag function. * * That HTML is a developer-authored constant, and is parsed with innerHTML * before any untrusted expressions have been mixed in. Therefor it is * considered safe by construction. * * @type {!TrustedTypePolicy|undefined} */ const policy = window.trustedTypes && trustedTypes.createPolicy('polymer-html-literal', {createHTML: (s) => s}); /** * Class representing a static string value which can be used to filter * strings by asseting that they have been created via this class. The * `value` property returns the string passed to the constructor. */ class LiteralString { /** * @param {!ITemplateArray} strings Constant parts of tagged template literal * @param {!Array<*>} values Variable parts of tagged template literal */ constructor(strings, values) { assertValidTemplateStringParameters(strings, values); const string = values.reduce( (acc, v, idx) => acc + literalValue(v) + strings[idx + 1], strings[0]); /** @type {string} */ this.value = string.toString(); } /** * @return {string} LiteralString string value * @override */ toString() { return this.value; } } /** * @param {*} value Object to stringify into HTML * @return {string} HTML stringified form of `obj` */ function literalValue(value) { if (value instanceof LiteralString) { return /** @type {!LiteralString} */(value).value; } else { throw new Error( `non-literal value passed to Polymer's htmlLiteral function: ${value}` ); } } /** * @param {*} value Object to stringify into HTML * @return {string} HTML stringified form of `obj` */ function htmlValue(value) { if (value instanceof HTMLTemplateElement) { // This might be an mXSS risk – mainly in the case where this template // contains untrusted content that was believed to be sanitized. // However we can't just use the XMLSerializer here because it misencodes // `>` characters inside style tags. // For an example of an actual case that hit this encoding issue, // see b/198592167 return /** @type {!HTMLTemplateElement } */(value).innerHTML; } else if (value instanceof LiteralString) { return literalValue(value); } else { throw new Error( `non-template value passed to Polymer's html function: ${value}`); } } /** * A template literal tag that creates an HTML <template> element from the * contents of the string. * * This allows you to write a Polymer Template in JavaScript. * * Templates can be composed by interpolating `HTMLTemplateElement`s in * expressions in the JavaScript template literal. The nested template's * `innerHTML` is included in the containing template. The only other * values allowed in expressions are those returned from `htmlLiteral` * which ensures only literal values from JS source ever reach the HTML, to * guard against XSS risks. * * All other values are disallowed in expressions to help prevent XSS * attacks; however, `htmlLiteral` can be used to compose static * string values into templates. This is useful to compose strings into * places that do not accept html, like the css text of a `style` * element. * * Example: * * static get template() { * return html` * <style>:host{ content:"..." }</style> * <div class="shadowed">${this.partialTemplate}</div> * ${super.template} * `; * } * static get partialTemplate() { return html`<span>Partial!</span>`; } * * @param {!ITemplateArray} strings Constant parts of tagged template literal * @param {...*} values Variable parts of tagged template literal * @return {!HTMLTemplateElement} Constructed HTMLTemplateElement */ export const html = function html(strings, ...values) { assertValidTemplateStringParameters(strings, values); const template = /** @type {!HTMLTemplateElement} */ (document.createElement('template')); let value = values.reduce( (acc, v, idx) => acc + htmlValue(v) + strings[idx + 1], strings[0]); if (policy) { value = policy.createHTML(value); } template.innerHTML = value; return template; }; /** * @param {!ITemplateArray} strings Constant parts of tagged template literal * @param {!Array<*>} values Array of values from quasis */ const assertValidTemplateStringParameters = (strings, values) => { // Note: if/when https://github.com/tc39/proposal-array-is-template-object // is standardized, use that instead when available, as it can perform an // unforgable check (though of course, the function itself can be forged). if (!Array.isArray(strings) || !Array.isArray(strings.raw) || (values.length !== strings.length - 1)) { // This is either caused by a browser bug, a compiler bug, or someone // calling the html template tag function as a regular function. // throw new TypeError('Invalid call to the html template tag'); } }; /** * An html literal tag that can be used with `html` to compose. * a literal string. * * Example: * * static get template() { * return html` * <style> * :host { display: block; } * ${this.styleTemplate()} * </style> * <div class="shadowed">${staticValue}</div> * ${super.template} * `; * } * static get styleTemplate() { * return htmlLiteral`.shadowed { background: gray; }`; * } * * @param {!ITemplateArray} strings Constant parts of tagged template literal * @param {...*} values Variable parts of tagged template literal * @return {!LiteralString} Constructed literal string */ export const htmlLiteral = function(strings, ...values) { return new LiteralString(strings, values); };