Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1676)

Unified Diff: appengine/config_service/ui/bower_components/polymer/lib/mixins/template-stamp.html

Issue 2923973003: Added base template for config ui. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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>

Powered by Google App Engine
This is Rietveld 408576698