| Index: appengine/config_service/ui/bower_components/polymer/lib/utils/templatize.html
|
| diff --git a/appengine/config_service/ui/bower_components/polymer/lib/utils/templatize.html b/appengine/config_service/ui/bower_components/polymer/lib/utils/templatize.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..31f792ec55dfb8010199f03c755980a52922b163
|
| --- /dev/null
|
| +++ b/appengine/config_service/ui/bower_components/polymer/lib/utils/templatize.html
|
| @@ -0,0 +1,473 @@
|
| +<!--
|
| +@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="boot.html">
|
| +<link rel="import" href="../mixins/property-effects.html">
|
| +<link rel="import" href="../mixins/mutable-data.html">
|
| +
|
| +<script>
|
| + (function() {
|
| + 'use strict';
|
| +
|
| + // Base class for HTMLTemplateElement extension that has property effects
|
| + // machinery for propagating host properties to children. This is an ES5
|
| + // class only because Babel (incorrectly) requires super() in the class
|
| + // constructor even though no `this` is used and it returns an instance.
|
| + let newInstance = null;
|
| + function HTMLTemplateElementExtension() { return newInstance; }
|
| + HTMLTemplateElementExtension.prototype = Object.create(HTMLTemplateElement.prototype, {
|
| + constructor: {
|
| + value: HTMLTemplateElementExtension,
|
| + writable: true
|
| + }
|
| + });
|
| + const DataTemplate = Polymer.PropertyEffects(HTMLTemplateElementExtension);
|
| + const MutableDataTemplate = Polymer.MutableData(DataTemplate);
|
| +
|
| + // Applies a DataTemplate subclass to a <template> instance
|
| + function upgradeTemplate(template, constructor) {
|
| + newInstance = template;
|
| + Object.setPrototypeOf(template, constructor.prototype);
|
| + new constructor();
|
| + newInstance = null;
|
| + }
|
| +
|
| + // Base class for TemplateInstance's
|
| + /**
|
| + * @constructor
|
| + * @implements {Polymer_PropertyEffects}
|
| + */
|
| + const base = Polymer.PropertyEffects(class {});
|
| + class TemplateInstanceBase extends base {
|
| + constructor(props) {
|
| + super();
|
| + this._configureProperties(props);
|
| + this.root = this._stampTemplate(this.__dataHost);
|
| + // Save list of stamped children
|
| + let children = this.children = [];
|
| + for (let n = this.root.firstChild; n; n=n.nextSibling) {
|
| + children.push(n);
|
| + n.__templatizeInstance = this;
|
| + }
|
| + if (this.__templatizeOwner.__hideTemplateChildren__) {
|
| + this._showHideChildren(true);
|
| + }
|
| + // Flush props only when props are passed if instance props exist
|
| + // or when there isn't instance props.
|
| + let options = this.__templatizeOptions;
|
| + if ((props && options.instanceProps) || !options.instanceProps) {
|
| + this._enableProperties();
|
| + }
|
| + }
|
| + /**
|
| + * Configure the given `props` by calling `_setPendingProperty`. Also
|
| + * sets any properties stored in `__hostProps`.
|
| + * @private
|
| + * @param {Object} props Object of property name-value pairs to set.
|
| + */
|
| + _configureProperties(props) {
|
| + let options = this.__templatizeOptions;
|
| + if (props) {
|
| + for (let iprop in options.instanceProps) {
|
| + if (iprop in props) {
|
| + this._setPendingProperty(iprop, props[iprop]);
|
| + }
|
| + }
|
| + }
|
| + for (let hprop in this.__hostProps) {
|
| + this._setPendingProperty(hprop, this.__dataHost['_host_' + hprop]);
|
| + }
|
| + }
|
| + /**
|
| + * Forwards a host property to this instance. This method should be
|
| + * called on instances from the `options.forwardHostProp` callback
|
| + * to propagate changes of host properties to each instance.
|
| + *
|
| + * Note this method enqueues the change, which are flushed as a batch.
|
| + *
|
| + * @param {string} prop Property or path name
|
| + * @param {*} value Value of the property to forward
|
| + */
|
| + forwardHostProp(prop, value) {
|
| + if (this._setPendingPropertyOrPath(prop, value, false, true)) {
|
| + this.__dataHost._enqueueClient(this);
|
| + }
|
| + }
|
| + /**
|
| + * @override
|
| + */
|
| + _addEventListenerToNode(node, eventName, handler) {
|
| + if (this._methodHost && this.__templatizeOptions.parentModel) {
|
| + // If this instance should be considered a parent model, decorate
|
| + // events this template instance as `model`
|
| + this._methodHost._addEventListenerToNode(node, eventName, (e) => {
|
| + e.model = this;
|
| + handler(e);
|
| + });
|
| + } else {
|
| + // Otherwise delegate to the template's host (which could be)
|
| + // another template instance
|
| + let templateHost = this.__dataHost.__dataHost;
|
| + if (templateHost) {
|
| + templateHost._addEventListenerToNode(node, eventName, handler);
|
| + }
|
| + }
|
| + }
|
| + /**
|
| + * Shows or hides the template instance top level child elements. For
|
| + * text nodes, `textContent` is removed while "hidden" and replaced when
|
| + * "shown."
|
| + * @param {boolean} hide Set to true to hide the children;
|
| + * set to false to show them.
|
| + * @protected
|
| + */
|
| + _showHideChildren(hide) {
|
| + let c = this.children;
|
| + for (let i=0; i<c.length; i++) {
|
| + let n = c[i];
|
| + // Ignore non-changes
|
| + if (Boolean(hide) != Boolean(n.__hideTemplateChildren__)) {
|
| + if (n.nodeType === Node.TEXT_NODE) {
|
| + if (hide) {
|
| + n.__polymerTextContent__ = n.textContent;
|
| + n.textContent = '';
|
| + } else {
|
| + n.textContent = n.__polymerTextContent__;
|
| + }
|
| + } else if (n.style) {
|
| + if (hide) {
|
| + n.__polymerDisplay__ = n.style.display;
|
| + n.style.display = 'none';
|
| + } else {
|
| + n.style.display = n.__polymerDisplay__;
|
| + }
|
| + }
|
| + }
|
| + n.__hideTemplateChildren__ = hide;
|
| + if (n._showHideChildren) {
|
| + n._showHideChildren(hide);
|
| + }
|
| + }
|
| + }
|
| + /**
|
| + * Overrides default property-effects implementation to intercept
|
| + * textContent bindings while children are "hidden" and cache in
|
| + * private storage for later retrieval.
|
| + *
|
| + * @override
|
| + */
|
| + _setUnmanagedPropertyToNode(node, prop, value) {
|
| + if (node.__hideTemplateChildren__ &&
|
| + node.nodeType == Node.TEXT_NODE && prop == 'textContent') {
|
| + node.__polymerTextContent__ = value;
|
| + } else {
|
| + super._setUnmanagedPropertyToNode(node, prop, value);
|
| + }
|
| + }
|
| + /**
|
| + * Find the parent model of this template instance. The parent model
|
| + * is either another templatize instance that had option `parentModel: true`,
|
| + * or else the host element.
|
| + *
|
| + * @return {Polymer.PropertyEffectsInterface} The parent model of this instance
|
| + */
|
| + get parentModel() {
|
| + let model = this.__parentModel;
|
| + if (!model) {
|
| + let options;
|
| + model = this
|
| + do {
|
| + // A template instance's `__dataHost` is a <template>
|
| + // `model.__dataHost.__dataHost` is the template's host
|
| + model = model.__dataHost.__dataHost;
|
| + } while ((options = model.__templatizeOptions) && !options.parentModel)
|
| + this.__parentModel = model;
|
| + }
|
| + return model;
|
| + }
|
| + }
|
| +
|
| + const MutableTemplateInstanceBase = Polymer.MutableData(TemplateInstanceBase);
|
| +
|
| + function findMethodHost(template) {
|
| + // Technically this should be the owner of the outermost template.
|
| + // In shadow dom, this is always getRootNode().host, but we can
|
| + // approximate this via cooperation with our dataHost always setting
|
| + // `_methodHost` as long as there were bindings (or id's) on this
|
| + // instance causing it to get a dataHost.
|
| + let templateHost = template.__dataHost;
|
| + return templateHost && templateHost._methodHost || templateHost;
|
| + }
|
| +
|
| + function createTemplatizerClass(template, templateInfo, options) {
|
| + // Anonymous class created by the templatize
|
| + /**
|
| + * @unrestricted
|
| + */
|
| + let base = options.mutableData ?
|
| + MutableTemplateInstanceBase : TemplateInstanceBase;
|
| + let klass = class extends base { }
|
| + klass.prototype.__templatizeOptions = options;
|
| + klass.prototype._bindTemplate(template);
|
| + addNotifyEffects(klass, template, templateInfo, options);
|
| + return klass;
|
| + }
|
| +
|
| + function addPropagateEffects(template, templateInfo, options) {
|
| + let userForwardHostProp = options.forwardHostProp;
|
| + if (userForwardHostProp) {
|
| + // Provide data API and property effects on memoized template class
|
| + let klass = templateInfo.templatizeTemplateClass;
|
| + if (!klass) {
|
| + let base = options.mutableData ? MutableDataTemplate : DataTemplate;
|
| + klass = templateInfo.templatizeTemplateClass =
|
| + class TemplatizedTemplate extends base {}
|
| + // Add template - >instances effects
|
| + // and host <- template effects
|
| + let hostProps = templateInfo.hostProps;
|
| + for (let prop in hostProps) {
|
| + klass.prototype._addPropertyEffect('_host_' + prop,
|
| + klass.prototype.PROPERTY_EFFECT_TYPES.PROPAGATE,
|
| + {fn: createForwardHostPropEffect(prop, userForwardHostProp)});
|
| + klass.prototype._createNotifyingProperty('_host_' + prop);
|
| + }
|
| + }
|
| + upgradeTemplate(template, klass);
|
| + // Mix any pre-bound data into __data; no need to flush this to
|
| + // instances since they pull from the template at instance-time
|
| + if (template.__dataProto) {
|
| + // Note, generally `__dataProto` could be chained, but it's guaranteed
|
| + // to not be since this is a vanilla template we just added effects to
|
| + Object.assign(template.__data, template.__dataProto);
|
| + }
|
| + // Clear any pending data for performance
|
| + template.__dataTemp = {};
|
| + template.__dataPending = null;
|
| + template.__dataOld = null;
|
| + template._enableProperties();
|
| + }
|
| + }
|
| +
|
| + function createForwardHostPropEffect(hostProp, userForwardHostProp) {
|
| + return function forwardHostProp(template, prop, props) {
|
| + userForwardHostProp.call(template.__templatizeOwner,
|
| + prop.substring('_host_'.length), props[prop]);
|
| + }
|
| + }
|
| +
|
| + function addNotifyEffects(klass, template, templateInfo, options) {
|
| + let hostProps = templateInfo.hostProps || {};
|
| + for (let iprop in options.instanceProps) {
|
| + delete hostProps[iprop];
|
| + let userNotifyInstanceProp = options.notifyInstanceProp;
|
| + if (userNotifyInstanceProp) {
|
| + klass.prototype._addPropertyEffect(iprop,
|
| + klass.prototype.PROPERTY_EFFECT_TYPES.NOTIFY,
|
| + {fn: createNotifyInstancePropEffect(iprop, userNotifyInstanceProp)});
|
| + }
|
| + }
|
| + if (options.forwardHostProp && template.__dataHost) {
|
| + for (let hprop in hostProps) {
|
| + klass.prototype._addPropertyEffect(hprop,
|
| + klass.prototype.PROPERTY_EFFECT_TYPES.NOTIFY,
|
| + {fn: createNotifyHostPropEffect()})
|
| + }
|
| + }
|
| + }
|
| +
|
| + function createNotifyInstancePropEffect(instProp, userNotifyInstanceProp) {
|
| + return function notifyInstanceProp(inst, prop, props) {
|
| + userNotifyInstanceProp.call(inst.__templatizeOwner,
|
| + inst, prop, props[prop]);
|
| + }
|
| + }
|
| +
|
| + function createNotifyHostPropEffect() {
|
| + return function notifyHostProp(inst, prop, props) {
|
| + inst.__dataHost._setPendingPropertyOrPath('_host_' + prop, props[prop], true, true);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Module for preparing and stamping instances of templates that utilize
|
| + * Polymer's data-binding and declarative event listener features.
|
| + *
|
| + * Example:
|
| + *
|
| + * // Get a template from somewhere, e.g. light DOM
|
| + * let template = this.querySelector('template');
|
| + * // Prepare the template
|
| + * let TemplateClass = Polymer.Templatize.templatize(template);
|
| + * // Instance the template with an initial data model
|
| + * let instance = new TemplateClass({myProp: 'initial'});
|
| + * // Insert the instance's DOM somewhere, e.g. element's shadow DOM
|
| + * this.shadowRoot.appendChild(instance.root);
|
| + * // Changing a property on the instance will propagate to bindings
|
| + * // in the template
|
| + * instance.myProp = 'new value';
|
| + *
|
| + * The `options` dictionary passed to `templatize` allows for customizing
|
| + * features of the generated template class, including how outer-scope host
|
| + * properties should be forwarded into template instances, how any instance
|
| + * properties added into the template's scope should be notified out to
|
| + * the host, and whether the instance should be decorated as a "parent model"
|
| + * of any event handlers.
|
| + *
|
| + * // Customze property forwarding and event model decoration
|
| + * let TemplateClass = Polymer.Tempaltize.templatize(template, this, {
|
| + * parentModel: true,
|
| + * instanceProps: {...},
|
| + * forwardHostProp(property, value) {...},
|
| + * notifyInstanceProp(instance, property, value) {...},
|
| + * });
|
| + *
|
| + *
|
| + * @namespace
|
| + * @memberof Polymer
|
| + * @summary Module for preparing and stamping instances of templates
|
| + * utilizing Polymer templating features.
|
| + */
|
| + const Templatize = {
|
| +
|
| + /**
|
| + * Returns an anonymous `Polymer.PropertyEffects` class bound to the
|
| + * `<template>` provided. Instancing the class will result in the
|
| + * template being stamped into document fragment stored as the instance's
|
| + * `root` property, after which it can be appended to the DOM.
|
| + *
|
| + * Templates may utilize all Polymer data-binding features as well as
|
| + * declarative event listeners. Event listeners and inline computing
|
| + * functions in the template will be called on the host of the template.
|
| + *
|
| + * The constructor returned takes a single argument dictionary of initial
|
| + * property values to propagate into template bindings. Additionally
|
| + * host properties can be forwarded in, and instance properties can be
|
| + * notified out by providing optional callbacks in the `options` dictionary.
|
| + *
|
| + * Valid configuration in `options` are as follows:
|
| + *
|
| + * - `forwardHostProp(property, value)`: Called when a property referenced
|
| + * in the template changed on the template's host. As this library does
|
| + * not retain references to templates instanced by the user, it is the
|
| + * templatize owner's responsibility to forward host property changes into
|
| + * user-stamped instances. The `instance.forwardHostProp(property, value)`
|
| + * method on the generated class should be called to forward host
|
| + * properties into the template to prevent unnecessary property-changed
|
| + * notifications. Any properties referenced in the template that are not
|
| + * defined in `instanceProps` will be notified up to the template's host
|
| + * automatically.
|
| + * - `instanceProps`: Dictionary of property names that will be added
|
| + * to the instance by the templatize owner. These properties shadow any
|
| + * host properties, and changes within the template to these properties
|
| + * will result in `notifyInstanceProp` being called.
|
| + * - `mutableData`: When `true`, the generated class will skip strict
|
| + * dirty-checking for objects and arrays (always consider them to be
|
| + * "dirty").
|
| + * - `notifyInstanceProp(instance, property, value)`: Called when
|
| + * an instance property changes. Users may choose to call `notifyPath`
|
| + * on e.g. the owner to notify the change.
|
| + * - `parentModel`: When `true`, events handled by declarative event listeners
|
| + * (`on-event="handler"`) will be decorated with a `model` property pointing
|
| + * to the template instance that stamped it. It will also be returned
|
| + * from `instance.parentModel` in cases where template instance nesting
|
| + * causes an inner model to shadow an outer model.
|
| + *
|
| + * Note that the class returned from `templatize` is generated only once
|
| + * for a given `<template>` using `options` from the first call for that
|
| + * template, and the cached class is returned for all subsequent calls to
|
| + * `templatize` for that template. As such, `options` callbacks should not
|
| + * close over owner-specific properties since only the first `options` is
|
| + * used; rather, callbacks are called bound to the `owner`, and so context
|
| + * needed from the callbacks (such as references to `instances` stamped)
|
| + * should be stored on the `owner` such that they can be retrieved via `this`.
|
| + *
|
| + * @memberof Polymer.Templatize
|
| + * @param {HTMLTemplateElement} template Template to templatize
|
| + * @param {*} owner Owner of the template instances; any optional callbacks
|
| + * will be bound to this owner.
|
| + * @param {*=} options Options dictionary (see summary for details)
|
| + * @return {TemplateInstanceBase} Generated class bound to the template
|
| + * provided
|
| + */
|
| + templatize(template, owner, options) {
|
| + options = options || {};
|
| + if (template.__templatizeOwner) {
|
| + throw new Error('A <template> can only be templatized once');
|
| + }
|
| + template.__templatizeOwner = owner;
|
| + let templateInfo = owner.constructor._parseTemplate(template);
|
| + // Get memoized base class for the prototypical template, which
|
| + // includes property effects for binding template & forwarding
|
| + let baseClass = templateInfo.templatizeInstanceClass;
|
| + if (!baseClass) {
|
| + baseClass = createTemplatizerClass(template, templateInfo, options);
|
| + templateInfo.templatizeInstanceClass = baseClass;
|
| + }
|
| + // Host property forwarding must be installed onto template instance
|
| + addPropagateEffects(template, templateInfo, options);
|
| + // Subclass base class and add reference for this specific template
|
| + let klass = class TemplateInstance extends baseClass {};
|
| + klass.prototype._methodHost = findMethodHost(template);
|
| + klass.prototype.__dataHost = template;
|
| + klass.prototype.__templatizeOwner = owner;
|
| + klass.prototype.__hostProps = templateInfo.hostProps;
|
| + return klass;
|
| + },
|
| +
|
| + /**
|
| + * Returns the template "model" associated with a given element, which
|
| + * serves as the binding scope for the template instance the element is
|
| + * contained in. A template model is an instance of
|
| + * `TemplateInstanceBase`, and should be used to manipulate data
|
| + * associated with this template instance.
|
| + *
|
| + * Example:
|
| + *
|
| + * let model = modelForElement(el);
|
| + * if (model.index < 10) {
|
| + * model.set('item.checked', true);
|
| + * }
|
| + *
|
| + * @memberof Polymer.Templatize
|
| + * @param {HTMLTemplateElement} template The model will be returned for
|
| + * elements stamped from this template
|
| + * @param {HTMLElement} el Element for which to return a template model.
|
| + * @return {TemplateInstanceBase} Template instance representing the
|
| + * binding scope for the element
|
| + */
|
| + modelForElement(template, el) {
|
| + let model;
|
| + while (el) {
|
| + // An element with a __templatizeInstance marks the top boundary
|
| + // of a scope; walk up until we find one, and then ensure that
|
| + // its __dataHost matches `this`, meaning this dom-repeat stamped it
|
| + if ((model = el.__templatizeInstance)) {
|
| + // Found an element stamped by another template; keep walking up
|
| + // from its __dataHost
|
| + if (model.__dataHost != template) {
|
| + el = model.__dataHost;
|
| + } else {
|
| + return model;
|
| + }
|
| + } else {
|
| + // Still in a template scope, keep going up until
|
| + // a __templatizeInstance is found
|
| + el = el.parentNode;
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| + }
|
| +
|
| + Polymer.Templatize = Templatize;
|
| +
|
| + })();
|
| +
|
| +</script>
|
|
|