diff options
Diffstat (limited to 'chromium/third_party/catapult/third_party/polymer2/bower_components/polymer/lib/elements/dom-if.html')
-rw-r--r-- | chromium/third_party/catapult/third_party/polymer2/bower_components/polymer/lib/elements/dom-if.html | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/chromium/third_party/catapult/third_party/polymer2/bower_components/polymer/lib/elements/dom-if.html b/chromium/third_party/catapult/third_party/polymer2/bower_components/polymer/lib/elements/dom-if.html new file mode 100644 index 00000000000..527ede86ae0 --- /dev/null +++ b/chromium/third_party/catapult/third_party/polymer2/bower_components/polymer/lib/elements/dom-if.html @@ -0,0 +1,288 @@ +<!-- +@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="../../polymer-element.html"> +<link rel="import" href="../utils/templatize.html"> +<link rel="import" href="../utils/debounce.html"> +<link rel="import" href="../utils/flush.html"> + +<script> + +(function() { + 'use strict'; + + /** + * The `<dom-if>` element will stamp a light-dom `<template>` child when + * the `if` property becomes truthy, and the template can use Polymer + * data-binding and declarative event features when used in the context of + * a Polymer element's template. + * + * When `if` becomes falsy, the stamped content is hidden but not + * removed from dom. When `if` subsequently becomes truthy again, the content + * is simply re-shown. This approach is used due to its favorable performance + * characteristics: the expense of creating template content is paid only + * once and lazily. + * + * Set the `restamp` property to true to force the stamped content to be + * created / destroyed when the `if` condition changes. + * + * @customElement + * @polymer + * @extends Polymer.Element + * @memberof Polymer + * @summary Custom element that conditionally stamps and hides or removes + * template content based on a boolean flag. + */ + class DomIf extends Polymer.Element { + + // Not needed to find template; can be removed once the analyzer + // can find the tag name from customElements.define call + static get is() { return 'dom-if'; } + + static get template() { return null; } + + static get properties() { + + return { + + /** + * Fired whenever DOM is added or removed/hidden by this template (by + * default, rendering occurs lazily). To force immediate rendering, call + * `render`. + * + * @event dom-change + */ + + /** + * A boolean indicating whether this template should stamp. + */ + if: { + type: Boolean, + observer: '__debounceRender' + }, + + /** + * When true, elements will be removed from DOM and discarded when `if` + * becomes false and re-created and added back to the DOM when `if` + * becomes true. By default, stamped elements will be hidden but left + * in the DOM when `if` becomes false, which is generally results + * in better performance. + */ + restamp: { + type: Boolean, + observer: '__debounceRender' + } + + }; + + } + + constructor() { + super(); + this.__renderDebouncer = null; + this.__invalidProps = null; + this.__instance = null; + this._lastIf = false; + this.__ctor = null; + } + + __debounceRender() { + // Render is async for 2 reasons: + // 1. To eliminate dom creation trashing if user code thrashes `if` in the + // same turn. This was more common in 1.x where a compound computed + // property could result in the result changing multiple times, but is + // mitigated to a large extent by batched property processing in 2.x. + // 2. To avoid double object propagation when a bag including values bound + // to the `if` property as well as one or more hostProps could enqueue + // the <dom-if> to flush before the <template>'s host property + // forwarding. In that scenario creating an instance would result in + // the host props being set once, and then the enqueued changes on the + // template would set properties a second time, potentially causing an + // object to be set to an instance more than once. Creating the + // instance async from flushing data ensures this doesn't happen. If + // we wanted a sync option in the future, simply having <dom-if> flush + // (or clear) its template's pending host properties before creating + // the instance would also avoid the problem. + this.__renderDebouncer = Polymer.Debouncer.debounce( + this.__renderDebouncer + , Polymer.Async.microTask + , () => this.__render()); + Polymer.enqueueDebouncer(this.__renderDebouncer); + } + + /** + * @return {void} + */ + disconnectedCallback() { + super.disconnectedCallback(); + if (!this.parentNode || + (this.parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE && + !this.parentNode.host)) { + this.__teardownInstance(); + } + } + + /** + * @return {void} + */ + connectedCallback() { + super.connectedCallback(); + this.style.display = 'none'; + if (this.if) { + this.__debounceRender(); + } + } + + /** + * Forces the element to render its content. Normally rendering is + * asynchronous to a provoking change. This is done for efficiency so + * that multiple changes trigger only a single render. The render method + * should be called if, for example, template rendering is required to + * validate application state. + * @return {void} + */ + render() { + Polymer.flush(); + } + + __render() { + if (this.if) { + if (!this.__ensureInstance()) { + // No template found yet + return; + } + this._showHideChildren(); + } else if (this.restamp) { + this.__teardownInstance(); + } + if (!this.restamp && this.__instance) { + this._showHideChildren(); + } + if (this.if != this._lastIf) { + this.dispatchEvent(new CustomEvent('dom-change', { + bubbles: true, + composed: true + })); + this._lastIf = this.if; + } + } + + __ensureInstance() { + let parentNode = this.parentNode; + // Guard against element being detached while render was queued + if (parentNode) { + if (!this.__ctor) { + let template = /** @type {HTMLTemplateElement} */(this.querySelector('template')); + if (!template) { + // Wait until childList changes and template should be there by then + let observer = new MutationObserver(() => { + if (this.querySelector('template')) { + observer.disconnect(); + this.__render(); + } else { + throw new Error('dom-if requires a <template> child'); + } + }); + observer.observe(this, {childList: true}); + return false; + } + this.__ctor = Polymer.Templatize.templatize(template, this, { + // dom-if templatizer instances require `mutable: true`, as + // `__syncHostProperties` relies on that behavior to sync objects + mutableData: true, + /** + * @param {string} prop Property to forward + * @param {*} value Value of property + * @this {this} + */ + forwardHostProp: function(prop, value) { + if (this.__instance) { + if (this.if) { + this.__instance.forwardHostProp(prop, value); + } else { + // If we have an instance but are squelching host property + // forwarding due to if being false, note the invalidated + // properties so `__syncHostProperties` can sync them the next + // time `if` becomes true + this.__invalidProps = this.__invalidProps || Object.create(null); + this.__invalidProps[Polymer.Path.root(prop)] = true; + } + } + } + }); + } + if (!this.__instance) { + this.__instance = new this.__ctor(); + parentNode.insertBefore(this.__instance.root, this); + } else { + this.__syncHostProperties(); + let c$ = this.__instance.children; + if (c$ && c$.length) { + // Detect case where dom-if was re-attached in new position + let lastChild = this.previousSibling; + if (lastChild !== c$[c$.length-1]) { + for (let i=0, n; (i<c$.length) && (n=c$[i]); i++) { + parentNode.insertBefore(n, this); + } + } + } + } + } + return true; + } + + __syncHostProperties() { + let props = this.__invalidProps; + if (props) { + for (let prop in props) { + this.__instance._setPendingProperty(prop, this.__dataHost[prop]); + } + this.__invalidProps = null; + this.__instance._flushProperties(); + } + } + + __teardownInstance() { + if (this.__instance) { + let c$ = this.__instance.children; + if (c$ && c$.length) { + // use first child parent, for case when dom-if may have been detached + let parent = c$[0].parentNode; + for (let i=0, n; (i<c$.length) && (n=c$[i]); i++) { + parent.removeChild(n); + } + } + this.__instance = null; + this.__invalidProps = null; + } + } + + /** + * Shows or hides the template instance top level child elements. For + * text nodes, `textContent` is removed while "hidden" and replaced when + * "shown." + * @return {void} + * @protected + */ + _showHideChildren() { + let hidden = this.__hideTemplateChildren__ || !this.if; + if (this.__instance) { + this.__instance._showHideChildren(hidden); + } + } + + } + + customElements.define(DomIf.is, DomIf); + + Polymer.DomIf = DomIf; + +})(); +</script> |