| Index: appengine/config_service/ui/bower_components/polymer/lib/mixins/template-stamp.html
|
| diff --git a/appengine/config_service/ui/bower_components/polymer/lib/mixins/template-stamp.html b/appengine/config_service/ui/bower_components/polymer/lib/mixins/template-stamp.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..643740da620fb0050e6bbcb1138736d3ecea0848
|
| --- /dev/null
|
| +++ b/appengine/config_service/ui/bower_components/polymer/lib/mixins/template-stamp.html
|
| @@ -0,0 +1,480 @@
|
| +<!--
|
| +@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
|
| +-->
|
| +
|
| +<link rel="import" href="../utils/boot.html">
|
| +<link rel="import" href="../utils/mixin.html">
|
| +
|
| +<script>
|
| +(function() {
|
| +
|
| + 'use strict';
|
| +
|
| + // 1.x backwards-compatible auto-wrapper for template type extensions
|
| + // This is a clear layering violation and gives favored-nation status to
|
| + // dom-if and dom-repeat templates. This is a conceit we're choosing to keep
|
| + // a.) to ease 1.x backwards-compatibility due to loss of `is`, and
|
| + // b.) to maintain if/repeat capability in parser-constrained elements
|
| + // (e.g. table, select) in lieu of native CE type extensions without
|
| + // massive new invention in this space (e.g. directive system)
|
| + const templateExtensions = {
|
| + 'dom-if': true,
|
| + 'dom-repeat': true
|
| + };
|
| + function wrapTemplateExtension(node) {
|
| + let is = node.getAttribute('is');
|
| + if (is && templateExtensions[is]) {
|
| + let t = node;
|
| + t.removeAttribute('is');
|
| + node = t.ownerDocument.createElement(is);
|
| + t.parentNode.replaceChild(node, t);
|
| + node.appendChild(t);
|
| + while(t.attributes.length) {
|
| + node.setAttribute(t.attributes[0].name, t.attributes[0].value);
|
| + t.removeAttribute(t.attributes[0].name);
|
| + }
|
| + }
|
| + return node;
|
| + }
|
| +
|
| + function findTemplateNode(root, nodeInfo) {
|
| + // recursively ascend tree until we hit root
|
| + let parent = nodeInfo.parentInfo && findTemplateNode(root, nodeInfo.parentInfo);
|
| + // unwind the stack, returning the indexed node at each level
|
| + if (parent) {
|
| + // note: marginally faster than indexing via childNodes
|
| + // (http://jsperf.com/childnodes-lookup)
|
| + for (let n=parent.firstChild, i=0; n; n=n.nextSibling) {
|
| + if (nodeInfo.parentIndex === i++) {
|
| + return n;
|
| + }
|
| + }
|
| + } else {
|
| + return root;
|
| + }
|
| + }
|
| +
|
| + // construct `$` map (from id annotations)
|
| + function applyIdToMap(inst, map, node, nodeInfo) {
|
| + if (nodeInfo.id) {
|
| + map[nodeInfo.id] = node;
|
| + }
|
| + }
|
| +
|
| + // install event listeners (from event annotations)
|
| + function applyEventListener(inst, node, nodeInfo) {
|
| + if (nodeInfo.events && nodeInfo.events.length) {
|
| + for (let j=0, e$=nodeInfo.events, e; (j<e$.length) && (e=e$[j]); j++) {
|
| + inst._addMethodEventListenerToNode(node, e.name, e.value, inst);
|
| + }
|
| + }
|
| + }
|
| +
|
| + // push configuration references at configure time
|
| + function applyTemplateContent(inst, node, nodeInfo) {
|
| + if (nodeInfo.templateInfo) {
|
| + node._templateInfo = nodeInfo.templateInfo;
|
| + }
|
| + }
|
| +
|
| + function createNodeEventHandler(context, eventName, methodName) {
|
| + // Instances can optionally have a _methodHost which allows redirecting where
|
| + // to find methods. Currently used by `templatize`.
|
| + context = context._methodHost || context;
|
| + let handler = function(e) {
|
| + if (context[methodName]) {
|
| + context[methodName](e, e.detail);
|
| + } else {
|
| + console.warn('listener method `' + methodName + '` not defined');
|
| + }
|
| + };
|
| + return handler;
|
| + }
|
| +
|
| + /**
|
| + * Element mixin that provides basic template parsing and stamping, including
|
| + * the following template-related features for stamped templates:
|
| + *
|
| + * - Declarative event listeners (`on-eventname="listener"`)
|
| + * - Map of node id's to stamped node instances (`this.$.id`)
|
| + * - Nested template content caching/removal and re-installation (performance
|
| + * optimization)
|
| + *
|
| + * @polymerMixin
|
| + * @memberof Polymer
|
| + * @summary Element class mixin that provides basic template parsing and stamping
|
| + */
|
| + Polymer.TemplateStamp = Polymer.dedupingMixin(superClass => {
|
| +
|
| + /**
|
| + * @polymerMixinClass
|
| + * @implements {Polymer_TemplateStamp}
|
| + */
|
| + class TemplateStamp extends superClass {
|
| +
|
| + /**
|
| + * Scans a template to produce template metadata.
|
| + *
|
| + * Template-specific metadata are stored in the object returned, and node-
|
| + * specific metadata are stored in objects in its flattened `nodeInfoList`
|
| + * array. Only nodes in the template that were parsed as nodes of
|
| + * interest contain an object in `nodeInfoList`. Each `nodeInfo` object
|
| + * contains an `index` (`childNodes` index in parent) and optionally
|
| + * `parent`, which points to node info of its parent (including its index).
|
| + *
|
| + * The template metadata object returned from this method has the following
|
| + * structure (many fields optional):
|
| + *
|
| + * ```js
|
| + * {
|
| + * // Flattened list of node metadata (for nodes that generated metadata)
|
| + * nodeInfoList: [
|
| + * {
|
| + * // `id` attribute for any nodes with id's for generating `$` map
|
| + * id: {string},
|
| + * // `on-event="handler"` metadata
|
| + * events: [
|
| + * {
|
| + * name: {string}, // event name
|
| + * value: {string}, // handler method name
|
| + * }, ...
|
| + * ],
|
| + * // Notes when the template contained a `<slot>` for shady DOM
|
| + * // optimization purposes
|
| + * hasInsertionPoint: {boolean},
|
| + * // For nested `<template>`` nodes, nested template metadata
|
| + * templateInfo: {object}, // nested template metadata
|
| + * // Metadata to allow efficient retrieval of instanced node
|
| + * // corresponding to this metadata
|
| + * parentInfo: {number}, // reference to parent nodeInfo>
|
| + * parentIndex: {number}, // index in parent's `childNodes` collection
|
| + * infoIndex: {number}, // index of this `nodeInfo` in `templateInfo.nodeInfoList`
|
| + * },
|
| + * ...
|
| + * ],
|
| + * // When true, the template had the `strip-whitespace` attribute
|
| + * // or was nested in a template with that setting
|
| + * stripWhitespace: {boolean},
|
| + * // For nested templates, nested template content is moved into
|
| + * // a document fragment stored here; this is an optimization to
|
| + * // avoid the cost of nested template cloning
|
| + * content: {DocumentFragment}
|
| + * }
|
| + * ```
|
| + *
|
| + * This method kicks off a recursive treewalk as follows:
|
| + *
|
| + * ```
|
| + * _parseTemplate <---------------------+
|
| + * _parseTemplateContent |
|
| + * _parseTemplateNode <------------|--+
|
| + * _parseTemplateNestedTemplate --+ |
|
| + * _parseTemplateChildNodes ---------+
|
| + * _parseTemplateNodeAttributes
|
| + * _parseTemplateNodeAttribute
|
| + *
|
| + * ```
|
| + *
|
| + * These methods may be overridden to add custom metadata about templates
|
| + * to either `templateInfo` or `nodeInfo`.
|
| + *
|
| + * Note that this method may be destructive to the template, in that
|
| + * e.g. event annotations may be removed after being noted in the
|
| + * template metadata.
|
| + *
|
| + * @param {HTMLTemplateElement} template Template to parse
|
| + * @param {Object=} outerTemplateInfo Template metadata from the outer
|
| + * template, for parsing nested templates
|
| + * @return {Object} Parsed template metadata
|
| + */
|
| + static _parseTemplate(template, outerTemplateInfo) {
|
| + // since a template may be re-used, memo-ize metadata
|
| + if (!template._templateInfo) {
|
| + let templateInfo = template._templateInfo = {};
|
| + templateInfo.nodeInfoList = [];
|
| + templateInfo.stripWhiteSpace =
|
| + (outerTemplateInfo && outerTemplateInfo.stripWhiteSpace) ||
|
| + template.hasAttribute('strip-whitespace');
|
| + this._parseTemplateContent(template, templateInfo, {parent: null});
|
| + }
|
| + return template._templateInfo;
|
| + }
|
| +
|
| + static _parseTemplateContent(template, templateInfo, nodeInfo) {
|
| + return this._parseTemplateNode(template.content, templateInfo, nodeInfo);
|
| + }
|
| +
|
| + /**
|
| + * Parses template node and adds template and node metadata based on
|
| + * the current node, and its `childNodes` and `attributes`.
|
| + *
|
| + * This method may be overridden to add custom node or template specific
|
| + * metadata based on this node.
|
| + *
|
| + * @param {Node} node Node to parse
|
| + * @param {Object} templateInfo Template metadata for current template
|
| + * @param {Object} nodeInfo Node metadata for current template.
|
| + * @return {boolean} `true` if the visited node added node-specific
|
| + * metadata to `nodeInfo`
|
| + */
|
| + static _parseTemplateNode(node, templateInfo, nodeInfo) {
|
| + let noted;
|
| + if (node.localName == 'template' && !node.hasAttribute('preserve-content')) {
|
| + noted = this._parseTemplateNestedTemplate(node, templateInfo, nodeInfo) || noted;
|
| + } else if (node.localName === 'slot') {
|
| + // For ShadyDom optimization, indicating there is an insertion point
|
| + templateInfo.hasInsertionPoint = true;
|
| + }
|
| + if (node.firstChild) {
|
| + noted = this._parseTemplateChildNodes(node, templateInfo, nodeInfo) || noted;
|
| + }
|
| + if (node.hasAttributes && node.hasAttributes()) {
|
| + noted = this._parseTemplateNodeAttributes(node, templateInfo, nodeInfo) || noted;
|
| + }
|
| + return noted;
|
| + }
|
| +
|
| + /**
|
| + * Parses template child nodes for the given root node.
|
| + *
|
| + * This method also wraps whitelisted legacy template extensions
|
| + * (`is="dom-if"` and `is="dom-repeat"`) with their equivalent element
|
| + * wrappers, collapses text nodes, and strips whitespace from the template
|
| + * if the `templateInfo.stripWhitespace` setting was provided.
|
| + *
|
| + * @param {Node} root Root node whose `childNodes` will be parsed
|
| + * @param {Object} templateInfo Template metadata for current template
|
| + * @param {Object} nodeInfo Node metadata for current template.
|
| + */
|
| + static _parseTemplateChildNodes(root, templateInfo, nodeInfo) {
|
| + for (let node=root.firstChild, parentIndex=0, next; node; node=next) {
|
| + // Wrap templates
|
| + if (node.localName == 'template') {
|
| + node = wrapTemplateExtension(node);
|
| + }
|
| + // collapse adjacent textNodes: fixes an IE issue that can cause
|
| + // text nodes to be inexplicably split =(
|
| + // note that root.normalize() should work but does not so we do this
|
| + // manually.
|
| + next = node.nextSibling;
|
| + if (node.nodeType === Node.TEXT_NODE) {
|
| + let n = next;
|
| + while (n && (n.nodeType === Node.TEXT_NODE)) {
|
| + node.textContent += n.textContent;
|
| + next = n.nextSibling;
|
| + root.removeChild(n);
|
| + n = next;
|
| + }
|
| + // optionally strip whitespace
|
| + if (templateInfo.stripWhiteSpace && !node.textContent.trim()) {
|
| + root.removeChild(node);
|
| + continue;
|
| + }
|
| + }
|
| + let childInfo = { parentIndex, parentInfo: nodeInfo };
|
| + if (this._parseTemplateNode(node, templateInfo, childInfo)) {
|
| + childInfo.infoIndex = templateInfo.nodeInfoList.push(childInfo) - 1;
|
| + }
|
| + // Increment if not removed
|
| + if (node.parentNode) {
|
| + parentIndex++;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parses template content for the given nested `<template>`.
|
| + *
|
| + * Nested template info is stored as `templateInfo` in the current node's
|
| + * `nodeInfo`. `template.content` is removed and stored in `templateInfo`.
|
| + * It will then be the responsibility of the host to set it back to the
|
| + * template and for users stamping nested templates to use the
|
| + * `_contentForTemplate` method to retrieve the content for this template
|
| + * (an optimization to avoid the cost of cloning nested template content).
|
| + *
|
| + * @param {HTMLTemplateElement} node Node to parse (a <template>)
|
| + * @param {Object} outerTemplateInfo Template metadata for current template
|
| + * that includes the template `node`
|
| + * @param {Object} nodeInfo Node metadata for current template.
|
| + * @return {boolean} `true` if the visited node added node-specific
|
| + * metadata to `nodeInfo`
|
| + */
|
| + static _parseTemplateNestedTemplate(node, outerTemplateInfo, nodeInfo) {
|
| + let templateInfo = this._parseTemplate(node, outerTemplateInfo);
|
| + let content = templateInfo.content =
|
| + node.content.ownerDocument.createDocumentFragment();
|
| + content.appendChild(node.content);
|
| + nodeInfo.templateInfo = templateInfo;
|
| + return true;
|
| + }
|
| +
|
| + /**
|
| + * Parses template node attributes and adds node metadata to `nodeInfo`
|
| + * for nodes of interest.
|
| + *
|
| + * @param {Node} node Node to parse
|
| + * @param {Object} templateInfo Template metadata for current template
|
| + * @param {Object} nodeInfo Node metadata for current template.
|
| + * @return {boolean} `true` if the visited node added node-specific
|
| + * metadata to `nodeInfo`
|
| + */
|
| + static _parseTemplateNodeAttributes(node, templateInfo, nodeInfo) {
|
| + // Make copy of original attribute list, since the order may change
|
| + // as attributes are added and removed
|
| + let noted;
|
| + let attrs = Array.from(node.attributes);
|
| + for (let i=attrs.length-1, a; (a=attrs[i]); i--) {
|
| + noted = this._parseTemplateNodeAttribute(node, templateInfo, nodeInfo, a.name, a.value) || noted;
|
| + }
|
| + return noted;
|
| + }
|
| +
|
| + /**
|
| + * Parses a single template node attribute and adds node metadata to
|
| + * `nodeInfo` for attributes of interest.
|
| + *
|
| + * This implementation adds metadata for `on-event="handler"` attributes
|
| + * and `id` attributes.
|
| + *
|
| + * @param {Node} node Node to parse
|
| + * @param {Object} templateInfo Template metadata for current template
|
| + * @param {Object} nodeInfo Node metadata for current template.
|
| + * @param {string} name Attribute name
|
| + * @param {*} value Attribute value
|
| + * @return {boolean} `true` if the visited node added node-specific
|
| + * metadata to `nodeInfo`
|
| + */
|
| + static _parseTemplateNodeAttribute(node, templateInfo, nodeInfo, name, value) {
|
| + // events (on-*)
|
| + if (name.slice(0, 3) === 'on-') {
|
| + node.removeAttribute(name);
|
| + nodeInfo.events = nodeInfo.events || [];
|
| + nodeInfo.events.push({
|
| + name: name.slice(3),
|
| + value
|
| + });
|
| + return true;
|
| + }
|
| + // static id
|
| + else if (name === 'id') {
|
| + nodeInfo.id = value;
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Returns the `content` document fragment for a given template.
|
| + *
|
| + * For nested templates, Polymer performs an optimization to cache nested
|
| + * template content to avoid the cost of cloning deeply nested templates.
|
| + * This method retrieves the cached content for a given template.
|
| + *
|
| + * @param {HTMLTemplateElement} template Template to retrieve `content` for
|
| + * @return {DocumentFragment} Content fragment
|
| + */
|
| + static _contentForTemplate(template) {
|
| + let templateInfo = template.__templateInfo;
|
| + return (templateInfo && templateInfo.content) || template.content;
|
| + }
|
| +
|
| + /**
|
| + * Clones the provided template content and returns a document fragment
|
| + * containing the cloned dom.
|
| + *
|
| + * The template is parsed (once and memoized) using this library's
|
| + * template parsing features, and provides the following value-added
|
| + * features:
|
| + * * Adds declarative event listeners for `on-event="handler"` attributes
|
| + * * Generates an "id map" for all nodes with id's under `$` on returned
|
| + * document fragment
|
| + * * Passes template info including `content` back to templates as
|
| + * `_templateInfo` (a performance optimization to avoid deep template
|
| + * cloning)
|
| + *
|
| + * Note that the memoized template parsing process is destructive to the
|
| + * template: attributes for bindings and declarative event listeners are
|
| + * removed after being noted in notes, and any nested `<template>.content`
|
| + * is removed and stored in notes as well.
|
| + *
|
| + * @param {HTMLTemplateElement} template Template to stamp
|
| + * @return {DocumentFragment} Cloned template content
|
| + */
|
| + _stampTemplate(template) {
|
| + // Polyfill support: bootstrap the template if it has not already been
|
| + if (template && !template.content &&
|
| + window.HTMLTemplateElement && HTMLTemplateElement.decorate) {
|
| + HTMLTemplateElement.decorate(template);
|
| + }
|
| + let templateInfo = this.constructor._parseTemplate(template);
|
| + let nodeInfo = templateInfo.nodeInfoList;
|
| + let content = templateInfo.content || template.content;
|
| + let dom = document.importNode(content, true);
|
| + // NOTE: ShadyDom optimization indicating there is an insertion point
|
| + dom.__noInsertionPoint = !templateInfo.hasInsertionPoint;
|
| + let nodes = dom.nodeList = new Array(nodeInfo.length);
|
| + dom.$ = {};
|
| + for (let i=0, l=nodeInfo.length, info; (i<l) && (info=nodeInfo[i]); i++) {
|
| + let node = nodes[i] = findTemplateNode(dom, info);
|
| + applyIdToMap(this, dom.$, node, info);
|
| + applyTemplateContent(this, node, info);
|
| + applyEventListener(this, node, info);
|
| + }
|
| + return dom;
|
| + }
|
| +
|
| + /**
|
| + * Adds an event listener by method name for the event provided.
|
| + *
|
| + * This method generates a handler function that looks up the method
|
| + * name at handling time.
|
| + *
|
| + * @param {Node} node Node to add listener on
|
| + * @param {string} eventName Name of event
|
| + * @param {string} methodName Name of method
|
| + * @param {*=} context Context the method will be called on (defaults
|
| + * to `node`)
|
| + * @return {Function} Generated handler function
|
| + */
|
| + _addMethodEventListenerToNode(node, eventName, methodName, context) {
|
| + context = context || node;
|
| + let handler = createNodeEventHandler(context, eventName, methodName);
|
| + this._addEventListenerToNode(node, eventName, handler);
|
| + return handler;
|
| + }
|
| +
|
| + /**
|
| + * Override point for adding custom or simulated event handling.
|
| + *
|
| + * @param {Node} node Node to add event listener to
|
| + * @param {string} eventName Name of event
|
| + * @param {Function} handler Listener function to add
|
| + */
|
| + _addEventListenerToNode(node, eventName, handler) {
|
| + node.addEventListener(eventName, handler);
|
| + }
|
| +
|
| + /**
|
| + * Override point for adding custom or simulated event handling.
|
| + *
|
| + * @param {Node} node Node to remove event listener from
|
| + * @param {string} eventName Name of event
|
| + * @param {Function} handler Listener function to remove
|
| + */
|
| + _removeEventListenerFromNode(node, eventName, handler) {
|
| + node.removeEventListener(eventName, handler);
|
| + }
|
| +
|
| + }
|
| +
|
| + return TemplateStamp;
|
| +
|
| + });
|
| +
|
| +})();
|
| +</script>
|
|
|