Files
gerrit/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.js
David Pursehouse a733ee4294 Merge branch 'stable-3.2'
* stable-3.2:
  Error Prone: Enable and fix ClassCanBeStatic
  AutoRegisterModulesTest: Declare inner classes as static
  Update git submodules
  Fix issue with auto registering ssh commands
  Convert plugin's name to lowercase when generate hook name
  Update git submodules
  Update git submodules
  ErrorProne: Increase severity of FunctionalInterfaceClash to ERROR
  Revert "LifecycleListener: Mark stop method as default to make it optional"
  Update git submodules
  LifecycleListener: Mark stop method as default to make it optional

Change-Id: Ie86ec489f985cf0c024d70e555c5f47d961a155d
2020-06-25 15:55:50 +09:00

165 lines
4.5 KiB
JavaScript

/**
* @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 {PolymerElement} from '@polymer/polymer/polymer-element.js';
/** @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 {
// lowercase in case plugin's name contains uppercase letters
// TODO: this still can not prevent if plugin has invalid char
// other than uppercase, but is the first step
// https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name
const pluginName = this._plugin.getPluginName() || 'unknown_plugin';
return pluginName.toLowerCase() + '-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) {
class HookPlaceholder extends PolymerElement {
static get is() { return hookName; }
static get properties() {
return {
plugin: Object,
content: Object,
};
}
}
customElements.define(HookPlaceholder.is, HookPlaceholder);
};
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;
};