@peter.naydenov/shortcuts 3.1.4 → 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 +3 -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 +48 -4
- package/package.json +9 -9
- package/src/main.js +4 -1
- 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/test/01-general.test.js +13 -1
- package/test-components/Block.jsx +2 -0
package/Changelog.md
CHANGED
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,7 +22,7 @@
|
|
|
22
22
|
</head>
|
|
23
23
|
<body>
|
|
24
24
|
<script type="module">
|
|
25
|
-
import { shortcuts, pluginKey, pluginClick } from '
|
|
25
|
+
import { shortcuts, pluginKey, pluginClick, pluginForm } from './src/main.js'
|
|
26
26
|
|
|
27
27
|
const options = {
|
|
28
28
|
onShortcut ( shortcut, { context, note }) {
|
|
@@ -36,9 +36,14 @@
|
|
|
36
36
|
const short = shortcuts ( options );
|
|
37
37
|
short.enablePlugin( pluginKey )
|
|
38
38
|
short.enablePlugin( pluginClick )
|
|
39
|
+
short.enablePlugin ( pluginForm )
|
|
39
40
|
|
|
40
41
|
|
|
41
|
-
short.load ( {
|
|
42
|
+
short.load ( {
|
|
43
|
+
test : {
|
|
44
|
+
'key:r' : () => console.log ( 'R was clicked' )
|
|
45
|
+
},
|
|
46
|
+
general : {
|
|
42
47
|
'key:q' : [ () => console.log('Q was clicked') ]
|
|
43
48
|
, 'key:r,o,s' : () => console.log ( 'ROS was clicked' )
|
|
44
49
|
, 'click:left-2' : () => console.log ( 'Mouse left click 2' )
|
|
@@ -67,15 +72,54 @@
|
|
|
67
72
|
setTimeout ( end, 3000 )
|
|
68
73
|
}
|
|
69
74
|
]
|
|
70
|
-
|
|
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
|
+
}
|
|
71
108
|
})
|
|
72
109
|
short.changeContext ( 'general' )
|
|
73
|
-
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
// short.changeContext ( )
|
|
113
|
+
// short.changeContext ( 'general' )
|
|
114
|
+
|
|
115
|
+
|
|
74
116
|
</script>
|
|
75
117
|
<div class="block" data-click="red-block">
|
|
76
118
|
<span>hello</span>
|
|
77
119
|
</div>
|
|
78
120
|
|
|
79
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>
|
|
80
124
|
</body>
|
|
81
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",
|
|
@@ -29,19 +29,19 @@
|
|
|
29
29
|
"@peter.naydenov/notice": "^2.4.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@peter.naydenov/visual-controller-for-react": "^3.0.
|
|
33
|
-
"@rollup/plugin-commonjs": "^28.0.
|
|
32
|
+
"@peter.naydenov/visual-controller-for-react": "^3.0.1",
|
|
33
|
+
"@rollup/plugin-commonjs": "^28.0.6",
|
|
34
34
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
35
35
|
"@rollup/plugin-terser": "^0.4.4",
|
|
36
|
-
"@vitejs/plugin-react": "^
|
|
37
|
-
"@vitest/browser": "^3.
|
|
36
|
+
"@vitejs/plugin-react": "^5.0.0",
|
|
37
|
+
"@vitest/browser": "^3.2.4",
|
|
38
38
|
"ask-for-promise": "^3.0.1",
|
|
39
|
-
"chai": "^5.2.
|
|
40
|
-
"mocha": "^11.
|
|
41
|
-
"playwright": "^1.
|
|
39
|
+
"chai": "^5.2.1",
|
|
40
|
+
"mocha": "^11.7.1",
|
|
41
|
+
"playwright": "^1.54.2",
|
|
42
42
|
"react": "^19.0.1",
|
|
43
43
|
"react-dom": "^19.0.1",
|
|
44
|
-
"vite": "^
|
|
44
|
+
"vite": "^7.1.2"
|
|
45
45
|
},
|
|
46
46
|
"keywords": [
|
|
47
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
|
|
|
@@ -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
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
function _registerShortcutEvents ( dependencies, pluginState ) {
|
|
4
|
+
const
|
|
5
|
+
{ regex, _defaults, ev } = dependencies
|
|
6
|
+
, {
|
|
7
|
+
currentContext : { name: contextName }
|
|
8
|
+
, shortcuts
|
|
9
|
+
, callbacks
|
|
10
|
+
} = pluginState
|
|
11
|
+
;
|
|
12
|
+
let watch=[], define=[], action=[];
|
|
13
|
+
if ( contextName == null ) return false
|
|
14
|
+
Object.entries ( shortcuts[contextName] ).forEach ( ([shortcutName, list ]) => {
|
|
15
|
+
let isFormEv = regex.test ( shortcutName );
|
|
16
|
+
if ( !isFormEv ) return
|
|
17
|
+
if ( shortcutName === 'FORM:WATCH' ) watch = list
|
|
18
|
+
if ( shortcutName === 'FORM:DEFINE' ) define = list
|
|
19
|
+
if ( shortcutName === 'FORM:ACTION' ) action = list
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
if ( action.length === 0 ) return false
|
|
23
|
+
|
|
24
|
+
let setTypes = new Set ();
|
|
25
|
+
if ( define.length === 0 ) define = [ _defaults.define ]
|
|
26
|
+
if ( watch.length === 0 ) watch = [ _defaults.watch ]
|
|
27
|
+
let watchList = watch.map ( el => el() )
|
|
28
|
+
.reduce ( ( res, el) => {
|
|
29
|
+
res.push ( el )
|
|
30
|
+
return res
|
|
31
|
+
}, [])
|
|
32
|
+
pluginState.watchList = document.querySelectorAll ( watchList )
|
|
33
|
+
pluginState.watchList.forEach ( el => setTypes.add (define[0](el)) )
|
|
34
|
+
|
|
35
|
+
pluginState.typeFn = define[0] ? define[0] : _defaults.define
|
|
36
|
+
action.forEach ( act => {
|
|
37
|
+
|
|
38
|
+
if ( !(act instanceof Function)) {
|
|
39
|
+
console.warn ( `Warning: The 'form:action' should be a function.` )
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
42
|
+
let list = act ()
|
|
43
|
+
if ( !(list instanceof Array) ) {
|
|
44
|
+
console.warn ( `Warning: The 'form:action' function should RETURN an array.` )
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
act().forEach ( ({fn, type, timing, wait=0 }) => {
|
|
48
|
+
if ( setTypes.has ( type) && fn instanceof Function ) {
|
|
49
|
+
let key = `${type}/${timing}`
|
|
50
|
+
const hasProperty = callbacks.hasOwnProperty ( key );
|
|
51
|
+
hasProperty ?
|
|
52
|
+
callbacks[key].push ( fn ) :
|
|
53
|
+
callbacks[key] = [ fn ]
|
|
54
|
+
if ( !hasProperty ) {
|
|
55
|
+
ev.on ( key, ( props, callbacks ) => { // Register the 'type/timing' as an event
|
|
56
|
+
callbacks.forEach ( cb => { if ( cb instanceof Function ) cb ( props ) })
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
} // if function
|
|
60
|
+
if ( timing === 'instant' ) pluginState.wait[`${type}`] = wait
|
|
61
|
+
}) // for each act
|
|
62
|
+
}) // for each action
|
|
63
|
+
if ( Object.keys(pluginState.callbacks).length > 0 ) return true
|
|
64
|
+
else return false
|
|
65
|
+
} // _registerShortcutEvents func.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
export default _registerShortcutEvents
|
|
70
|
+
|
|
71
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// import all plugin files here
|
|
4
|
+
import _listenDOM from './_listenDOM.js'
|
|
5
|
+
import _normalizeShortcutName from './_normalizeShortcutName.js'
|
|
6
|
+
import _registerShortcutEvents from './_registerShortcutEvents.js'
|
|
7
|
+
import _defaults from './_defaults.js'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
function pluginForm ( dependencies, state, options ) {
|
|
12
|
+
/**
|
|
13
|
+
* 'form: watch' - A function. Should return a string. Define a selection that will be watched for changes. example: 'input, select.color, textarea, #name'
|
|
14
|
+
* 'form: define' - A function that receives every watched element. Should return text value that represents the type of the
|
|
15
|
+
* element according custom specification. Types could be specific for every single form.
|
|
16
|
+
* 'form:action' - List of Callback objects.
|
|
17
|
+
* Callback definition object:
|
|
18
|
+
* {
|
|
19
|
+
* fn: function to be called
|
|
20
|
+
* type: fn should be executed on type of the element
|
|
21
|
+
* timing: 'in' | 'out' | 'instant' - when to execute the function
|
|
22
|
+
* wait: time in milliseconds to wait before executing the function again. Works only with mode 'instant'.
|
|
23
|
+
* }
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
let
|
|
27
|
+
{ currentContext, shortcuts } = state
|
|
28
|
+
, { inAPI } = dependencies
|
|
29
|
+
, deps = {
|
|
30
|
+
ev: dependencies.ev
|
|
31
|
+
, mainDependencies : dependencies
|
|
32
|
+
, regex : /FORM\s*\:/i
|
|
33
|
+
, _defaults
|
|
34
|
+
}
|
|
35
|
+
, pluginState = {
|
|
36
|
+
currentContext
|
|
37
|
+
, shortcuts
|
|
38
|
+
, callbacks : {} // Functions callbacks arranged by 'type/timing' : [ callback, ...otherCallbacks ]
|
|
39
|
+
, typeFn : '' // Type definition function
|
|
40
|
+
, watchList : [] // list of watched elements
|
|
41
|
+
, wait : {} // wait time for 'instant' mode
|
|
42
|
+
} // pluginState
|
|
43
|
+
;
|
|
44
|
+
function resetState () {
|
|
45
|
+
pluginState.callbacks = {}
|
|
46
|
+
pluginState.typeFn = ''
|
|
47
|
+
pluginState.watchList = []
|
|
48
|
+
pluginState.wait = {}
|
|
49
|
+
} // resetState func.
|
|
50
|
+
|
|
51
|
+
// Read shortcuts names from all context entities and normalize entries related to the plugin
|
|
52
|
+
inAPI._normalizeWithPlugins ( _normalizeShortcutName )
|
|
53
|
+
let formListener = _listenDOM ( deps, pluginState );
|
|
54
|
+
|
|
55
|
+
if ( currentContext.name ) {
|
|
56
|
+
let hasFormShortcuts = _registerShortcutEvents ( deps, pluginState )
|
|
57
|
+
if ( hasFormShortcuts ) formListener.start ()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let pluginAPI = {
|
|
61
|
+
getPrefix : ( ) => 'form'
|
|
62
|
+
, shortcutName : key => { // Format a key string according plugin needs
|
|
63
|
+
return _normalizeShortcutName ( key )
|
|
64
|
+
}
|
|
65
|
+
, contextChange : ( ) => {
|
|
66
|
+
resetState ()
|
|
67
|
+
let hasFormShortcuts = _registerShortcutEvents ( deps, pluginState )
|
|
68
|
+
if ( hasFormShortcuts ) formListener.start ()
|
|
69
|
+
else formListener.stop ()
|
|
70
|
+
}
|
|
71
|
+
, mute : () => formListener.stop ()
|
|
72
|
+
, unmute : () => formListener.start ()
|
|
73
|
+
, destroy : () => {
|
|
74
|
+
formListener.stop ()
|
|
75
|
+
pluginState = null
|
|
76
|
+
pluginAPI = null
|
|
77
|
+
}
|
|
78
|
+
}; // pluginAPI
|
|
79
|
+
Object.freeze ( pluginAPI )
|
|
80
|
+
return pluginAPI
|
|
81
|
+
} // pluginForm func.
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
export default pluginForm
|
package/test/01-general.test.js
CHANGED
|
@@ -8,6 +8,7 @@ import '../test-components/style.css'
|
|
|
8
8
|
import {
|
|
9
9
|
pluginClick,
|
|
10
10
|
pluginKey
|
|
11
|
+
, pluginForm
|
|
11
12
|
, shortcuts
|
|
12
13
|
} from '../src/main.js'
|
|
13
14
|
import { expect } from 'chai'
|
|
@@ -35,6 +36,17 @@ short.load ({
|
|
|
35
36
|
, extra : {
|
|
36
37
|
'key : p,r,o,b,a': () => b = true
|
|
37
38
|
}
|
|
39
|
+
, extend : {
|
|
40
|
+
'form : watch' : () => 'input'
|
|
41
|
+
, 'form : define' : () => 'input'
|
|
42
|
+
, 'form : action' : () => [
|
|
43
|
+
{
|
|
44
|
+
fn : (e) => console.log ( e.target )
|
|
45
|
+
, type : 'input'
|
|
46
|
+
, mode : 'in'
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
38
50
|
})
|
|
39
51
|
|
|
40
52
|
beforeEach ( () => {
|
|
@@ -245,7 +257,7 @@ test ( 'List shortcuts', () => {
|
|
|
245
257
|
let all = short.listShortcuts ();
|
|
246
258
|
expect ( all ).to.be.an ( 'array' )
|
|
247
259
|
|
|
248
|
-
expect ( all ).to.have.lengthOf (
|
|
260
|
+
expect ( all ).to.have.lengthOf ( 3 )
|
|
249
261
|
expect ( all[0] ).to.have.property ( 'context' )
|
|
250
262
|
expect ( all[0] ).to.have.property ( 'shortcuts' )
|
|
251
263
|
expect ( all[0].shortcuts ).to.be.an('array')
|
|
@@ -3,6 +3,8 @@ return <>
|
|
|
3
3
|
<div className="block" data-click="red"><span id='rspan'>Red</span> </div>
|
|
4
4
|
<button className="big-btn" data-click="mega">Mega button</button>
|
|
5
5
|
<p>Some text with <a href="#" target="_blank">link <span id="anchor">in</span></a> it</p>
|
|
6
|
+
<p><input id="name" type="text" /></p>
|
|
7
|
+
<p><input type="text" id="age" /></p>
|
|
6
8
|
</>
|
|
7
9
|
}
|
|
8
10
|
|