The change converts the following files to typescript: * elements/shared/gr-js-api-interface/gr-public-js-api.ts Change-Id: I07e48b9aa3078f90ac99e7addd58e8771bec4486
162 lines
4.5 KiB
TypeScript
162 lines
4.5 KiB
TypeScript
/**
|
|
* @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';
|
|
import {HookApi, HookCallback, PluginApi} from '../gr-plugin-types';
|
|
|
|
export class GrDomHooksManager {
|
|
private _hooks: Record<string, GrDomHook>;
|
|
|
|
private _plugin: PluginApi;
|
|
|
|
constructor(plugin: PluginApi) {
|
|
this._plugin = plugin;
|
|
this._hooks = {};
|
|
}
|
|
|
|
_getHookName(endpointName: string, moduleName?: string) {
|
|
if (moduleName) {
|
|
return endpointName + ' ' + 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: string =
|
|
this._plugin.getPluginName() || 'unknown_plugin';
|
|
return pluginName.toLowerCase() + '-autogenerated-' + endpointName;
|
|
}
|
|
}
|
|
|
|
getDomHook(endpointName: string, moduleName?: string) {
|
|
const hookName = this._getHookName(endpointName, moduleName);
|
|
if (!this._hooks[hookName]) {
|
|
this._hooks[hookName] = new GrDomHook(hookName, moduleName);
|
|
}
|
|
return this._hooks[hookName];
|
|
}
|
|
}
|
|
|
|
export class GrDomHook implements HookApi {
|
|
private _instances: HTMLElement[] = [];
|
|
|
|
private _attachCallbacks: HookCallback[] = [];
|
|
|
|
private _detachCallbacks: HookCallback[] = [];
|
|
|
|
private _moduleName: string;
|
|
|
|
private _lastAttachedPromise: Promise<HTMLElement> | null = null;
|
|
|
|
constructor(hookName: string, moduleName?: string) {
|
|
if (moduleName) {
|
|
this._moduleName = moduleName;
|
|
} else {
|
|
this._moduleName = hookName;
|
|
this._createPlaceholder(hookName);
|
|
}
|
|
}
|
|
|
|
_createPlaceholder(hookName: string) {
|
|
class HookPlaceholder extends PolymerElement {
|
|
static get is() {
|
|
return hookName;
|
|
}
|
|
|
|
static get properties() {
|
|
return {
|
|
plugin: Object,
|
|
content: Object,
|
|
};
|
|
}
|
|
}
|
|
|
|
customElements.define(HookPlaceholder.is, HookPlaceholder);
|
|
}
|
|
|
|
handleInstanceDetached(instance: HTMLElement) {
|
|
const index = this._instances.indexOf(instance);
|
|
if (index !== -1) {
|
|
this._instances.splice(index, 1);
|
|
}
|
|
this._detachCallbacks.forEach(callback => callback(instance));
|
|
}
|
|
|
|
handleInstanceAttached(instance: HTMLElement) {
|
|
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.
|
|
*/
|
|
getLastAttached(): Promise<HTMLElement> {
|
|
if (this._instances.length) {
|
|
return Promise.resolve(this._instances.slice(-1)[0]);
|
|
}
|
|
if (!this._lastAttachedPromise) {
|
|
let resolve: HookCallback;
|
|
const promise = new Promise<HTMLElement>(r => {
|
|
resolve = r;
|
|
this._attachCallbacks.push(resolve);
|
|
});
|
|
this._lastAttachedPromise = promise.then((element: HTMLElement) => {
|
|
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.
|
|
*/
|
|
getAllAttached() {
|
|
return this._instances;
|
|
}
|
|
|
|
/**
|
|
* Install a new callback to invoke when a new instance of DOM hook element
|
|
* is attached.
|
|
*/
|
|
onAttached(callback: HookCallback) {
|
|
this._attachCallbacks.push(callback);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Install a new callback to invoke when an instance of DOM hook element
|
|
* is detached.
|
|
*
|
|
*/
|
|
onDetached(callback: HookCallback) {
|
|
this._detachCallbacks.push(callback);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Name of DOM hook element that will be installed into the endpoint.
|
|
*/
|
|
getModuleName() {
|
|
return this._moduleName;
|
|
}
|
|
}
|