@peter.naydenov/shortcuts 2.2.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,20 +6,16 @@
6
6
  ![npm bundle size](https://img.shields.io/bundlephobia/minzip/%40peter.naydenov%2Fshortcuts)
7
7
 
8
8
 
9
+
10
+ Describe all page activities as list of shortcuts wrapped in contexts. Switch among available contexts.
11
+ Library has a plugin system to extend the possible `shortcut names`/`event coverage`. Plugins role is to convert DOM events to shortcut strings, then the core part will trigger the action functions related to the shortcut. At the moment we have 2 plugins:
12
+ - `key` - converts keyboard events to shortcut names;
13
+ - `click` - converts mouse events to shortcut names;
9
14
 
10
- Define a context based keyboard-shortcuts and describe a mouse clicks. Switch among contexts.
15
+ Planned work on the plugins for `scroll`, `drag-drop`, `input-change`, etc...
11
16
 
12
17
 
13
18
 
14
-
15
- ## What's new?
16
-
17
- - Version 1.1.x and above are coming with method `emit` that make possible to trigger shortcuts programmatically. In `shortcuts` you can mix keyboard, mouse and programmatical events that is prity everything that can happen in a web page;
18
- - Method `setDependencies` comes after version 2.0.0. You can insert external libraries and modules that you will need to access from action functions. They will come as **dependencies** object. In function `emit` will come as first argument. Other arguments are attached behind the dependencies object;
19
- - Another html data attribute is added - `data-quick-click`. Example: `<button data-click="id" data-quick-click>Click me</button>`. This attribute is saying to `shortcuts` that target element don't need to wait for more then 1 click and shortcut can be executed immediately after the click. Attribute is available in version 2.0.0 and above;
20
- - Method `listShortcuts` is added in version 2.0.0. It returns a list of shortcuts for requested context. If context is not set, will return a list of all shortcuts;
21
-
22
-
23
19
  ## Shortcut Description Rules
24
20
  The shortcuts definition includes a context name and a set of rules(object). The rules are a set of key-value pairs. The key is a shortcut name and the value is a function or array of functions, to be executed when the shortcut is triggered (action function).
25
21
 
@@ -44,14 +40,28 @@ The shortcuts definition includes a context name and a set of rules(object). The
44
40
  ]
45
41
  }
46
42
  }
43
+ // shortcutName after v.3.0.0 have a plugin prefix. - 'pluginPrefix:shortcutName'.
44
+ // For example: 'key:s+alt' - for 's+alt' shortcut that is handled by 'key' plugin.
47
45
  ```
48
46
 
49
47
  Load a shortcut definition by calling `load` method.
50
48
 
51
49
  ```js
52
- include shortcuts from '@peter.naydenov/shortcuts'
50
+ // for es6 module projects:
51
+ include { shortcuts, pluginKey, pluginClick } from '@peter.naydenov/shortcuts'
52
+ // for commonjs projects:
53
+ const { shortcuts, pluginKey, pluginClick } = require('@peter.naydenov/shortcuts')
54
+
55
+
56
+
53
57
  const short = shortcuts ();
58
+ // Load a needed plugins
59
+ // short.enablePlugin ( pluginCode, ?pluginOptions )
60
+ short.enablePlugin ( pluginKey )
61
+ short.enablePlugin ( pluginClick )
62
+ // Load a shortcut definition
54
63
  short.load ( shortcutDefinition )
64
+
55
65
  ```
56
66
 
57
67
  Shortcuts are working only if contex is active. To activate a context call `changeContext` method.
@@ -104,39 +114,45 @@ short.getNote ()
104
114
 
105
115
 
106
116
 
107
- ## Mouse Event Descriptions
117
+ ## Plugin 'click' Shortcut Descriptions
108
118
  Mouse event name is build from the following parts:
109
119
  ```js
110
- // mouse-click-<mouse button>-<number of clicks>
120
+ // click:<mouse button>-<number of clicks>-<modifier key>-<modifier key>-<modifier key>
111
121
  // example:
112
- // mouse-click-left-2 -> for double click with left mouse button
113
- // mouse-click-right-3 -> for triple click with right mouse button
122
+ // click: left-2 -> for double click with left mouse button
123
+ // click: right-3 -> for triple click with right mouse button
114
124
 
115
125
  // mouse button options: left, right, middle
116
126
  ```
117
127
 
118
- The modifier keys `ctrl`, `alt`, and `shift` are supported. They are added to the mouse event by sign `+`:
128
+ The modifier keys `ctrl`, `alt`, and `shift` are supported. They are added to the mouse event by sign `-`:
119
129
 
120
130
  ```js
121
131
  // example:
122
- // ctrl+mouse-click-left-1 -> for single click with left mouse button and ctrl key pressed
132
+ // click: left-1-ctrl -> for single click with left mouse button and ctrl key pressed
123
133
  ```
124
- Order of describing mouse event and modifier keys is not important.
134
+
135
+ Order of describing click event and modifier keys is not important.
125
136
 
126
137
  ```js
127
138
  // example:
128
- // mouse-click-left-1+ctrl -> same as above
139
+ // click: ctrl-left-1 -> same as above
129
140
 
130
141
  // These 3 descriptions are equal:
131
- // mouse-click-left-1+ctrl+alt+shift
132
- // alt+shift+mouse-click-left-1+ctrl
133
- // mouse-click-left-1+shift+ctrl+alt
142
+ // click: left-1-ctrl-alt-shift
143
+ // click: alt-shift-left-1-ctrl
144
+ // click: left-1-shift-ctrl-alt
134
145
  ```
135
146
 
136
- Multiple clicks are detected automatically by time interval between clicks. The default interval is 320ms but you can change it by setting `mouseWait` option. Read more in section `Options`.
147
+ Multiple clicks are detected automatically by time interval between clicks. The default interval is 320ms but you can change it by setting `mouseWait` click plugin option.
148
+ ```js
149
+ short.enablePlugin ( pluginClick, { mouseWait: 500 }) // set the interval to 500ms
150
+ ```
151
+
152
+ Read more in section `Options`.
137
153
 
138
154
 
139
- ## Define a mouse targets
155
+ ## Define a Click Targets
140
156
  Target HTML elements for `shortcuts` are defined by `data-click` attribute. The value of the attribute is the name of the target. Example:
141
157
 
142
158
  ```html
@@ -144,7 +160,7 @@ Target HTML elements for `shortcuts` are defined by `data-click` attribute. The
144
160
  <!-- target name is 'id' -->
145
161
  ```
146
162
 
147
- Attribute is customizable by setting `clickTarget` option. Read more in section `Options`.
163
+ Attribute is customizable by setting `clickTarget` click plugin option. Read more in section `Options`.
148
164
 
149
165
  If current shortcuts context contain definition for 2 or more clicks, this may slow down the execution of single shortcuts because `shortcuts` will wait for the time interval to detect multiple clicks. To avoid this for specific targets, you can set `data-quick-click` attribute to the target element. Example:
150
166
 
@@ -157,17 +173,18 @@ Using a <a> tag is a special case. It's always recognized as a target, and alway
157
173
  ```html
158
174
  <a href="#">Click me</a>
159
175
  <!-- Recognized as a target and will not wait for more then 1 click -->
160
- <!-- Take care for the action from shortcut `mouse-click-left-1`. -->
176
+ <!-- Take care for the action from shortcut `click: left-1`. -->
161
177
  ```
162
178
 
163
- Clicking on <a> tag will not execute anything. All events are blocked by default. In your `mouse-click-left-1` action function you can write a code to execute the default action. Example:
179
+ Clicking on <a> tag will execute default browser behaviour. In your `click:left-1` action function you can take the control. Example:
164
180
 
165
181
  ```js
