@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.
- package/Changelog.md +11 -0
- package/README.md +38 -9
- package/dist/main.d.ts +120 -0
- package/dist/methods/_normalizeWithPlugins.d.ts +2 -0
- package/dist/methods/_readShortcutWithPlugins.d.ts +2 -0
- package/dist/methods/_systemAction.d.ts +2 -0
- package/dist/methods/changeContext.d.ts +2 -0
- package/dist/methods/index.d.ts +17 -0
- package/dist/methods/listShortcuts.d.ts +17 -0
- package/dist/methods/load.d.ts +2 -0
- package/dist/methods/unload.d.ts +2 -0
- package/dist/plugins/click/_findTarget.d.ts +2 -0
- package/dist/plugins/click/_listenDOM.d.ts +5 -0
- package/dist/plugins/click/_normalizeShortcutName.d.ts +2 -0
- package/dist/plugins/click/_readClickEvent.d.ts +2 -0
- package/dist/plugins/click/_registerShortcutEvents.d.ts +2 -0
- package/dist/plugins/click/index.d.ts +15 -0
- package/dist/plugins/form/_defaults.d.ts +5 -0
- package/dist/plugins/form/_listenDOM.d.ts +5 -0
- package/dist/plugins/form/_normalizeShortcutName.d.ts +2 -0
- package/dist/plugins/form/_registerShortcutEvents.d.ts +2 -0
- package/dist/plugins/form/index.d.ts +10 -0
- package/dist/plugins/key/_listenDOM.d.ts +5 -0
- package/dist/plugins/key/_normalizeShortcutName.d.ts +2 -0
- package/dist/plugins/key/_readKeyEvent.d.ts +2 -0
- package/dist/plugins/key/_registerShortcutEvents.d.ts +2 -0
- package/dist/plugins/key/_specialChars.d.ts +32 -0
- package/dist/plugins/key/index.d.ts +15 -0
- package/dist/shortcuts.cjs +1 -1
- package/dist/shortcuts.esm.mjs +1 -1
- package/dist/shortcuts.umd.js +1 -1
- package/package.json +9 -5
- package/src/main.js +74 -20
- package/src/methods/changeContext.js +2 -1
- package/src/methods/load.js +4 -3
- package/src/methods/unload.js +3 -3
- package/src/plugins/click/_listenDOM.js +1 -1
- package/src/plugins/click/index.js +10 -0
- package/src/plugins/form/index.js +8 -13
- package/src/plugins/key/index.js +10 -0
- package/test/01-general.test.js +64 -5
- package/test/02-key.test.js +136 -38
- package/test/03-click.test.js +88 -56
- package/test/04-form.test.js +52 -9
- package/tsconfig.json +23 -0
package/test/02-key.test.js
CHANGED
|
@@ -47,9 +47,9 @@ const contextDefinition = {
|
|
|
47
47
|
// Single click with right button
|
|
48
48
|
'click: right-1': () => b = true
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
125
|
-
|
|
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 (
|
|
130
|
+
await wait ( 480 )
|
|
131
131
|
await waitFor ( () => {
|
|
132
132
|
expect ( b ).to.equal ( true )
|
|
133
133
|
}, { timeout: 1000, interval: 12 })
|
|
134
|
-
|
|
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
|
-
|
|
251
|
+
it ( 'Pause and resume', async () => {
|
|
139
252
|
short.enablePlugin ( pluginKey )
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
158
|
-
|
|
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.
|
|
163
|
-
await userEvent.keyboard ( '
|
|
264
|
+
short.resume ( 'key : p,r,o,b,a' )
|
|
265
|
+
await userEvent.keyboard ( 'proba' )
|
|
266
|
+
await wait ( 500 )
|
|
164
267
|
await waitFor ( () => {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
})
|
package/test/03-click.test.js
CHANGED
|
@@ -256,65 +256,97 @@ describe ( 'Click plugin', () => {
|
|
|
256
256
|
|
|
257
257
|
|
|
258
258
|
it ( 'Click on anchor', async () => {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
package/test/04-form.test.js
CHANGED
|
@@ -53,13 +53,13 @@ const contextDefinition = {
|
|
|
53
53
|
, extend : {
|
|
54
54
|
'form : watch' : () => 'input'
|
|
55
55
|
, 'form : define' : () => 'input'
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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.
|
|
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
|
+
}
|