|  | /** | 
|  | * @license | 
|  | * Copyright (C) 2017 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | * http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  | import '../../../scripts/bundled-polymer.js'; | 
|  |  | 
|  | import {Polymer} from '@polymer/polymer/lib/legacy/polymer-fn.js'; | 
|  | const $_documentContainer = document.createElement('template'); | 
|  |  | 
|  | $_documentContainer.innerHTML = `<dom-module id="gr-dom-hooks"> | 
|  |  | 
|  | </dom-module>`; | 
|  |  | 
|  | document.head.appendChild($_documentContainer.content); | 
|  |  | 
|  | /** @constructor */ | 
|  | export function GrDomHooksManager(plugin) { | 
|  | this._plugin = plugin; | 
|  | this._hooks = {}; | 
|  | } | 
|  |  | 
|  | GrDomHooksManager.prototype._getHookName = function(endpointName, | 
|  | opt_moduleName) { | 
|  | if (opt_moduleName) { | 
|  | return endpointName + ' ' + opt_moduleName; | 
|  | } else { | 
|  | return this._plugin.getPluginName() + '-autogenerated-' + endpointName; | 
|  | } | 
|  | }; | 
|  |  | 
|  | GrDomHooksManager.prototype.getDomHook = function(endpointName, | 
|  | opt_moduleName) { | 
|  | const hookName = this._getHookName(endpointName, opt_moduleName); | 
|  | if (!this._hooks[hookName]) { | 
|  | this._hooks[hookName] = new GrDomHook(hookName, opt_moduleName); | 
|  | } | 
|  | return this._hooks[hookName]; | 
|  | }; | 
|  |  | 
|  | /** @constructor */ | 
|  | export function GrDomHook(hookName, opt_moduleName) { | 
|  | this._instances = []; | 
|  | this._attachCallbacks = []; | 
|  | this._detachCallbacks = []; | 
|  | if (opt_moduleName) { | 
|  | this._moduleName = opt_moduleName; | 
|  | } else { | 
|  | this._moduleName = hookName; | 
|  | this._createPlaceholder(hookName); | 
|  | } | 
|  | } | 
|  |  | 
|  | GrDomHook.prototype._createPlaceholder = function(hookName) { | 
|  | Polymer({ | 
|  | is: hookName, | 
|  | properties: { | 
|  | plugin: Object, | 
|  | content: Object, | 
|  | }, | 
|  | }); | 
|  | }; | 
|  |  | 
|  | GrDomHook.prototype.handleInstanceDetached = function(instance) { | 
|  | const index = this._instances.indexOf(instance); | 
|  | if (index !== -1) { | 
|  | this._instances.splice(index, 1); | 
|  | } | 
|  | this._detachCallbacks.forEach(callback => callback(instance)); | 
|  | }; | 
|  |  | 
|  | GrDomHook.prototype.handleInstanceAttached = function(instance) { | 
|  | this._instances.push(instance); | 
|  | this._attachCallbacks.forEach(callback => callback(instance)); | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Get instance of last DOM hook element attached into the endpoint. | 
|  | * Returns a Promise, that's resolved when attachment is done. | 
|  | * | 
|  | * @return {!Promise<!Element>} | 
|  | */ | 
|  | GrDomHook.prototype.getLastAttached = function() { | 
|  | if (this._instances.length) { | 
|  | return Promise.resolve(this._instances.slice(-1)[0]); | 
|  | } | 
|  | if (!this._lastAttachedPromise) { | 
|  | let resolve; | 
|  | const promise = new Promise(r => resolve = r); | 
|  | this._attachCallbacks.push(resolve); | 
|  | this._lastAttachedPromise = promise.then(element => { | 
|  | this._lastAttachedPromise = null; | 
|  | const index = this._attachCallbacks.indexOf(resolve); | 
|  | if (index !== -1) { | 
|  | this._attachCallbacks.splice(index, 1); | 
|  | } | 
|  | return element; | 
|  | }); | 
|  | } | 
|  | return this._lastAttachedPromise; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Get all DOM hook elements. | 
|  | */ | 
|  | GrDomHook.prototype.getAllAttached = function() { | 
|  | return this._instances; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Install a new callback to invoke when a new instance of DOM hook element | 
|  | * is attached. | 
|  | * | 
|  | * @param {function(Element)} callback | 
|  | */ | 
|  | GrDomHook.prototype.onAttached = function(callback) { | 
|  | this._attachCallbacks.push(callback); | 
|  | return this; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Install a new callback to invoke when an instance of DOM hook element | 
|  | * is detached. | 
|  | * | 
|  | * @param {function(Element)} callback | 
|  | */ | 
|  | GrDomHook.prototype.onDetached = function(callback) { | 
|  | this._detachCallbacks.push(callback); | 
|  | return this; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Name of DOM hook element that will be installed into the endpoint. | 
|  | */ | 
|  | GrDomHook.prototype.getModuleName = function() { | 
|  | return this._moduleName; | 
|  | }; | 
|  |  | 
|  | GrDomHook.prototype.getPublicAPI = function() { | 
|  | const result = {}; | 
|  | const exposedMethods = [ | 
|  | 'onAttached', | 
|  | 'onDetached', | 
|  | 'getLastAttached', | 
|  | 'getAllAttached', | 
|  | 'getModuleName', | 
|  | ]; | 
|  | for (const p of exposedMethods) { | 
|  | result[p] = this[p].bind(this); | 
|  | } | 
|  | return result; | 
|  | }; |