UNPKG

terriajs

Version:

Geospatial data visualization platform.

143 lines (126 loc) 4.12 kB
import { ReactElement } from "react"; import TerriaFeature from "../../Models/Feature/Feature"; import { BaseModel } from "../../Models/Definition/Model"; import Terria from "../../Models/Terria"; import ViewState from "../../ReactViewModels/ViewState"; /** * DomElement type from @types/domhandler */ export interface DomElement { attribs?: { [s: string]: string }; children?: DomElement[]; data?: any; name?: string; next?: DomElement; parent?: DomElement; prev?: DomElement; type?: string; } /** * The context for a transformation of custom components to React. * Note: these will need to be passed into appropriate function parameters * For example `parseCustomMarkdownToReact(someHtml, context)` * - where context: ProcessNodeContext */ export interface ProcessNodeContext { /** * The Terria instance for which this HTML is being processed. */ readonly terria?: Terria; /** * The Terria instance for which this HTML is being processed. */ readonly viewState?: ViewState; /** * The catalog item for which this HTML is being processed. */ readonly catalogItem?: BaseModel; /** * The feature for which this HTML is being processed. */ readonly feature?: TerriaFeature; } /** * A custom component type, e.g. `<chart>`. */ export default abstract class CustomComponent { /** * Gets the name of the DOM element for this custom component. For example, * if this custom component is derived from a `<chart>` tag, the name property's * value would be `"chart"`. */ abstract get name(): string; /** * Gets the custom attributes for this tag, eg. ["src-preview"]. * Used so that when the user-supplied html is sanitized, these attributes are not stripped. */ abstract get attributes(): string[]; /** * Determine if a given DOM node should be processed by this component. By * default, this method returns `true` if the node name matches the * {@link CustomComponent#name} property. If this method returns `true`, * {@link CustomComponent#processNode} will be called. * * @param context The context for the custom component * @param node The node that should possibly be processed. */ // eslint-disable-next-line @typescript-eslint/no-unused-vars shouldProcessNode(context: ProcessNodeContext, node: DomElement): boolean { return this.name === node.name; } /** * Transforms a DOM element into a React element. This function is passed to * to html-to-react's `processingInstructions`. * * @param context Context for the custom component. * @param node The DOM node to transformed to React. * @param children The already-transformed React elements that are this node's children. * @param index The index of this node in its parent's list of children. */ abstract processNode( context: ProcessNodeContext, node: DomElement, children: ReactElement[], index: number ): ReactElement | undefined; private static readonly _types = new Map<string, CustomComponent>(); /** * Registers a custom component. * @param component The component to register. */ static register(component: CustomComponent) { this._types.set(component.name, component); } /** * Unregister all components */ static unregisterAll() { this._types.clear(); } /** * Checks if a custom component with a given name is registered. * @param name The name of the custom component. * @returns True if the custom component is registered, otherwise false. */ static isRegistered(name: string): boolean { return this._types.has(name); } /** * Gets the names of the registered custom components. */ static get names(): string[] { return Array.from(this._types.keys()); } /** * Gets the registered custom components. */ static get values(): CustomComponent[] { return Array.from(this._types.values()); } /** * Gets all attributes of all custom components. */ static get attributes(): string[] { return this.values.reduce((p, c) => p.concat(c.attributes), [] as string[]); } }