123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- /* -----------------------------------------------------------------------------
- | Copyright (c) Jupyter Development Team.
- | Distributed under the terms of the Modified BSD License.
- |----------------------------------------------------------------------------*/
- import { JSONExt, ReadonlyPartialJSONObject } from '@lumino/coreutils';
- import { IDisposable } from '@lumino/disposable';
- import { CommandRegistry } from '@lumino/commands';
- import { ElementDataset } from '@lumino/virtualdom';
- /**
- * The command data attribute added to nodes that are connected.
- */
- const COMMAND_ATTR = 'commandlinker-command';
- /**
- * The args data attribute added to nodes that are connected.
- */
- const ARGS_ATTR = 'commandlinker-args';
- /**
- * A static class that provides helper methods to generate clickable nodes that
- * execute registered commands with pre-populated arguments.
- */
- export class CommandLinker implements IDisposable {
- /**
- * Instantiate a new command linker.
- */
- constructor(options: CommandLinker.IOptions) {
- this._commands = options.commands;
- document.body.addEventListener('click', this);
- }
- /**
- * Test whether the linker is disposed.
- */
- get isDisposed(): boolean {
- return this._isDisposed;
- }
- /**
- * Dispose of the resources held by the linker.
- */
- dispose(): void {
- if (this.isDisposed) {
- return;
- }
- this._isDisposed = true;
- document.body.removeEventListener('click', this);
- }
- /**
- * Connect a command/argument pair to a given node so that when it is clicked,
- * the command will execute.
- *
- * @param node - The node being connected.
- *
- * @param command - The command ID to execute upon click.
- *
- * @param args - The arguments with which to invoke the command.
- *
- * @returns The same node that was passed in, after it has been connected.
- *
- * #### Notes
- * Only `click` events will execute the command on a connected node. So, there
- * are two considerations that are relevant:
- * 1. If a node is connected, the default click action will be prevented.
- * 2. The `HTMLElement` passed in should be clickable.
- */
- connectNode(
- node: HTMLElement,
- command: string,
- args?: ReadonlyPartialJSONObject
- ): HTMLElement {
- node.setAttribute(`data-${COMMAND_ATTR}`, command);
- if (args !== void 0) {
- node.setAttribute(`data-${ARGS_ATTR}`, JSON.stringify(args));
- }
- return node;
- }
- /**
- * Disconnect a node that has been connected to execute a command on click.
- *
- * @param node - The node being disconnected.
- *
- * @returns The same node that was passed in, after it has been disconnected.
- *
- * #### Notes
- * This method is safe to call multiple times and is safe to call on nodes
- * that were never connected.
- *
- * This method can be called on rendered virtual DOM nodes that were populated
- * using the `populateVNodeDataset` method in order to disconnect them from
- * executing their command/argument pair.
- */
- disconnectNode(node: HTMLElement): HTMLElement {
- node.removeAttribute(`data-${COMMAND_ATTR}`);
- node.removeAttribute(`data-${ARGS_ATTR}`);
- return node;
- }
- /**
- * Handle the DOM events for the command linker helper class.
- *
- * @param event - The DOM event sent to the class.
- *
- * #### Notes
- * This method implements the DOM `EventListener` interface and is
- * called in response to events on the panel's DOM node. It should
- * not be called directly by user code.
- */
- handleEvent(event: Event): void {
- switch (event.type) {
- case 'click':
- this._evtClick(event as MouseEvent);
- break;
- default:
- return;
- }
- }
- /**
- * Populate the `dataset` attribute within the collection of attributes used
- * to instantiate a virtual DOM node with the values necessary for its
- * rendered DOM node to respond to clicks by executing a command/argument
- * pair.
- *
- * @param command - The command ID to execute upon click.
- *
- * @param args - The arguments with which to invoke the command.
- *
- * @returns A `dataset` collection for use within virtual node attributes.
- *
- * #### Notes
- * The return value can be used on its own as the value for the `dataset`
- * attribute of a virtual element, or it can be added to an existing `dataset`
- * as in the example below.
- *
- * #### Example
- * ```typescript
- * let command = 'some:command-id';
- * let args = { alpha: 'beta' };
- * let anchor = h.a({
- * className: 'some-class',
- * dataset: {
- * foo: '1',
- * bar: '2',
- * ../...linker.populateVNodeDataset(command, args)
- * }
- * }, 'some text');
- * ```
- */
- populateVNodeDataset(
- command: string,
- args?: ReadonlyPartialJSONObject
- ): ElementDataset {
- let dataset: ElementDataset;
- if (args !== void 0) {
- dataset = { [ARGS_ATTR]: JSON.stringify(args), [COMMAND_ATTR]: command };
- } else {
- dataset = { [COMMAND_ATTR]: command };
- }
- return dataset;
- }
- /**
- * The global click handler that deploys commands/argument pairs that are
- * attached to the node being clicked.
- */
- private _evtClick(event: MouseEvent): void {
- let target = event.target as HTMLElement;
- while (target && target.parentElement) {
- if (target.hasAttribute(`data-${COMMAND_ATTR}`)) {
- event.preventDefault();
- const command = target.getAttribute(`data-${COMMAND_ATTR}`);
- if (!command) {
- return;
- }
- const argsValue = target.getAttribute(`data-${ARGS_ATTR}`);
- let args = JSONExt.emptyObject;
- if (argsValue) {
- args = JSON.parse(argsValue);
- }
- void this._commands.execute(command, args);
- return;
- }
- target = target.parentElement;
- }
- }
- private _commands: CommandRegistry;
- private _isDisposed = false;
- }
- /**
- * A namespace for command linker statics.
- */
- export namespace CommandLinker {
- /**
- * The instantiation options for a command linker.
- */
- export interface IOptions {
- /**
- * The command registry instance that all linked commands will use.
- */
- commands: CommandRegistry;
- }
- }
|