@peter.naydenov/shortcuts 3.1.3 → 3.2.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/Changelog.md +7 -0
- package/README.md +64 -2
- package/dist/shortcuts.cjs +1 -1
- package/dist/shortcuts.esm.mjs +1 -1
- package/dist/shortcuts.umd.js +1 -1
- package/index.html +68 -16
- package/package.json +14 -12
- package/src/main.js +7 -4
- package/src/methods/changeContext.js +3 -1
- package/src/plugins/form/_defaults.js +18 -0
- package/src/plugins/form/_listenDOM.js +90 -0
- package/src/plugins/form/_normalizeShortcutName.js +21 -0
- package/src/plugins/form/_registerShortcutEvents.js +71 -0
- package/src/plugins/form/index.js +84 -0
- package/src/plugins/key/_listenDOM.js +1 -1
- package/test/01-general.test.js +299 -0
- package/test-components/Block.jsx +2 -0
- package/vitest-example/HelloWorld.js +9 -0
- package/vitest-example/HelloWorld.test.js +11 -0
- package/vitest.workspace.js +19 -0
- package/cypress/fixtures/example.json +0 -5
- package/cypress/support/commands.js +0 -25
- package/cypress/support/component-index.html +0 -14
- package/cypress/support/component.js +0 -27
- package/cypress/support/e2e.js +0 -20
- package/cypress.config.js +0 -10
- package/test/01-general.cy.js +0 -246
package/Changelog.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
## Release History
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
### 3.2.0 ( 2025-08-15)
|
|
5
|
+
- [x] Plugin 'form' was added. It allows you to listen for form elements changes.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### 3.1.4 ( 2025-05-3)
|
|
9
|
+
- [x] Dependency update. @peter.naydenov/notice - v.2.4.1
|
|
10
|
+
|
|
4
11
|
|
|
5
12
|
### 3.1.3 ( 2025-01-12)
|
|
6
13
|
- [x] Dependency update. @peter.naydenov/notice - v.2.4.0
|
package/README.md
CHANGED
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
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
|
|
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 3 plugins:
|
|
12
12
|
- `key` - converts keyboard events to shortcut names;
|
|
13
13
|
- `click` - converts mouse events to shortcut names;
|
|
14
|
+
- `form` - watches for form elements changes;
|
|
14
15
|
|
|
15
|
-
Planned work on the plugins for `scroll`, `drag-drop`,
|
|
16
|
+
Planned work on the plugins for `scroll`, `drag-drop`, etc...
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
|
|
@@ -249,6 +250,67 @@ Special characters that are available for your shortcut descriptions:
|
|
|
249
250
|
|
|
250
251
|
|
|
251
252
|
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
## Plugin 'form' Shortcut Descriptions
|
|
256
|
+
`Form` plugin is used to watch for changes in inputs, textareas, select and textarea elements. All 3 possible shortcuts are predefined: 'form: watch', 'form: define' and 'form: action'.
|
|
257
|
+
```js
|
|
258
|
+
`form: watch` // (function). Should return list of elements to watch
|
|
259
|
+
`form: define` // (function). Define every element you are watching as a type(own definition).
|
|
260
|
+
`form: action` // (function). Function should return a list of objects with action function definitions.
|
|
261
|
+
```
|
|
262
|
+
Action definitions have 4 possible properties:
|
|
263
|
+
```js
|
|
264
|
+
{
|
|
265
|
+
fn // (function) Action function
|
|
266
|
+
, type // (string) Type of the element. Available types are according to `form: define` reponses
|
|
267
|
+
, timing // (string) Possible values are: 'in', 'out', 'instant'
|
|
268
|
+
, wait // (number) It's a event reducer timer in milliseconds. Worsk only for 'timing: instant'
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Definition Example:
|
|
273
|
+
```js
|
|
274
|
+
const shortcutScope = {
|
|
275
|
+
...
|
|
276
|
+
, 'form : watch' : () => 'input, button' // Will select all inputs and buttons elements on the page.
|
|
277
|
+
, 'form : define' : ( target ) => { // Target is a DOM element selected by 'form: watch'
|
|
278
|
+
if ( target.tagName === 'INPUT' ) { // Will define inputs as 'input' type
|
|
279
|
+
return 'input' // (String) Custom according your preference
|
|
280
|
+
}
|
|
281
|
+
if ( target.tagName === 'BUTTON' ) { // Will define buttons as 'button' type
|
|
282
|
+
return 'button'
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
, 'form : action' : () => [
|
|
286
|
+
{
|
|
287
|
+
fn: ({target}) => { console.log ( target)}
|
|
288
|
+
, type : 'input' // According to 'form: define'
|
|
289
|
+
, timing : 'in' // on focus in
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
fn: ({target}) => { console.log ( 'extra')}
|
|
293
|
+
, type : 'input'
|
|
294
|
+
, timing : 'in' // on focus in
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
fn: () => { console.log ( 'Update content') }
|
|
298
|
+
, type : 'input'
|
|
299
|
+
, timing : 'instant' // on content change. on each change
|
|
300
|
+
, wait : 500 // Wait 500ms between changes.
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
fn: () => { console.log('It was a button') }
|
|
304
|
+
, type : 'button' // According to 'form: define'
|
|
305
|
+
, timing : 'out' // on focus out
|
|
306
|
+
}
|
|
307
|
+
] // form: action
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
`form:watch` can contains `.someClass` for selecting elements by class name or `#someId` for selecting elements by id. It's could be everything that works in querySelectorAll. The `form:define` gives you a way to separate different inputs and privide a custom callback for each of them or use single callback for all inputs.
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
|
|
252
314
|
## Action Functions
|
|
253
315
|
Action functions are called when a shortcut is triggered. There is a difference among plugin action functions. Arguments are slightly different.
|
|
254
316
|
|
package/dist/shortcuts.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("@peter.naydenov/notice");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 u=!1;Object.entries(e).forEach((([e,r])=>{e===t&&(u=!0),n[e]={},Object.entries(r).forEach((([t,r])=>{let i=t,u=t.toUpperCase().trim(),c=s.map(((e,t)=>u.startsWith(e)?t:null)).filter((e=>null!==e));if(c.length){let e=c[0];i=o[e].shortcutName(t)}r instanceof Function&&(r=[r]),n[e][i]=r}))})),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(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 u(e){const t=e.toUpperCase(),n=/CLICK\s*\:/i.test(t),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],u=0,c=t.indexOf(":");return n?(t.slice(c+1).trim().split("-").map((e=>e.trim())).forEach((e=>{o.includes(e)?i=e:r.includes(e)?s.push(e):isNaN(e)||(u=e)})),`CLICK:${i}-${u}${s.length>0?"-":""}${s.sort().join("-")}`):e}function c(e,t){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=e,u=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${t}`,c=[];return r&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),c.length>0?`${u}${c.length>0?"-":""}${c.sort().join("-")}`:`${u}`}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)}exports.pluginClick=function(e,t,n){let{currentContext:o,shortcuts:r}=t,{inAPI:i}=e,a={ev:e.ev,_findTarget:s,_readClickEvent:c,mainDependencies:e,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(e,t){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=e,{listenOptions:s,currentContext:u}=t,{mouseWait:c}=s;let l=null,a=null,m=null,p=null,h=0;function f(){const e=r(a,h),t={target:l,targetProps:l?l.getBoundingClientRect():null,x:a.clientX,y:a.clientY,context:u.name,note:u.note,event:a,dependencies:i.extra,type:"click"};n.emit(e,t),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),c))):(l=o(e,t,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),c)))):void(m=setTimeout(f,c)))}function g(n){let r=s.maxClicks;return clearTimeout(m),p?(clearTimeout(p),void(p=setTimeout((()=>p=null),c))):(l=o(e,t,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),c)))):void(m=setTimeout(f,c)))}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,m),h=l(a,m);h>0&&p.start();let f={getPrefix:()=>"click",shortcutName:e=>u(e),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(e,t,s={}){let{currentContext:u,shortcuts:c,exposeShortcut:l}=t,{inAPI:a}=e,m={ev:e.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:e,regex:/KEY\s*\:/i},p={currentContext:u,shortcuts:c,active:!1,listenOptions:{keyWait:s.keyWait?s.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys
|
|
1
|
+
"use strict";var e=require("@peter.naydenov/notice");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 u=!1;Object.entries(e).forEach((([e,r])=>{e===t&&(u=!0),n[e]={},Object.entries(r).forEach((([t,r])=>{let i=t,u=t.toUpperCase().trim(),c=s.map(((e,t)=>u.startsWith(e)?t:null)).filter((e=>null!==e));if(c.length){let e=c[0];i=o[e].shortcutName(t)}r instanceof Function&&(r=[r]),n[e][i]=r}))})),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(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 u(e){const t=e.toUpperCase(),n=/CLICK\s*\:/i.test(t),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],u=0,c=t.indexOf(":");return n?(t.slice(c+1).trim().split("-").map((e=>e.trim())).forEach((e=>{o.includes(e)?i=e:r.includes(e)?s.push(e):isNaN(e)||(u=e)})),`CLICK:${i}-${u}${s.length>0?"-":""}${s.sort().join("-")}`):e}function c(e,t){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=e,u=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${t}`,c=[];return r&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),c.length>0?`${u}${c.length>0?"-":""}${c.sort().join("-")}`:`${u}`}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)}exports.pluginClick=function(e,t,n){let{currentContext:o,shortcuts:r}=t,{inAPI:i}=e,a={ev:e.ev,_findTarget:s,_readClickEvent:c,mainDependencies:e,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(e,t){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=e,{listenOptions:s,currentContext:u}=t,{mouseWait:c}=s;let l=null,a=null,m=null,p=null,h=0;function f(){const e=r(a,h),t={target:l,targetProps:l?l.getBoundingClientRect():null,x:a.clientX,y:a.clientY,context:u.name,note:u.note,event:a,dependencies:i.extra,type:"click"};n.emit(e,t),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),c))):(l=o(e,t,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),c)))):void(m=setTimeout(f,c)))}function g(n){let r=s.maxClicks;return clearTimeout(m),p?(clearTimeout(p),void(p=setTimeout((()=>p=null),c))):(l=o(e,t,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),c)))):void(m=setTimeout(f,c)))}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,m),h=l(a,m);h>0&&p.start();let f={getPrefix:()=>"click",shortcutName:e=>u(e),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(e,t,s={}){let{currentContext:u,shortcuts:c,exposeShortcut:l}=t,{inAPI:a}=e,m={ev:e.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:e,regex:/KEY\s*\:/i},p={currentContext:u,shortcuts:c,active:!1,listenOptions:{keyWait:s.keyWait?s.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys};a._normalizeWithPlugins(n);let h=function(e,t){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=e,{currentContext:s,streamKeys:u,listenOptions:c}=t,{keyWait:l}=c;let a=[],m=null,p=!0,h=!1;const f=()=>p=!1,d=()=>p=!0,g=()=>h=!0,x=()=>!1===p;function y(){let e=a.map((e=>[e.join("+")]));const t={wait:f,end:d,ignore:g,isWaiting:x,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!p){let o=e.at(-1);n.emit(o,t),h&&(e=e.slice(0,-1),h=!1)}if(p){const o=`KEY:${e.join(",")}`;n.emit(o,t),a=[],m=null}}function C(t){if(clearTimeout(m),o.hasOwnProperty(t.code))return a.push(r(t,o)),u&&u({key:t.key,context:s.name,note:s.note,dependencies:e.extra}),c.keyIgnore?(clearTimeout(c.keyIgnore),void(c.keyIgnore=setTimeout((()=>c.keyIgnore=null),l))):p&&a.length===c.maxSequence?(y(),void(c.keyIgnore=setTimeout((()=>c.keyIgnore=null),l))):void(p?m=setTimeout(y,l):y())}function k(t){if(!o.hasOwnProperty(t.code)){if(clearTimeout(m),u&&u({key:t.key,context:s.name,note:s.note,dependencies:e.extra}),c.keyIgnore)return clearTimeout(c.keyIgnore),void(c.keyIgnore=setTimeout((()=>c.keyIgnore=null),l));if(a.push(r(t,o)),p&&a.length===c.maxSequence)return y(),void(c.keyIgnore=setTimeout((()=>c.keyIgnore=null),l));p?m=setTimeout(y,l):y()}}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)}}}(m,p),f=r(m,p);f>0&&h.start();let d={getPrefix:()=>"key",shortcutName:e=>n(e),contextChange:e=>{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=e(),r={},i={},s={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!n.onShortcut||"function"!=typeof n.onShortcut)&&n.onShortcut},u={ev:o,inAPI:r,API:i,extra:{}};return i.enablePlugin=(e,t={})=>{const n=e.name;if(-1===r._systemAction(n,"none")){let n;n=e(u,s,t),s.plugins.push(n)}},i.disablePlugin=e=>{const t=r._systemAction(e,"destroy");-1!==t&&(s.plugins=s.plugins.filter(((e,n)=>n!==t)))},i.mutePlugin=e=>r._systemAction(e,"mute"),i.unmutePlugin=e=>r._systemAction(e,"unmute"),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="*")=>{let t=r._readShortcutWithPlugins(e);o.stop(t)},i.resume=(e="*")=>{const t=r._readShortcutWithPlugins(e);o.start(t)},i.emit=(e,...t)=>o.emit(r._readShortcutWithPlugins(e),...t),i.listContexts=()=>Object.keys(s.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)})),i};
|
package/dist/shortcuts.esm.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
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
|
|
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};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();let 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();let 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};
|
package/dist/shortcuts.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
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();let 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();let 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=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){let o=!1;"*"!==t&&(n.includes(t)||(e[t].every((e=>{const t=e(...s);return"string"!=typeof t||"STOP"!==t.toUpperCase()||(o=!0,!1)})),o||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}}));
|
|
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();let 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};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();let 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=function(){let e={"*":[]},t={},n=new Set,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=new Set},emit:function(){const[i,...s]=arguments;function c(t){let o=!1;"*"!==t&&(n.has(t)||(e[t].every((e=>{const t=e(...s);return"string"!=typeof t||"STOP"!==t.toUpperCase()||(o=!0,!1)})),o||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.has(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.add(o);else{const o=Object.keys(e),r=Object.keys(t);n=new Set([...r,...o])}},start:function(e){"*"!==e?n.delete(e):n.clear()},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/index.html
CHANGED
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
</head>
|
|
23
23
|
<body>
|
|
24
24
|
<script type="module">
|
|
25
|
-
import
|
|
25
|
+
import { shortcuts, pluginKey, pluginClick, pluginForm } from './src/main.js'
|
|
26
26
|
|
|
27
27
|
const options = {
|
|
28
|
-
onShortcut (
|
|
28
|
+
onShortcut ( shortcut, { context, note }) {
|
|
29
29
|
console.log ( '-- RESULTS --->' )
|
|
30
30
|
console.log ( 'Shortcut', shortcut )
|
|
31
31
|
console.log ( 'Context:', context )
|
|
@@ -33,41 +33,93 @@
|
|
|
33
33
|
} // onShortcut func.
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
const short =
|
|
37
|
-
short.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
const short = shortcuts ( options );
|
|
37
|
+
short.enablePlugin( pluginKey )
|
|
38
|
+
short.enablePlugin( pluginClick )
|
|
39
|
+
short.enablePlugin ( pluginForm )
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
short.load ( {
|
|
43
|
+
test : {
|
|
44
|
+
'key:r' : () => console.log ( 'R was clicked' )
|
|
45
|
+
},
|
|
46
|
+
general : {
|
|
47
|
+
'key:q' : [ () => console.log('Q was clicked') ]
|
|
48
|
+
, 'key:r,o,s' : () => console.log ( 'ROS was clicked' )
|
|
49
|
+
, 'click:left-2' : () => console.log ( 'Mouse left click 2' )
|
|
50
|
+
, 'key:r' : [
|
|
42
51
|
({isWaiting}) => {
|
|
43
52
|
if ( !isWaiting() ) {
|
|
44
53
|
console.log ( 'R was clicked' )
|
|
45
54
|
}
|
|
46
55
|
}
|
|
47
56
|
]
|
|
48
|
-
, 'shift+w' : [
|
|
57
|
+
, 'key:shift+w' : [
|
|
49
58
|
({wait, end, ignore, isWaiting, note }) => {
|
|
59
|
+
console.log ( 'HIT a shift + w')
|
|
50
60
|
ignore ()
|
|
51
61
|
if ( isWaiting () ) {
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
end ()
|
|
63
|
+
console.log('END')
|
|
54
64
|
}
|
|
55
65
|
else {
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
console.log('WAIT')
|
|
67
|
+
wait ()
|
|
58
68
|
}
|
|
59
69
|
},
|
|
60
|
-
() =>
|
|
70
|
+
({end}) => {
|
|
71
|
+
console.log ( 'W' )
|
|
72
|
+
setTimeout ( end, 3000 )
|
|
73
|
+
}
|
|
61
74
|
]
|
|
62
|
-
|
|
75
|
+
, 'form : watch' : () => 'input, button'
|
|
76
|
+
, 'form : define' : (target) => {
|
|
77
|
+
if ( target.tagName === 'INPUT' ) {
|
|
78
|
+
return 'input'
|
|
79
|
+
}
|
|
80
|
+
if ( target.tagName === 'BUTTON' ) {
|
|
81
|
+
return 'button'
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
, 'form : action' : () => [
|
|
85
|
+
{
|
|
86
|
+
fn: ({target}) => { console.log ( target)}
|
|
87
|
+
, type : 'input'
|
|
88
|
+
, timing : 'in'
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
fn: ({target}) => { console.log ( 'extra')}
|
|
92
|
+
, type : 'input'
|
|
93
|
+
, timing : 'in'
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
fn: () => { console.log ( 'Update content') }
|
|
97
|
+
, type : 'input'
|
|
98
|
+
, timing : 'instant'
|
|
99
|
+
, wait : 500
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
fn: () => { console.log('It was a button') }
|
|
103
|
+
, type : 'button'
|
|
104
|
+
, timing : 'out'
|
|
105
|
+
}
|
|
106
|
+
] // form: action
|
|
107
|
+
}
|
|
63
108
|
})
|
|
64
109
|
short.changeContext ( 'general' )
|
|
65
|
-
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
// short.changeContext ( )
|
|
113
|
+
// short.changeContext ( 'general' )
|
|
114
|
+
|
|
115
|
+
|
|
66
116
|
</script>
|
|
67
117
|
<div class="block" data-click="red-block">
|
|
68
118
|
<span>hello</span>
|
|
69
119
|
</div>
|
|
70
120
|
|
|
71
121
|
<button class="big-btn" data-click="mega-button" draggable>Mega button</button>
|
|
122
|
+
<p><input id="name" type="text" placeholder="Name"/></p>
|
|
123
|
+
<p><input id="age" type="text" placeholder="Age" /></p>
|
|
72
124
|
</body>
|
|
73
125
|
</html>
|
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": "3.
|
|
4
|
+
"version": "3.2.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Peter Naydenov",
|
|
7
7
|
"main": "./dist/shortcuts.umd.js",
|
|
@@ -19,27 +19,29 @@
|
|
|
19
19
|
"scripts": {
|
|
20
20
|
"dev": "vite",
|
|
21
21
|
"build": "rollup -c",
|
|
22
|
-
"test": "
|
|
22
|
+
"test": "vitest --workspace=vitest.workspace.js"
|
|
23
23
|
},
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
26
26
|
"url": "git+https://github.com/PeterNaydenov/shortcuts"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@peter.naydenov/notice": "^2.4.
|
|
29
|
+
"@peter.naydenov/notice": "^2.4.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@
|
|
33
|
-
"@rollup/plugin-
|
|
32
|
+
"@peter.naydenov/visual-controller-for-react": "^3.0.1",
|
|
33
|
+
"@rollup/plugin-commonjs": "^28.0.6",
|
|
34
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
34
35
|
"@rollup/plugin-terser": "^0.4.4",
|
|
35
|
-
"@vitejs/plugin-react": "^
|
|
36
|
+
"@vitejs/plugin-react": "^5.0.0",
|
|
37
|
+
"@vitest/browser": "^3.2.4",
|
|
36
38
|
"ask-for-promise": "^3.0.1",
|
|
37
|
-
"chai": "^5.1
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"react": "^19.0.
|
|
41
|
-
"react-dom": "^19.0.
|
|
42
|
-
"vite": "^
|
|
39
|
+
"chai": "^5.2.1",
|
|
40
|
+
"mocha": "^11.7.1",
|
|
41
|
+
"playwright": "^1.54.2",
|
|
42
|
+
"react": "^19.0.1",
|
|
43
|
+
"react-dom": "^19.0.1",
|
|
44
|
+
"vite": "^7.1.2"
|
|
43
45
|
},
|
|
44
46
|
"keywords": [
|
|
45
47
|
"shortcut",
|
package/src/main.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Shortcuts
|
|
5
5
|
* ========
|
|
6
6
|
*
|
|
7
|
-
* Create shortcuts for your web application based on keyboard and mouse events.
|
|
7
|
+
* Create shortcuts for your web application based on keyboard and mouse and DOM events.
|
|
8
8
|
* Repository: https://github.com/PeterNaydenov/shortcuts
|
|
9
9
|
*
|
|
10
10
|
* History notes:
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* - Method 'emit' was added on September 30st, 2023
|
|
14
14
|
* - Version 2.0.0 was published on October 16th, 2023
|
|
15
15
|
* - Version 3.0.0. Plugin system. Published on March 5th, 2024
|
|
16
|
+
* - Version 3.2.0. Added plugin 'form'. Published on August 15th, 2025
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
|
|
@@ -23,6 +24,7 @@ import methods from './methods/index.js'
|
|
|
23
24
|
// Plugins
|
|
24
25
|
import pluginKey from './plugins/key/index.js'
|
|
25
26
|
import pluginClick from './plugins/click/index.js'
|
|
27
|
+
import pluginForm from './plugins/form/index.js'
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
|
|
@@ -103,21 +105,21 @@ function main ( options = {} ) {
|
|
|
103
105
|
/**
|
|
104
106
|
* @function getContext
|
|
105
107
|
* @description Get current context name
|
|
106
|
-
* @returns {string} - Current context name
|
|
108
|
+
* @returns {string|null} - Current context name
|
|
107
109
|
*/
|
|
108
110
|
API.getContext = () => state.currentContext.name
|
|
109
111
|
|
|
110
112
|
/**
|
|
111
113
|
* @function getNote
|
|
112
114
|
* @description Get current context note
|
|
113
|
-
* @returns {string} - Current context note
|
|
115
|
+
* @returns {string|null} - Current context note
|
|
114
116
|
*/
|
|
115
117
|
API.getNote = () => state.currentContext.note
|
|
116
118
|
|
|
117
119
|
/**
|
|
118
120
|
* @function setNote
|
|
119
121
|
* @description Set current context note
|
|
120
|
-
* @param {string} note - Context note
|
|
122
|
+
* @param {string|null} note - Context note
|
|
121
123
|
* @returns {void}
|
|
122
124
|
*/
|
|
123
125
|
API.setNote = (note=null) => { if (typeof note === 'string' || note == null ) state.currentContext.note = note }
|
|
@@ -194,6 +196,7 @@ export { main as shortcuts }
|
|
|
194
196
|
export {
|
|
195
197
|
pluginKey
|
|
196
198
|
, pluginClick
|
|
199
|
+
, pluginForm
|
|
197
200
|
}
|
|
198
201
|
|
|
199
202
|
|
|
@@ -29,7 +29,9 @@ return function changeContext ( contextName = false ) {
|
|
|
29
29
|
const current = currentContext.name;
|
|
30
30
|
|
|
31
31
|
if ( !contextName ) { // Switch off all shortcuts if contextName is not defined
|
|
32
|
-
ev.reset ()
|
|
32
|
+
ev.reset ()
|
|
33
|
+
// All DOM/Mouse listeners provides trigger signal to notice(the event emitter).
|
|
34
|
+
// If event emitter was reset, all DOM/Mouse listener signals will be ignored.
|
|
33
35
|
currentContext.name = null
|
|
34
36
|
return
|
|
35
37
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const _defaults = {
|
|
2
|
+
watch : () => 'input, select, textarea, button, a'
|
|
3
|
+
, define: (el) => {
|
|
4
|
+
if ( el.type === 'checkbox' || el.type === 'radio' ) {
|
|
5
|
+
return 'checkbox'
|
|
6
|
+
}
|
|
7
|
+
if ( el.type == 'button' || el.type=='submit' ) {
|
|
8
|
+
return 'button'
|
|
9
|
+
}
|
|
10
|
+
return 'input'
|
|
11
|
+
} // define
|
|
12
|
+
} // defaults
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
export default _defaults
|
|
17
|
+
|
|
18
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
function _listenDOM ( dependencies, state ) {
|
|
6
|
+
const { ev } = dependencies;
|
|
7
|
+
let timeout = null;
|
|
8
|
+
|
|
9
|
+
function setupData ( dependencies, state, event, type) {
|
|
10
|
+
return {
|
|
11
|
+
target : event.target
|
|
12
|
+
// TODO: Find if is possible to add some size and positioning data
|
|
13
|
+
, context : state.currentContext.name
|
|
14
|
+
, note : state.currentContext.note
|
|
15
|
+
, event
|
|
16
|
+
, dependencies : dependencies.mainDependencies.extra
|
|
17
|
+
, type
|
|
18
|
+
}
|
|
19
|
+
} // setupData func.
|
|
20
|
+
|
|
21
|
+
function listenFocusIn ( event ) { // Timing: in
|
|
22
|
+
const
|
|
23
|
+
{ callbacks, typeFn } = state
|
|
24
|
+
, target = event.target
|
|
25
|
+
, type = typeFn ( target )
|
|
26
|
+
, prop = setupData ( dependencies, state, event, type )
|
|
27
|
+
, key = `${type}/in`
|
|
28
|
+
;
|
|
29
|
+
if ( callbacks[key] == null ) return
|
|
30
|
+
ev.emit ( key, prop, callbacks[key] )
|
|
31
|
+
} // focusIn func.
|
|
32
|
+
|
|
33
|
+
function listenFocusOut ( event ) { // Timing: out
|
|
34
|
+
const
|
|
35
|
+
{ callbacks, typeFn } = state
|
|
36
|
+
, prop = setupData ( dependencies, state, event, "form-out" )
|
|
37
|
+
, target = event.target
|
|
38
|
+
, type = typeFn ( target )
|
|
39
|
+
, key = `${type}/out`
|
|
40
|
+
;
|
|
41
|
+
if ( callbacks[key] == null ) return
|
|
42
|
+
ev.emit ( key, prop, callbacks[key] )
|
|
43
|
+
} // focusOut func.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
function listenInput ( event ) { // Timing: instant
|
|
47
|
+
const
|
|
48
|
+
{ callbacks, typeFn } = state
|
|
49
|
+
, prop = setupData ( dependencies, state, event, "form-instant" )
|
|
50
|
+
, target = event.target
|
|
51
|
+
, type = typeFn ( target )
|
|
52
|
+
, wait = state.wait[`${type}`]
|
|
53
|
+
, key = `${type}/instant`
|
|
54
|
+
;
|
|
55
|
+
if ( callbacks[key] == null ) return
|
|
56
|
+
if ( wait === 0 ) {
|
|
57
|
+
ev.emit ( key, prop, callbacks[key] )
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
let fn = () => ev.emit ( key, prop, callbacks[key] )
|
|
61
|
+
clearTimeout ( timeout )
|
|
62
|
+
timeout = setTimeout ( fn, wait )
|
|
63
|
+
} // input func.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
function start () {
|
|
67
|
+
if ( state.active ) return
|
|
68
|
+
document.addEventListener ( 'focusin', listenFocusIn );
|
|
69
|
+
document.addEventListener ( 'focusout', listenFocusOut );
|
|
70
|
+
document.addEventListener ( 'input', listenInput );
|
|
71
|
+
state.active = true
|
|
72
|
+
} // start func.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
function stop () {
|
|
76
|
+
if ( !state.active ) return
|
|
77
|
+
document.removeEventListener ( 'focusin', listenFocusIn );
|
|
78
|
+
document.removeEventListener ( 'focusout', listenFocusOut );
|
|
79
|
+
document.removeEventListener ( 'input', listenInput );
|
|
80
|
+
state.active = false
|
|
81
|
+
} // stop func.
|
|
82
|
+
|
|
83
|
+
return { start, stop }
|
|
84
|
+
} // _listenDOM func.
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
export default _listenDOM
|
|
89
|
+
|
|
90
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
function _normalizeShortcutName ( name ) {
|
|
4
|
+
const
|
|
5
|
+
upperCase = name.toUpperCase ()
|
|
6
|
+
, regex = /FORM\s*\:/i
|
|
7
|
+
, isKeyboardShortcut = regex.test ( upperCase )
|
|
8
|
+
, sliceIndex = upperCase.indexOf ( ':' )
|
|
9
|
+
;
|
|
10
|
+
|
|
11
|
+
if ( !isKeyboardShortcut ) return name
|
|
12
|
+
let shortcut = upperCase.slice(sliceIndex+1).trim ()
|
|
13
|
+
|
|
14
|
+
return `FORM:${shortcut}`
|
|
15
|
+
} // _normalizeShortcutName func.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
export default _normalizeShortcutName
|
|
20
|
+
|
|
21
|
+
|