@peter.naydenov/shortcuts 3.4.0 → 3.5.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.
Files changed (45) hide show
  1. package/Changelog.md +11 -0
  2. package/README.md +38 -9
  3. package/dist/main.d.ts +120 -0
  4. package/dist/methods/_normalizeWithPlugins.d.ts +2 -0
  5. package/dist/methods/_readShortcutWithPlugins.d.ts +2 -0
  6. package/dist/methods/_systemAction.d.ts +2 -0
  7. package/dist/methods/changeContext.d.ts +2 -0
  8. package/dist/methods/index.d.ts +17 -0
  9. package/dist/methods/listShortcuts.d.ts +17 -0
  10. package/dist/methods/load.d.ts +2 -0
  11. package/dist/methods/unload.d.ts +2 -0
  12. package/dist/plugins/click/_findTarget.d.ts +2 -0
  13. package/dist/plugins/click/_listenDOM.d.ts +5 -0
  14. package/dist/plugins/click/_normalizeShortcutName.d.ts +2 -0
  15. package/dist/plugins/click/_readClickEvent.d.ts +2 -0
  16. package/dist/plugins/click/_registerShortcutEvents.d.ts +2 -0
  17. package/dist/plugins/click/index.d.ts +15 -0
  18. package/dist/plugins/form/_defaults.d.ts +5 -0
  19. package/dist/plugins/form/_listenDOM.d.ts +5 -0
  20. package/dist/plugins/form/_normalizeShortcutName.d.ts +2 -0
  21. package/dist/plugins/form/_registerShortcutEvents.d.ts +2 -0
  22. package/dist/plugins/form/index.d.ts +10 -0
  23. package/dist/plugins/key/_listenDOM.d.ts +5 -0
  24. package/dist/plugins/key/_normalizeShortcutName.d.ts +2 -0
  25. package/dist/plugins/key/_readKeyEvent.d.ts +2 -0
  26. package/dist/plugins/key/_registerShortcutEvents.d.ts +2 -0
  27. package/dist/plugins/key/_specialChars.d.ts +32 -0
  28. package/dist/plugins/key/index.d.ts +15 -0
  29. package/dist/shortcuts.cjs +1 -1
  30. package/dist/shortcuts.esm.mjs +1 -1
  31. package/dist/shortcuts.umd.js +1 -1
  32. package/package.json +9 -5
  33. package/src/main.js +74 -20
  34. package/src/methods/changeContext.js +2 -1
  35. package/src/methods/load.js +4 -3
  36. package/src/methods/unload.js +3 -3
  37. package/src/plugins/click/_listenDOM.js +1 -1
  38. package/src/plugins/click/index.js +10 -0
  39. package/src/plugins/form/index.js +8 -13
  40. package/src/plugins/key/index.js +10 -0
  41. package/test/01-general.test.js +64 -5
  42. package/test/02-key.test.js +136 -38
  43. package/test/03-click.test.js +88 -56
  44. package/test/04-form.test.js +52 -9
  45. package/tsconfig.json +23 -0
@@ -47,9 +47,9 @@ const contextDefinition = {
47
47
  // Single click with right button
48
48
  'click: right-1': () => b = true
49
49
  }
