UNPKG

5.85 kBJavaScriptView Raw
1/* -----------------------------------------------------------------------------
2| Copyright (c) Jupyter Development Team.
3| Distributed under the terms of the Modified BSD License.
4|----------------------------------------------------------------------------*/
5import { JSONExt } from '@lumino/coreutils';
6/**
7 * The command data attribute added to nodes that are connected.
8 */
9const COMMAND_ATTR = 'commandlinker-command';
10/**
11 * The args data attribute added to nodes that are connected.
12 */
13const ARGS_ATTR = 'commandlinker-args';
14/**
15 * A static class that provides helper methods to generate clickable nodes that
16 * execute registered commands with pre-populated arguments.
17 */
18export class CommandLinker {
19 /**
20 * Instantiate a new command linker.
21 */
22 constructor(options) {
23 this._isDisposed = false;
24 this._commands = options.commands;
25 document.body.addEventListener('click', this);
26 }
27 /**
28 * Test whether the linker is disposed.
29 */
30 get isDisposed() {
31 return this._isDisposed;
32 }
33 /**
34 * Dispose of the resources held by the linker.
35 */
36 dispose() {
37 if (this.isDisposed) {
38 return;
39 }
40 this._isDisposed = true;
41 document.body.removeEventListener('click', this);
42 }
43 /**
44 * Connect a command/argument pair to a given node so that when it is clicked,
45 * the command will execute.
46 *
47 * @param node - The node being connected.
48 *
49 * @param command - The command ID to execute upon click.
50 *
51 * @param args - The arguments with which to invoke the command.
52 *
53 * @returns The same node that was passed in, after it has been connected.
54 *
55 * #### Notes
56 * Only `click` events will execute the command on a connected node. So, there
57 * are two considerations that are relevant:
58 * 1. If a node is connected, the default click action will be prevented.
59 * 2. The `HTMLElement` passed in should be clickable.
60 */
61 connectNode(node, command, args) {
62 node.setAttribute(`data-${COMMAND_ATTR}`, command);
63 if (args !== void 0) {
64 node.setAttribute(`data-${ARGS_ATTR}`, JSON.stringify(args));
65 }
66 return node;
67 }
68 /**
69 * Disconnect a node that has been connected to execute a command on click.
70 *
71 * @param node - The node being disconnected.
72 *
73 * @returns The same node that was passed in, after it has been disconnected.
74 *
75 * #### Notes
76 * This method is safe to call multiple times and is safe to call on nodes
77 * that were never connected.
78 *
79 * This method can be called on rendered virtual DOM nodes that were populated
80 * using the `populateVNodeDataset` method in order to disconnect them from
81 * executing their command/argument pair.
82 */
83 disconnectNode(node) {
84 node.removeAttribute(`data-${COMMAND_ATTR}`);
85 node.removeAttribute(`data-${ARGS_ATTR}`);
86 return node;
87 }
88 /**
89 * Handle the DOM events for the command linker helper class.
90 *
91 * @param event - The DOM event sent to the class.
92 *
93 * #### Notes
94 * This method implements the DOM `EventListener` interface and is
95 * called in response to events on the panel's DOM node. It should
96 * not be called directly by user code.
97 */
98 handleEvent(event) {
99 switch (event.type) {
100 case 'click':
101 this._evtClick(event);
102 break;
103 default:
104 return;
105 }
106 }
107 /**
108 * Populate the `dataset` attribute within the collection of attributes used
109 * to instantiate a virtual DOM node with the values necessary for its
110 * rendered DOM node to respond to clicks by executing a command/argument
111 * pair.
112 *
113 * @param command - The command ID to execute upon click.
114 *
115 * @param args - The arguments with which to invoke the command.
116 *
117 * @returns A `dataset` collection for use within virtual node attributes.
118 *
119 * #### Notes
120 * The return value can be used on its own as the value for the `dataset`
121 * attribute of a virtual element, or it can be added to an existing `dataset`
122 * as in the example below.
123 *
124 * #### Example
125 * ```typescript
126 * let command = 'some:command-id';
127 * let args = { alpha: 'beta' };
128 * let anchor = h.a({
129 * className: 'some-class',
130 * dataset: {
131 * foo: '1',
132 * bar: '2',
133 * ../...linker.populateVNodeDataset(command, args)
134 * }
135 * }, 'some text');
136 * ```
137 */
138 populateVNodeDataset(command, args) {
139 let dataset;
140 if (args !== void 0) {
141 dataset = { [ARGS_ATTR]: JSON.stringify(args), [COMMAND_ATTR]: command };
142 }
143 else {
144 dataset = { [COMMAND_ATTR]: command };
145 }
146 return dataset;
147 }
148 /**
149 * The global click handler that deploys commands/argument pairs that are
150 * attached to the node being clicked.
151 */
152 _evtClick(event) {
153 let target = event.target;
154 while (target && target.parentElement) {
155 if (target.hasAttribute(`data-${COMMAND_ATTR}`)) {
156 event.preventDefault();
157 const command = target.getAttribute(`data-${COMMAND_ATTR}`);
158 if (!command) {
159 return;
160 }
161 const argsValue = target.getAttribute(`data-${ARGS_ATTR}`);
162 let args = JSONExt.emptyObject;
163 if (argsValue) {
164 args = JSON.parse(argsValue);
165 }
166 void this._commands.execute(command, args);
167 return;
168 }
169 target = target.parentElement;
170 }
171 }
172}
173//# sourceMappingURL=commandlinker.js.map
\No newline at end of file