@peter.naydenov/shortcuts 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Changelog.md +24 -0
- package/Migration.guide.md +51 -0
- package/README.md +59 -4
- package/index.html +1 -1
- package/package.json +4 -3
- package/src/main.js +97 -50
- package/src/methods/_findTarget.js +19 -0
- package/src/{listen.js → methods/_listen.js} +67 -44
- package/src/{readKeyEvent.js → methods/_readKeyEvent.js} +6 -6
- package/src/{readMouseEvent.js → methods/_readMouseEvent.js} +4 -4
- package/src/{readShortcut.js → methods/_readShortcut.js} +4 -3
- package/src/methods/_specialChars.js +38 -0
- package/src/{changeContext.js → methods/changeContext.js} +18 -2
- package/src/methods/index.js +29 -0
- package/src/methods/listShortcuts.js +40 -0
- package/src/{load.js → methods/load.js} +13 -4
- package/src/{unload.js → methods/unload.js} +11 -3
- package/test/01-general.cy.js +91 -8
- package/test-components/Block.jsx +1 -0
- package/blueprint-docs.md +0 -73
- package/dist/assets/index-3c4377c6.js +0 -1
- package/dist/index.html +0 -32
- package/dist/vite.svg +0 -1
- package/src/findTarget.js +0 -18
- package/src/specialChars.js +0 -31
package/Changelog.md
CHANGED
|
@@ -1,13 +1,37 @@
|
|
|
1
1
|
## Release History
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### 2.0.0 ( 2023-10-14 )
|
|
6
|
+
- [x] HTML attribute `data-quick-click` is available to speed up single click response;
|
|
7
|
+
- [x] Documentation on methods `pause` and `resume`;
|
|
8
|
+
- [x] Method `listShortcuts` to get names of all shortcuts defined;
|
|
9
|
+
- [x] Arguments for `onShortcut` and `streamKeys` converted to named arguments;
|
|
10
|
+
- [x] Method `setDependencies` to add objects to the "**dependencies**" object available as named argument in all action functions;
|
|
11
|
+
- [x] Method `getDependencies` to look at existing `dependencies` list;
|
|
12
|
+
- [x] Methods `onShortcut` and `streamKeys` have a new argument `dependencies` to pass dependencies to the callback;
|
|
13
|
+
- [x] Dependencies are aviailable for `emit` method as well as first argument;
|
|
14
|
+
- [x] JSdoc type description for public methods;
|
|
15
|
+
- [x] Tag <a> is always a target, regardless of argument 'data-click'. Tag <a> is always a `data-quick-click` target also;
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### 1.1.1 (2023-09-30)
|
|
20
|
+
- [x] Mouse faster response when maxClicks achived. (maxClicks is automatically calculated according shortcut definitions);
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
3
24
|
### 1.1.0 (2023-09-30)
|
|
4
25
|
- [x] Method `emit` was added. Not documented yet;
|
|
5
26
|
|
|
27
|
+
|
|
28
|
+
|
|
6
29
|
### 1.0.1 (2023-09-23)
|
|
7
30
|
- [x] Mouse click: preventDefault();
|
|
8
31
|
- [x] Dependencies update: @peter.naydenov/notice - v.2.2.1
|
|
9
32
|
|
|
10
33
|
|
|
34
|
+
|
|
11
35
|
### 1.0.0 (2023-08-14)
|
|
12
36
|
|
|
13
37
|
- [x] Initial code;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Migration Guides
|
|
2
|
+
|
|
3
|
+
## From version 1.x.x to version 2.x.x
|
|
4
|
+
There are 2 breaking changes: in action functions and in emit method.
|
|
5
|
+
### Action functions
|
|
6
|
+
Version 1.x.x:
|
|
7
|
+
```js
|
|
8
|
+
function ( shortcut, contextName, contextNote ) {
|
|
9
|
+
// ...
|
|
10
|
+
}
|
|
11
|
+
```
|
|
12
|
+
In version 2.x.x:
|
|
13
|
+
```js
|
|
14
|
+
function ({ shortcut, context, note, dependencies } ) {
|
|
15
|
+
// Change:
|
|
16
|
+
// - all arguments are named(properties of single object);
|
|
17
|
+
// - argument order doesn't matter;
|
|
18
|
+
// - added argument `dependencies` to pass dependencies to all action function;
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Emit method
|
|
23
|
+
|
|
24
|
+
Version 1.x.x:
|
|
25
|
+
```js
|
|
26
|
+
let result = null;
|
|
27
|
+
const myAllContext = {
|
|
28
|
+
myAll: {
|
|
29
|
+
'yo' : r => result = r
|
|
30
|
+
}}
|
|
31
|
+
short.load ( myAllContext )
|
|
32
|
+
short.changeContext ( 'myAll' )
|
|
33
|
+
short.emit ( 'yo', 'hello' )
|
|
34
|
+
// result == 'hello'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
In version 2.x.x:
|
|
38
|
+
```js
|
|
39
|
+
let result = null;
|
|
40
|
+
const myAllContext = {
|
|
41
|
+
myAll: {
|
|
42
|
+
'yo' : ( dependencies, r ) => result = r
|
|
43
|
+
// Change:
|
|
44
|
+
// - first argument is always dependencies object;
|
|
45
|
+
// - event-data is available from position 2 of arguments list;
|
|
46
|
+
}}
|
|
47
|
+
short.load ( myAllContext )
|
|
48
|
+
short.changeContext ( 'myAll' )
|
|
49
|
+
short.emit ( 'yo', 'hello' )
|
|
50
|
+
// result == 'hello'
|
|
51
|
+
```
|
package/README.md
CHANGED
|
@@ -11,8 +11,11 @@ Define a context based keyboard-shortcuts and describe a mouse clicks. Switch am
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
## What's new?
|
|
14
|
-
Version 1.1.0 is coming with new method `emit` that make possible to trigger context functions also programmatically. In `shortcuts` you can mix keyboard, mouse and programmatical events that is prity everything that can happen in a web page.
|
|
15
14
|
|
|
15
|
+
- Version 1.1.x and above are coming with method `emit` that make possible to trigger shortcuts programmatically. In `shortcuts` you can mix keyboard, mouse and programmatical events that is prity everything that can happen in a web page;
|
|
16
|
+
- Method `setDependencies` comes after version 2.0.0. You can insert external libraries and modules that you will need to access from action functions. They will come as **dependencies** object. In function `emit` will come as first argument. Other arguments are attached behind the dependencies object;
|
|
17
|
+
- Another html data attribute is added - `data-quick-click`. Example: `<button data-click="id" data-quick-click>Click me</button>`. This attribute is saying to `shortcuts` that target element don't need to wait for more then 1 click and shortcut can be executed immediately after the click. Attribute is available in version 2.0.0 and above;
|
|
18
|
+
- Method `listShortcuts` is added in version 2.0.0. It returns a list of shortcuts for requested context. If context is not set, will return a list of all shortcuts;
|
|
16
19
|
|
|
17
20
|
|
|
18
21
|
## Shortcut Description Rules
|
|
@@ -22,7 +25,7 @@ The shortcuts definition includes a context name and a set of rules(object). The
|
|
|
22
25
|
// { context: { shortcutName: actionFunction } }
|
|
23
26
|
// or
|
|
24
27
|
// { context: { shortcutName: [ actionFunction1, actionFunction2 ] }}
|
|
25
|
-
|
|
28
|
+
|
|
26
29
|
// Shortcut definition object:
|
|
27
30
|
{
|
|
28
31
|
contextName : {
|
|
@@ -40,6 +43,7 @@ The shortcuts definition includes a context name and a set of rules(object). The
|
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
45
|
```
|
|
46
|
+
|
|
43
47
|
Load a shortcut definition by calling `load` method.
|
|
44
48
|
|
|
45
49
|
```js
|
|
@@ -130,6 +134,43 @@ Order of describing mouse event and modifier keys is not important.
|
|
|
130
134
|
Multiple clicks are detected automatically by time interval between clicks. The default interval is 320ms but you can change it by setting `mouseWait` option. Read more in section `Options`.
|
|
131
135
|
|
|
132
136
|
|
|
137
|
+
## Define a mouse targets
|
|
138
|
+
Target HTML elements for `shortcuts` are defined by `data-click` attribute. The value of the attribute is the name of the target. Example:
|
|
139
|
+
|
|
140
|
+
```html
|
|
141
|
+
<button data-click="id">Click me</button>
|
|
142
|
+
<!-- target name is 'id' -->
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Attribute is customizable by setting `clickTarget` option. Read more in section `Options`.
|
|
146
|
+
|
|
147
|
+
If current shortcuts context contain definition for 2 or more clicks, this may slow down the execution of single shortcuts because `shortcuts` will wait for the time interval to detect multiple clicks. To avoid this for specific targets, you can set `data-quick-click` attribute to the target element. Example:
|
|
148
|
+
|
|
149
|
+
```html
|
|
150
|
+
<button data-click="id" data-quick-click>Click me</button>
|
|
151
|
+
<!-- target name is 'id' and will not wait for more then 1 click -->
|
|
152
|
+
```
|
|
153
|
+
Using a <a> tag is a special case. It's always recognized as a target, and always with attribute `data-quick-click`. No need to set it manually. Example:
|
|
154
|
+
|
|
155
|
+
```html
|
|
156
|
+
<a href="#">Click me</a>
|
|
157
|
+
<!-- Recognized as a target and will not wait for more then 1 click -->
|
|
158
|
+
<!-- Take care for the action from shortcut `mouse-click-left-1`. -->
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Clicking on <a> tag will not execute anything. All events are blocked by default. In your `mouse-click-left-1` action function you can write a code to execute the default action. Example:
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
{
|
|
165
|
+
contextName : {
|
|
166
|
+
'mouse-click-left-1' : function ( {target, event} ) {
|
|
167
|
+
if ( target.tagName === 'A' ) { // All targets that are <a> tags will execute the default action
|
|
168
|
+
window.location.href = target.href // Go to the link
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
133
174
|
|
|
134
175
|
|
|
135
176
|
|
|
@@ -200,6 +241,7 @@ Description of keyboard action functions is:
|
|
|
200
241
|
function myKeyHandler ({
|
|
201
242
|
context // (string) Name of the current context;
|
|
202
243
|
, note // (string) Name of the note or null if note isn't set;
|
|
244
|
+
, dependencies // (object) Object with dependencies that you have set by calling `setDependencies` method;
|
|
203
245
|
, wait // (function). Call it to stop a sequence timer and write shortcut sequence without a timer.
|
|
204
246
|
, end // (function). Recover the sequence timer;
|
|
205
247
|
, ignore // (function). Call it to ignore the current shortcut from the sequence;
|
|
@@ -219,6 +261,7 @@ Mouse action functions can be described like:
|
|
|
219
261
|
function myMouseHandler ({
|
|
220
262
|
context // (string) Name of the current context;
|
|
221
263
|
, note // (string) Name of the note or null if note isn't set;
|
|
264
|
+
, dependencies // (object) Object with dependencies that you have set by calling `setDependencies` method;
|
|
222
265
|
, target // (DOM element). Target element of the mouse event;
|
|
223
266
|
, targetProps // (object). Coordinates of the target element (top, left, right, bottom, width, height) or null if target element is not available;
|
|
224
267
|
, x // (number). X coordinate of the target element;
|
|
@@ -250,6 +293,16 @@ Description of the methods of shortcut instance:
|
|
|
250
293
|
, setNote : 'Set a note to current context.'
|
|
251
294
|
```
|
|
252
295
|
|
|
296
|
+
### How to 'pause' and 'resume'?
|
|
297
|
+
When you want to stop execution of shortcuts, call `short.pause()`. It's equal to `short.pause('*')`. Will stop all shortcuts in the active context. Stop for single shortcut is by calling `short.pause('shortcutName')`. To resume shortcuts execution call `short.resume()`. It's equal to `short.resume('*')`. Will resume all shortcuts in the active context. Resume for single shortcut is by calling `short.resume('shortcutName')`.
|
|
298
|
+
|
|
299
|
+
```js
|
|
300
|
+
// pause all shortcuts in the active context
|
|
301
|
+
short.pause () // will stop all shortcuts in the active context
|
|
302
|
+
short.resume ( 'shift+a' ) // will resume only 'shift+a' shortcut
|
|
303
|
+
|
|
304
|
+
short.resume ('*') // will resume all shortcuts
|
|
305
|
+
```
|
|
253
306
|
|
|
254
307
|
|
|
255
308
|
|
|
@@ -282,10 +335,11 @@ const short = shortcuts ( shortcuts.getDefaults () ) // same as above
|
|
|
282
335
|
|
|
283
336
|
### onShortcut option
|
|
284
337
|
```js
|
|
285
|
-
function onShortcut ( shortcut, context, note ) {
|
|
338
|
+
function onShortcut ({ shortcut, context, note, dependencies }) {
|
|
286
339
|
// shortcut - (string) Triggered shortcut name
|
|
287
340
|
// context - (string) Name of the current context
|
|
288
341
|
// note - (string) Name of the note or null if note isn't set
|
|
342
|
+
// dependencies - (object) Object with dependencies that you have set by calling `setDependencies` method
|
|
289
343
|
}
|
|
290
344
|
```
|
|
291
345
|
|
|
@@ -293,10 +347,11 @@ const short = shortcuts ( shortcuts.getDefaults () ) // same as above
|
|
|
293
347
|
|
|
294
348
|
### streamKeys option
|
|
295
349
|
```js
|
|
296
|
-
function streamKeys ( key, context, note ) {
|
|
350
|
+
function streamKeys ({ key, context, note, dependencies }) {
|
|
297
351
|
// key - (string) Pressed key name
|
|
298
352
|
// context - (string) Name of the current context
|
|
299
353
|
// note - (string) Name of the note or null if note isn't set
|
|
354
|
+
// dependencies - (object) Object with dependencies that you have set by calling `setDependencies` method
|
|
300
355
|
}
|
|
301
356
|
```
|
|
302
357
|
|
package/index.html
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
import sc from '/src/main.js'
|
|
26
26
|
|
|
27
27
|
const options = {
|
|
28
|
-
onShortcut ( shortcut, context, note ) {
|
|
28
|
+
onShortcut ({ shortcut, context, note }) {
|
|
29
29
|
console.log ( '-- RESULTS --->' )
|
|
30
30
|
console.log ( 'Shortcut', shortcut )
|
|
31
31
|
console.log ( 'Context:', context )
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peter.naydenov/shortcuts",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Context control of shortcuts based on keyboard and mouse events",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shortcut",
|
|
@@ -25,12 +25,13 @@
|
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@vitejs/plugin-react": "^4.1.0",
|
|
28
|
+
"ask-for-promise": "^1.4.0",
|
|
28
29
|
"chai": "^4.3.10",
|
|
29
|
-
"cypress": "^13.3.
|
|
30
|
+
"cypress": "^13.3.1",
|
|
30
31
|
"mocha": "^10.2.0",
|
|
31
32
|
"react": "^18.2.0",
|
|
32
33
|
"react-dom": "^18.2.0",
|
|
33
|
-
"vite": "^4.4.
|
|
34
|
+
"vite": "^4.4.11"
|
|
34
35
|
},
|
|
35
36
|
"author": "Peter Naydenov",
|
|
36
37
|
"license": "MIT"
|
package/src/main.js
CHANGED
|
@@ -10,21 +10,13 @@
|
|
|
10
10
|
* - Development was started on June 21st, 2023
|
|
11
11
|
* - First version was published on August 14th, 2023
|
|
12
12
|
* - Method 'emit' was added on September 30st, 2023
|
|
13
|
+
* - Version 2.0.0 was published on October 14th, 2023
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
|
|
17
|
-
import notice
|
|
18
|
-
|
|
19
|
-
import listen from './listen.js'
|
|
20
|
-
import readShortcut from './readShortcut.js'
|
|
21
|
-
import readKeyEvent from './readKeyEvent.js'
|
|
22
|
-
import readMouseEvent from './readMouseEvent.js'
|
|
23
|
-
import findTarget from './findTarget.js'
|
|
24
|
-
import specialChars from './specialChars.js'
|
|
25
|
-
import load from './load.js'
|
|
26
|
-
import unload from './unload.js'
|
|
27
|
-
import changeContext from './changeContext.js'
|
|
18
|
+
import notice from '@peter.naydenov/notice' // Docs: https://github.com/PeterNaydenov/notice
|
|
19
|
+
import methods from './methods/index.js'
|
|
28
20
|
|
|
29
21
|
|
|
30
22
|
|
|
@@ -33,53 +25,108 @@ import changeContext from './changeContext.js'
|
|
|
33
25
|
function main ( options = {} ) {
|
|
34
26
|
const
|
|
35
27
|
ev = notice () // Event emitter instance
|
|
36
|
-
,
|
|
37
|
-
,
|
|
38
|
-
,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
28
|
+
, inAPI = {} // API for internal methods
|
|
29
|
+
, API = {} // API for public methods
|
|
30
|
+
, state = {
|
|
31
|
+
currentContext : { name: null, note: null } // Context data container
|
|
32
|
+
, shortcuts : {} // shortcuts = { contextName : { shortcut : callback[] } }
|
|
33
|
+
, listenOptions : {
|
|
34
|
+
mouseWait : options.mouseWait ? options.mouseWait : 320 // 320 ms
|
|
35
|
+
, maxClicks : 1 // The maximum number of clicks in a sequence. Controlled automatically by 'changeContext' function.
|
|
36
|
+
, keyWait : options.keyWait ? options.keyWait : 480 // 480 ms
|
|
37
|
+
, maxSequence : 1 // How many keys can be pressed in a sequence. Controlled automatically by 'changeContext' function.
|
|
38
|
+
, clickTarget : options.clickTarget ? options.clickTarget : 'click' // Data-attribute name for click target ( data-click )
|
|
39
|
+
, listenFor : (options.listenFor && Array.isArray(options.listenFor)) ? options.listenFor : [ 'mouse', 'keyboard' ] // What to listen for: ['mouse'], ['keyboard'], ['mouse', 'keyboard']
|
|
40
|
+
, keyIgnore : null // Timer for ignoring key presses after max sequence or null. Not a public option.
|
|
41
|
+
}
|
|
42
|
+
, exposeShortcut : (options.onShortcut && ( typeof options.onShortcut === 'function')) ? options.onShortcut : false
|
|
43
|
+
, streamKeys : (options.streamKeys && ( typeof options.streamKeys === 'function')) ? options.streamKeys : false
|
|
44
|
+
} // state
|
|
52
45
|
, dependencies = {
|
|
53
|
-
|
|
54
|
-
,
|
|
55
|
-
,
|
|
56
|
-
,
|
|
57
|
-
, ev
|
|
58
|
-
, exposeShortcut
|
|
59
|
-
, streamKeys
|
|
46
|
+
ev
|
|
47
|
+
, inAPI
|
|
48
|
+
, API
|
|
49
|
+
, extra : {}
|
|
60
50
|
}
|
|
61
51
|
;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @function getContext
|
|
55
|
+
* @description Get current context name
|
|
56
|
+
* @returns {string} - Current context name
|
|
57
|
+
*/
|
|
58
|
+
API.getContext = () => state.currentContext.name
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @function getNote
|
|
62
|
+
* @description Get current context note
|
|
63
|
+
* @returns {string} - Current context note
|
|
64
|
+
*/
|
|
65
|
+
API.getNote = () => state.currentContext.note
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @function setNote
|
|
69
|
+
* @description Set current context note
|
|
70
|
+
* @param {string} note - Context note
|
|
71
|
+
* @returns {void}
|
|
72
|
+
*/
|
|
73
|
+
API.setNote = (note=null) => { if (typeof note === 'string' || note == null ) state.currentContext.note = note }
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @function pause
|
|
77
|
+
* @description Pause shortcut(s) in current context
|
|
78
|
+
* @param {string} [name='*' ] - Shortcut name that should be paused. Default is '*' - all shortcuts in current context.
|
|
79
|
+
* @returns {void}
|
|
80
|
+
*/
|
|
81
|
+
API.pause = (name='*') => ev.stop ( inAPI._readShortcut(name) )
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @function resume
|
|
85
|
+
* @description Resume shortcut(s) in current context
|
|
86
|
+
* @param {string} [name='*' ] - Shortcut name that should be resumed. Default is '*' - all shortcuts in current context.
|
|
87
|
+
* @returns {void}
|
|
88
|
+
*/
|
|
89
|
+
API.resume = (name='*') => ev.start ( inAPI._readShortcut(name) )
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @function emit
|
|
93
|
+
* @description Emit event for shortcut in current context
|
|
94
|
+
* @param {string} name - Shortcut name
|
|
95
|
+
* @param {any} [args] - Arguments for callback function
|
|
96
|
+
* @returns {void}
|
|
97
|
+
**/
|
|
98
|
+
API.emit = (name,...args) => ev.emit ( inAPI._readShortcut(name), dependencies.extra, ...args )
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @function listContexts
|
|
102
|
+
* @description List all context names
|
|
103
|
+
* @returns {string[]} - Array of context names
|
|
104
|
+
*/
|
|
105
|
+
API.listContexts = () => Object.keys ( shortcuts )
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @function setDependencies
|
|
109
|
+
* @description Set a dependency package that will be provided to each action function
|
|
110
|
+
* @param {object} deps - Enumerate external dependencies
|
|
111
|
+
* @returns {void}
|
|
112
|
+
*/
|
|
113
|
+
API.setDependencies = (deps) => dependencies.extra = { ...dependencies.extra, ...deps }
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
Object.entries ( methods ).forEach ( ([ name, method ]) => {
|
|
118
|
+
if ( name.startsWith('_') ) inAPI [ name ] = method ( dependencies, state )
|
|
119
|
+
else API [ name ] = method ( dependencies, state )
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
inAPI._listen ()
|
|
123
|
+
return API
|
|
77
124
|
} // main func.
|
|
78
125
|
|
|
79
126
|
|
|
80
127
|
|
|
81
128
|
main.getDefaults = () => ({
|
|
82
|
-
mouseWait : 320 // 320 ms
|
|
129
|
+
mouseWait : 320 // 320 ms
|
|
83
130
|
, keyWait : 480 // 480 ms
|
|
84
131
|
, clickTarget : 'click' // Data-attribute name for click target ( data-click )
|
|
85
132
|
, listenFor : [ 'mouse', 'keyboard' ]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
function _findTarget ( dependencies, state ) {
|
|
4
|
+
const { listenOptions : {clickTarget}} = state;
|
|
5
|
+
return function _findTarget ( target ) {
|
|
6
|
+
const t = target;
|
|
7
|
+
if ( t === document ) return null
|
|
8
|
+
if ( t === document.body ) return null
|
|
9
|
+
|
|
10
|
+
if ( t.dataset[clickTarget] ) return t
|
|
11
|
+
if ( t.nodeName === 'A' ) return t
|
|
12
|
+
return _findTarget ( t.parentNode )
|
|
13
|
+
}} // _findTarget func.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
export default _findTarget
|
|
18
|
+
|
|
19
|
+
|
|
@@ -2,22 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
function
|
|
5
|
+
function _listen ( dependencies, state ) {
|
|
6
|
+
// Listen for input signals and generate event titles
|
|
7
|
+
return function _listen () {
|
|
6
8
|
const {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
, {
|
|
9
|
+
ev
|
|
10
|
+
, inAPI : {
|
|
11
|
+
_findTarget
|
|
12
|
+
, _specialChars
|
|
13
|
+
, _readKeyEvent
|
|
14
|
+
, _readMouseEvent
|
|
15
|
+
}
|
|
16
|
+
} = dependencies
|
|
17
|
+
, {
|
|
18
|
+
exposeShortcut
|
|
19
|
+
, currentContext
|
|
20
|
+
, streamKeys
|
|
21
|
+
, listenOptions
|
|
22
|
+
} = state
|
|
23
|
+
, {
|
|
16
24
|
mouseWait
|
|
17
25
|
, keyWait
|
|
18
26
|
, clickTarget
|
|
19
|
-
, listenFor
|
|
20
|
-
} =
|
|
27
|
+
, listenFor
|
|
28
|
+
} = listenOptions
|
|
21
29
|
;
|
|
22
30
|
|
|
23
31
|
let
|
|
@@ -54,10 +62,18 @@ function listen ( dependencies, options, currentContext ) { // Listen for inpu
|
|
|
54
62
|
ignore = false
|
|
55
63
|
}
|
|
56
64
|
}
|
|
57
|
-
|
|
65
|
+
const data = {
|
|
66
|
+
wait: waitKeys
|
|
67
|
+
, end:endKeys
|
|
68
|
+
, ignore:ignoreKeys
|
|
69
|
+
, isWaiting:waitingKeys
|
|
70
|
+
, note: currentContext.note
|
|
71
|
+
, context: currentContext.name
|
|
72
|
+
, dependencies : dependencies.extra
|
|
73
|
+
};
|
|
58
74
|
if ( sequence ) {
|
|
59
|
-
ev.emit ( res.join(','),
|
|
60
|
-
if ( exposeShortcut ) exposeShortcut ( res.join(','), currentContext.name, currentContext.note
|
|
75
|
+
ev.emit ( res.join(','), data )
|
|
76
|
+
if ( exposeShortcut ) exposeShortcut ({ shortcut:res.join(','), context: currentContext.name, note:currentContext.note, dependencies:dependencies.extra })
|
|
61
77
|
// Reset:
|
|
62
78
|
r = []
|
|
63
79
|
keyTimer = null
|
|
@@ -68,7 +84,7 @@ function listen ( dependencies, options, currentContext ) { // Listen for inpu
|
|
|
68
84
|
|
|
69
85
|
function mouseSequenceEnd () { // Execute when mouse sequence ends
|
|
70
86
|
const
|
|
71
|
-
mouseEvent =
|
|
87
|
+
mouseEvent = _readMouseEvent ( mouseDomEvent, count )
|
|
72
88
|
, data = {
|
|
73
89
|
target : mouseTarget
|
|
74
90
|
, targetProps : mouseTarget ? mouseTarget.getBoundingClientRect() : null
|
|
@@ -77,10 +93,11 @@ function listen ( dependencies, options, currentContext ) { // Listen for inpu
|
|
|
77
93
|
, context : currentContext.name
|
|
78
94
|
, note : currentContext.note
|
|
79
95
|
, event : mouseDomEvent
|
|
96
|
+
, dependencies : dependencies.extra
|
|
80
97
|
}
|
|
81
98
|
;
|
|
82
99
|
ev.emit ( mouseEvent.join('+'), data )
|
|
83
|
-
if ( exposeShortcut ) exposeShortcut ( mouseEvent.join('+'), currentContext.name, currentContext.note )
|
|
100
|
+
if ( exposeShortcut ) exposeShortcut ({ shortcut: mouseEvent.join('+'), context:currentContext.name, note:currentContext.note, dependencies:dependencies.extra })
|
|
84
101
|
// Reset:
|
|
85
102
|
mouseTimer = null
|
|
86
103
|
mouseIgnore = null
|
|
@@ -93,6 +110,7 @@ function listen ( dependencies, options, currentContext ) { // Listen for inpu
|
|
|
93
110
|
|
|
94
111
|
function listenMouse () {
|
|
95
112
|
window.addEventListener ( 'contextmenu', event => { // Listen for right mouse clicks
|
|
113
|
+
let targetMax = listenOptions.maxClicks; // Maximum number of clicks per target
|
|
96
114
|
event.preventDefault ()
|
|
97
115
|
clearTimeout ( mouseTimer )
|
|
98
116
|
if ( mouseIgnore ) {
|
|
@@ -100,18 +118,21 @@ function listen ( dependencies, options, currentContext ) { // Listen for inpu
|
|
|
100
118
|
mouseIgnore = setTimeout ( () => mouseIgnore=null, mouseWait )
|
|
101
119
|
return
|
|
102
120
|
}
|
|
103
|
-
|
|
121
|
+
mouseTarget = _findTarget ( event.target )
|
|
122
|
+
if ( mouseTarget && mouseTarget.dataset.hasOwnProperty('quickClick')) targetMax = 1
|
|
123
|
+
if ( mouseTarget && mouseTarget.tagName === 'A' ) targetMax = 1
|
|
124
|
+
mouseDomEvent = event
|
|
125
|
+
count++
|
|
126
|
+
if ( count >= targetMax ) {
|
|
104
127
|
mouseSequenceEnd ()
|
|
105
|
-
mouseIgnore = setTimeout ( () => mouseIgnore=null, mouseWait )
|
|
128
|
+
if ( targetMax > 1 ) mouseIgnore = setTimeout ( () => mouseIgnore=null, mouseWait )
|
|
106
129
|
return
|
|
107
130
|
}
|
|
108
|
-
mouseTarget = findTarget (event.target, clickTarget )
|
|
109
|
-
mouseDomEvent = event
|
|
110
|
-
count++
|
|
111
131
|
mouseTimer = setTimeout ( mouseSequenceEnd, mouseWait )
|
|
112
132
|
})
|
|
113
133
|
|
|
114
134
|
document.addEventListener ( 'click', event => { // Listen for left and middle mouse clicks
|
|
135
|
+
let targetMax = listenOptions.maxClicks; // Maximum number of clicks per target
|
|
115
136
|
event.preventDefault ()
|
|
116
137
|
clearTimeout ( mouseTimer )
|
|
117
138
|
if ( mouseIgnore ) {
|
|
@@ -119,14 +140,16 @@ function listen ( dependencies, options, currentContext ) { // Listen for inpu
|
|
|
119
140
|
mouseIgnore = setTimeout ( () => mouseIgnore=null, mouseWait )
|
|
120
141
|
return
|
|
121
142
|
}
|
|
122
|
-
|
|
143
|
+
mouseTarget = _findTarget ( event.target )
|
|
144
|
+
if ( mouseTarget && mouseTarget.dataset.hasOwnProperty('quickClick')) targetMax = 1
|
|
145
|
+
if ( mouseTarget && mouseTarget.tagName === 'A' ) targetMax = 1
|
|
146
|
+
mouseDomEvent = event
|
|
147
|
+
count++
|
|
148
|
+
if ( count >= targetMax ) {
|
|
123
149
|
mouseSequenceEnd ()
|
|
124
|
-
mouseIgnore = setTimeout ( () => mouseIgnore=null, mouseWait )
|
|
150
|
+
if ( targetMax > 1 ) mouseIgnore = setTimeout ( () => mouseIgnore=null, mouseWait )
|
|
125
151
|
return
|
|
126
152
|
}
|
|
127
|
-
mouseTarget = findTarget ( event.target, clickTarget )
|
|
128
|
-
mouseDomEvent = event
|
|
129
|
-
count++
|
|
130
153
|
mouseTimer = setTimeout ( mouseSequenceEnd, mouseWait )
|
|
131
154
|
})
|
|
132
155
|
} // listenMouse func.
|
|
@@ -136,17 +159,17 @@ function listen ( dependencies, options, currentContext ) { // Listen for inpu
|
|
|
136
159
|
function listenKeyboard () {
|
|
137
160
|
document.addEventListener ( 'keydown', event => { // Listen for special keyboard keys
|
|
138
161
|
clearTimeout ( keyTimer )
|
|
139
|
-
if (
|
|
162
|
+
if ( _specialChars.hasOwnProperty(event.code) ) r.push ( _readKeyEvent ( event, _specialChars ))
|
|
140
163
|
else return
|
|
141
|
-
if ( streamKeys ) streamKeys ( event.key, currentContext.name, currentContext.note )
|
|
142
|
-
if (
|
|
143
|
-
clearTimeout (
|
|
144
|
-
|
|
164
|
+
if ( streamKeys ) streamKeys ({ key:event.key, context:currentContext.name, note:currentContext.note, dependencies:dependencies.extra })
|
|
165
|
+
if ( listenOptions.keyIgnore ) {
|
|
166
|
+
clearTimeout ( listenOptions.keyIgnore )
|
|
167
|
+
listenOptions.keyIgnore = setTimeout ( () => listenOptions.keyIgnore=null, keyWait )
|
|
145
168
|
return
|
|
146
169
|
}
|
|
147
|
-
if ( sequence && r.length ===
|
|
170
|
+
if ( sequence && r.length === listenOptions.maxSequence ) {
|
|
148
171
|
keySequenceEnd ()
|
|
149
|
-
|
|
172
|
+
listenOptions.keyIgnore = setTimeout ( () => listenOptions.keyIgnore=null, keyWait )
|
|
150
173
|
return
|
|
151
174
|
}
|
|
152
175
|
if ( sequence ) keyTimer = setTimeout ( keySequenceEnd, keyWait )
|
|
@@ -154,18 +177,18 @@ function listen ( dependencies, options, currentContext ) { // Listen for inpu
|
|
|
154
177
|
})
|
|
155
178
|
|
|
156
179
|
document.addEventListener ( 'keypress', event => { // Listen for regular keyboard keys
|
|
157
|
-
if (
|
|
180
|
+
if ( _specialChars.hasOwnProperty(event.code) ) return
|
|
158
181
|
clearTimeout ( keyTimer )
|
|
159
|
-
if ( streamKeys ) streamKeys ( event.key, currentContext.name, currentContext.note )
|
|
160
|
-
if (
|
|
161
|
-
clearTimeout (
|
|
162
|
-
|
|
182
|
+
if ( streamKeys ) streamKeys ({ key:event.key, context:currentContext.name, note:currentContext.note, dependencies:dependencies.extra })
|
|
183
|
+
if ( listenOptions.keyIgnore ) {
|
|
184
|
+
clearTimeout ( listenOptions.keyIgnore )
|
|
185
|
+
listenOptions.keyIgnore = setTimeout ( () => listenOptions.keyIgnore=null, keyWait )
|
|
163
186
|
return
|
|
164
187
|
}
|
|
165
|
-
r.push (
|
|
166
|
-
if ( sequence && r.length ===
|
|
188
|
+
r.push ( _readKeyEvent ( event, _specialChars ))
|
|
189
|
+
if ( sequence && r.length === listenOptions.maxSequence ) {
|
|
167
190
|
keySequenceEnd ()
|
|
168
|
-
|
|
191
|
+
listenOptions.keyIgnore = setTimeout ( () => listenOptions.keyIgnore=null, keyWait )
|
|
169
192
|
return
|
|
170
193
|
}
|
|
171
194
|
if ( sequence ) keyTimer = setTimeout ( keySequenceEnd, keyWait )
|
|
@@ -178,10 +201,10 @@ function listen ( dependencies, options, currentContext ) { // Listen for inpu
|
|
|
178
201
|
if ( listenFor.includes('mouse') ) listenMouse ()
|
|
179
202
|
if ( listenFor.includes('keyboard') ) listenKeyboard ()
|
|
180
203
|
|
|
181
|
-
} //
|
|
204
|
+
}} // _listen func.
|
|
182
205
|
|
|
183
206
|
|
|
184
207
|
|
|
185
|
-
export default
|
|
208
|
+
export default _listen
|
|
186
209
|
|
|
187
210
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
function
|
|
3
|
+
function _readKeyEvent () {
|
|
4
|
+
return function _readKeyEvent ( event, _specialChars ) {
|
|
5
5
|
let
|
|
6
6
|
{ shiftKey, altKey, ctrlKey } = event
|
|
7
7
|
, falseKeys = [ 'ControlLeft','ControlRight', 'ShiftLeft', 'ShiftRight', 'AltLeft', 'AltRight', 'Meta' ]
|
|
@@ -15,13 +15,13 @@ function readKeyEvent ( event, specialChars ) {
|
|
|
15
15
|
if ( shiftKey ) res.push ( 'SHIFT' )
|
|
16
16
|
if ( altKey ) res.push ( 'ALT' )
|
|
17
17
|
|
|
18
|
-
if (
|
|
19
|
-
else if (
|
|
18
|
+
if ( _specialChars.hasOwnProperty ( key ) ) res.push ( _specialChars[key].toUpperCase () )
|
|
19
|
+
else if ( !falseKeys.includes(key) ) res.push ( key.toUpperCase () )
|
|
20
20
|
return res.sort ()
|
|
21
|
-
} //
|
|
21
|
+
}} // _readKeyEvent func.
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
export default
|
|
25
|
+
export default _readKeyEvent
|
|
26
26
|
|
|
27
27
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
function
|
|
3
|
+
function _readMouseEvent () {
|
|
4
|
+
return function _readMouseEvent ( event, count ) {
|
|
5
5
|
let
|
|
6
6
|
{ shiftKey, altKey, ctrlKey, key, button } = event
|
|
7
7
|
, mouseNames = [ 'LEFT', 'MIDDLE', 'RIGHT' ]
|
|
@@ -15,10 +15,10 @@ function readMouseEvent ( event, count ) {
|
|
|
15
15
|
if ( altKey ) res.push ( 'ALT' )
|
|
16
16
|
|
|
17
17
|
return res.sort ()
|
|
18
|
-
} //
|
|
18
|
+
}} // _readMouseEvent func.
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
export default
|
|
22
|
+
export default _readMouseEvent
|
|
23
23
|
|
|
24
24
|
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
// [ crtl+s, shift+alt+o]
|
|
3
|
-
function
|
|
3
|
+
function _readShortcut () {
|
|
4
|
+
return function _readShortcut ( txt ) {
|
|
4
5
|
const r = txt
|
|
5
6
|
.split ( ',' )
|
|
6
7
|
.map ( (x) => x.trim() )
|
|
7
8
|
.map ( (x) => x.split ( '+' ).map(x => x.toUpperCase()).sort().join('+') )
|
|
8
9
|
.join ( ',' );
|
|
9
10
|
return r
|
|
10
|
-
} //
|
|
11
|
+
}} // _readShortcut func.
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
export default
|
|
15
|
+
export default _readShortcut
|
|
15
16
|
|
|
16
17
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function _specialChars () {
|
|
2
|
+
return {
|
|
3
|
+
'ArrowLeft' : 'LEFT'
|
|
4
|
+
, 'ArrowUp' : 'UP'
|
|
5
|
+
, 'ArrowRight' : 'RIGHT'
|
|
6
|
+
, 'ArrowDown' : 'DOWN'
|
|
7
|
+
, 'Enter' : 'ENTER'
|
|
8
|
+
, 'NumpadEnter' : 'ENTER'
|
|
9
|
+
, 'Escape' : 'ESC'
|
|
10
|
+
, 'Backspace' : 'BACKSPACE'
|
|
11
|
+
, 'Space' : 'SPACE'
|
|
12
|
+
, 'Tab' : 'TAB'
|
|
13
|
+
, 'Backquote' : '`'
|
|
14
|
+
, 'BracketLeft' : '['
|
|
15
|
+
, 'BracketRight': ']'
|
|
16
|
+
, 'Equal' : '='
|
|
17
|
+
, 'Slash' : '/'
|
|
18
|
+
, 'Backslash' : '\\'
|
|
19
|
+
, 'IntlBackslash' : '`'
|
|
20
|
+
, 'F1' : 'F1'
|
|
21
|
+
, 'F2' : 'F2'
|
|
22
|
+
, 'F3' : 'F3'
|
|
23
|
+
, 'F4' : 'F4'
|
|
24
|
+
, 'F5' : 'F5'
|
|
25
|
+
, 'F6' : 'F6'
|
|
26
|
+
, 'F7' : 'F7'
|
|
27
|
+
, 'F8' : 'F8'
|
|
28
|
+
, 'F9' : 'F9'
|
|
29
|
+
, 'F10' : 'F10'
|
|
30
|
+
, 'F11' : 'F11'
|
|
31
|
+
, 'F12' : 'F12'
|
|
32
|
+
}}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
export default _specialChars
|
|
37
|
+
|
|
38
|
+
|
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
function changeContext (
|
|
3
|
+
function changeContext ( dependencies, state ) {
|
|
4
|
+
const
|
|
5
|
+
{
|
|
6
|
+
shortcuts
|
|
7
|
+
, listenOptions
|
|
8
|
+
, currentContext
|
|
9
|
+
} = state
|
|
10
|
+
, { ev } = dependencies
|
|
11
|
+
;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @function changeContext
|
|
15
|
+
* @description Change current context with shortcuts belonging to it.
|
|
16
|
+
* @param {string} [contextName=false] - Name of context to change to. Default 'false' will switch off all shortcuts.
|
|
17
|
+
* @returns {void}
|
|
18
|
+
*/
|
|
4
19
|
return function changeContext ( contextName = false ) {
|
|
5
20
|
const current = currentContext.name;
|
|
21
|
+
|
|
6
22
|
listenOptions.maxSequence = 1
|
|
7
23
|
listenOptions.maxClicks = 1
|
|
8
24
|
|
|
@@ -37,7 +53,7 @@ return function changeContext ( contextName = false ) {
|
|
|
37
53
|
}
|
|
38
54
|
list.forEach ( fn => ev.on ( shortcutName, fn ) ) // Enable new context shortcuts
|
|
39
55
|
})
|
|
40
|
-
currentContext.name = contextName
|
|
56
|
+
currentContext.name = contextName
|
|
41
57
|
}} // changeContext func.
|
|
42
58
|
|
|
43
59
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import _findTarget from './_findTarget.js'
|
|
2
|
+
import _listen from './_listen.js'
|
|
3
|
+
import _readKeyEvent from './_readKeyEvent.js'
|
|
4
|
+
import _readMouseEvent from './_readMouseEvent.js'
|
|
5
|
+
import _readShortcut from './_readShortcut.js'
|
|
6
|
+
import _specialChars from './_specialChars.js'
|
|
7
|
+
|
|
8
|
+
import load from './load.js'
|
|
9
|
+
import unload from './unload.js'
|
|
10
|
+
import changeContext from './changeContext.js'
|
|
11
|
+
import listShortcuts from './listShortcuts.js'
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
// Internal methods
|
|
17
|
+
_findTarget
|
|
18
|
+
, _listen
|
|
19
|
+
, _readKeyEvent
|
|
20
|
+
, _readMouseEvent
|
|
21
|
+
, _readShortcut
|
|
22
|
+
, _specialChars
|
|
23
|
+
|
|
24
|
+
// Public methods
|
|
25
|
+
, changeContext
|
|
26
|
+
, listShortcuts
|
|
27
|
+
, load
|
|
28
|
+
, unload
|
|
29
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
/**
|
|
3
|
+
* @typedef {object} contextShortcuts
|
|
4
|
+
* @property {string} context - Context name
|
|
5
|
+
* @property {string[]} shortcuts - List of shortcuts in a context
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
function listShortcuts ( dependencies, state ) {
|
|
11
|
+
const shortcuts = state.shortcuts;
|
|
12
|
+
/**
|
|
13
|
+
* List all shortcuts in all contexts or in a specific context.
|
|
14
|
+
* @param {string}[ contextName=null] - List of shortcuts for provided context name. (optional)
|
|
15
|
+
* @returns {string[]|contextShortcuts[]} - List of shortcuts for a specified context or list of contextShortcuts for all contexts.
|
|
16
|
+
*/
|
|
17
|
+
return function listShortcuts ( contextName=null ) {
|
|
18
|
+
|
|
19
|
+
// Create a list of shortcuts for a specific context:
|
|
20
|
+
if ( contextName != null ) {
|
|
21
|
+
let context = shortcuts[contextName];
|
|
22
|
+
if ( context == null ) return null
|
|
23
|
+
return Object.entries ( context ).map ( ([shortcut, callbacks]) => shortcut )
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Create a list of allShortcuts for each context:
|
|
27
|
+
return Object.keys ( shortcuts ).map ( contextName => {
|
|
28
|
+
let result = {};
|
|
29
|
+
result['context'] = contextName
|
|
30
|
+
result['shortcuts'] = Object.entries ( shortcuts[contextName] ).map ( ([shortcut, callbacks]) => shortcut )
|
|
31
|
+
return result
|
|
32
|
+
}) // map
|
|
33
|
+
|
|
34
|
+
}} // listShortcuts func.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
export default listShortcuts
|
|
39
|
+
|
|
40
|
+
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
function load ( dependencies, state ) {
|
|
4
|
+
const
|
|
5
|
+
{ shortcuts } = state
|
|
6
|
+
, {
|
|
7
|
+
inAPI : { _readShortcut }
|
|
8
|
+
, API : { changeContext, getContext }
|
|
9
|
+
} = dependencies;
|
|
10
|
+
/**
|
|
11
|
+
* Load a context with shortcuts object
|
|
12
|
+
* @param {Object} obj - Context description object: { contextName : { shortcut : callback[] }
|
|
13
|
+
* @returns {void}
|
|
14
|
+
*/
|
|
6
15
|
return function load ( obj ) {
|
|
7
16
|
const
|
|
8
17
|
currentContextName = getContext ()
|
|
@@ -14,7 +23,7 @@ return function load ( obj ) {
|
|
|
14
23
|
if ( contextName === currentContextName ) hasChanges = true;
|
|
15
24
|
shortcuts [ contextName ] = {}
|
|
16
25
|
description.forEach ( ([ title, callbackList ]) => {
|
|
17
|
-
const name =
|
|
26
|
+
const name = _readShortcut ( title );
|
|
18
27
|
if ( callbackList instanceof Function ) callbackList = [ callbackList ]
|
|
19
28
|
shortcuts [contextName][ name ] = callbackList
|
|
20
29
|
}) // shortcuts.forEach
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
function unload ( dependencies, state ) {
|
|
4
|
+
const
|
|
5
|
+
{ currentContext, shortcuts } = state
|
|
6
|
+
, { ev } = dependencies
|
|
7
|
+
;
|
|
8
|
+
/**
|
|
9
|
+
* @function unload
|
|
10
|
+
* @description Unload a non-active context with shortcuts.
|
|
11
|
+
* @param {string} contextName - Context name to unload
|
|
12
|
+
* @returns {void}
|
|
13
|
+
*/
|
|
6
14
|
return function unload ( contextName ) {
|
|
7
15
|
const current = currentContext.name;
|
|
8
16
|
if ( current === contextName ) {
|
package/test/01-general.cy.js
CHANGED
|
@@ -4,11 +4,13 @@ import '../test-components/style.css'
|
|
|
4
4
|
import shortcuts from '../src/main.js'
|
|
5
5
|
import { expect } from 'chai'
|
|
6
6
|
|
|
7
|
+
import askForPromise from 'ask-for-promise'
|
|
8
|
+
|
|
7
9
|
let
|
|
8
10
|
a = false
|
|
9
11
|
, b = false
|
|
10
12
|
;
|
|
11
|
-
const short = shortcuts ({onShortcut : (
|
|
13
|
+
const short = shortcuts ({onShortcut : ({shortcut, context, note}) => console.log (shortcut, context, note)});
|
|
12
14
|
short.load ({
|
|
13
15
|
general : {
|
|
14
16
|
'shift+a': [ () => a = true ]
|
|
@@ -32,7 +34,7 @@ it ( 'Simple shortcut', done => {
|
|
|
32
34
|
let res = false;
|
|
33
35
|
short.changeContext ( 'general' )
|
|
34
36
|
cy.get('body').type ( '{shift}a' )
|
|
35
|
-
cy.wait (
|
|
37
|
+
cy.wait ( 30 ) // Default wait sequence timeout is 480 ms, but maxSequence is 1, so we don't need to wait for timeout
|
|
36
38
|
.then ( () => {
|
|
37
39
|
expect ( a ).to.be.true
|
|
38
40
|
done ()
|
|
@@ -81,11 +83,10 @@ it ( 'Single mouse click', done => {
|
|
|
81
83
|
})
|
|
82
84
|
short.changeContext ( 'extra' )
|
|
83
85
|
cy.get('#rspan').click ()
|
|
84
|
-
cy.wait (
|
|
85
|
-
.then ( () =>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
})
|
|
86
|
+
cy.wait ( 10 ) // Default wait mouse timeout is 320 ms, but maxClicks is 1, so we don't need to wait for timeout
|
|
87
|
+
.then ( () => expect ( a ).to.be.true )
|
|
88
|
+
cy.wait ( 300 ) // ...but mouseIgnore still active, so we better wait to not interfere with next test
|
|
89
|
+
.then ( () => done() )
|
|
89
90
|
}) // it mouse click
|
|
90
91
|
|
|
91
92
|
|
|
@@ -117,12 +118,94 @@ it ( 'Emit custom event', () => {
|
|
|
117
118
|
const myAllContext = {
|
|
118
119
|
myAll: {
|
|
119
120
|
'mouse-click-leff-1' : () => console.log ( 'nothing' )
|
|
120
|
-
, 'yo' : r => result = r
|
|
121
|
+
, 'yo' : (dependencies,r) => result = r
|
|
121
122
|
}}
|
|
122
123
|
short.load ( myAllContext )
|
|
123
124
|
short.changeContext ( 'myAll' )
|
|
124
125
|
short.emit ( 'yo', 'hello' )
|
|
125
126
|
expect ( result ).to.be.equal ( 'hello' )
|
|
127
|
+
short.changeContext ( 'general' )
|
|
128
|
+
short.unload ( 'myAll' )
|
|
126
129
|
}) // it emit custom event
|
|
127
130
|
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
it ( 'Dependencies on shortcuts', done => {
|
|
134
|
+
const task = askForPromise ();
|
|
135
|
+
expect ( a ).to.be.false
|
|
136
|
+
expect ( b ).to.be.false
|
|
137
|
+
|
|
138
|
+
short.setDependencies ({ task })
|
|
139
|
+
|
|
140
|
+
short.load ({
|
|
141
|
+
'extra' : { // load will overwrite existing 'extra' context definition
|
|
142
|
+
'mouse-click-left-1' : ({dependencies}) => {
|
|
143
|
+
const { task } = dependencies;
|
|
144
|
+
expect ( task ).to.have.property ( 'done' )
|
|
145
|
+
expect ( task ).to.have.property ( 'promise' )
|
|
146
|
+
a = true
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}) // load will restart the selected context
|
|
150
|
+
|
|
151
|
+
short.changeContext ( 'extra' )
|
|
152
|
+
cy.get('#rspan').click ()
|
|
153
|
+
cy.wait ( 350 ) // Default wait mouse timeout is 320 ms
|
|
154
|
+
.then ( () => {
|
|
155
|
+
expect ( a ).to.be.true
|
|
156
|
+
done ()
|
|
157
|
+
})
|
|
158
|
+
}) // it dependencies on shortcuts
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
it ( 'List shortcuts', () => {
|
|
163
|
+
let general = short.listShortcuts ('general');
|
|
164
|
+
expect ( general ).to.be.an('array')
|
|
165
|
+
expect ( general ).to.have.lengthOf ( 1 )
|
|
166
|
+
expect ( general[0] ).to.be.equal ( 'A+SHIFT' )
|
|
167
|
+
|
|
168
|
+
let fail = short.listShortcuts ('somethingNotExisting');
|
|
169
|
+
expect ( fail ).to.be.null
|
|
170
|
+
|
|
171
|
+
let all = short.listShortcuts ();
|
|
172
|
+
expect ( all ).to.be.an('array')
|
|
173
|
+
|
|
174
|
+
expect ( all ).to.have.lengthOf ( 2 )
|
|
175
|
+
expect ( all[0] ).to.have.property ( 'context' )
|
|
176
|
+
expect ( all[0] ).to.have.property ( 'shortcuts' )
|
|
177
|
+
expect ( all[0].shortcuts ).to.be.an('array')
|
|
178
|
+
expect ( all[0].shortcuts ).to.have.lengthOf ( 1 )
|
|
179
|
+
expect ( all[0].shortcuts[0] ).to.be.equal ( 'A+SHIFT' )
|
|
180
|
+
expect ( all[0].context ).to.be.equal ( 'general' )
|
|
181
|
+
|
|
182
|
+
}) // it list shortcuts
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
it ( 'Click on anchor', done => {
|
|
187
|
+
// Click on anchor that don't have click-data attribute.
|
|
188
|
+
let result = 'none';
|
|
189
|
+
short.load ({ 'extra' : {
|
|
190
|
+
'mouse-click-left-1' : ({target, context }) => {
|
|
191
|
+
expect ( context ).to.be.equal ( 'extra' )
|
|
192
|
+
expect ( target.nodeName ).to.be.equal ( 'A' )
|
|
193
|
+
result = target.nodeName
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
})
|
|
197
|
+
short.changeContext ( 'extra' )
|
|
198
|
+
cy.get ( '#anchor' ).click ()
|
|
199
|
+
cy.wait ( 3 ) // Consider mouse click has some latency
|
|
200
|
+
// According Cypress documentation:
|
|
201
|
+
// It is unsafe to chain further commands that rely on the subject after .click().
|
|
202
|
+
// source docs: https://docs.cypress.io/api/commands/click
|
|
203
|
+
.then ( () => {
|
|
204
|
+
short.changeContext ( 'general' )
|
|
205
|
+
expect ( result ).to.be.equal ( 'A' )
|
|
206
|
+
done ()
|
|
207
|
+
})
|
|
208
|
+
}) // it click on anchor
|
|
209
|
+
|
|
210
|
+
|
|
128
211
|
}) // describe
|
|
@@ -2,6 +2,7 @@ function Block () {
|
|
|
2
2
|
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
|
+
<p>Some text with <a href="#" target="_blank">link <span id="anchor">in</span></a> it</p>
|
|
5
6
|
</>
|
|
6
7
|
}
|
|
7
8
|
|
package/blueprint-docs.md
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# Shortcuts (@peter.naydenov/shortcuts)
|
|
2
|
-
*UNDER HEAVY DEVELOPMENT - early experimental stage*
|
|
3
|
-
|
|
4
|
-
Build a keyboard shortcuts maps and describe a mouse clicks. Control them on context.
|
|
5
|
-
|
|
6
|
-
Tread it as a "**draft**" during `HEAVY DEVELOPMENT` stage. the API will change frequently and version of the package will not be updated. Will stay at `0.0.1` until the API get usable.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
Create shortcuts for your web application based on keyboard and mouse events.
|
|
13
|
-
|
|
14
|
-
Listen for keyboard, mouse and touch events and converts them into event-emmiter events.
|
|
15
|
-
Define a shortcut library with shortcut names and callback functions. The callback functions will be called when the shortcut is pressed. Library `shortcuts` supports a context switching and that allows
|
|
16
|
-
to add, remove and change multiple shortcuts by changing the current context.
|
|
17
|
-
|
|
18
|
-
- Context switching;
|
|
19
|
-
- Listen for keyboard, mouse and touch events;
|
|
20
|
-
- Read a shortcut sequences;
|
|
21
|
-
- Multiple mouse clicks events for left and right mouse buttons;
|
|
22
|
-
- The delay between keypresses and mouse clicks in shortcut sequences are controlled by parameters;
|
|
23
|
-
- Centralized control over mouse click event. All clicks on the page can be described by a single callback function;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Define and conrol shortcuts in your application. Setup a stage, create a shortcut name and associate a list of callback function with it. The callback function will be called when the shortcut is pressed. Changing the stage will stop all shortcuts associated with it old stage and start all shortcuts associated with the new stage.
|
|
27
|
-
|
|
28
|
-
Event sources: keyboard, mouse, touch;
|
|
29
|
-
|
|
30
|
-
## Installation
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
npm i @peter.naydenov/shortcuts
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
From the project file:
|
|
37
|
-
|
|
38
|
-
```js
|
|
39
|
-
import shortcuts from '@peter.naydenov/shortcuts'
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Methods
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
```js
|
|
47
|
-
'load' : 'Provide context objects, shortcuts related to the context and list of callback functions'
|
|
48
|
-
, 'unload' : 'Remove context objects and shortcuts'
|
|
49
|
-
, 'changeContext' : 'Change the current context. Change active list of shortcuts'
|
|
50
|
-
, 'pause' : 'Disable all shortcuts. No change of context'
|
|
51
|
-
, 'resume' : 'Resume shortcuts after pause'
|
|
52
|
-
, 'getContext' : 'Return the current context name'
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
## Keyboard Action functions
|
|
57
|
-
Keypress will create an event with name of pressed keys. If `shortcut` has a callback function associated with this name, the callback function will be called.
|
|
58
|
-
|
|
59
|
-
The callback function will receive an object with the following properties:
|
|
60
|
-
|
|
61
|
-
```js
|
|
62
|
-
function keyCallback (key) {
|
|
63
|
-
console.log(key)
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
Every shortcut is defined by a callback function. The callback function will be called when the shortcut is pressed. The callback function will receive an object with the following properties:
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
```js
|
|
70
|
-
function keyCallback (key) {
|
|
71
|
-
console.log(key)
|
|
72
|
-
}
|
|
73
|
-
```
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))i(o);new MutationObserver(o=>{for(const l of o)if(l.type==="childList")for(const u of l.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&i(u)}).observe(document,{childList:!0,subtree:!0});function t(o){const l={};return o.integrity&&(l.integrity=o.integrity),o.referrerPolicy&&(l.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?l.credentials="include":o.crossOrigin==="anonymous"?l.credentials="omit":l.credentials="same-origin",l}function i(o){if(o.ep)return;o.ep=!0;const l=t(o);fetch(o.href,l)}})();function M(){function r(){let e={},t={},i=[],o=!1,l="";function u(n,s){e[n]||(e[n]=[]),e[n].push(s)}function c(n,s){t[n]||(t[n]=[]),t[n].push(s)}function y(n,s){if(s){e[n]&&(e[n]=e[n].filter(g=>g!==s)),t[n]&&(t[n]=t[n].filter(g=>g!==s)),e[n]&&e[n].length===0&&delete e[n],t[n]&&t[n].length===0&&delete e[n];return}t[n]&&delete t[n],e[n]&&delete e[n]}function f(){e={},t={},i=[]}function m(n,s){o=!!n,s&&typeof s=="string"&&(l=s)}function d(){const[n,...s]=arguments;if(o&&(console.log(`${l} Event "${n}" was triggered.`),s.length>0&&(console.log("Arguments:"),console.log(...s),console.log("^----"))),n=="*"&&Object.keys(e).forEach(E=>{i.includes(E)||e[E].forEach(F=>F(...s))}),t[n]){if(i.includes(n))return;t[n].forEach(g=>g(...s)),delete t[n]}if(e[n]){if(i.includes(n))return;e[n].forEach(g=>g(...s))}}function k(n){if(n==="*"){i=[];return}i=i.filter(s=>n!=s)}function p(n){if(n==="*"){const s=Object.keys(e);i=[...Object.keys(t),...s];return}i.push(n)}return{on:u,once:c,off:y,reset:f,emit:d,stop:p,start:k,debug:m}}return new r}function P(r,e,t){const{specialChars:i,readKeyEvent:o,readMouseEvent:l,findTarget:u,ev:c,exposeShortcut:y,streamKeys:f}=r,{mouseWait:m,keyWait:d,clickTarget:k,listenFor:p}=e;let n=[],s=null,g=null,E=null,F=null,h=null,T=!0,L=!1,S=0;const A=()=>T=!1,b=()=>T=!0,O=()=>L=!0,v=()=>T===!1;function I(){let a=n.map(K=>[K.join("+")]);if(!T){let K=a.at(-1);c.emit(K,{wait:A,end:b,ignore:O,isWaiting:v,note:t.note,context:t.name}),L&&(a=a.slice(0,-1),L=!1)}T&&(c.emit(a.join(","),{wait:A,end:b,ignore:O,isWaiting:v,note:t.note,context:t.name}),y&&y(a.join(","),t.name,t.note),n=[],E=null)}function w(){const a=l(g,S),K={target:s,targetProps:s?s.getBoundingClientRect():null,x:g.clientX,y:g.clientY,context:t.name,note:t.note,event:g};c.emit(a.join("+"),K),y&&y(a.join("+"),t.name,t.note),F=null,h=null,s=null,g=null,S=0}function q(){window.addEventListener("contextmenu",a=>{if(clearTimeout(F),h){clearTimeout(h),h=setTimeout(()=>h=null,m);return}if(S===e.maxClicks){w(),h=setTimeout(()=>h=null,m);return}a.preventDefault(),s=u(a.target,k),g=a,S++,F=setTimeout(w,m)}),document.addEventListener("click",a=>{if(clearTimeout(F),h){clearTimeout(h),h=setTimeout(()=>h=null,m);return}if(S===e.maxClicks){w(),h=setTimeout(()=>h=null,m);return}s=u(a.target,k),g=a,S++,F=setTimeout(w,m)})}function j(){document.addEventListener("keydown",a=>{if(clearTimeout(E),i.hasOwnProperty(a.code))n.push(o(a,i));else return;if(f&&f(a.key,t.name,t.note),e.keyIgnore){clearTimeout(e.keyIgnore),e.keyIgnore=setTimeout(()=>e.keyIgnore=null,d);return}if(T&&n.length===e.maxSequence){I(),e.keyIgnore=setTimeout(()=>e.keyIgnore=null,d);return}T?E=setTimeout(I,d):I()}),document.addEventListener("keypress",a=>{if(!i.hasOwnProperty(a.code)){if(clearTimeout(E),f&&f(a.key,t.name,t.note),e.keyIgnore){clearTimeout(e.keyIgnore),e.keyIgnore=setTimeout(()=>e.keyIgnore=null,d);return}if(n.push(o(a,i)),T&&n.length===e.maxSequence){I(),e.keyIgnore=setTimeout(()=>e.keyIgnore=null,d);return}T?E=setTimeout(I,d):I()}})}p.includes("mouse")&&q(),p.includes("keyboard")&&j()}function B(r){return r.split(",").map(t=>t.trim()).map(t=>t.split("+").map(i=>i.toUpperCase()).sort().join("+")).join(",")}function D(r,e){let{shiftKey:t,altKey:i,ctrlKey:o}=r,l=["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"],u=r.code.replace("Key","").replace("Digit",""),c=[];return o&&c.push("CTRL"),t&&c.push("SHIFT"),i&&c.push("ALT"),e.hasOwnProperty(u)?c.push(e[u].toUpperCase()):l.includes(u)||c.push(u.toUpperCase()),c.sort()}function U(r,e){let{shiftKey:t,altKey:i,ctrlKey:o,key:l,button:u}=r,c=["LEFT","MIDDLE","RIGHT"],y=`MOUSE-CLICK-${c[u]}-${e}`,f=[];return f.push(y),o&&f.push("CTRL"),t&&f.push("SHIFT"),i&&f.push("ALT"),f.sort()}function $(r,e){let t=r;for(;t&&!t.dataset[e];)if(t=t.parentNode,t===document||t===document.body)return null;return t}const x={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 N(r,e,t,i){return function(l){const u=i(),c=Object.keys(l);let y=!1;c.forEach(f=>{const m=Object.entries(l[f]);f===u&&(y=!0),r[f]={},m.forEach(([d,k])=>{const p=e(d);k instanceof Function&&(k=[k]),r[f][p]=k})}),y&&(t(),t(u))}}function H(r,e,t){return function(o){if(t.name===o){e.emit("shortcuts-error",`Context '${o}' can't be removed during is current active context. Change the context first`);return}if(!r[o]){e.emit("shortcuts-error",`Context '${o}' does not exist`);return}delete r[o]}}function R(r,e,t,i){return function(l=!1){const u=i.name;if(e.maxSequence=1,e.maxClicks=1,e.keyIgnore>=0&&(clearTimeout(e.keyIgnore),e.keyIgnore=null),!l){t.reset(),i.name=null;return}if(u!==l){if(!r[l]){t.emit("shortcuts-error",`Context '${l}' does not exist`);return}r[u]&&t.reset(),Object.entries(r[l]).forEach(([c,y])=>{if(c.includes("MOUSE-CLICK-")){let[,,,m]=c.split("-"),d=parseInt(m);e.maxClicks<d&&(e.maxClicks=d)}else{let m=c.split(",").length;e.maxSequence<m&&(e.maxSequence=m)}y.forEach(m=>t.on(c,m))}),i.name=l}}}function W(r={}){const e=M(),t={name:null,note:null},i=r.onShortcut&&typeof r.onShortcut=="function"?r.onShortcut:!1,o=r.streamKeys&&typeof r.streamKeys=="function"?r.streamKeys:!1,l={mouseWait:r.mouseWait?r.mouseWait:320,maxClicks:1,keyWait:r.keyWait?r.keyWait:480,maxSequence:1,clickTarget:r.clickTarget?r.clickTarget:"click",listenFor:r.listenFor&&Array.isArray(r.listenFor)?r.listenFor:["mouse","keyboard"],keyIgnore:null},u={},c=()=>t.name,y=()=>t.note,f=(d=null)=>{(typeof d=="string"||d==null)&&(t.note=d)};return P({specialChars:x,readKeyEvent:D,readMouseEvent:U,findTarget:$,ev:e,exposeShortcut:i,streamKeys:o},l,t),{load:N(u,B,R(u,l,e,t),c),unload:H(u,e,t),changeContext:R(u,l,e,t),pause:()=>e.stop(),resume:()=>e.start(),listContexts:()=>Object.keys(u),getContext:c,getNote:y,setNote:f}}W.getDefaults=()=>({mouseWait:320,keyWait:480,clickTarget:"click",listenFor:["mouse","keyboard"],onShortcut:!1,streamKeys:!1});const G={onShortcut(r,e,t){console.log("-- RESULTS --->"),console.log("Shortcut",r),console.log("Context:",e),t&&console.log("Note:",t)}},C=W(G);C.load({general:{q:[()=>console.log("Q was clicked")],"r,o,s":()=>console.log("ROS was clicked"),"mouse-click-left-2":()=>console.log("Mouse left click 2"),r:[({isWaiting:r})=>{r()||console.log("R was clicked")}],"shift+w":[({wait:r,end:e,ignore:t,isWaiting:i,note:o})=>{t(),i()?(console.log("END"),e()):(console.log("WAIT"),r())},()=>console.log("W")]}});C.changeContext("general");C.setNote("some");
|
package/dist/index.html
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>Vite App</title>
|
|
8
|
-
<style>
|
|
9
|
-
.block {
|
|
10
|
-
width: 100px;
|
|
11
|
-
height: 100px;
|
|
12
|
-
background-color: red;
|
|
13
|
-
}
|
|
14
|
-
.big-btn {
|
|
15
|
-
width: 200px;
|
|
16
|
-
height: 200px;
|
|
17
|
-
margin-left: 320px;
|
|
18
|
-
background-color: skyblue;
|
|
19
|
-
border-radius: 10px;
|
|
20
|
-
}
|
|
21
|
-
</style>
|
|
22
|
-
<script type="module" crossorigin src="/assets/index-3c4377c6.js"></script>
|
|
23
|
-
</head>
|
|
24
|
-
<body>
|
|
25
|
-
|
|
26
|
-
<div class="block" data-click="red-block">
|
|
27
|
-
<span>hello</span>
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
|
-
<button class="big-btn" data-click="mega-button" draggable>Mega button</button>
|
|
31
|
-
</body>
|
|
32
|
-
</html>
|
package/dist/vite.svg
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/src/findTarget.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
function findTarget ( target, dataName ) {
|
|
5
|
-
let t = target
|
|
6
|
-
while ( t && !t.dataset[dataName] ) {
|
|
7
|
-
t = t.parentNode;
|
|
8
|
-
if ( t === document ) return null
|
|
9
|
-
if ( t === document.body ) return null
|
|
10
|
-
}
|
|
11
|
-
return t
|
|
12
|
-
} // findTarget func.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export default findTarget
|
|
17
|
-
|
|
18
|
-
|
package/src/specialChars.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
'ArrowLeft' : 'LEFT'
|
|
3
|
-
, 'ArrowUp' : 'UP'
|
|
4
|
-
, 'ArrowRight' : 'RIGHT'
|
|
5
|
-
, 'ArrowDown' : 'DOWN'
|
|
6
|
-
, 'Enter' : 'ENTER'
|
|
7
|
-
, 'NumpadEnter' : 'ENTER'
|
|
8
|
-
, 'Escape' : 'ESC'
|
|
9
|
-
, 'Backspace' : 'BACKSPACE'
|
|
10
|
-
, 'Space' : 'SPACE'
|
|
11
|
-
, 'Tab' : 'TAB'
|
|
12
|
-
, 'Backquote' : '`'
|
|
13
|
-
, 'BracketLeft' : '['
|
|
14
|
-
, 'BracketRight': ']'
|
|
15
|
-
, 'Equal' : '='
|
|
16
|
-
, 'Slash' : '/'
|
|
17
|
-
, 'Backslash' : '\\'
|
|
18
|
-
, 'IntlBackslash' : '`'
|
|
19
|
-
, 'F1' : 'F1'
|
|
20
|
-
, 'F2' : 'F2'
|
|
21
|
-
, 'F3' : 'F3'
|
|
22
|
-
, 'F4' : 'F4'
|
|
23
|
-
, 'F5' : 'F5'
|
|
24
|
-
, 'F6' : 'F6'
|
|
25
|
-
, 'F7' : 'F7'
|
|
26
|
-
, 'F8' : 'F8'
|
|
27
|
-
, 'F9' : 'F9'
|
|
28
|
-
, 'F10' : 'F10'
|
|
29
|
-
, 'F11' : 'F11'
|
|
30
|
-
, 'F12' : 'F12'
|
|
31
|
-
}
|