50
- , extra : {
51
- 'key : p,r,o,b,a': () => b = true
52
- }
50
+ , extra : {
51
+ 'key : p,r,o,b,a': () => b = true
52
+ }
53
53
  , extend : {
54
54
  'form : watch' : () => 'input'
55
55
  , 'form : define' : () => 'input'
@@ -121,54 +121,152 @@ describe ( 'Key plugin', () => {
121
121
 
122
122
 
123
123
 
124
- it ( 'Key sequence', async () => {
125
- // enable key plugin and normalize shortcuts related to the plugin 'key'
124
+ it ( 'Key sequence', async () => {
125
+ // enable key plugin and normalize shortcuts related to the plugin 'key'
126
126
  short.enablePlugin ( pluginKey )
127
127
  short.changeContext ( 'extra' )
128
128
  // Execute key sequence: 'p,r,o,b,a'
129
129
  await userEvent.keyboard ( 'proba' )
130
- await wait ( 12 )
130
+ await wait ( 480 )
131
131
  await waitFor ( () => {
132
132
  expect ( b ).to.equal ( true )
133
133
  }, { timeout: 1000, interval: 12 })
134
- }) // it key sequence
134
+ }) // it key sequence
135
+
136
+
137
+
138
+
139
+ it ( 'Mute and unmute key plugin', async () => {
140
+ const result = [];
141
+ let i = 0;
142
+ result.push ( 'init' )
135
143
 
144
+ short.enablePlugin ( pluginKey )
145
+ short.setDependencies ({ result })
146
+ short.load ({
147
+ 'local': {
148
+ 'key: x,y,z' : ({ dependencies }) => {
149
+ let { result } = dependencies;
150
+ result.push ( i++ )
151
+ }
152
+ }
153
+ })
154
+
155
+ short.changeContext ( 'local' )
156
+
157
+ // Test 1: Plugin should work normally
158
+ await userEvent.keyboard ( 'xyz' )
159
+ await waitFor ( () => {
160
+ // We checking if the shortcut works
161
+ expect ( result ).to.have.lengthOf ( 2 )
162
+ expect ( i ).to.equal ( 1 )
163
+ }, { timeout: 1000, interval: 12 })
164
+
165
+ // Test 2: Mute plugin - should not trigger
166
+ short.mutePlugin ( 'key' )
167
+ await userEvent.keyboard ( 'xyz' )
168
+ await waitFor ( () => {
169
+ // Plugin is muted, so we don't expect any changes
170
+ expect ( result ).to.have.lengthOf ( 2 )
171
+ expect ( i ).to.equal ( 1 )
172
+ }, { timeout: 1000, interval: 12 })
173
+
174
+ // Test 3: Unmute plugin - should work again
175
+ short.unmutePlugin ( 'key' )
176
+ await userEvent.keyboard ( 'xyz' )
177
+ await waitFor ( () => {
178
+ // Plugin is unmuted, should work again
179
+ expect ( result ).to.have.lengthOf ( 3 )
180
+ expect ( i ).to.equal ( 2 )
181
+ }, { timeout: 1000, interval: 12 })
182
+ }) // it mute and unmute key plugin
183
+
184
+
185
+
186
+ it ( 'Arguments of key handler', async () => {
187
+ /**
188
+ * Need to know arguments for 'key' handler
189
+ * function myKeyHandler ({
190
+ * wait // (function). Function to pause key sequence processing
191
+ * , end // (function). Function to end key sequence processing
192
+ * , ignore // (function). Function to ignore current key in sequence
193
+ * , isWaiting // (function). Check if sequence is waiting
194
+ * , note // (string). Current context note or null
195
+ * , context // (string). Current context name
196
+ * , dependencies // (object). External dependencies object
197
+ * , type // (string). Event type ('key')
198
+ * }) {
199
+ * // Body of the handler. Do something...
200
+ * }
201
+ */
202
+ let test = [];
203
+ let i = 0;
204
+ short.enablePlugin ( pluginKey )
205
+ short.setDependencies ({ test })
206
+ short.load ({
207
+ 'local' : {
208
+ 'key: a' : ({
209
+ wait
210
+ , end
211
+ , ignore
212
+ , isWaiting
213
+ , note
214
+ , context
215
+ , dependencies
216
+ , type
217
+ }) => {
218
+ const
219
+ { test } = dependencies
220
+ , result = {
221
+ wait: typeof wait
222
+ , end: typeof end
223
+ , ignore: typeof ignore
224
+ , isWaiting: typeof isWaiting
225
+ , note
226
+ , context
227
+ , type
228
+ }
229
+ ;
230
+ test.push ( result )
231
+ i++
232
+ }
233
+ } // local
234
+ })
235
+ short.changeContext ( 'local' )
236
+ await userEvent.keyboard ( 'a' )
237
+ await wait ( 50 ) // Wait for key processing
238
+ await waitFor ( () => {
239
+ expect ( i ).to.be.equal ( 1 )
240
+ let result = test[0];
241
+ expect ( result.wait ).to.be.equal ( 'function' )
242
+ expect ( result.end ).to.be.equal ( 'function' )
243
+ expect ( result.ignore ).to.be.equal ( 'function' )
244
+ expect ( result.isWaiting ).to.be.equal ( 'function' )
245
+ expect ( result.context ).to.be.equal ( 'local' )
246
+ expect ( result.type ).to.be.equal ( 'key' )
247
+ }, { timeout: 1000, interval: 12 })
248
+ }) // it arguments of key handler
136
249
 
137
250
 
138
- it ( 'Mute key plugin', async () => {
251
+ it ( 'Pause and resume', async () => {
139
252
  short.enablePlugin ( pluginKey )
140
- const result = [];
141
- let i = 0;
142
- result.push ( 'init' )
143
-
144
- short.setDependencies ({ result })
145
- short.load ({
146
- 'local': {
147
- 'key: g,t,i ' : ({dependencies}) => {
148
- let { result } = dependencies;
149
- result.push ( i++ )
150
- }
151
- }
152
- })
153
-
154
- short.changeContext ( 'local' )
155
- await userEvent.keyboard ( 'gti' )
253
+ expect ( b ).to.be.equal ( false )
254
+ short.changeContext ( 'extra' )
255
+ // Shortcut name will be normalized by the plugin
256
+ short.pause ( 'key : p,r,o,b,a' )
257
+ // Execute key sequence: 'p,r,o,b,a'
258
+ await userEvent.keyboard ( 'proba' )
259
+ await wait ( 500 )
156
260
  await waitFor ( () => {
157
- // We checking if the shortcut works
158
- expect ( result ).to.have.lengthOf ( 2 )
159
- expect ( i ).to.equal ( 1 )
160
- }, { timeout: 1000, interval: 12 })
261
+ expect ( b ).to.be.equal ( false )
262
+ }, { timeout: 1000, interval: 30 })
161
263
 
162
- short.mutePlugin ( 'key' )
163
- await userEvent.keyboard ( 'gti' )
264
+ short.resume ( 'key : p,r,o,b,a' )
265
+ await userEvent.keyboard ( 'proba' )
266
+ await wait ( 500 )
164
267
  await waitFor ( () => {
165
- // Plugin is muted, so we don't expect any changes
166
- expect ( result ).to.have.lengthOf ( 2 )
167
- expect ( i ).to.equal ( 1 )
168
- }, { timeout: 1000, interval: 12 })
169
- }) // it mute key plugin
170
-
171
-
172
-
268
+ expect ( b ).to.be.equal ( true )
269
+ }, { timeout: 1000, interval: 30 })
270
+ }) // it pause and resume
173
271
 
