UNPKG

altair-graphql-core

Version:

Several of the core logic for altair graphql client

125 lines 4.73 kB
import { PLUGIN_CREATE_ACTION_EVENT, PLUGIN_ENGINE_READY, PLUGIN_GET_APP_STYLE_URL_EVENT, PLUGIN_SUBSCRIBE_TO_EVENT, getActionEvent, } from './events'; import { instanceTypes } from './frame-worker'; const mainInstanceOnlyEvents = [ 'createPanel', 'destroyPanel', 'createAction', ]; // methods to be excluded from the generic listener creation since they are handled specially const speciallyHandledMethods = ['on', 'createAction']; function getCssStyles(relevantClasses) { try { const styleSheets = Array.from(document.styleSheets); return styleSheets .map((sheet) => { return Array.from(sheet.cssRules) .map((rule) => rule.cssText) .join(''); }) .filter((css) => { return relevantClasses.some((htmlClass) => css.includes(`.${htmlClass}`)); }); } catch { return []; } } export class PluginParentEngine { constructor(worker, opts) { this.worker = worker; this.opts = opts; this.subscribedEvents = []; } start(context) { this.context = context; this.prepareListeners(); this.handleEvents(); if (this.worker.getInstanceType() === instanceTypes.MAIN) { this.handleActionEvents(); } // send a message to the worker to indicate that the plugin engine is ready this.worker.send(PLUGIN_ENGINE_READY); } prepareListeners() { if (!this.context) { return; } // loop over all the context object method and create a listener for each Object.entries(this.context).forEach(([k, fn]) => { // skip the methods that are handled specially if (speciallyHandledMethods.includes(k)) { return; } // skip the main frame only events if the frame is not the main frame if (this.worker.getInstanceType() !== instanceTypes.MAIN && mainInstanceOnlyEvents.includes(k)) { return; } this.worker.respond(k, async (...args) => { return fn(...args); }); }); } handleEvents() { this.worker.respond(PLUGIN_SUBSCRIBE_TO_EVENT, async (event) => { if (typeof event !== 'string') { return; } // we only need to subscribe to an event once here. In the frame, we manage the listeners separately if (this.subscribedEvents.includes(event)) { return; } if (!this.context) { return; } this.context.on(event, (...args) => { this.worker.request(event, ...args); }); // keep track of the events that have been subscribed to this.subscribedEvents.push(event); }); this.worker.respond(PLUGIN_GET_APP_STYLE_URL_EVENT, async () => { const styleSheets = Array.from(document.styleSheets); // Get the style sheet URLs // FYI for some reason I haven't figured out yet, we can't link to the stylesheets // in the browser extensions directly from the sandboxed iframe. const styleUrls = styleSheets .map((sheet) => { if (sheet?.href) { return sheet.href; } return ''; }) .filter(Boolean); const htmlClasses = Array.from(document.documentElement.classList); // Get the styles that are applicable to the current theme of the page // Doesn't work crossorigin cases. e.g. when loading from CDN. Fallback to theme instead. const styles = getCssStyles(htmlClasses).filter((s) => s.trim().length > 0); return { styleUrls, styles, htmlClasses, theme: this.opts?.theme }; }); } handleActionEvents() { // handle the createAction method specially this.worker.respond(PLUGIN_CREATE_ACTION_EVENT, async (opts) => { if (!this.context) { return; } let id = ''; // create action and assign the real id to the id variable id = await this.context.createAction({ ...opts, execute: async (...args) => { if (!id) { return; } return this.worker.request(getActionEvent(id), ...args); }, }); return id; }); } destroy() { this.worker.destroy(); } } //# sourceMappingURL=parent-engine.js.map