123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- /*-----------------------------------------------------------------------------
- | Copyright (c) Jupyter Development Team.
- | Distributed under the terms of the Modified BSD License.
- |----------------------------------------------------------------------------*/
- import {
- JSONObject
- } from 'phosphor/lib/algorithm/json';
- import {
- IDisposable
- } from 'phosphor/lib/core/disposable';
- import {
- Token
- } from 'phosphor/lib/core/token';
- import {
- CommandRegistry
- } from 'phosphor/lib/ui/commandregistry';
- import {
- IElementAttrs
- } from 'phosphor/lib/ui/vdom';
- /**
- * 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';
- /* tslint:disable */
- /**
- * The command linker token.
- */
- export
- const ICommandLinker = new Token<ICommandLinker>('jupyter.services.command-linker');
- /* tslint:enable */
- /**
- * A helper class to generate clickables that execute commands.
- */
- export
- interface ICommandLinker extends IDisposable {
- /**
- * 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: JSONObject): HTMLElement;
- /**
- * 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 `populateVNodeAttributes` method in order to disconnect them from
- * executing their command/argument pair.
- */
- disconnectNode(node: HTMLElement): HTMLElement;
- /**
- * Populate the attributes used to instantiate a virtual DOM node with the
- * data set values necessary for its rendered DOM node to respond to clicks by
- * executing a command/argument pair
- *
- * @param attrs - The attributes that will eventually be used to instantiate
- * a virtual DOM node.
- *
- * @param command - The command ID to execute upon click.
- *
- * @param args - The arguments with which to invoke the command.
- *
- * #### Notes
- * The attributes instance that is returned is identical to the attributes
- * instance that was passed in, i.e., this method mutates the original.
- */
- populateVNodeAttrs(attrs: IElementAttrs, command: string, args: JSONObject): IElementAttrs;
- }
- /**
- * A static class that provides helper methods to generate clickable nodes that
- * execute registered commands with pre-populated arguments.
- */
- export
- class CommandLinker implements ICommandLinker {
- /**
- * 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._commands === null;
- }
- /**
- * Dispose of the resources held by the linker.
- */
- dispose(): void {
- if (this._commands === null) {
- return;
- }
- this._commands = null;
- 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: JSONObject): HTMLElement {
- let argsValue = JSON.stringify(args);
- node.setAttribute(`data-${COMMAND_ATTR}`, command);
- if (argsValue) {
- node.setAttribute(`data-${ARGS_ATTR}`, argsValue);
- }
- 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 `populateVNodeAttributes` 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 attributes used to instantiate a virtual DOM node with the
- * data set values necessary for its rendered DOM node to respond to clicks by
- * executing a command/argument pair
- *
- * @param attrs - The attributes that will eventually be used to instantiate
- * a virtual DOM node.
- *
- * @param command - The command ID to execute upon click.
- *
- * @param args - The arguments with which to invoke the command.
- *
- * #### Notes
- * The attributes instance that is returned is identical to the attributes
- * instance that was passed in, i.e., this method mutates the original.
- */
- populateVNodeAttrs(attrs: IElementAttrs, command: string, args: JSONObject): IElementAttrs {
- let argsValue = JSON.stringify(args);
- attrs.dataset = attrs.dataset || {};
- attrs.dataset[COMMAND_ATTR] = command;
- if (argsValue) {
- attrs.dataset[ARGS_ATTR] = argsValue;
- }
- return attrs;
- }
- /**
- * 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();
- let command = target.getAttribute(`data-${COMMAND_ATTR}`);
- let argsValue = target.getAttribute(`data-${ARGS_ATTR}`);
- let args: JSONObject;
- if (argsValue) {
- args = JSON.parse(argsValue);
- }
- this._commands.execute(command, args);
- return;
- }
- target = target.parentElement;
- }
- }
- private _commands: CommandRegistry = null;
- }
- /**
- * 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;
- }
- }
|