174
272
  })
@@ -256,65 +256,97 @@ describe ( 'Click plugin', () => {
256
256
 
257
257
 
258
258
  it ( 'Click on anchor', async () => {
259
- // Click on anchor that don't have click-data attribute.
260
- let result = 'none';
261
- short.enablePlugin ( pluginClick )
262
- short.load ({ 'extra' : {
263
- 'click: 1 - left' : ({target, context, event }) => { // Order of button name and number of click is not important
264
- event.preventDefault ()
265
- expect ( context ).to.be.equal ( 'extra' )
266
- expect ( target.nodeName ).to.be.equal ( 'A' )
267
- result = target.nodeName
268
- }
269
- }
270
- })
271
- short.changeContext ( 'extra' )
272
- let loc = document.querySelector ( '#anchor' ) || false;
273
- if ( loc ) await userEvent.click ( loc )
274
- expect ( result ).to.be.equal ( 'A' )
259
+ // Click on anchor that don't have click-data attribute.
260
+ let result = 'none';
261
+ short.enablePlugin ( pluginClick )
262
+ short.load ({ 'extra' : {
263
+ 'click: 1 - left' : ({target, context, event }) => { // Order of button name and number of click is not important
264
+ event.preventDefault ()
265
+ expect ( context ).to.be.equal ( 'extra' )
266
+ expect ( target.nodeName ).to.be.equal ( 'A' )
267
+ result = target.nodeName
268
+ }
269
+ }
270
+ })
271
+ short.changeContext ( 'extra' )
272
+ let loc = document.querySelector ( '#anchor' ) || false;
273
+ if ( loc ) await userEvent.click ( loc )
274
+ expect ( result ).to.be.equal ( 'A' )
275
275
  }) // it click on anchor
276
276
 
277
277
 
278
278
 
279
- it ( 'Mute click plugin', async () => {
280
- const
281
- result = []
282
- , trg = document.querySelector ( '#rspan' )
283
- ;
284
-
285
- let i = 0;
286
- result.push ( 'init' )
287
-
288
-
289
- short.load ({
290
- 'local' : {
291
- 'click: left-1 ' : ({dependencies}) => {
292
- let { result } = dependencies;
293
- result.push ( i++ )
294
- }
295
- }
296
- })
297
- short.setDependencies ({ result })
298
- short.enablePlugin ( pluginClick )
299
- short.changeContext ( 'local' )
300
-
301
-
302
- await userEvent.click ( trg )
303
- await wait( 330 )
304
- await waitFor ( () => {
305
- // We checking if the shortcut works
306
- expect ( result ).to.have.lengthOf ( 2 )
307
- expect ( i ).to.equal ( 1 )
308
- }, { timeout: 1000, interval: 12 })
309
-
310
- short.mutePlugin ( 'click' )
311
-
312
- await userEvent.click ( trg )
313
- await waitFor ( () => {
314
- // Plugin is muted, so we don't expect any changes
315
- expect ( result ).to.have.lengthOf ( 2 )
316
- expect ( i ).to.equal ( 1 )
317
- }, { timeout: 1000, interval: 12 })
318
- }) // it mute click plugin
279
+ it ( 'Mute and unmute click plugin', async () => {
280
+ const
281
+ result = []
282
+ , trg = document.querySelector ( '#rspan' )
283
+ ;
284
+
285
+ let i = 0;
286
+ result.push ( 'init' )
287
+
288
+
289
+ short.load ({
290
+ 'local' : {
291
+ 'click: left-1 ' : ({dependencies}) => {
292
+ let { result } = dependencies;
293
+ result.push ( i++ )
294
+ }
295
+ }
296
+ })
297
+ short.setDependencies ({ result })
298
+ short.enablePlugin ( pluginClick )
299
+ short.changeContext ( 'local' )
300
+
301
+
302
+ await userEvent.click ( trg )
303
+ await wait( 330 )
304
+ await waitFor ( () => {
305
+ // We checking if the shortcut works
306
+ expect ( result ).to.have.lengthOf ( 2 )
307
+ expect ( i ).to.equal ( 1 )
308
+ }, { timeout: 1000, interval: 12 })
309
+
310
+ short.mutePlugin ( 'click' )
311
+
312
+ await userEvent.click ( trg )
313
+ await waitFor ( () => {
314
+ // Plugin is muted, so we don't expect any changes
315
+ expect ( result ).to.have.lengthOf ( 2 )
316
+ expect ( i ).to.equal ( 1 )
317
+ }, { timeout: 1000, interval: 12 })
318
+
319
+ short.unmutePlugin ( 'click' )
320
+
321
+ await userEvent.click ( trg )
322
+ await wait ( 330 )
323
+ await waitFor ( () => {
324
+ // Plugin is unmuted, should work again
325
+ expect ( result ).to.have.lengthOf ( 3 )
326
+ expect ( i ).to.equal ( 2 )
327
+ }, { timeout: 1000, interval: 12 })
328
+ }) // it mute and unmute click plugin
329
+
330
+
331
+
332
+ it ( 'Pause and resume', async () => {
333
+ let target = document.querySelector ( '#rspan' )
334
+ short.enablePlugin ( pluginClick )
335
+ expect ( b ).to.be.equal ( false )
336
+ short.changeContext ( 'touch' )
337
+ short.pause ( 'click: left-1' )
338
+ await userEvent.click ( target )
339
+ await wait ( 400 )
340
+ await waitFor ( () => {
341
+ expect ( b ).to.be.equal ( false )
342
+ }, { timeout: 1000, interval: 30 })
343
+ short.resume ( 'click: left-1' )
344
+ await userEvent.click ( target )
345
+ await wait ( 400 )
346
+ await waitFor ( () => {
347
+ expect ( b ).to.be.equal ( true )
348
+ expect ( c ).to.be.equal ( 'red' )
349
+ }, { timeout: 1000, interval: 30 })
350
+ }) // it pause and resume
319
351
 
320
352
  }) // describe
