@peter.naydenov/shortcuts 3.1.4 → 3.2.1
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 +9 -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
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
### 3.2.1 ( 2025-08-15)
|
|
6
|
+
- [x] Fix: Old build files were not deleted after release.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### 3.2.0 ( 2025-08-15)
|
|
11
|
+
- [x] Plugin 'form' was added. It allows you to listen for form elements changes.
|
|
12
|
+
- [ ] Miss: Old build files were not deleted after release.
|
|
13
|
+
|
|
5
14
|
### 3.1.4 ( 2025-05-3)
|
|
6
15
|
- [x] Dependency update. @peter.naydenov/notice - v.2.4.1
|
|
7
16
|
|
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,exposeShortcut:l};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};
|
|
1
|
+
"use strict";var t=require("@peter.naydenov/notice");var e={_normalizeWithPlugins:function(t,e){return function(t){const n=e.shortcuts;Object.keys(n).forEach((e=>{Object.entries(n[e]).forEach((([o,r])=>{const i=t(o);i!==o&&(delete n[e][o],n[e][i]=r)}))}))}},_readShortcutWithPlugins:function(t,e){return function(n){const{inAPI:o}=t,r=n.split(":")[0],i=o._systemAction(r,"none");let s=n;return-1!==i&&(s=e.plugins[i].shortcutName(n)),s}},_systemAction:function(t,e){return function(t,n,o=null){return e.plugins.findIndex((e=>e.getPrefix()===t&&(e[n]&&e[n](o),!0)))}},changeContext:function(t,e){const{shortcuts:n,currentContext:o}=e,{ev:r}=t;return function(t=!1){const i=o.name;if(!t)return r.reset(),void(o.name=null);i!==t&&(n[t]?(n[i]&&r.reset(),o.name=t,e.plugins.forEach((e=>e.contextChange(t))),Object.entries(n[t]).forEach((([t,e])=>{e.forEach((e=>r.on(t,e)))})),r.on("*",((...t)=>{e.exposeShortcut&&e.exposeShortcut(...t)}))):r.emit("@shortcuts-error",`Context '${t}' does not exist`))}},listShortcuts:function(t,e){const n=e.shortcuts;return function(t=null){if(null!=t){let e=n[t];return null==e?null:Object.entries(e).map((([t,e])=>t))}return Object.keys(n).map((t=>{let e={};return e.context=t,e.shortcuts=Object.entries(n[t]).map((([t,e])=>t)),e}))}},load:function(t,e){const{shortcuts:n,plugins:o}=e,{API:{changeContext:r,getContext:i}}=t;return function(t){const e=i(),s=o.map((t=>t.getPrefix().toUpperCase()));let c=!1;Object.entries(t).forEach((([t,r])=>{t===e&&(c=!0),n[t]={},Object.entries(r).forEach((([e,r])=>{let i=e,c=e.toUpperCase().trim(),u=s.map(((t,e)=>c.startsWith(t)?e:null)).filter((t=>null!==t));if(u.length){let t=u[0];i=o[t].shortcutName(e)}r instanceof Function&&(r=[r]),n[t][i]=r}))})),c&&(r(),r(e))}},unload:function(t,e){const{currentContext:n,shortcuts:o}=e,{ev:r}=t;return function(t){n.name!==t?o[t]?delete o[t]:r.emit("shortcuts-error",`Context '${t}' does not exist`):r.emit("shortcuts-error",`Context '${t}' can't be removed during is current active context. Change the context first`)}}};function n(t){const e=t.toUpperCase(),n=/KEY\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`KEY:${e.slice(o+1).split(",").map((t=>t.trim())).map((t=>t.split("+").map((t=>t.trim())).sort().join("+"))).join(",")}`}function o(t,e){let{shiftKey:n,altKey:o,ctrlKey:r}=t,i=t.code.replace("Key","").replace("Digit",""),s=[];return r&&s.push("CTRL"),n&&s.push("SHIFT"),o&&s.push("ALT"),e.hasOwnProperty(i)?s.push(e[i].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(i)||s.push(i.toUpperCase()),s.sort()}function r(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach((([t,e])=>{if(!o.test(t))return;n++;let i=t.slice(4).split(",").length;r.maxSequence<i&&(r.maxSequence=i)})),n)}function i(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}}function s(t,e,n){const{listenOptions:{clickTarget:o}}=e;let r=n;return r===document||r===document.body?null:r.dataset[o]||"A"===r.nodeName?r:s(t,e,r.parentNode)}function c(t){const e=t.toUpperCase(),n=/CLICK\s*\:/i.test(e),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],c=0,u=e.indexOf(":");return n?(e.slice(u+1).trim().split("-").map((t=>t.trim())).forEach((t=>{o.includes(t)?i=t:r.includes(t)?s.push(t):isNaN(t)||(c=t)})),`CLICK:${i}-${c}${s.length>0?"-":""}${s.sort().join("-")}`):t}function u(t,e){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=t,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${e}`,u=[];return r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function 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 l(t){const e=t.toUpperCase(),n=/FORM\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`FORM:${e.slice(o+1).trim()}`}function m(t,e){const{regex:n,_defaults:o,ev:r}=t,{currentContext:{name:i},shortcuts:s,callbacks:c}=e;let u=[],a=[],l=[];if(null==i)return!1;if(Object.entries(s[i]).forEach((([t,e])=>{n.test(t)&&("FORM:WATCH"===t&&(u=e),"FORM:DEFINE"===t&&(a=e),"FORM:ACTION"===t&&(l=e))})),0===l.length)return!1;let m=new Set;0===a.length&&(a=[o.define]),0===u.length&&(u=[o.watch]);let p=u.map((t=>t())).reduce(((t,e)=>(t.push(e),t)),[]);return e.watchList=document.querySelectorAll(p),e.watchList.forEach((t=>m.add(a[0](t)))),e.typeFn=a[0]?a[0]:o.define,l.forEach((t=>{if(!(t instanceof Function))return console.warn("Warning: The 'form:action' should be a function."),!1;if(!(t()instanceof Array))return console.warn("Warning: The 'form:action' function should RETURN an array."),!1;t().forEach((({fn:t,type:n,timing:o,wait:i=0})=>{if(m.has(n)&&t instanceof Function){let e=`${n}/${o}`;const i=c.hasOwnProperty(e);i?c[e].push(t):c[e]=[t],i||r.on(e,((t,e)=>{e.forEach((e=>{e instanceof Function&&e(t)}))}))}"instant"===o&&(e.wait[`${n}`]=i)}))})),Object.keys(e.callbacks).length>0}const p={watch:()=>"input, select, textarea, button, a",define:t=>"checkbox"===t.type||"radio"===t.type?"checkbox":"button"==t.type||"submit"==t.type?"button":"input"};exports.pluginClick=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,l={ev:t.ev,_findTarget:s,_readClickEvent:u,mainDependencies:t,regex:/CLICK\s*\:/i},m={currentContext:o,shortcuts:r,listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,clickTarget:n.clickTarget?n.clickTarget:"click"}};i._normalizeWithPlugins(c);let p=function(t,e){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=t,{listenOptions:s,currentContext:c}=e,{mouseWait:u}=s;let a=null,l=null,m=null,p=null,f=0;function h(){const t=r(l,f),e={target:a,targetProps:a?a.getBoundingClientRect():null,x:l.clientX,y:l.clientY,context:c.name,note:c.note,event:l,dependencies:i.extra,type:"click"};n.emit(t,e),m=null,p=null,a=null,l=null,f=0}function d(n){let r=s.maxClicks;return clearTimeout(m),p?(clearTimeout(p),void(p=setTimeout((()=>p=null),u))):(a=o(t,e,n.target),a&&a.dataset.hasOwnProperty("quickClick")&&(r=1),a&&"A"===a.tagName&&(r=1),l=n,f++,f>=r?(h(),void(r>1&&(p=setTimeout((()=>p=null),u)))):void(m=setTimeout(h,u)))}function g(n){let r=s.maxClicks;return clearTimeout(m),p?(clearTimeout(p),void(p=setTimeout((()=>p=null),u))):(a=o(t,e,n.target),a&&a.dataset.hasOwnProperty("quickClick")&&(r=1),a&&"A"===a.tagName&&(r=1),l=n,f++,f>=r?(h(),void(r>1&&(p=setTimeout((()=>p=null),u)))):void(m=setTimeout(h,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)}}}(l,m),f=a(l,m);f>0&&p.start();let h={getPrefix:()=>"click",shortcutName:t=>c(t),contextChange:()=>{f=a(l,m),f<1&&p.stop(),f>0&&p.start()},mute:()=>p.stop(),unmute:()=>p.start(),destroy:()=>{p.stop(),m=null,h=null}};return Object.freeze(h),h},exports.pluginForm=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,mainDependencies:t,regex:/FORM\s*\:/i,_defaults:p},c={currentContext:o,shortcuts:r,callbacks:{},typeFn:"",watchList:[],wait:{}};i._normalizeWithPlugins(l);let u=function(t,e){const{ev:n}=t;let o=null;function r(t,e,n,o){return{target:n.target,context:e.currentContext.name,note:e.currentContext.note,event:n,dependencies:t.mainDependencies.extra,type:o}}function i(o){const{callbacks:i,typeFn:s}=e,c=s(o.target),u=r(t,e,o,c),a=`${c}/in`;null!=i[a]&&n.emit(a,u,i[a])}function s(o){const{callbacks:i,typeFn:s}=e,c=r(t,e,o,"form-out"),u=`${s(o.target)}/out`;null!=i[u]&&n.emit(u,c,i[u])}function c(i){const{callbacks:s,typeFn:c}=e,u=r(t,e,i,"form-instant"),a=c(i.target),l=e.wait[`${a}`],m=`${a}/instant`;null!=s[m]&&(0!==l?(clearTimeout(o),o=setTimeout((()=>n.emit(m,u,s[m])),l)):n.emit(m,u,s[m]))}return{start:function(){e.active||(document.addEventListener("focusin",i),document.addEventListener("focusout",s),document.addEventListener("input",c),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("focusin",i),document.removeEventListener("focusout",s),document.removeEventListener("input",c),e.active=!1)}}}(s,c);if(o.name){m(s,c)&&u.start()}let a={getPrefix:()=>"form",shortcutName:t=>l(t),contextChange:()=>{c.callbacks={},c.typeFn="",c.watchList=[],c.wait={},m(s,c)?u.start():u.stop()},mute:()=>u.stop(),unmute:()=>u.start(),destroy:()=>{u.stop(),c=null,a=null}};return Object.freeze(a),a},exports.pluginKey=function(t,e,s={}){let{currentContext:c,shortcuts:u,exposeShortcut:a}=e,{inAPI:l}=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};l._normalizeWithPlugins(n);let f=function(t,e){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=t,{currentContext:s,streamKeys:c,listenOptions:u}=e,{keyWait:a}=u;let l=[],m=null,p=!0,f=!1;const h=()=>p=!1,d=()=>p=!0,g=()=>f=!0,x=()=>!1===p;function y(){let t=l.map((t=>[t.join("+")]));const e={wait:h,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),f&&(t=t.slice(0,-1),f=!1)}if(p){const o=`KEY:${t.join(",")}`;n.emit(o,e),l=[],m=null}}function C(e){if(clearTimeout(m),o.hasOwnProperty(e.code))return l.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),a))):p&&l.length===u.maxSequence?(y(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),a))):void(p?m=setTimeout(y,a):y())}function v(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),a));if(l.push(r(e,o)),p&&l.length===u.maxSequence)return y(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),a));p?m=setTimeout(y,a):y()}}return{start:function(){e.active||(document.addEventListener("keydown",C),document.addEventListener("keypress",v),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("keydown",C),document.removeEventListener("keypress",v),e.active=!1)}}}(m,p),h=r(m,p);h>0&&f.start();let d={getPrefix:()=>"key",shortcutName:t=>n(t),contextChange:t=>{h=r(m,p),h<1&&f.stop(),h>0&&f.start()},mute:()=>f.stop(),unmute:()=>f.start(),destroy:()=>{f.stop(),p=null,d=null}};return Object.freeze(d),d},exports.shortcuts=function(n={}){const o=t(),r={},i={},s={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!n.onShortcut||"function"!=typeof n.onShortcut)&&n.onShortcut},c={ev:o,inAPI:r,API:i,extra:{}};return i.enablePlugin=(t,e={})=>{const n=t.name;if(-1===r._systemAction(n,"none")){let n;n=t(c,s,e),s.plugins.push(n)}},i.disablePlugin=t=>{const e=r._systemAction(t,"destroy");-1!==e&&(s.plugins=s.plugins.filter(((t,n)=>n!==e)))},i.mutePlugin=t=>r._systemAction(t,"mute"),i.unmutePlugin=t=>r._systemAction(t,"unmute"),i.getContext=()=>s.currentContext.name,i.getNote=()=>s.currentContext.note,i.setNote=(t=null)=>{"string"!=typeof t&&null!=t||(s.currentContext.note=t)},i.pause=(t="*")=>{let e=r._readShortcutWithPlugins(t);o.stop(e)},i.resume=(t="*")=>{const e=r._readShortcutWithPlugins(t);o.start(e)},i.emit=(t,...e)=>o.emit(r._readShortcutWithPlugins(t),...e),i.listContexts=()=>Object.keys(s.shortcuts),i.setDependencies=t=>c.extra={...c.extra,...t},i.getDependencies=()=>c.extra,Object.entries(e).forEach((([t,e])=>{t.startsWith("_")?r[t]=e(c,s):i[t]=e(c,s)})),i};
|
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,exposeShortcut:l};a._normalizeWithPlugins(n);let h=function(t,e){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=t,{currentContext:s,streamKeys:c,listenOptions:u}=e,{keyWait:l}=u;let a=[],m=null,p=!0,h=!1;const f=()=>p=!1,d=()=>p=!0,g=()=>h=!0,x=()=>!1===p;function y(){let t=a.map((t=>[t.join("+")]));const e={wait:f,end:d,ignore:g,isWaiting:x,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!p){let o=t.at(-1);n.emit(o,e),h&&(t=t.slice(0,-1),h=!1)}if(p){const o=`KEY:${t.join(",")}`;n.emit(o,e),a=[],m=null}}function C(e){if(clearTimeout(m),o.hasOwnProperty(e.code))return a.push(r(e,o)),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore?(clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l))):p&&a.length===u.maxSequence?(y(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l))):void(p?m=setTimeout(y,l):y())}function k(e){if(!o.hasOwnProperty(e.code)){if(clearTimeout(m),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore)return clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l));if(a.push(r(e,o)),p&&a.length===u.maxSequence)return y(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l));p?m=setTimeout(y,l):y()}}return{start:function(){e.active||(document.addEventListener("keydown",C),document.addEventListener("keypress",k),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("keydown",C),document.removeEventListener("keypress",k),e.active=!1)}}}(m,p),f=r(m,p);f>0&&h.start();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};
|
|
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:a}=e,{inAPI:l}=t,m={ev:t.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:t,regex:/KEY\s*\:/i},f={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};l._normalizeWithPlugins(n);let p=function(t,e){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=t,{currentContext:s,streamKeys:c,listenOptions:u}=e,{keyWait:a}=u;let l=[],m=null,f=!0,p=!1;const h=()=>f=!1,d=()=>f=!0,g=()=>p=!0,x=()=>!1===f;function y(){let t=l.map((t=>[t.join("+")]));const e={wait:h,end:d,ignore:g,isWaiting:x,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!f){let o=t.at(-1);n.emit(o,e),p&&(t=t.slice(0,-1),p=!1)}if(f){const o=`KEY:${t.join(",")}`;n.emit(o,e),l=[],m=null}}function C(e){if(clearTimeout(m),o.hasOwnProperty(e.code))return l.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),a))):f&&l.length===u.maxSequence?(y(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),a))):void(f?m=setTimeout(y,a):y())}function v(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),a));if(l.push(r(e,o)),f&&l.length===u.maxSequence)return y(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),a));f?m=setTimeout(y,a):y()}}return{start:function(){e.active||(document.addEventListener("keydown",C),document.addEventListener("keypress",v),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("keydown",C),document.removeEventListener("keypress",v),e.active=!1)}}}(m,f),h=r(m,f);h>0&&p.start();let d={getPrefix:()=>"key",shortcutName:t=>n(t),contextChange:t=>{h=r(m,f),h<1&&p.stop(),h>0&&p.start()},mute:()=>p.stop(),unmute:()=>p.start(),destroy:()=>{p.stop(),f=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 a(t,e){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=t,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${e}`,u=[];return r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function l(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach((([t,e])=>{if(!o.test(t))return;n++;let[,i]=t.slice(6).split("-");r.maxClicks<i&&(r.maxClicks=i)})),n)}function m(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,_findTarget:c,_readClickEvent:a,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 f=function(t,e){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=t,{listenOptions:s,currentContext:c}=e,{mouseWait:u}=s;let a=null,l=null,m=null,f=null,p=0;function h(){const t=r(l,p),e={target:a,targetProps:a?a.getBoundingClientRect():null,x:l.clientX,y:l.clientY,context:c.name,note:c.note,event:l,dependencies:i.extra,type:"click"};n.emit(t,e),m=null,f=null,a=null,l=null,p=0}function d(n){let r=s.maxClicks;return clearTimeout(m),f?(clearTimeout(f),void(f=setTimeout((()=>f=null),u))):(a=o(t,e,n.target),a&&a.dataset.hasOwnProperty("quickClick")&&(r=1),a&&"A"===a.tagName&&(r=1),l=n,p++,p>=r?(h(),void(r>1&&(f=setTimeout((()=>f=null),u)))):void(m=setTimeout(h,u)))}function g(n){let r=s.maxClicks;return clearTimeout(m),f?(clearTimeout(f),void(f=setTimeout((()=>f=null),u))):(a=o(t,e,n.target),a&&a.dataset.hasOwnProperty("quickClick")&&(r=1),a&&"A"===a.tagName&&(r=1),l=n,p++,p>=r?(h(),void(r>1&&(f=setTimeout((()=>f=null),u)))):void(m=setTimeout(h,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),p=l(s,m);p>0&&f.start();let h={getPrefix:()=>"click",shortcutName:t=>u(t),contextChange:()=>{p=l(s,m),p<1&&f.stop(),p>0&&f.start()},mute:()=>f.stop(),unmute:()=>f.start(),destroy:()=>{f.stop(),m=null,h=null}};return Object.freeze(h),h}function f(t){const e=t.toUpperCase(),n=/FORM\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`FORM:${e.slice(o+1).trim()}`}function p(t,e){const{regex:n,_defaults:o,ev:r}=t,{currentContext:{name:i},shortcuts:s,callbacks:c}=e;let u=[],a=[],l=[];if(null==i)return!1;if(Object.entries(s[i]).forEach((([t,e])=>{n.test(t)&&("FORM:WATCH"===t&&(u=e),"FORM:DEFINE"===t&&(a=e),"FORM:ACTION"===t&&(l=e))})),0===l.length)return!1;let m=new Set;0===a.length&&(a=[o.define]),0===u.length&&(u=[o.watch]);let f=u.map((t=>t())).reduce(((t,e)=>(t.push(e),t)),[]);return e.watchList=document.querySelectorAll(f),e.watchList.forEach((t=>m.add(a[0](t)))),e.typeFn=a[0]?a[0]:o.define,l.forEach((t=>{if(!(t instanceof Function))return console.warn("Warning: The 'form:action' should be a function."),!1;if(!(t()instanceof Array))return console.warn("Warning: The 'form:action' function should RETURN an array."),!1;t().forEach((({fn:t,type:n,timing:o,wait:i=0})=>{if(m.has(n)&&t instanceof Function){let e=`${n}/${o}`;const i=c.hasOwnProperty(e);i?c[e].push(t):c[e]=[t],i||r.on(e,((t,e)=>{e.forEach((e=>{e instanceof Function&&e(t)}))}))}"instant"===o&&(e.wait[`${n}`]=i)}))})),Object.keys(e.callbacks).length>0}const h={watch:()=>"input, select, textarea, button, a",define:t=>"checkbox"===t.type||"radio"===t.type?"checkbox":"button"==t.type||"submit"==t.type?"button":"input"};function d(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,mainDependencies:t,regex:/FORM\s*\:/i,_defaults:h},c={currentContext:o,shortcuts:r,callbacks:{},typeFn:"",watchList:[],wait:{}};i._normalizeWithPlugins(f);let u=function(t,e){const{ev:n}=t;let o=null;function r(t,e,n,o){return{target:n.target,context:e.currentContext.name,note:e.currentContext.note,event:n,dependencies:t.mainDependencies.extra,type:o}}function i(o){const{callbacks:i,typeFn:s}=e,c=s(o.target),u=r(t,e,o,c),a=`${c}/in`;null!=i[a]&&n.emit(a,u,i[a])}function s(o){const{callbacks:i,typeFn:s}=e,c=r(t,e,o,"form-out"),u=`${s(o.target)}/out`;null!=i[u]&&n.emit(u,c,i[u])}function c(i){const{callbacks:s,typeFn:c}=e,u=r(t,e,i,"form-instant"),a=c(i.target),l=e.wait[`${a}`],m=`${a}/instant`;null!=s[m]&&(0!==l?(clearTimeout(o),o=setTimeout((()=>n.emit(m,u,s[m])),l)):n.emit(m,u,s[m]))}return{start:function(){e.active||(document.addEventListener("focusin",i),document.addEventListener("focusout",s),document.addEventListener("input",c),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("focusin",i),document.removeEventListener("focusout",s),document.removeEventListener("input",c),e.active=!1)}}}(s,c);if(o.name){p(s,c)&&u.start()}let a={getPrefix:()=>"form",shortcutName:t=>f(t),contextChange:()=>{c.callbacks={},c.typeFn="",c.watchList=[],c.wait={},p(s,c)?u.start():u.stop()},mute:()=>u.stop(),unmute:()=>u.start(),destroy:()=>{u.stop(),c=null,a=null}};return Object.freeze(a),a}function g(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,d as pluginForm,s as pluginKey,g 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(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).shortcuts={})}(this,(function(t){"use strict";var e={_normalizeWithPlugins:function(t,e){return function(t){const n=e.shortcuts;Object.keys(n).forEach((e=>{Object.entries(n[e]).forEach((([o,r])=>{const i=t(o);i!==o&&(delete n[e][o],n[e][i]=r)}))}))}},_readShortcutWithPlugins:function(t,e){return function(n){const{inAPI:o}=t,r=n.split(":")[0],i=o._systemAction(r,"none");let s=n;return-1!==i&&(s=e.plugins[i].shortcutName(n)),s}},_systemAction:function(t,e){return function(t,n,o=null){return e.plugins.findIndex((e=>e.getPrefix()===t&&(e[n]&&e[n](o),!0)))}},changeContext:function(t,e){const{shortcuts:n,currentContext:o}=e,{ev:r}=t;return function(t=!1){const i=o.name;if(!t)return r.reset(),void(o.name=null);i!==t&&(n[t]?(n[i]&&r.reset(),o.name=t,e.plugins.forEach((e=>e.contextChange(t))),Object.entries(n[t]).forEach((([t,e])=>{e.forEach((e=>r.on(t,e)))})),r.on("*",((...t)=>{e.exposeShortcut&&e.exposeShortcut(...t)}))):r.emit("@shortcuts-error",`Context '${t}' does not exist`))}},listShortcuts:function(t,e){const n=e.shortcuts;return function(t=null){if(null!=t){let e=n[t];return null==e?null:Object.entries(e).map((([t,e])=>t))}return Object.keys(n).map((t=>{let e={};return e.context=t,e.shortcuts=Object.entries(n[t]).map((([t,e])=>t)),e}))}},load:function(t,e){const{shortcuts:n,plugins:o}=e,{API:{changeContext:r,getContext:i}}=t;return function(t){const e=i(),s=o.map((t=>t.getPrefix().toUpperCase()));let c=!1;Object.entries(t).forEach((([t,r])=>{t===e&&(c=!0),n[t]={},Object.entries(r).forEach((([e,r])=>{let i=e,c=e.toUpperCase().trim(),u=s.map(((t,e)=>c.startsWith(t)?e:null)).filter((t=>null!==t));if(u.length){let t=u[0];i=o[t].shortcutName(e)}r instanceof Function&&(r=[r]),n[t][i]=r}))})),c&&(r(),r(e))}},unload:function(t,e){const{currentContext:n,shortcuts:o}=e,{ev:r}=t;return function(t){n.name!==t?o[t]?delete o[t]:r.emit("shortcuts-error",`Context '${t}' does not exist`):r.emit("shortcuts-error",`Context '${t}' can't be removed during is current active context. Change the context first`)}}};function n(t){const e=t.toUpperCase(),n=/KEY\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`KEY:${e.slice(o+1).split(",").map((t=>t.trim())).map((t=>t.split("+").map((t=>t.trim())).sort().join("+"))).join(",")}`}function o(t,e){let{shiftKey:n,altKey:o,ctrlKey:r}=t,i=t.code.replace("Key","").replace("Digit",""),s=[];return r&&s.push("CTRL"),n&&s.push("SHIFT"),o&&s.push("ALT"),e.hasOwnProperty(i)?s.push(e[i].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(i)||s.push(i.toUpperCase()),s.sort()}function r(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach((([t,e])=>{if(!o.test(t))return;n++;let i=t.slice(4).split(",").length;r.maxSequence<i&&(r.maxSequence=i)})),n)}function i(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}}function s(t,e,n){const{listenOptions:{clickTarget:o}}=e;let r=n;return r===document||r===document.body?null:r.dataset[o]||"A"===r.nodeName?r:s(t,e,r.parentNode)}function c(t){const e=t.toUpperCase(),n=/CLICK\s*\:/i.test(e),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],c=0,u=e.indexOf(":");return n?(e.slice(u+1).trim().split("-").map((t=>t.trim())).forEach((t=>{o.includes(t)?i=t:r.includes(t)?s.push(t):isNaN(t)||(c=t)})),`CLICK:${i}-${c}${s.length>0?"-":""}${s.sort().join("-")}`):t}function u(t,e){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=t,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${e}`,u=[];return r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function l(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach((([t,e])=>{if(!o.test(t))return;n++;let[,i]=t.slice(6).split("-");r.maxClicks<i&&(r.maxClicks=i)})),n)}function a(t){const e=t.toUpperCase(),n=/FORM\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`FORM:${e.slice(o+1).trim()}`}function f(t,e){const{regex:n,_defaults:o,ev:r}=t,{currentContext:{name:i},shortcuts:s,callbacks:c}=e;let u=[],l=[],a=[];if(null==i)return!1;if(Object.entries(s[i]).forEach((([t,e])=>{n.test(t)&&("FORM:WATCH"===t&&(u=e),"FORM:DEFINE"===t&&(l=e),"FORM:ACTION"===t&&(a=e))})),0===a.length)return!1;let f=new Set;0===l.length&&(l=[o.define]),0===u.length&&(u=[o.watch]);let m=u.map((t=>t())).reduce(((t,e)=>(t.push(e),t)),[]);return e.watchList=document.querySelectorAll(m),e.watchList.forEach((t=>f.add(l[0](t)))),e.typeFn=l[0]?l[0]:o.define,a.forEach((t=>{if(!(t instanceof Function))return console.warn("Warning: The 'form:action' should be a function."),!1;if(!(t()instanceof Array))return console.warn("Warning: The 'form:action' function should RETURN an array."),!1;t().forEach((({fn:t,type:n,timing:o,wait:i=0})=>{if(f.has(n)&&t instanceof Function){let e=`${n}/${o}`;const i=c.hasOwnProperty(e);i?c[e].push(t):c[e]=[t],i||r.on(e,((t,e)=>{e.forEach((e=>{e instanceof Function&&e(t)}))}))}"instant"===o&&(e.wait[`${n}`]=i)}))})),Object.keys(e.callbacks).length>0}const m={watch:()=>"input, select, textarea, button, a",define:t=>"checkbox"===t.type||"radio"===t.type?"checkbox":"button"==t.type||"submit"==t.type?"button":"input"};t.pluginClick=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,a={ev:t.ev,_findTarget:s,_readClickEvent:u,mainDependencies:t,regex:/CLICK\s*\:/i},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(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,f=null,m=null,p=0;function h(){const t=r(a,p),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),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(t,e,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(t,e,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(){e.active||(window.addEventListener("contextmenu",g),document.addEventListener("click",d),e.active=!0)},stop:function(){e.active&&(window.removeEventListener("contextmenu",g),document.removeEventListener("click",d),e.active=!1)}}}(a,f),p=l(a,f);p>0&&m.start();let h={getPrefix:()=>"click",shortcutName:t=>c(t),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},t.pluginForm=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,mainDependencies:t,regex:/FORM\s*\:/i,_defaults:m},c={currentContext:o,shortcuts:r,callbacks:{},typeFn:"",watchList:[],wait:{}};i._normalizeWithPlugins(a);let u=function(t,e){const{ev:n}=t;let o=null;function r(t,e,n,o){return{target:n.target,context:e.currentContext.name,note:e.currentContext.note,event:n,dependencies:t.mainDependencies.extra,type:o}}function i(o){const{callbacks:i,typeFn:s}=e,c=s(o.target),u=r(t,e,o,c),l=`${c}/in`;null!=i[l]&&n.emit(l,u,i[l])}function s(o){const{callbacks:i,typeFn:s}=e,c=r(t,e,o,"form-out"),u=`${s(o.target)}/out`;null!=i[u]&&n.emit(u,c,i[u])}function c(i){const{callbacks:s,typeFn:c}=e,u=r(t,e,i,"form-instant"),l=c(i.target),a=e.wait[`${l}`],f=`${l}/instant`;null!=s[f]&&(0!==a?(clearTimeout(o),o=setTimeout((()=>n.emit(f,u,s[f])),a)):n.emit(f,u,s[f]))}return{start:function(){e.active||(document.addEventListener("focusin",i),document.addEventListener("focusout",s),document.addEventListener("input",c),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("focusin",i),document.removeEventListener("focusout",s),document.removeEventListener("input",c),e.active=!1)}}}(s,c);if(o.name){f(s,c)&&u.start()}let l={getPrefix:()=>"form",shortcutName:t=>a(t),contextChange:()=>{c.callbacks={},c.typeFn="",c.watchList=[],c.wait={},f(s,c)?u.start():u.stop()},mute:()=>u.stop(),unmute:()=>u.start(),destroy:()=>{u.stop(),c=null,l=null}};return Object.freeze(l),l},t.pluginKey=function(t,e,s={}){let{currentContext:c,shortcuts:u,exposeShortcut:l}=e,{inAPI:a}=t,f={ev:t.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:t,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(t,e){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=t,{currentContext:s,streamKeys:c,listenOptions:u}=e,{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 t=a.map((t=>[t.join("+")]));const e={wait:h,end:d,ignore:g,isWaiting:y,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!m){let o=t.at(-1);n.emit(o,e),p&&(t=t.slice(0,-1),p=!1)}if(m){const o=`KEY:${t.join(",")}`;n.emit(o,e),a=[],f=null}}function C(e){if(clearTimeout(f),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))):m&&a.length===u.maxSequence?(x(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l))):void(m?f=setTimeout(x,l):x())}function k(e){if(!o.hasOwnProperty(e.code)){if(clearTimeout(f),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)),m&&a.length===u.maxSequence)return x(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l));m?f=setTimeout(x,l):x()}}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)}}}(f,m),h=r(f,m);h>0&&p.start();let d={getPrefix:()=>"key",shortcutName:t=>n(t),contextChange:t=>{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},t.shortcuts=function(t={}){const n=function(){let t={"*":[]},e={},n=new Set,o=!1,r="";return{on:function(e,n){t[e]||(t[e]=[]),t[e].push(n)},once:function(t,n){"*"!==t&&(e[t]||(e[t]=[]),e[t].push(n))},off:function(n,o){if(o)return t[n]&&(t[n]=t[n].filter((t=>t!==o))),e[n]&&(e[n]=e[n].filter((t=>t!==o))),t[n]&&0===t[n].length&&delete t[n],void(e[n]&&0===e[n].length&&delete t[n]);e[n]&&delete e[n],t[n]&&delete t[n]},reset:function(){t={"*":[]},e={},n=new Set},emit:function(){const[i,...s]=arguments;function c(e){let o=!1;"*"!==e&&(n.has(e)||(t[e].every((t=>{const e=t(...s);return"string"!=typeof e||"STOP"!==e.toUpperCase()||(o=!0,!1)})),o||t["*"].forEach((t=>t(i,...s)))))}if(o&&(console.log(`${r} Event "${i}" was triggered.`),s.length>0&&(console.log("Arguments:"),console.log(...s),console.log("^----"))),"*"!==i){if(e[i]){if(n.has(i))return;e[i].forEach((t=>t(...s))),delete e[i]}t[i]&&c(i)}else Object.keys(t).forEach((t=>c(t)))},stop:function(o){if("*"!==o)n.add(o);else{const o=Object.keys(t),r=Object.keys(e);n=new Set([...r,...o])}},start:function(t){"*"!==t?n.delete(t):n.clear()},debug:function(t,e){o=!!t,e&&"string"==typeof e&&(r=e)}}}(),o={},r={},i={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!t.onShortcut||"function"!=typeof t.onShortcut)&&t.onShortcut},s={ev:n,inAPI:o,API:r,extra:{}};return r.enablePlugin=(t,e={})=>{const n=t.name;if(-1===o._systemAction(n,"none")){let n;n=t(s,i,e),i.plugins.push(n)}},r.disablePlugin=t=>{const e=o._systemAction(t,"destroy");-1!==e&&(i.plugins=i.plugins.filter(((t,n)=>n!==e)))},r.mutePlugin=t=>o._systemAction(t,"mute"),r.unmutePlugin=t=>o._systemAction(t,"unmute"),r.getContext=()=>i.currentContext.name,r.getNote=()=>i.currentContext.note,r.setNote=(t=null)=>{"string"!=typeof t&&null!=t||(i.currentContext.note=t)},r.pause=(t="*")=>{let e=o._readShortcutWithPlugins(t);n.stop(e)},r.resume=(t="*")=>{const e=o._readShortcutWithPlugins(t);n.start(e)},r.emit=(t,...e)=>n.emit(o._readShortcutWithPlugins(t),...e),r.listContexts=()=>Object.keys(i.shortcuts),r.setDependencies=t=>s.extra={...s.extra,...t},r.getDependencies=()=>s.extra,Object.entries(e).forEach((([t,e])=>{t.startsWith("_")?o[t]=e(s,i):r[t]=e(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.1
|
|
4
|
+
"version": "3.2.1",
|
|
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
|
|