166
182
  {
167
183
  contextName : {
168
- 'mouse-click-left-1' : function ( {target, event} ) {
169
- if ( target.tagName === 'A' ) { // All targets that are <a> tags will execute the default action
170
- window.location.href = target.href // Go to the link
184
+ 'click:left-1' : function ( {target, event} ) {
185
+ if ( target.tagName === 'A' ) { // To prevent default action on <a> tag
186
+ event.preventDefault ()
187
+ // do something...
171
188
  }
172
189
  }
173
190
  }
@@ -176,35 +193,35 @@ Clicking on <a> tag will not execute anything. All events are blocked by default
176
193
 
177
194
 
178
195
 
179
- ## Keyboard Event Descriptions
196
+ ## Plugin 'key' Event Descriptions
180
197
  Keyboard event description contains a key name and a modifier keys if they are used. The modifier keys `ctrl`, `alt`, and `shift` are supported. They are added to the keyboard event by sign `+`:
181
198
 
182
199
  ```js
183
200
  // example:
184
- // ctrl+alt+shift+a -> for key 'a' with ctrl, alt and shift keys pressed
201
+ // key: ctrl+alt+shift+a -> for key 'a' with ctrl, alt and shift keys pressed
185
202
  ```
186
203
 
187
204
  Keyboard event description support a shortcut sequenses. These means that you can press a sequence of keys to trigger a shortcut. The sequence elements are separated by sign "," ( coma ):
188
205
 
189
206
  ```js
190
207
  // example:
191
- // a,b,c -> for key 'a' then key 'b' then key 'c'
208
+ // key: a,b,c -> for key 'a' then key 'b' then key 'c'
192
209
 
193
- // g+shift,o,t,o -> for key 'g' with shift, then key 'o', then key 't' then key 'o'
210
+ // key: g+shift,o,t,o -> for key 'g' with shift, then key 'o', then key 't' then key 'o'
194
211
  ```
195
212
 
196
213
  Order of describing keyboard event and modifier keys is not important, but sequence elements are:
197
214
 
198
215
  ```js
199
216
  // example:
200
- // a+ctrl,l,o,t -> a with ctrl, then l, then o, then t
217
+ // key: a+ctrl,l,o,t -> a with ctrl, then l, then o, then t
201
218
  // this is equal to:
202
- // ctrl+a,l,o,t
219
+ // key: ctrl+a,l,o,t
203
220
  // but not equal to:
204
- // ctrl+a,o,t,l
221
+ // key: ctrl+a,o,t,l
205
222
  ```
206
223
 
207
- Keyboard sequence is detected automatically by time interval between key presses. The default interval is 480ms but you can change it by setting `keyWait` option. Read more in section `Options`.
224
+ Keyboard sequence is detected automatically by time interval between key presses. The default interval is 480ms but you can change it by setting `keyWait` key plugin option. Read more in section `Options`.
208
225
 
209
226
  There is a way to disable automatic sequence detection and mark the begining and the end of the sequense by using a keyboard action functions. Read more in section `Keyboard Action Functions`.
210
227
 
@@ -226,19 +243,19 @@ Special characters that are available for your shortcut descriptions:
226
243
  - ']' - close square bracket key
227
244
  - '`' - backtick key
228
245
 
229
- **Warning**: For keys with two symbols, in shortcut description use the lower one. Examples: Use '=' instead of '+', use '/' instead of '?', etc. Modifier keys are available for special characters too.
246
+ **Warning**: For keys with two symbols(look at the keyboard), in shortcut description use the lower one. Examples: Use '=' instead of '+', use '/' instead of '?', etc. Modifier keys are available for special characters too.
230
247
 
231
248
  **Warining**: Some of the shortcuts are used by OS and the browswer, so they are not available.
232
249
 
233
250
 
234
251
 
235
252
  ## Action Functions
236
- Action functions are called when a shortcut is triggered. They is a difference between keyboard and mouse action functions. Arguments are slightly different.
253
+ Action functions are called when a shortcut is triggered. There is a difference among plugin action functions. Arguments are slightly different.
237
254
 
238
255
 
239
256
 
240
257
  ### Keyboard Action Functions
241
- Description of keyboard action functions is:
258
+ Description of `key` plugin action functions is:
242
259
  ```js
243
260
  function myKeyHandler ({
244
261
  context // (string) Name of the current context;
@@ -257,7 +274,7 @@ function myKeyHandler ({
257
274
 
258
275
 
259
276
  ### Mouse Action Functions
260
- Mouse action functions can be described like:
277
+ Click plugin action functions can be described like:
261
278
 
262
279
  ```js
263
280
  function myMouseHandler ({
@@ -285,16 +302,23 @@ Description of the methods of shortcut instance:
285
302
  ```js
286
303
  load : 'Load and extend a shortcut definition.'
287
304
  , unload : 'Remove a shortcut context with all its shortcuts.'
288
- , changeContext : 'Switch to existing shortcut context.'
305
+
306
+ , enablePlugin : 'Enable a plugin.'
307
+ , disablePlugin : 'Disable a plugin.'
308
+ , mutePlugin : 'Mute a plugin. All events for the plugin will be ignored.'
309
+ , unmutePlugin : 'Unmute a plugin. All events for the plugin will be listened again.'
310
+
311
+ , changeContext : 'Switch to existing shortcut context or shitch off the context(if no argument).'
312
+ , getContext : 'Return a name of current context or null if there is no context selected'
289
313
  , emit : 'Trigger a shortcut or custom event programmatically.'
290
314
  , pause : 'Stop listening for shortcuts.'
291
315
  , resume : 'Resume listening for shortcuts.'
292
316
  , listContexts : 'Return list of available contexts.'
293
- , getContext : 'Return a name of current context or null if there is no context selected'
317
+ , listShortcuts : 'Return list of shortcuts per context.'
294
318
  , getNote : `Return a name of current note or null if note isn't set`
295
319
  , setNote : 'Set a note to current context.'
296
320
  , setDependencies : 'Set dependencies that will be available in action functions.'
297
- , getDependencies : 'Return dependencies object.'
321
+ , getDependencies : 'Return a dependencies object.'
298
322
  ```
299
323
 
300
324
  ### How to 'pause' and 'resume'?
@@ -312,27 +336,44 @@ short.resume ('*') // will resume all shortcuts
312
336
 
313
337
  ## Options
314
338
 
315
- By `options` you can customize the behavior of the shortcuts. Here is the list of available options:
339
+ Shortcut receives `options` during the start. Here is the list of available options:
316
340
 
317
341
  ```js
318
- mouseWait : 'Timeout for entering multiple mouse events. Default value - 320.'
319
- , keyWait : 'Timeout for entering shortcut sequence in ms. Default value - 480'
320
- , clickTarget : 'Data attribute name to recognize click items in HTML. Default value - click' // data attribute 'click' means attribute ( data-click='someName' )
321
- , listenFor : `List input signal sources. Default value - [ 'mouse', 'keyboard' ]`
322
- , onShortcut : 'False or a callback function that is called when a shortcut is triggered. Default value - false'
342
+ onShortcut : 'Callback function that is called when a shortcut is triggered. Default value - false'
343
+ ```
344
+ ```js
345
+ const short = shortcut ({onShortcut: (shortcut) => console.log(shortcut) }) // Log in console each triggered shortcut
346
+ ```
347
+
348
+
349
+
350
+ ### Plugin 'key' options
351
+ ```js
352
+ keyWait : 'Timeout for entering shortcut sequence in ms. Default value - 480'
323
353
  , streamKeys : 'False or a callback function that is called when a key is pressed. Default value - false'
324
354
  ```
325
355
 
326
- You can request default list of options with their default values:
327
356
 
357
+
358
+ ### Plugin 'click' options
328
359
  ```js
329
- shortcuts.getDefaults ()
330
- // Note: This method is availalble on the original shortcuts object, not on the shortcuts instance.
360
+ mouseWait : 'Timeout for entering multiple mouse events. Default value - 320.'
361
+ , clickTarget : 'Data attribute name to recognize click items in HTML. Default value - click' // data attribute 'click' means attribute ( data-click='someName' )
362
+ ```
363
+
364
+ Plugin options are provided as a second argument during the plugin enabling. It's look like this:
365
+
366
+ ```js
367
+ short.enablePlugin ( pluginKey, {
368
+ keyWait: 500 // set the interval to 500ms
369
+ , streamKeys: (key) => console.log(key) // Log in console each pressed key
370
+ })
371
+
372
+ short.enablePlugin ( pluginClick, {
373
+ mouseWait: 200 // set the interval between multiple clicks to 200ms
374
+ , clickTarget: 'puk' // data attribute 'puk' means attribute ( data-puk='someName' )
375
+ })
331
376
 
332
- // start a shortcuts with default options
333
- const short = shortcuts ()
334
- const short = shortcuts ( shortcuts.getDefaults () ) // same as above
335
- // The idea behind getDefaults is to see what options are available and what are their default values.
336
377
  ```
337
378
 
338
379
 
@@ -361,6 +402,13 @@ const short = shortcuts ( shortcuts.getDefaults () ) // same as above
361
402
 
362
403
 
363
404
 
405
+ ## Links
406
+
407
+ - [History of changes](https://github.com/PeterNaydenov/shortcuts/blob/main/Changelog.md)
408
+ - [Migration guide](https://github.com/PeterNaydenov/shortcuts/blob/main/Migration.guide.md)
409
+ - [How to make a plugin](https://github.com/PeterNaydenov/shortcuts/blob/main/How.to.make.plugins.md)
410
+
411
+
364
412
 
365
413
  ## Credits
366
414
  '@peter.naydenov/shortcuts' was created and supported by Peter Naydenov.
@@ -1 +1 @@
1
- "use strict";var e=require("@peter.naydenov/notice");var t={_findTarget:function(e,t){const{listenOptions:{clickTarget:n}}=t;return function e(t){const o=t;return o===document||o===document.body?null:o.dataset[n]||"A"===o.nodeName?o:e(o.parentNode)}},_listen:function(e,t){return function(){const{ev:n,inAPI:{_findTarget:o,_specialChars:r,_readKeyEvent:i,_readMouseEvent:s}}=e,{exposeShortcut:u,currentContext:c,streamKeys:a,listenOptions:l}=t,{mouseWait:m,keyWait:d,clickTarget:p,listenFor:h}=l;let y=[],k=null,f=null,g=null,x=null,T=null,C=!0,F=!1,v=0;const I=()=>C=!1,E=()=>C=!0,S=()=>F=!0,A=()=>!1===C;function O(){let t=y.map((e=>[e.join("+")]));if(!C){let e=t.at(-1);n.emit(e,{wait:I,end:E,ignore:S,isWaiting:A,note:c.note,context:c.name}),F&&(t=t.slice(0,-1),F=!1)}const o={wait:I,end:E,ignore:S,isWaiting:A,note:c.note,context:c.name,dependencies:e.extra};C&&(n.emit(t.join(","),o),u&&u({shortcut:t.join(","),context:c.name,note:c.note,dependencies:e.extra}),y=[],g=null)}function K(){const t=s(f,v),o={target:k,targetProps:k?k.getBoundingClientRect():null,x:f.clientX,y:f.clientY,context:c.name,note:c.note,event:f,dependencies:e.extra};n.emit(t.join("+"),o),u&&u({shortcut:t.join("+"),context:c.name,note:c.note,dependencies:e.extra}),x=null,T=null,k=null,f=null,v=0}h.includes("mouse")&&(window.addEventListener("contextmenu",(e=>{let t=l.maxClicks;return e.preventDefault(),clearTimeout(x),T?(clearTimeout(T),void(T=setTimeout((()=>T=null),m))):(k=o(e.target),k&&k.dataset.hasOwnProperty("quickClick")&&(t=1),k&&"A"===k.tagName&&(t=1),f=e,v++,v>=t?(K(),void(t>1&&(T=setTimeout((()=>T=null),m)))):void(x=setTimeout(K,m)))})),document.addEventListener("click",(e=>{let t=l.maxClicks;return e.preventDefault(),clearTimeout(x),T?(clearTimeout(T),void(T=setTimeout((()=>T=null),m))):(k=o(e.target),k&&k.dataset.hasOwnProperty("quickClick")&&(t=1),k&&"A"===k.tagName&&(t=1),f=e,v++,v>=t?(K(),void(t>1&&(T=setTimeout((()=>T=null),m)))):void(x=setTimeout(K,m)))}))),h.includes("keyboard")&&(document.addEventListener("keydown",(t=>{if(clearTimeout(g),r.hasOwnProperty(t.code))return y.push(i(t,r)),a&&a({key:t.key,context:c.name,note:c.note,dependencies:e.extra}),l.keyIgnore?(clearTimeout(l.keyIgnore),void(l.keyIgnore=setTimeout((()=>l.keyIgnore=null),d))):C&&y.length===l.maxSequence?(O(),void(l.keyIgnore=setTimeout((()=>l.keyIgnore=null),d))):void(C?g=setTimeout(O,d):O())})),document.addEventListener("keypress",(t=>{if(!r.hasOwnProperty(t.code)){if(clearTimeout(g),a&&a({key:t.key,context:c.name,note:c.note,dependencies:e.extra}),l.keyIgnore)return clearTimeout(l.keyIgnore),void(l.keyIgnore=setTimeout((()=>l.keyIgnore=null),d));if(y.push(i(t,r)),C&&y.length===l.maxSequence)return O(),void(l.keyIgnore=setTimeout((()=>l.keyIgnore=null),d));C?g=setTimeout(O,d):O()}})))}},_readKeyEvent:function(){return function(e,t){let{shiftKey:n,altKey:o,ctrlKey:r}=e,i=e.code.replace("Key","").replace("Digit",""),s=[];return r&&s.push("CTRL"),n&&s.push("SHIFT"),o&&s.push("ALT"),t.hasOwnProperty(i)?s.push(t[i].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(i)||s.push(i.toUpperCase()),s.sort()}},_readMouseEvent:function(){return function(e,t){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=e,u=`MOUSE-CLICK-${["LEFT","MIDDLE","RIGHT"][s]}-${t}`,c=[];return c.push(u),r&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),c.sort()}},_readShortcut:function(){return function(e){return e.split(",").map((e=>e.trim())).map((e=>e.split("+").map((e=>e.toUpperCase())).sort().join("+"))).join(",")}},_specialChars:function(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}},changeContext:function(e,t){const{shortcuts:n,listenOptions:o,currentContext:r}=t,{ev:i}=e;return function(e=!1){const t=r.name;if(o.maxSequence=1,o.maxClicks=1,o.keyIgnore>=0&&(clearTimeout(o.keyIgnore),o.keyIgnore=null),!e)return i.reset(),void(r.name=null);t!==e&&(n[e]?(n[t]&&i.reset(),Object.entries(n[e]).forEach((([e,t])=>{if(e.includes("MOUSE-CLICK-")){let[,,,t]=e.split("-"),n=parseInt(t);o.maxClicks<n&&(o.maxClicks=n)}else{let t=e.split(",").length;o.maxSequence<t&&(o.maxSequence=t)}t.forEach((t=>i.on(e,t)))})),r.name=e):i.emit("shortcuts-error",`Context '${e}' does not exist`))}},listShortcuts:function(e,t){const n=t.shortcuts;return function(e=null){if(null!=e){let t=n[e];return null==t?null:Object.entries(t).map((([e,t])=>e))}return Object.keys(n).map((e=>{let t={};return t.context=e,t.shortcuts=Object.entries(n[e]).map((([e,t])=>e)),t}))}},load:function(e,t){const{shortcuts:n}=t,{inAPI:{_readShortcut:o},API:{changeContext:r,getContext:i}}=e;return function(e){const t=i(),s=Object.keys(e);let u=!1;s.forEach((r=>{const i=Object.entries(e[r]);r===t&&(u=!0),n[r]={},i.forEach((([e,t])=>{const i=o(e);t instanceof Function&&(t=[t]),n[r][i]=t}))})),u&&(r(),r(t))}},unload:function(e,t){const{currentContext:n,shortcuts:o}=t,{ev:r}=e;return function(e){n.name!==e?o[e]?delete o[e]:r.emit("shortcuts-error",`Context '${e}' does not exist`):r.emit("shortcuts-error",`Context '${e}' can't be removed during is current active context. Change the context first`)}}};function n(n={}){const o=e(),r={},i={},s={currentContext:{name:null,note:null},shortcuts:{},listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,keyWait:n.keyWait?n.keyWait:480,maxSequence:1,clickTarget:n.clickTarget?n.clickTarget:"click",listenFor:n.listenFor&&Array.isArray(n.listenFor)?n.listenFor:["mouse","keyboard"],keyIgnore:null},exposeShortcut:!(!n.onShortcut||"function"!=typeof n.onShortcut)&&n.onShortcut,streamKeys:!(!n.streamKeys||"function"!=typeof n.streamKeys)&&n.streamKeys},u={ev:o,inAPI:r,API:i,extra:{}};return i.getContext=()=>s.currentContext.name,i.getNote=()=>s.currentContext.note,i.setNote=(e=null)=>{"string"!=typeof e&&null!=e||(s.currentContext.note=e)},i.pause=(e="*")=>o.stop(r._readShortcut(e)),i.resume=(e="*")=>o.start(r._readShortcut(e)),i.emit=(e,...t)=>o.emit(r._readShortcut(e),u.extra,...t),i.listContexts=()=>Object.keys(shortcuts),i.setDependencies=e=>u.extra={...u.extra,...e},i.getDependencies=()=>u.extra,Object.entries(t).forEach((([e,t])=>{e.startsWith("_")?r[e]=t(u,s):i[e]=t(u,s)})),r._listen(),i}n.getDefaults=()=>({mouseWait:320,keyWait:480,clickTarget:"click",listenFor:["mouse","keyboard"],onShortcut:!1,streamKeys:!1}),module.exports=n;
1
+ "use strict";var t=require("@peter.naydenov/notice");var e={_normalizeWithPlugins:function(t,e){return function(t){const n=e.shortcuts;Object.keys(n).forEach((e=>{Object.entries(n[e]).forEach((([o,r])=>{const i=t(o);i!==o&&(delete n[e][o],n[e][i]=r)}))}))}},_readShortcutWithPlugins:function(t,e){return function(n){const{inAPI:o}=t,r=n.split(":")[0],i=o._systemAction(r,"none");let s=n;return-1!==i&&(s=e.plugins[i].shortcutName(n)),s}},_systemAction:function(t,e){return function(t,n,o=null){return e.plugins.findIndex((e=>e.getPrefix()===t&&(e[n]&&e[n](o),!0)))}},changeContext:function(t,e){const{shortcuts:n,currentContext:o}=e,{ev:r}=t;return function(t=!1){const i=o.name;if(!t)return r.reset(),void(o.name=null);i!==t&&(n[t]?(n[i]&&r.reset(),o.name=t,e.plugins.forEach((e=>e.contextChange(t))),Object.entries(n[t]).forEach((([t,e])=>{e.forEach((e=>r.on(t,e)))})),r.on("*",((...t)=>{e.exposeShortcut&&e.exposeShortcut(...t)}))):r.emit("@shortcuts-error",`Context '${t}' does not exist`))}},listShortcuts:function(t,e){const n=e.shortcuts;return function(t=null){if(null!=t){let e=n[t];return null==e?null:Object.entries(e).map((([t,e])=>t))}return Object.keys(n).map((t=>{let e={};return e.context=t,e.shortcuts=Object.entries(n[t]).map((([t,e])=>t)),e}))}},load:function(t,e){const{shortcuts:n,plugins:o}=e,{API:{changeContext:r,getContext:i}}=t;return function(t){const e=i(),s=o.map((t=>t.getPrefix().toUpperCase()));let c=!1;Object.entries(t).forEach((([t,r])=>{t===e&&(c=!0),n[t]={},Object.entries(r).forEach((([e,r])=>{let i=e,c=e.toUpperCase().trim(),u=s.map(((t,e)=>c.startsWith(t)?e:null)).filter((t=>null!==t));if(u.length){let t=u[0];i=o[t].shortcutName(e)}r instanceof Function&&(r=[r]),n[t][i]=r}))})),c&&(r(),r(e))}},unload:function(t,e){const{currentContext:n,shortcuts:o}=e,{ev:r}=t;return function(t){n.name!==t?o[t]?delete o[t]:r.emit("shortcuts-error",`Context '${t}' does not exist`):r.emit("shortcuts-error",`Context '${t}' can't be removed during is current active context. Change the context first`)}}};function n(t){const e=t.toUpperCase(),n=/KEY\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`KEY:${e.slice(o+1).split(",").map((t=>t.trim())).map((t=>t.split("+").map((t=>t.trim())).sort().join("+"))).join(",")}`}function o(t,e){let{shiftKey:n,altKey:o,ctrlKey:r}=t,i=t.code.replace("Key","").replace("Digit",""),s=[];return r&&s.push("CTRL"),n&&s.push("SHIFT"),o&&s.push("ALT"),e.hasOwnProperty(i)?s.push(e[i].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(i)||s.push(i.toUpperCase()),s.sort()}function r(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach((([t,e])=>{if(!o.test(t))return;n++;let i=t.slice(4).split(",").length;r.maxSequence<i&&(r.maxSequence=i)})),n)}function i(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}}function s(t,e,n){const{listenOptions:{clickTarget:o}}=e;let r=n;return r===document||r===document.body?null:r.dataset[o]||"A"===r.nodeName?r:s(t,e,r.parentNode)}function c(t){const e=t.toUpperCase(),n=/CLICK\s*\:/i.test(e),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],c=0,u=e.indexOf(":");return n?(e.slice(u+1).trim().split("-").map((t=>t.trim())).forEach((t=>{o.includes(t)?i=t:r.includes(t)?s.push(t):isNaN(t)||(c=t)})),`CLICK:${i}-${c}${s.length>0?"-":""}${s.sort().join("-")}`):t}function u(t,e){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=t,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${e}`,u=[];return r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function l(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach((([t,e])=>{if(!o.test(t))return;n++;let[,i]=t.slice(6).split("-");r.maxClicks<i&&(r.maxClicks=i)})),n)}exports.pluginClick=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,a={ev:t.ev,_findTarget:s,_readClickEvent:u,mainDependencies:t,regex:/CLICK\s*\:/i},m={currentContext:o,shortcuts:r,listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,clickTarget:n.clickTarget?n.clickTarget:"click"}};i._normalizeWithPlugins(c);let p=function(t,e){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=t,{listenOptions:s,currentContext:c}=e,{mouseWait:u}=s;let l=null,a=null,m=null,p=null,h=0;function f(){const t=r(a,h),e={target:l,targetProps:l?l.getBoundingClientRect():null,x:a.clientX,y:a.clientY,context:c.name,note:c.note,event:a,dependencies:i.extra,type:"click"};n.emit(t,e),m=null,p=null,l=null,a=null,h=0}function d(n){let r=s.maxClicks;return clearTimeout(m),p?(clearTimeout(p),void(p=setTimeout((()=>p=null),u))):(l=o(t,e,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(r=1),l&&"A"===l.tagName&&(r=1),a=n,h++,h>=r?(f(),void(r>1&&(p=setTimeout((()=>p=null),u)))):void(m=setTimeout(f,u)))}function g(n){let r=s.maxClicks;return clearTimeout(m),p?(clearTimeout(p),void(p=setTimeout((()=>p=null),u))):(l=o(t,e,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(r=1),l&&"A"===l.tagName&&(r=1),a=n,h++,h>=r?(f(),void(r>1&&(p=setTimeout((()=>p=null),u)))):void(m=setTimeout(f,u)))}return{start:function(){e.active||(window.addEventListener("contextmenu",g),document.addEventListener("click",d),e.active=!0)},stop:function(){e.active&&(window.removeEventListener("contextmenu",g),document.removeEventListener("click",d),e.active=!1)}}}(a,m),h=l(a,m);h>0&&p.start();const f={getPrefix:()=>"click",shortcutName:t=>c(t),contextChange:()=>{h=l(a,m),h<1&&p.stop(),h>0&&p.start()},mute:()=>p.stop(),unmute:()=>p.start(),destroy:()=>{p.stop(),m=null,f=null}};return Object.freeze(f),f},exports.pluginKey=function(t,e,s={}){let{currentContext:c,shortcuts:u,exposeShortcut:l}=e,{inAPI:a}=t,m={ev:t.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:t,regex:/KEY\s*\:/i},p={currentContext:c,shortcuts:u,active:!1,listenOptions:{keyWait:s.keyWait?s.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys,exposeShortcut:l};a._normalizeWithPlugins(n);let h=function(t,e){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=t,{currentContext:s,streamKeys:c,listenOptions:u}=e,{keyWait:l}=u;let a=[],m=null,p=!0,h=!1;const f=()=>p=!1,d=()=>p=!0,g=()=>h=!0,x=()=>!1===p;function y(){let t=a.map((t=>[t.join("+")]));const e={wait:f,end:d,ignore:g,isWaiting:x,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!p){let o=t.at(-1);n.emit(o,e),h&&(t=t.slice(0,-1),h=!1)}if(p){const o=`KEY:${t.join(",")}`;n.emit(o,e),a=[],m=null}}function C(e){if(clearTimeout(m),o.hasOwnProperty(e.code))return a.push(r(e,o)),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore?(clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l))):p&&a.length===u.maxSequence?(y(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l))):void(p?m=setTimeout(y,l):y())}function k(e){if(!o.hasOwnProperty(e.code)){if(clearTimeout(m),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore)return clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l));if(a.push(r(e,o)),p&&a.length===u.maxSequence)return y(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l));p?m=setTimeout(y,l):y()}}return{start:function(){e.active||(document.addEventListener("keydown",C),document.addEventListener("keypress",k),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("keydown",C),document.removeEventListener("keypress",k),e.active=!1)}}}(m,p),f=r(m,p);f>0&&h.start();const d={getPrefix:()=>"key",shortcutName:t=>n(t),contextChange:t=>{f=r(m,p),f<1&&h.stop(),f>0&&h.start()},mute:()=>h.stop(),unmute:()=>h.start(),destroy:()=>{h.stop(),p=null,d=null}};return Object.freeze(d),d},exports.shortcuts=function(n={}){const o=t(),r={},i={},s={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!n.onShortcut||"function"!=typeof n.onShortcut)&&n.onShortcut},c={ev:o,inAPI:r,API:i,extra:{}};return i.enablePlugin=(t,e={})=>{const n=t.name;if(-1===r._systemAction(n,"none")){let n;n=t(c,s,e),s.plugins.push(n)}},i.disablePlugin=t=>{const e=r._systemAction(t,"destroy");-1!==e&&(s.plugins=s.plugins.filter(((t,n)=>n!==e)))},i.mutePlugin=t=>r._systemAction(t,"mute"),i.unmutePlugin=t=>r._systemAction(t,"unmute"),i.getContext=()=>s.currentContext.name,i.getNote=()=>s.currentContext.note,i.setNote=(t=null)=>{"string"!=typeof t&&null!=t||(s.currentContext.note=t)},i.pause=(t="*")=>{let e=r._readShortcutWithPlugins(t);o.stop(e)},i.resume=(t="*")=>{const e=r._readShortcutWithPlugins(t);o.start(e)},i.emit=(t,...e)=>o.emit(r._readShortcutWithPlugins(t),...e),i.listContexts=()=>Object.keys(s.shortcuts),i.setDependencies=t=>c.extra={...c.extra,...t},i.getDependencies=()=>c.extra,Object.entries(e).forEach((([t,e])=>{t.startsWith("_")?r[t]=e(c,s):i[t]=e(c,s)})),i};
@@ -1 +1 @@
1
- import e from"@peter.naydenov/notice";var t={_findTarget:function(e,t){const{listenOptions:{clickTarget:n}}=t;return function e(t){const o=t;return o===document||o===document.body?null:o.dataset[n]||"A"===o.nodeName?o:e(o.parentNode)}},_listen:function(e,t){return function(){const{ev:n,inAPI:{_findTarget:o,_specialChars:r,_readKeyEvent:i,_readMouseEvent:s}}=e,{exposeShortcut:u,currentContext:c,streamKeys:a,listenOptions:l}=t,{mouseWait:m,keyWait:d,clickTarget:p,listenFor:h}=l;let y=[],k=null,f=null,g=null,x=null,T=null,C=!0,F=!1,v=0;const I=()=>C=!1,E=()=>C=!0,S=()=>F=!0,A=()=>!1===C;function O(){let t=y.map((e=>[e.join("+")]));if(!C){let e=t.at(-1);n.emit(e,{wait:I,end:E,ignore:S,isWaiting:A,note:c.note,context:c.name}),F&&(t=t.slice(0,-1),F=!1)}const o={wait:I,end:E,ignore:S,isWaiting:A,note:c.note,context:c.name,dependencies:e.extra};C&&(n.emit(t.join(","),o),u&&u({shortcut:t.join(","),context:c.name,note:c.note,dependencies:e.extra}),y=[],g=null)}function K(){const t=s(f,v),o={target:k,targetProps:k?k.getBoundingClientRect():null,x:f.clientX,y:f.clientY,context:c.name,note:c.note,event:f,dependencies:e.extra};n.emit(t.join("+"),o),u&&u({shortcut:t.join("+"),context:c.name,note:c.note,dependencies:e.extra}),x=null,T=null,k=null,f=null,v=0}h.includes("mouse")&&(window.addEventListener("contextmenu",(e=>{let t=l.maxClicks;return e.preventDefault(),clearTimeout(x),T?(clearTimeout(T),void(T=setTimeout((()=>T=null),m))):(k=o(e.target),k&&k.dataset.hasOwnProperty("quickClick")&&(t=1),k&&"A"===k.tagName&&(t=1),f=e,v++,v>=t?(K(),void(t>1&&(T=setTimeout((()=>T=null),m)))):void(x=setTimeout(K,m)))})),document.addEventListener("click",(e=>{let t=l.maxClicks;return e.preventDefault(),clearTimeout(x),T?(clearTimeout(T),void(T=setTimeout((()=>T=null),m))):(k=o(e.target),k&&k.dataset.hasOwnProperty("quickClick")&&(t=1),k&&"A"===k.tagName&&(t=1),f=e,v++,v>=t?(K(),void(t>1&&(T=setTimeout((()=>T=null),m)))):void(x=setTimeout(K,m)))}))),h.includes("keyboard")&&(document.addEventListener("keydown",(t=>{if(clearTimeout(g),r.hasOwnProperty(t.code))return y.push(i(t,r)),a&&a({key:t.key,context:c.name,note:c.note,dependencies:e.extra}),l.keyIgnore?(clearTimeout(l.keyIgnore),void(l.keyIgnore=setTimeout((()=>l.keyIgnore=null),d))):C&&y.length===l.maxSequence?(O(),void(l.keyIgnore=setTimeout((()=>l.keyIgnore=null),d))):void(C?g=setTimeout(O,d):O())})),document.addEventListener("keypress",(t=>{if(!r.hasOwnProperty(t.code)){if(clearTimeout(g),a&&a({key:t.key,context:c.name,note:c.note,dependencies:e.extra}),l.keyIgnore)return clearTimeout(l.keyIgnore),void(l.keyIgnore=setTimeout((()=>l.keyIgnore=null),d));if(y.push(i(t,r)),C&&y.length===l.maxSequence)return O(),void(l.keyIgnore=setTimeout((()=>l.keyIgnore=null),d));C?g=setTimeout(O,d):O()}})))}},_readKeyEvent:function(){return function(e,t){let{shiftKey:n,altKey:o,ctrlKey:r}=e,i=e.code.replace("Key","").replace("Digit",""),s=[];return r&&s.push("CTRL"),n&&s.push("SHIFT"),o&&s.push("ALT"),t.hasOwnProperty(i)?s.push(t[i].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(i)||s.push(i.toUpperCase()),s.sort()}},_readMouseEvent:function(){return function(e,t){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=e,u=`MOUSE-CLICK-${["LEFT","MIDDLE","RIGHT"][s]}-${t}`,c=[];return c.push(u),r&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),c.sort()}},_readShortcut:function(){return function(e){return e.split(",").map((e=>e.trim())).map((e=>e.split("+").map((e=>e.toUpperCase())).sort().join("+"))).join(",")}},_specialChars:function(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}},changeContext:function(e,t){const{shortcuts:n,listenOptions:o,currentContext:r}=t,{ev:i}=e;return function(e=!1){const t=r.name;if(o.maxSequence=1,o.maxClicks=1,o.keyIgnore>=0&&(clearTimeout(o.keyIgnore),o.keyIgnore=null),!e)return i.reset(),void(r.name=null);t!==e&&(n[e]?(n[t]&&i.reset(),Object.entries(n[e]).forEach((([e,t])=>{if(e.includes("MOUSE-CLICK-")){let[,,,t]=e.split("-"),n=parseInt(t);o.maxClicks<n&&(o.maxClicks=n)}else{let t=e.split(",").length;o.maxSequence<t&&(o.maxSequence=t)}t.forEach((t=>i.on(e,t)))})),r.name=e):i.emit("shortcuts-error",`Context '${e}' does not exist`))}},listShortcuts:function(e,t){const n=t.shortcuts;return function(e=null){if(null!=e){let t=n[e];return null==t?null:Object.entries(t).map((([e,t])=>e))}return Object.keys(n).map((e=>{let t={};return t.context=e,t.shortcuts=Object.entries(n[e]).map((([e,t])=>e)),t}))}},load:function(e,t){const{shortcuts:n}=t,{inAPI:{_readShortcut:o},API:{changeContext:r,getContext:i}}=e;return function(e){const t=i(),s=Object.keys(e);let u=!1;s.forEach((r=>{const i=Object.entries(e[r]);r===t&&(u=!0),n[r]={},i.forEach((([e,t])=>{const i=o(e);t instanceof Function&&(t=[t]),n[r][i]=t}))})),u&&(r(),r(t))}},unload:function(e,t){const{currentContext:n,shortcuts:o}=t,{ev:r}=e;return function(e){n.name!==e?o[e]?delete o[e]:r.emit("shortcuts-error",`Context '${e}' does not exist`):r.emit("shortcuts-error",`Context '${e}' can't be removed during is current active context. Change the context first`)}}};function n(n={}){const o=e(),r={},i={},s={currentContext:{name:null,note:null},shortcuts:{},listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,keyWait:n.keyWait?n.keyWait:480,maxSequence:1,clickTarget:n.clickTarget?n.clickTarget:"click",listenFor:n.listenFor&&Array.isArray(n.listenFor)?n.listenFor:["mouse","keyboard"],keyIgnore:null},exposeShortcut:!(!n.onShortcut||"function"!=typeof n.onShortcut)&&n.onShortcut,streamKeys:!(!n.streamKeys||"function"!=typeof n.streamKeys)&&n.streamKeys},u={ev:o,inAPI:r,API:i,extra:{}};return i.getContext=()=>s.currentContext.name,i.getNote=()=>s.currentContext.note,i.setNote=(e=null)=>{"string"!=typeof e&&null!=e||(s.currentContext.note=e)},i.pause=(e="*")=>o.stop(r._readShortcut(e)),i.resume=(e="*")=>o.start(r._readShortcut(e)),i.emit=(e,...t)=>o.emit(r._readShortcut(e),u.extra,...t),i.listContexts=()=>Object.keys(shortcuts),i.setDependencies=e=>u.extra={...u.extra,...e},i.getDependencies=()=>u.extra,Object.entries(t).forEach((([e,t])=>{e.startsWith("_")?r[e]=t(u,s):i[e]=t(u,s)})),r._listen(),i}n.getDefaults=()=>({mouseWait:320,keyWait:480,clickTarget:"click",listenFor:["mouse","keyboard"],onShortcut:!1,streamKeys:!1});export{n as default};
1
+ import t from"@peter.naydenov/notice";var e={_normalizeWithPlugins:function(t,e){return function(t){const n=e.shortcuts;Object.keys(n).forEach((e=>{Object.entries(n[e]).forEach((([o,r])=>{const i=t(o);i!==o&&(delete n[e][o],n[e][i]=r)}))}))}},_readShortcutWithPlugins:function(t,e){return function(n){const{inAPI:o}=t,r=n.split(":")[0],i=o._systemAction(r,"none");let s=n;return-1!==i&&(s=e.plugins[i].shortcutName(n)),s}},_systemAction:function(t,e){return function(t,n,o=null){return e.plugins.findIndex((e=>e.getPrefix()===t&&(e[n]&&e[n](o),!0)))}},changeContext:function(t,e){const{shortcuts:n,currentContext:o}=e,{ev:r}=t;return function(t=!1){const i=o.name;if(!t)return r.reset(),void(o.name=null);i!==t&&(n[t]?(n[i]&&r.reset(),o.name=t,e.plugins.forEach((e=>e.contextChange(t))),Object.entries(n[t]).forEach((([t,e])=>{e.forEach((e=>r.on(t,e)))})),r.on("*",((...t)=>{e.exposeShortcut&&e.exposeShortcut(...t)}))):r.emit("@shortcuts-error",`Context '${t}' does not exist`))}},listShortcuts:function(t,e){const n=e.shortcuts;return function(t=null){if(null!=t){let e=n[t];return null==e?null:Object.entries(e).map((([t,e])=>t))}return Object.keys(n).map((t=>{let e={};return e.context=t,e.shortcuts=Object.entries(n[t]).map((([t,e])=>t)),e}))}},load:function(t,e){const{shortcuts:n,plugins:o}=e,{API:{changeContext:r,getContext:i}}=t;return function(t){const e=i(),s=o.map((t=>t.getPrefix().toUpperCase()));let c=!1;Object.entries(t).forEach((([t,r])=>{t===e&&(c=!0),n[t]={},Object.entries(r).forEach((([e,r])=>{let i=e,c=e.toUpperCase().trim(),u=s.map(((t,e)=>c.startsWith(t)?e:null)).filter((t=>null!==t));if(u.length){let t=u[0];i=o[t].shortcutName(e)}r instanceof Function&&(r=[r]),n[t][i]=r}))})),c&&(r(),r(e))}},unload:function(t,e){const{currentContext:n,shortcuts:o}=e,{ev:r}=t;return function(t){n.name!==t?o[t]?delete o[t]:r.emit("shortcuts-error",`Context '${t}' does not exist`):r.emit("shortcuts-error",`Context '${t}' can't be removed during is current active context. Change the context first`)}}};function n(t){const e=t.toUpperCase(),n=/KEY\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`KEY:${e.slice(o+1).split(",").map((t=>t.trim())).map((t=>t.split("+").map((t=>t.trim())).sort().join("+"))).join(",")}`}function o(t,e){let{shiftKey:n,altKey:o,ctrlKey:r}=t,i=t.code.replace("Key","").replace("Digit",""),s=[];return r&&s.push("CTRL"),n&&s.push("SHIFT"),o&&s.push("ALT"),e.hasOwnProperty(i)?s.push(e[i].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(i)||s.push(i.toUpperCase()),s.sort()}function r(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach((([t,e])=>{if(!o.test(t))return;n++;let i=t.slice(4).split(",").length;r.maxSequence<i&&(r.maxSequence=i)})),n)}function i(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}}function s(t,e,s={}){let{currentContext:c,shortcuts:u,exposeShortcut:l}=e,{inAPI:a}=t,m={ev:t.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:t,regex:/KEY\s*\:/i},p={currentContext:c,shortcuts:u,active:!1,listenOptions:{keyWait:s.keyWait?s.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys,exposeShortcut:l};a._normalizeWithPlugins(n);let h=function(t,e){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=t,{currentContext:s,streamKeys:c,listenOptions:u}=e,{keyWait:l}=u;let a=[],m=null,p=!0,h=!1;const f=()=>p=!1,d=()=>p=!0,g=()=>h=!0,x=()=>!1===p;function y(){let t=a.map((t=>[t.join("+")]));const e={wait:f,end:d,ignore:g,isWaiting:x,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!p){let o=t.at(-1);n.emit(o,e),h&&(t=t.slice(0,-1),h=!1)}if(p){const o=`KEY:${t.join(",")}`;n.emit(o,e),a=[],m=null}}function C(e){if(clearTimeout(m),o.hasOwnProperty(e.code))return a.push(r(e,o)),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore?(clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l))):p&&a.length===u.maxSequence?(y(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l))):void(p?m=setTimeout(y,l):y())}function k(e){if(!o.hasOwnProperty(e.code)){if(clearTimeout(m),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore)return clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l));if(a.push(r(e,o)),p&&a.length===u.maxSequence)return y(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l));p?m=setTimeout(y,l):y()}}return{start:function(){e.active||(document.addEventListener("keydown",C),document.addEventListener("keypress",k),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("keydown",C),document.removeEventListener("keypress",k),e.active=!1)}}}(m,p),f=r(m,p);f>0&&h.start();const d={getPrefix:()=>"key",shortcutName:t=>n(t),contextChange:t=>{f=r(m,p),f<1&&h.stop(),f>0&&h.start()},mute:()=>h.stop(),unmute:()=>h.start(),destroy:()=>{h.stop(),p=null,d=null}};return Object.freeze(d),d}function c(t,e,n){const{listenOptions:{clickTarget:o}}=e;let r=n;return r===document||r===document.body?null:r.dataset[o]||"A"===r.nodeName?r:c(t,e,r.parentNode)}function u(t){const e=t.toUpperCase(),n=/CLICK\s*\:/i.test(e),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],c=0,u=e.indexOf(":");return n?(e.slice(u+1).trim().split("-").map((t=>t.trim())).forEach((t=>{o.includes(t)?i=t:r.includes(t)?s.push(t):isNaN(t)||(c=t)})),`CLICK:${i}-${c}${s.length>0?"-":""}${s.sort().join("-")}`):t}function l(t,e){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=t,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${e}`,u=[];return r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function a(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach((([t,e])=>{if(!o.test(t))return;n++;let[,i]=t.slice(6).split("-");r.maxClicks<i&&(r.maxClicks=i)})),n)}function m(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,_findTarget:c,_readClickEvent:l,mainDependencies:t,regex:/CLICK\s*\:/i},m={currentContext:o,shortcuts:r,listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,clickTarget:n.clickTarget?n.clickTarget:"click"}};i._normalizeWithPlugins(u);let p=function(t,e){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=t,{listenOptions:s,currentContext:c}=e,{mouseWait:u}=s;let l=null,a=null,m=null,p=null,h=0;function f(){const t=r(a,h),e={target:l,targetProps:l?l.getBoundingClientRect():null,x:a.clientX,y:a.clientY,context:c.name,note:c.note,event:a,dependencies:i.extra,type:"click"};n.emit(t,e),m=null,p=null,l=null,a=null,h=0}function d(n){let r=s.maxClicks;return clearTimeout(m),p?(clearTimeout(p),void(p=setTimeout((()=>p=null),u))):(l=o(t,e,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(r=1),l&&"A"===l.tagName&&(r=1),a=n,h++,h>=r?(f(),void(r>1&&(p=setTimeout((()=>p=null),u)))):void(m=setTimeout(f,u)))}function g(n){let r=s.maxClicks;return clearTimeout(m),p?(clearTimeout(p),void(p=setTimeout((()=>p=null),u))):(l=o(t,e,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(r=1),l&&"A"===l.tagName&&(r=1),a=n,h++,h>=r?(f(),void(r>1&&(p=setTimeout((()=>p=null),u)))):void(m=setTimeout(f,u)))}return{start:function(){e.active||(window.addEventListener("contextmenu",g),document.addEventListener("click",d),e.active=!0)},stop:function(){e.active&&(window.removeEventListener("contextmenu",g),document.removeEventListener("click",d),e.active=!1)}}}(s,m),h=a(s,m);h>0&&p.start();const f={getPrefix:()=>"click",shortcutName:t=>u(t),contextChange:()=>{h=a(s,m),h<1&&p.stop(),h>0&&p.start()},mute:()=>p.stop(),unmute:()=>p.start(),destroy:()=>{p.stop(),m=null,f=null}};return Object.freeze(f),f}function p(n={}){const o=t(),r={},i={},s={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!n.onShortcut||"function"!=typeof n.onShortcut)&&n.onShortcut},c={ev:o,inAPI:r,API:i,extra:{}};return i.enablePlugin=(t,e={})=>{const n=t.name;if(-1===r._systemAction(n,"none")){let n;n=t(c,s,e),s.plugins.push(n)}},i.disablePlugin=t=>{const e=r._systemAction(t,"destroy");-1!==e&&(s.plugins=s.plugins.filter(((t,n)=>n!==e)))},i.mutePlugin=t=>r._systemAction(t,"mute"),i.unmutePlugin=t=>r._systemAction(t,"unmute"),i.getContext=()=>s.currentContext.name,i.getNote=()=>s.currentContext.note,i.setNote=(t=null)=>{"string"!=typeof t&&null!=t||(s.currentContext.note=t)},i.pause=(t="*")=>{let e=r._readShortcutWithPlugins(t);o.stop(e)},i.resume=(t="*")=>{const e=r._readShortcutWithPlugins(t);o.start(e)},i.emit=(t,...e)=>o.emit(r._readShortcutWithPlugins(t),...e),i.listContexts=()=>Object.keys(s.shortcuts),i.setDependencies=t=>c.extra={...c.extra,...t},i.getDependencies=()=>c.extra,Object.entries(e).forEach((([t,e])=>{t.startsWith("_")?r[t]=e(c,s):i[t]=e(c,s)})),i}export{m as pluginClick,s as pluginKey,p as shortcuts};
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).shortcuts=t()}(this,(function(){"use strict";var e={_findTarget:function(e,t){const{listenOptions:{clickTarget:n}}=t;return function e(t){const o=t;return o===document||o===document.body?null:o.dataset[n]||"A"===o.nodeName?o:e(o.parentNode)}},_listen:function(e,t){return function(){const{ev:n,inAPI:{_findTarget:o,_specialChars:r,_readKeyEvent:i,_readMouseEvent:s}}=e,{exposeShortcut:c,currentContext:u,streamKeys:l,listenOptions:a}=t,{mouseWait:d,keyWait:f,clickTarget:m,listenFor:h}=a;let p=[],g=null,y=null,k=null,x=null,T=null,C=!0,F=!1,E=0;const v=()=>C=!1,I=()=>C=!0,S=()=>F=!0,A=()=>!1===C;function O(){let t=p.map((e=>[e.join("+")]));if(!C){let e=t.at(-1);n.emit(e,{wait:v,end:I,ignore:S,isWaiting:A,note:u.note,context:u.name}),F&&(t=t.slice(0,-1),F=!1)}const o={wait:v,end:I,ignore:S,isWaiting:A,note:u.note,context:u.name,dependencies:e.extra};C&&(n.emit(t.join(","),o),c&&c({shortcut:t.join(","),context:u.name,note:u.note,dependencies:e.extra}),p=[],k=null)}function b(){const t=s(y,E),o={target:g,targetProps:g?g.getBoundingClientRect():null,x:y.clientX,y:y.clientY,context:u.name,note:u.note,event:y,dependencies:e.extra};n.emit(t.join("+"),o),c&&c({shortcut:t.join("+"),context:u.name,note:u.note,dependencies:e.extra}),x=null,T=null,g=null,y=null,E=0}h.includes("mouse")&&(window.addEventListener("contextmenu",(e=>{let t=a.maxClicks;return e.preventDefault(),clearTimeout(x),T?(clearTimeout(T),void(T=setTimeout((()=>T=null),d))):(g=o(e.target),g&&g.dataset.hasOwnProperty("quickClick")&&(t=1),g&&"A"===g.tagName&&(t=1),y=e,E++,E>=t?(b(),void(t>1&&(T=setTimeout((()=>T=null),d)))):void(x=setTimeout(b,d)))})),document.addEventListener("click",(e=>{let t=a.maxClicks;return e.preventDefault(),clearTimeout(x),T?(clearTimeout(T),void(T=setTimeout((()=>T=null),d))):(g=o(e.target),g&&g.dataset.hasOwnProperty("quickClick")&&(t=1),g&&"A"===g.tagName&&(t=1),y=e,E++,E>=t?(b(),void(t>1&&(T=setTimeout((()=>T=null),d)))):void(x=setTimeout(b,d)))}))),h.includes("keyboard")&&(document.addEventListener("keydown",(t=>{if(clearTimeout(k),r.hasOwnProperty(t.code))return p.push(i(t,r)),l&&l({key:t.key,context:u.name,note:u.note,dependencies:e.extra}),a.keyIgnore?(clearTimeout(a.keyIgnore),void(a.keyIgnore=setTimeout((()=>a.keyIgnore=null),f))):C&&p.length===a.maxSequence?(O(),void(a.keyIgnore=setTimeout((()=>a.keyIgnore=null),f))):void(C?k=setTimeout(O,f):O())})),document.addEventListener("keypress",(t=>{if(!r.hasOwnProperty(t.code)){if(clearTimeout(k),l&&l({key:t.key,context:u.name,note:u.note,dependencies:e.extra}),a.keyIgnore)return clearTimeout(a.keyIgnore),void(a.keyIgnore=setTimeout((()=>a.keyIgnore=null),f));if(p.push(i(t,r)),C&&p.length===a.maxSequence)return O(),void(a.keyIgnore=setTimeout((()=>a.keyIgnore=null),f));C?k=setTimeout(O,f):O()}})))}},_readKeyEvent:function(){return function(e,t){let{shiftKey:n,altKey:o,ctrlKey:r}=e,i=e.code.replace("Key","").replace("Digit",""),s=[];return r&&s.push("CTRL"),n&&s.push("SHIFT"),o&&s.push("ALT"),t.hasOwnProperty(i)?s.push(t[i].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(i)||s.push(i.toUpperCase()),s.sort()}},_readMouseEvent:function(){return function(e,t){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=e,c=`MOUSE-CLICK-${["LEFT","MIDDLE","RIGHT"][s]}-${t}`,u=[];return u.push(c),r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.sort()}},_readShortcut:function(){return function(e){return e.split(",").map((e=>e.trim())).map((e=>e.split("+").map((e=>e.toUpperCase())).sort().join("+"))).join(",")}},_specialChars:function(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}},changeContext:function(e,t){const{shortcuts:n,listenOptions:o,currentContext:r}=t,{ev:i}=e;return function(e=!1){const t=r.name;if(o.maxSequence=1,o.maxClicks=1,o.keyIgnore>=0&&(clearTimeout(o.keyIgnore),o.keyIgnore=null),!e)return i.reset(),void(r.name=null);t!==e&&(n[e]?(n[t]&&i.reset(),Object.entries(n[e]).forEach((([e,t])=>{if(e.includes("MOUSE-CLICK-")){let[,,,t]=e.split("-"),n=parseInt(t);o.maxClicks<n&&(o.maxClicks=n)}else{let t=e.split(",").length;o.maxSequence<t&&(o.maxSequence=t)}t.forEach((t=>i.on(e,t)))})),r.name=e):i.emit("shortcuts-error",`Context '${e}' does not exist`))}},listShortcuts:function(e,t){const n=t.shortcuts;return function(e=null){if(null!=e){let t=n[e];return null==t?null:Object.entries(t).map((([e,t])=>e))}return Object.keys(n).map((e=>{let t={};return t.context=e,t.shortcuts=Object.entries(n[e]).map((([e,t])=>e)),t}))}},load:function(e,t){const{shortcuts:n}=t,{inAPI:{_readShortcut:o},API:{changeContext:r,getContext:i}}=e;return function(e){const t=i(),s=Object.keys(e);let c=!1;s.forEach((r=>{const i=Object.entries(e[r]);r===t&&(c=!0),n[r]={},i.forEach((([e,t])=>{const i=o(e);t instanceof Function&&(t=[t]),n[r][i]=t}))})),c&&(r(),r(t))}},unload:function(e,t){const{currentContext:n,shortcuts:o}=t,{ev:r}=e;return function(e){n.name!==e?o[e]?delete o[e]:r.emit("shortcuts-error",`Context '${e}' does not exist`):r.emit("shortcuts-error",`Context '${e}' can't be removed during is current active context. Change the context first`)}}};function t(t={}){const n=new function(){let e={"*":[]},t={},n=[],o=!1,r="";return{on:function(t,n){e[t]||(e[t]=[]),e[t].push(n)},once:function(e,n){"*"!==e&&(t[e]||(t[e]=[]),t[e].push(n))},off:function(n,o){if(o)return e[n]&&(e[n]=e[n].filter((e=>e!==o))),t[n]&&(t[n]=t[n].filter((e=>e!==o))),e[n]&&0===e[n].length&&delete e[n],void(t[n]&&0===t[n].length&&delete e[n]);t[n]&&delete t[n],e[n]&&delete e[n]},reset:function(){e={"*":[]},t={},n=[]},emit:function(){const[i,...s]=arguments;function c(t){"*"!==t&&(n.includes(t)||(e[t].forEach((e=>e(...s))),e["*"].forEach((e=>e(i,...s)))))}if(o&&(console.log(`${r} Event "${i}" was triggered.`),s.length>0&&(console.log("Arguments:"),console.log(...s),console.log("^----"))),"*"!==i){if(t[i]){if(n.includes(i))return;t[i].forEach((e=>e(...s))),delete t[i]}e[i]&&c(i)}else Object.keys(e).forEach((e=>c(e)))},stop:function(o){if("*"!==o)n.push(o);else{const o=Object.keys(e),r=Object.keys(t);n=[...r,...o]}},start:function(e){n="*"!==e?n.filter((t=>e!=t)):[]},debug:function(e,t){o=!!e,t&&"string"==typeof t&&(r=t)}}},o={},r={},i={currentContext:{name:null,note:null},shortcuts:{},listenOptions:{mouseWait:t.mouseWait?t.mouseWait:320,maxClicks:1,keyWait:t.keyWait?t.keyWait:480,maxSequence:1,clickTarget:t.clickTarget?t.clickTarget:"click",listenFor:t.listenFor&&Array.isArray(t.listenFor)?t.listenFor:["mouse","keyboard"],keyIgnore:null},exposeShortcut:!(!t.onShortcut||"function"!=typeof t.onShortcut)&&t.onShortcut,streamKeys:!(!t.streamKeys||"function"!=typeof t.streamKeys)&&t.streamKeys},s={ev:n,inAPI:o,API:r,extra:{}};return r.getContext=()=>i.currentContext.name,r.getNote=()=>i.currentContext.note,r.setNote=(e=null)=>{"string"!=typeof e&&null!=e||(i.currentContext.note=e)},r.pause=(e="*")=>n.stop(o._readShortcut(e)),r.resume=(e="*")=>n.start(o._readShortcut(e)),r.emit=(e,...t)=>n.emit(o._readShortcut(e),s.extra,...t),r.listContexts=()=>Object.keys(shortcuts),r.setDependencies=e=>s.extra={...s.extra,...e},r.getDependencies=()=>s.extra,Object.entries(e).forEach((([e,t])=>{e.startsWith("_")?o[e]=t(s,i):r[e]=t(s,i)})),o._listen(),r}return t.getDefaults=()=>({mouseWait:320,keyWait:480,clickTarget:"click",listenFor:["mouse","keyboard"],onShortcut:!1,streamKeys:!1}),t}));
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).shortcuts={})}(this,(function(e){"use strict";var t={_normalizeWithPlugins:function(e,t){return function(e){const n=t.shortcuts;Object.keys(n).forEach((t=>{Object.entries(n[t]).forEach((([o,r])=>{const i=e(o);i!==o&&(delete n[t][o],n[t][i]=r)}))}))}},_readShortcutWithPlugins:function(e,t){return function(n){const{inAPI:o}=e,r=n.split(":")[0],i=o._systemAction(r,"none");let s=n;return-1!==i&&(s=t.plugins[i].shortcutName(n)),s}},_systemAction:function(e,t){return function(e,n,o=null){return t.plugins.findIndex((t=>t.getPrefix()===e&&(t[n]&&t[n](o),!0)))}},changeContext:function(e,t){const{shortcuts:n,currentContext:o}=t,{ev:r}=e;return function(e=!1){const i=o.name;if(!e)return r.reset(),void(o.name=null);i!==e&&(n[e]?(n[i]&&r.reset(),o.name=e,t.plugins.forEach((t=>t.contextChange(e))),Object.entries(n[e]).forEach((([e,t])=>{t.forEach((t=>r.on(e,t)))})),r.on("*",((...e)=>{t.exposeShortcut&&t.exposeShortcut(...e)}))):r.emit("@shortcuts-error",`Context '${e}' does not exist`))}},listShortcuts:function(e,t){const n=t.shortcuts;return function(e=null){if(null!=e){let t=n[e];return null==t?null:Object.entries(t).map((([e,t])=>e))}return Object.keys(n).map((e=>{let t={};return t.context=e,t.shortcuts=Object.entries(n[e]).map((([e,t])=>e)),t}))}},load:function(e,t){const{shortcuts:n,plugins:o}=t,{API:{changeContext:r,getContext:i}}=e;return function(e){const t=i(),s=o.map((e=>e.getPrefix().toUpperCase()));let c=!1;Object.entries(e).forEach((([e,r])=>{e===t&&(c=!0),n[e]={},Object.entries(r).forEach((([t,r])=>{let i=t,c=t.toUpperCase().trim(),u=s.map(((e,t)=>c.startsWith(e)?t:null)).filter((e=>null!==e));if(u.length){let e=u[0];i=o[e].shortcutName(t)}r instanceof Function&&(r=[r]),n[e][i]=r}))})),c&&(r(),r(t))}},unload:function(e,t){const{currentContext:n,shortcuts:o}=t,{ev:r}=e;return function(e){n.name!==e?o[e]?delete o[e]:r.emit("shortcuts-error",`Context '${e}' does not exist`):r.emit("shortcuts-error",`Context '${e}' can't be removed during is current active context. Change the context first`)}}};function n(e){const t=e.toUpperCase(),n=/KEY\s*\:/i.test(t),o=t.indexOf(":");if(!n)return e;return`KEY:${t.slice(o+1).split(",").map((e=>e.trim())).map((e=>e.split("+").map((e=>e.trim())).sort().join("+"))).join(",")}`}function o(e,t){let{shiftKey:n,altKey:o,ctrlKey:r}=e,i=e.code.replace("Key","").replace("Digit",""),s=[];return r&&s.push("CTRL"),n&&s.push("SHIFT"),o&&s.push("ALT"),t.hasOwnProperty(i)?s.push(t[i].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(i)||s.push(i.toUpperCase()),s.sort()}function r(e,t){let n=0;const{regex:o}=e,{listenOptions:r,currentContext:{name:i},shortcuts:s}=t;return null==i?0:(Object.entries(s[i]).forEach((([e,t])=>{if(!o.test(e))return;n++;let i=e.slice(4).split(",").length;r.maxSequence<i&&(r.maxSequence=i)})),n)}function i(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}}function s(e,t,n){const{listenOptions:{clickTarget:o}}=t;let r=n;return r===document||r===document.body?null:r.dataset[o]||"A"===r.nodeName?r:s(e,t,r.parentNode)}function c(e){const t=e.toUpperCase(),n=/CLICK\s*\:/i.test(t),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],c=0,u=t.indexOf(":");return n?(t.slice(u+1).trim().split("-").map((e=>e.trim())).forEach((e=>{o.includes(e)?i=e:r.includes(e)?s.push(e):isNaN(e)||(c=e)})),`CLICK:${i}-${c}${s.length>0?"-":""}${s.sort().join("-")}`):e}function u(e,t){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=e,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${t}`,u=[];return r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function l(e,t){let n=0;const{regex:o}=e,{listenOptions:r,currentContext:{name:i},shortcuts:s}=t;return null==i?0:(Object.entries(s[i]).forEach((([e,t])=>{if(!o.test(e))return;n++;let[,i]=e.slice(6).split("-");r.maxClicks<i&&(r.maxClicks=i)})),n)}e.pluginClick=function(e,t,n){let{currentContext:o,shortcuts:r}=t,{inAPI:i}=e,a={ev:e.ev,_findTarget:s,_readClickEvent:u,mainDependencies:e,regex:/CLICK\s*\:/i},f={currentContext:o,shortcuts:r,listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,clickTarget:n.clickTarget?n.clickTarget:"click"}};i._normalizeWithPlugins(c);let m=function(e,t){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=e,{listenOptions:s,currentContext:c}=t,{mouseWait:u}=s;let l=null,a=null,f=null,m=null,p=0;function h(){const e=r(a,p),t={target:l,targetProps:l?l.getBoundingClientRect():null,x:a.clientX,y:a.clientY,context:c.name,note:c.note,event:a,dependencies:i.extra,type:"click"};n.emit(e,t),f=null,m=null,l=null,a=null,p=0}function d(n){let r=s.maxClicks;return clearTimeout(f),m?(clearTimeout(m),void(m=setTimeout((()=>m=null),u))):(l=o(e,t,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(r=1),l&&"A"===l.tagName&&(r=1),a=n,p++,p>=r?(h(),void(r>1&&(m=setTimeout((()=>m=null),u)))):void(f=setTimeout(h,u)))}function g(n){let r=s.maxClicks;return clearTimeout(f),m?(clearTimeout(m),void(m=setTimeout((()=>m=null),u))):(l=o(e,t,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(r=1),l&&"A"===l.tagName&&(r=1),a=n,p++,p>=r?(h(),void(r>1&&(m=setTimeout((()=>m=null),u)))):void(f=setTimeout(h,u)))}return{start:function(){t.active||(window.addEventListener("contextmenu",g),document.addEventListener("click",d),t.active=!0)},stop:function(){t.active&&(window.removeEventListener("contextmenu",g),document.removeEventListener("click",d),t.active=!1)}}}(a,f),p=l(a,f);p>0&&m.start();const h={getPrefix:()=>"click",shortcutName:e=>c(e),contextChange:()=>{p=l(a,f),p<1&&m.stop(),p>0&&m.start()},mute:()=>m.stop(),unmute:()=>m.start(),destroy:()=>{m.stop(),f=null,h=null}};return Object.freeze(h),h},e.pluginKey=function(e,t,s={}){let{currentContext:c,shortcuts:u,exposeShortcut:l}=t,{inAPI:a}=e,f={ev:e.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:e,regex:/KEY\s*\:/i},m={currentContext:c,shortcuts:u,active:!1,listenOptions:{keyWait:s.keyWait?s.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys,exposeShortcut:l};a._normalizeWithPlugins(n);let p=function(e,t){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=e,{currentContext:s,streamKeys:c,listenOptions:u}=t,{keyWait:l}=u;let a=[],f=null,m=!0,p=!1;const h=()=>m=!1,d=()=>m=!0,g=()=>p=!0,y=()=>!1===m;function x(){let e=a.map((e=>[e.join("+")]));const t={wait:h,end:d,ignore:g,isWaiting:y,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!m){let o=e.at(-1);n.emit(o,t),p&&(e=e.slice(0,-1),p=!1)}if(m){const o=`KEY:${e.join(",")}`;n.emit(o,t),a=[],f=null}}function C(t){if(clearTimeout(f),o.hasOwnProperty(t.code))return a.push(r(t,o)),c&&c({key:t.key,context:s.name,note:s.note,dependencies:e.extra}),u.keyIgnore?(clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l))):m&&a.length===u.maxSequence?(x(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l))):void(m?f=setTimeout(x,l):x())}function k(t){if(!o.hasOwnProperty(t.code)){if(clearTimeout(f),c&&c({key:t.key,context:s.name,note:s.note,dependencies:e.extra}),u.keyIgnore)return clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l));if(a.push(r(t,o)),m&&a.length===u.maxSequence)return x(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l));m?f=setTimeout(x,l):x()}}return{start:function(){t.active||(document.addEventListener("keydown",C),document.addEventListener("keypress",k),t.active=!0)},stop:function(){t.active&&(document.removeEventListener("keydown",C),document.removeEventListener("keypress",k),t.active=!1)}}}(f,m),h=r(f,m);h>0&&p.start();const d={getPrefix:()=>"key",shortcutName:e=>n(e),contextChange:e=>{h=r(f,m),h<1&&p.stop(),h>0&&p.start()},mute:()=>p.stop(),unmute:()=>p.start(),destroy:()=>{p.stop(),m=null,d=null}};return Object.freeze(d),d},e.shortcuts=function(e={}){const n=new function(){let e={"*":[]},t={},n=[],o=!1,r="";return{on:function(t,n){e[t]||(e[t]=[]),e[t].push(n)},once:function(e,n){"*"!==e&&(t[e]||(t[e]=[]),t[e].push(n))},off:function(n,o){if(o)return e[n]&&(e[n]=e[n].filter((e=>e!==o))),t[n]&&(t[n]=t[n].filter((e=>e!==o))),e[n]&&0===e[n].length&&delete e[n],void(t[n]&&0===t[n].length&&delete e[n]);t[n]&&delete t[n],e[n]&&delete e[n]},reset:function(){e={"*":[]},t={},n=[]},emit:function(){const[i,...s]=arguments;function c(t){"*"!==t&&(n.includes(t)||(e[t].forEach((e=>e(...s))),e["*"].forEach((e=>e(i,...s)))))}if(o&&(console.log(`${r} Event "${i}" was triggered.`),s.length>0&&(console.log("Arguments:"),console.log(...s),console.log("^----"))),"*"!==i){if(t[i]){if(n.includes(i))return;t[i].forEach((e=>e(...s))),delete t[i]}e[i]&&c(i)}else Object.keys(e).forEach((e=>c(e)))},stop:function(o){if("*"!==o)n.push(o);else{const o=Object.keys(e),r=Object.keys(t);n=[...r,...o]}},start:function(e){n="*"!==e?n.filter((t=>e!=t)):[]},debug:function(e,t){o=!!e,t&&"string"==typeof t&&(r=t)}}},o={},r={},i={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!e.onShortcut||"function"!=typeof e.onShortcut)&&e.onShortcut},s={ev:n,inAPI:o,API:r,extra:{}};return r.enablePlugin=(e,t={})=>{const n=e.name;if(-1===o._systemAction(n,"none")){let n;n=e(s,i,t),i.plugins.push(n)}},r.disablePlugin=e=>{const t=o._systemAction(e,"destroy");-1!==t&&(i.plugins=i.plugins.filter(((e,n)=>n!==t)))},r.mutePlugin=e=>o._systemAction(e,"mute"),r.unmutePlugin=e=>o._systemAction(e,"unmute"),r.getContext=()=>i.currentContext.name,r.getNote=()=>i.currentContext.note,r.setNote=(e=null)=>{"string"!=typeof e&&null!=e||(i.currentContext.note=e)},r.pause=(e="*")=>{let t=o._readShortcutWithPlugins(e);n.stop(t)},r.resume=(e="*")=>{const t=o._readShortcutWithPlugins(e);n.start(t)},r.emit=(e,...t)=>n.emit(o._readShortcutWithPlugins(e),...t),r.listContexts=()=>Object.keys(i.shortcuts),r.setDependencies=e=>s.extra={...s.extra,...e},r.getDependencies=()=>s.extra,Object.entries(t).forEach((([e,t])=>{e.startsWith("_")?o[e]=t(s,i):r[e]=t(s,i)})),r}}));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@peter.naydenov/shortcuts",
3
3
  "description": "Context control of shortcuts based on keyboard and mouse events",
4
- "version": "2.2.0",
4
+ "version": "3.0.0",
5
5
  "license": "MIT",
6
6
  "author": "Peter Naydenov",
7
7
  "main": "./dist/shortcuts.umd.js",
@@ -19,7 +19,7 @@
19
19
  "scripts": {
20
20
  "dev": "vite",
21
21
  "build": "rollup -c",
22
- "test": "cypress run --component --browser chrome test"
22
+ "test": "cypress open --component --browser chrome test"
23
23
  },
24
24
  "repository": {
25
25
  "type": "git",
@@ -34,12 +34,12 @@
34
34
  "@rollup/plugin-terser": "^0.4.4",
35
35
  "@vitejs/plugin-react": "^4.2.1",
36
36
  "ask-for-promise": "^2.0.3",
37
- "chai": "^5.0.3",
38
- "cypress": "^13.6.4",
37
+ "chai": "^5.1.0",
38
+ "cypress": "^13.6.6",
39
39
  "mocha": "^10.3.0",
40
40
  "react": "^18.2.0",
41
41
  "react-dom": "^18.2.0",
42
- "vite": "^5.1.1"
42
+ "vite": "^5.1.5"
43
43
  },
44
44
  "keywords": [
45
45
  "shortcut",