@@ -53,13 +53,13 @@ const contextDefinition = {
53
53
  , extend : {
54
54
  'form : watch' : () => 'input'
55
55
  , 'form : define' : () => 'input'
56
- , 'form : action' : () => [
57
- {
58
- fn : (e) => console.log ( e.target )
59
- , type : 'input'
60
- , mode : 'in'
61
- }
62
- ]
56
+ , 'form : action' : () => [
57
+ {
58
+ fn : (e) => console.log ( e.target )
59
+ , type : 'input'
60
+ , timing : 'in'
61
+ }
62
+ ]
63
63
  }
64
64
  }
65
65
 
@@ -67,7 +67,7 @@ let short = shortcuts ();
67
67
 
68
68
 
69
69
 
70
- describe.skip ( 'Form plugin', () => {
70
+ describe.only ( 'Form plugin', () => {
71
71
 
72
72
  beforeEach ( async () => {
73
73
  short.load ( contextDefinition )
@@ -86,5 +86,48 @@ describe.skip ( 'Form plugin', () => {
86
86
  }) // afterEach
87
87
 
88
88
 
89
-
89
+ it ( 'Shortcut when plugin is not installed', async () => {
90
+ const ls = short.listShortcuts ( 'extend' )
91
+ expect ( ls ).to.includes ( 'form : action' )
92
+ }) // it Shortcuts when plugin is not installed
93
+
94
+
95
+ it ( 'Shortcuts when plugin is enabled', async () => {
96
+ short.enablePlugin ( pluginForm )
97
+ const ls = short.listShortcuts ( 'extend' )
98
+ expect ( ls ).to.includes ( 'FORM:WATCH' )
99
+ // Shortcut names are normalized by the plugins!
100
+ expect ( ls ).to.not.includes ( 'form : watch' )
101
+ }) // it Shortcuts when plugin is enabled
102
+
103
+
104
+
105
+ it ( 'Simpler form listener. Only "form:action" defined', async () => {
106
+ // Uses predefined 'watch' and 'define' functions
107
+ short.enablePlugin ( pluginForm )
108
+ let edit = 'none';
109
+
110
+ const contextExtension = {
111
+ 'local' : {
112
+ 'form: action' : () => [{
113
+ fn : () => edit = 'changed'
114
+ , type : 'input'
115
+ , timing : 'instant'
116
+ }]
117
+ }
118
+ };
119
+ short.load ( contextExtension )
120
+ short.changeContext ( 'local' )
121
+ let input = document.getElementById ( 'name' )
122
+ input.focus ()
123
+ await userEvent.keyboard ( 'hello' )
124
+ await wait ( 50 )
125
+ await waitFor ( () => {
126
+ expect ( edit ).to.equal ( 'changed' )
127
+ }, { timeout: 1000, interval: 12 })
128
+ }) // it Simpler form listener
129
+
130
+
131
+
132
+
90
133
  }) // describe
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "allowJs": true,
4
+ "declaration": true,
5
+ "emitDeclarationOnly": true,
6
+ "outDir": "dist",
7
+ "target": "ES2020",
8
+ "module": "ESNext",
9
+ "moduleResolution": "node",
10
+ "esModuleInterop": true,
11
+ "allowSyntheticDefaultImports": true,
12
+ "strict": false,
13
+ "skipLibCheck": true
14
+ },
15
+ "include": [
16
+ "src/**/*.js"
17
+ ],
18
+ "exclude": [
19
+ "node_modules",
20
+ "dist",
21
+ "test"
22
+ ]
23
+ }