@peter.naydenov/shortcuts 2.2.0 → 3.0.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/src/main.js CHANGED
@@ -3,6 +3,7 @@
3
3
  /**
4
4
  * Shortcuts
5
5
  * ========
6
+ *
6
7
  * Create shortcuts for your web application based on keyboard and mouse events.
7
8
  * Repository: https://github.com/PeterNaydenov/shortcuts
8
9
  *
@@ -11,6 +12,7 @@
11
12
  * - First version was published on August 14th, 2023
12
13
  * - Method 'emit' was added on September 30st, 2023
13
14
  * - Version 2.0.0 was published on October 16th, 2023
15
+ * - Version 3.0.0. Plugin system. Published on March 5th, 2024
14
16
  */
15
17
 
16
18
 
@@ -18,11 +20,16 @@
18
20
  import notice from '@peter.naydenov/notice' // Docs: https://github.com/PeterNaydenov/notice
19
21
  import methods from './methods/index.js'
20
22
 
23
+ // Plugins
24
+ import pluginKey from './plugins/key/index.js'
25
+ import pluginClick from './plugins/click/index.js'
26
+
21
27
 
22
28
 
23
29
 
24
30
 
25
31
  function main ( options = {} ) {
32
+
26
33
  const
27
34
  ev = notice () // Event emitter instance
28
35
  , inAPI = {} // API for internal methods
@@ -30,17 +37,8 @@ function main ( options = {} ) {
30
37
  , state = {
31
38
  currentContext : { name: null, note: null } // Context data container
32
39
  , 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
40
+ , plugins : [] // Array of active plugins
41
+ , exposeShortcut : (options.onShortcut && ( typeof options.onShortcut === 'function')) ? options.onShortcut : false // Keyboard shortcut log function
44
42
  } // state
45
43
  , dependencies = {
46
44
  ev
@@ -50,6 +48,58 @@ function main ( options = {} ) {
50
48
  }
51
49
  ;
52
50
 
51
+
52
+
53
+ // ---------------------- > PLUGIN METHODS < ---------------------- //
54
+ /**
55
+ * @function enablePlugin
56
+ * @description Enable a plugin
57
+ * @returns {void}
58
+ */
59
+ API.enablePlugin = ( plugin,options={}) => {
60
+ const
61
+ name = plugin.name
62
+ , ix = inAPI._systemAction ( name, 'none' )
63
+ ;
64
+
65
+ if ( ix === -1 ) { // If plugin is not registered
66
+ let plugApp; // Started instance of the plugin
67
+ plugApp = plugin ( dependencies, state, options )
68
+ state.plugins.push ( plugApp )
69
+ }
70
+ } // enable func.
71
+
72
+
73
+
74
+ /**
75
+ * @function disablePlugin
76
+ * @description Disable a plugin
77
+ * @returns {void}
78
+ */
79
+ API.disablePlugin = pluginName => {
80
+ const ix = inAPI._systemAction ( pluginName, 'destroy' );
81
+ if ( ix !== -1 ) state.plugins = state.plugins.filter ( (plugin, i) => i !== ix )
82
+ } // disable func.
83
+
84
+
85
+ /**
86
+ * @function mutePlugin
87
+ * @description Mute a plugin
88
+ * @returns number - Index of the plugin in the plugins array ( -1 if not found ).
89
+ */
90
+ API.mutePlugin = pluginName => inAPI._systemAction ( pluginName, 'mute' )
91
+
92
+ /**
93
+ * @function unmute
94
+ * @description Unmute a plugin
95
+ * @returns number - Index of the plugin in the plugins array ( -1 if not found ).
96
+ */
97
+ API.unmutePlugin = pluginName => inAPI._systemAction ( pluginName, 'unmute' )
98
+
99
+
100
+
101
+
102
+ // ---------------------- > PUBLIC METHODS < ---------------------- //
53
103
  /**
54
104
  * @function getContext
55
105
  * @description Get current context name
@@ -78,7 +128,10 @@ function main ( options = {} ) {
78
128
  * @param {string} [name='*' ] - Shortcut name that should be paused. Default is '*' - all shortcuts in current context.
79
129
  * @returns {void}
80
130
  */
81
- API.pause = (name='*') => ev.stop ( inAPI._readShortcut(name) )
131
+ API.pause = (name='*') => {
132
+ let pausedEvent = inAPI._readShortcutWithPlugins ( name );
133
+ ev.stop ( pausedEvent )
134
+ }
82
135
 
83
136
  /**
84
137
  * @function resume
@@ -86,7 +139,10 @@ function main ( options = {} ) {
86
139
  * @param {string} [name='*' ] - Shortcut name that should be resumed. Default is '*' - all shortcuts in current context.
87
140
  * @returns {void}
88
141
  */
89
- API.resume = (name='*') => ev.start ( inAPI._readShortcut(name) )
142
+ API.resume = (name='*') => {
143
+ const resumedEvent = inAPI._readShortcutWithPlugins ( name )
144
+ ev.start ( resumedEvent )
145
+ }
90
146
 
91
147
  /**
92
148
  * @function emit
@@ -95,14 +151,17 @@ function main ( options = {} ) {
95
151
  * @param {any} [args] - Arguments for callback function
96
152
  * @returns {void}
97
153
  **/
98
- API.emit = (name,...args) => ev.emit ( inAPI._readShortcut(name), dependencies.extra, ...args )
154
+ API.emit = (name,...args) => ev.emit ( inAPI._readShortcutWithPlugins ( name ), ...args )
155
+
99
156
 
100
157
  /**
101
158
  * @function listContexts
102
159
  * @description List all context names
103
160
  * @returns {string[]} - Array of context names
104
161
  */
105
- API.listContexts = () => Object.keys ( shortcuts )
162
+ API.listContexts = () => Object.keys ( state.shortcuts )
163
+
164
+
106
165
 
107
166
  /**
108
167
  * @function setDependencies
@@ -110,7 +169,7 @@ function main ( options = {} ) {
110
169
  * @param {object} deps - Enumerate external dependencies
111
170
  * @returns {void}
112
171
  */
113
- API.setDependencies = (deps) => dependencies.extra = { ...dependencies.extra, ...deps }
172
+ API.setDependencies = deps => dependencies.extra = { ...dependencies.extra, ...deps }
114
173
 
115
174
  /**
116
175
  * @function getDependencies
@@ -125,24 +184,16 @@ function main ( options = {} ) {
125
184
  if ( name.startsWith('_') ) inAPI [ name ] = method ( dependencies, state )
126
185
  else API [ name ] = method ( dependencies, state )
127
186
  })
128
-
129
- inAPI._listen ()
187
+
130
188
  return API
131
189
  } // main func.
132
190
 
133
191
 
134
192
 
135
- main.getDefaults = () => ({
136
- mouseWait : 320 // 320 ms
137
- , keyWait : 480 // 480 ms
138
- , clickTarget : 'click' // Data-attribute name for click target ( data-click )
139
- , listenFor : [ 'mouse', 'keyboard' ]
140
- , onShortcut : false // Shortcut log function or false
141
- , streamKeys : false // Stream keys function or false
142
- })
143
-
144
-
145
-
146
- export default main
193
+ export { main as shortcuts }
194
+ export {
195
+ pluginKey
196
+ , pluginClick
197
+ }
147
198
 
148
199
 
@@ -0,0 +1,25 @@
1
+ function _normalizeWithPlugins ( dependencies, state ) {
2
+ /**
3
+ * @function _normalizeWithPlugins
4
+ * @description Function used by plugins during the enable process to normalize the existing and related to the plugin shortcut names.
5
+ * @param {function} _normalizeShortcutName - Plugin internal 'normalize' function.
6
+ * @returns {void}
7
+ */
8
+ return function _normalizeWithPlugins ( _normalizeShortcutName ) {
9
+ const shortcuts = state.shortcuts;
10
+ Object.keys ( shortcuts ).forEach ( contextName => {
11
+ Object.entries (shortcuts[contextName]).forEach ( ([shortcutName, callbackList]) => {
12
+ const name = _normalizeShortcutName ( shortcutName )
13
+ if ( name !== shortcutName ) {
14
+ delete shortcuts[contextName][shortcutName]
15
+ shortcuts[contextName][name] = callbackList
16
+ }
17
+ })
18
+ })
19
+ }} // _normalizeWithPlugins func.
20
+
21
+
22
+
23
+ export default _normalizeWithPlugins
24
+
25
+
@@ -0,0 +1,24 @@
1
+ 'use strict'
2
+ function _readShortcutWithPlugins ( dependencies, state ) {
3
+ /**
4
+ * @function _readShortcutWithPlugins
5
+ * @description Searches for belonging plugin and call the plugin method to normalize the shortcut name.
6
+ * @param {string} shortcut - The shortcut to read.
7
+ * @returns {string} - The normalized shortcut name.
8
+ */
9
+ return function _readShortcutWithPlugins ( shortcut ) {
10
+ const
11
+ { inAPI } = dependencies
12
+ , pluginName = shortcut.split(':')[0]
13
+ , ix = inAPI._systemAction ( pluginName, 'none' ) // Find a index. Don't call any method.
14
+ ;
15
+ let pausedEvent = shortcut;
16
+ if ( ix !== -1 ) pausedEvent = state.plugins[ix].shortcutName ( shortcut )
17
+ return pausedEvent
18
+ }} // _readShortcutWithPlugins func.
19
+
20
+
21
+
22
+ export default _readShortcutWithPlugins
23
+
24
+
@@ -0,0 +1,25 @@
1
+ 'use strict'
2
+
3
+ function _systemAction ( dependencies, state ) {
4
+ /**
5
+ * @function _systemAction
6
+ * @description Call a specifc plugin method.
7
+ * @param {string} pluginName - The name of the plugin.
8
+ * @param {string} fn - The name of the method to call.
9
+ * @param {any} params - The parameters to pass to the method.
10
+ */
11
+ return function _systemAction ( pluginName, fn, params=null ) { // Specific plugin command: Mute, unmute, pause, resume, destroy
12
+ return state.plugins.findIndex ( plugin => {
13
+ if ( plugin.getPrefix() === pluginName ) {
14
+ if ( plugin[fn] ) plugin[fn]( params )
15
+ return true
16
+ }
17
+ return false
18
+ })
19
+ }} // _systemAction func.
20
+
21
+
22
+
23
+ export default _systemAction
24
+
25
+
@@ -3,13 +3,22 @@
3
3
  function changeContext ( dependencies, state ) {
4
4
  const
5
5
  {
6
- shortcuts
7
- , listenOptions
8
- , currentContext
6
+ shortcuts
7
+ , currentContext
9
8
  } = state
10
9
  , { ev } = dependencies
11
10
  ;
12
11
 
12
+
13
+
14
+ function expose () {
15
+ ev.on ( '*', (...args) => {
16
+ if ( state.exposeShortcut ) state.exposeShortcut ( ...args )
17
+ })
18
+ } // expose func.
19
+
20
+
21
+
13
22
  /**
14
23
  * @function changeContext
15
24
  * @description Change current context with shortcuts belonging to it.
@@ -19,14 +28,6 @@ const
19
28
  return function changeContext ( contextName = false ) {
20
29
  const current = currentContext.name;
21
30
 
22
- listenOptions.maxSequence = 1
23
- listenOptions.maxClicks = 1
24
-
25
- if ( listenOptions.keyIgnore >= 0 ) {
26
- clearTimeout ( listenOptions.keyIgnore )
27
- listenOptions.keyIgnore = null
28
- }
29
-
30
31
  if ( !contextName ) { // Switch off all shortcuts if contextName is not defined
31
32
  ev.reset ()
32
33
  currentContext.name = null
@@ -34,26 +35,19 @@ return function changeContext ( contextName = false ) {
34
35
  }
35
36
  if ( current === contextName ) return // Do nothing if contextName is the same as current
36
37
  if ( !shortcuts [ contextName ] ) { // If contextName is not defined
37
- ev.emit ( 'shortcuts-error', `Context '${ contextName }' does not exist` )
38
+ ev.emit ( '@shortcuts-error', `Context '${ contextName }' does not exist` )
38
39
  return
39
40
  }
40
41
  if ( shortcuts[current] ) {
41
42
  ev.reset () // Disable all shortcuts from current context
42
43
  }
43
- Object.entries ( shortcuts [ contextName ]).forEach ( ([shortcutName, list ]) => { // Enable new context shortcuts and set a listenOptions 'maxSequence' and 'maxClicks'
44
- let isMouseEv = shortcutName.includes ( 'MOUSE-CLICK-' );
45
- if ( isMouseEv ) { // Set mouse max clicks
46
- let [ , , , count ] = shortcutName.split('-')
47
- let c = parseInt ( count ); // Number of clicks
48
- if ( listenOptions.maxClicks < c ) listenOptions.maxClicks = c
49
- }
50
- else { // Set key max sequence
51
- let sequenceArraySize = shortcutName.split(',').length;
52
- if ( listenOptions.maxSequence < sequenceArraySize ) listenOptions.maxSequence = sequenceArraySize
53
- }
54
- list.forEach ( fn => ev.on ( shortcutName, fn ) ) // Enable new context shortcuts
55
- })
56
- currentContext.name = contextName
44
+
45
+ currentContext.name = contextName
46
+ state.plugins.forEach ( plugin => plugin.contextChange ( contextName ) ) // Inform plugins for context change
47
+ Object.entries ( shortcuts[contextName] ).forEach ( ([shortcutName, list ]) => { // Enable new context shortcuts
48
+ list.forEach ( fn => ev.on ( shortcutName, fn ) )
49
+ })
50
+ expose ()
57
51
  }} // changeContext func.
58
52
 
59
53
 
@@ -1,9 +1,6 @@
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'
1
+ import _normalizeWithPlugins from './_normalizeWithPlugins.js'
2
+ import _readShortcutWithPlugins from './_readShortcutWithPlugins.js'
3
+ import _systemAction from './_systemAction.js'
7
4
 
8
5
  import load from './load.js'
9
6
  import unload from './unload.js'
@@ -14,13 +11,10 @@ import listShortcuts from './listShortcuts.js'
14
11
 
15
12
  export default {
16
13
  // Internal methods
17
- _findTarget
18
- , _listen
19
- , _readKeyEvent
20
- , _readMouseEvent
21
- , _readShortcut
22
- , _specialChars
23
-
14
+ _normalizeWithPlugins
15
+ , _readShortcutWithPlugins
16
+ , _systemAction
17
+
24
18
  // Public methods
25
19
  , changeContext
26
20
  , listShortcuts
@@ -2,32 +2,39 @@
2
2
 
3
3
  function load ( dependencies, state ) {
4
4
  const
5
- { shortcuts } = state
5
+ { shortcuts, plugins } = state
6
6
  , {
7
- inAPI : { _readShortcut }
8
- , API : { changeContext, getContext }
9
- } = dependencies;
7
+ API : { changeContext, getContext }
8
+ } = dependencies;
10
9
  /**
11
10
  * Load a context with shortcuts object
12
- * @param {Object} obj - Context description object: { contextName : { shortcut : callback[] }
11
+ * @param {Object} shortcutsUpdate - Context description object: { contextName : { shortcut : callback[] }
13
12
  * @returns {void}
14
13
  */
15
- return function load ( obj ) {
14
+ return function load ( shortcutsUpdate ) {
16
15
  const
17
16
  currentContextName = getContext ()
18
- , contextList = Object.keys ( obj )
17
+ , pluginPrefixList = plugins.map ( plugin => plugin.getPrefix().toUpperCase() )
19
18
  ;
20
19
  let hasChanges = false;
21
- contextList.forEach ( contextName => {
22
- const description = Object.entries ( obj [ contextName ] );
23
- if ( contextName === currentContextName ) hasChanges = true;
20
+
21
+ Object.entries ( shortcutsUpdate ).forEach ( ([contextName, contextShortcuts]) => {
22
+ if ( contextName === currentContextName ) hasChanges = true; // If changes in current context will need to reload it
24
23
  shortcuts [ contextName ] = {}
25
- description.forEach ( ([ title, callbackList ]) => {
26
- const name = _readShortcut ( title );
24
+ Object.entries ( contextShortcuts ).forEach ( ([ title, callbackList ]) => {
25
+ let
26
+ name = title
27
+ , test = title.toUpperCase().trim()
28
+ ;
29
+ let pluginIndexList = pluginPrefixList.map ( (prefix,i) => test.startsWith ( prefix ) ? i : null ).filter ( i => i !== null );
30
+ if ( pluginIndexList.length ) {
31
+ let id = pluginIndexList[0];
32
+ name = plugins[id].shortcutName ( title )
33
+ }
27
34
  if ( callbackList instanceof Function ) callbackList = [ callbackList ]
28
35
  shortcuts [contextName][ name ] = callbackList
29
- }) // shortcuts.forEach
30
- }) // contextList.forEach
36
+ }) // contextShortcuts.forEach
37
+ }) // shortcutsUpdate.forEach
31
38
  if ( hasChanges ) { // Reload context shortcuts after loading process if context was active
32
39
  changeContext ()
33
40
  changeContext ( currentContextName )
@@ -0,0 +1,20 @@
1
+ 'use strict'
2
+
3
+ function _findTarget ( dependencies, state, target ) {
4
+
5
+ const { listenOptions : {clickTarget}} = state;
6
+
7
+ let t = target;
8
+ if ( t === document ) return null
9
+ if ( t === document.body ) return null
10
+
11
+ if ( t.dataset[clickTarget] ) return t
12
+ if ( t.nodeName === 'A' ) return t
13
+ return _findTarget ( dependencies, state, t.parentNode )
14
+ } // _findTarget func.
15
+
16
+
17
+
18
+ export default _findTarget
19
+
20
+
@@ -0,0 +1,117 @@
1
+ 'use strict'
2
+
3
+
4
+ function _listenDOM ( dependencies, state ) {
5
+ const {
6
+ ev
7
+ , _findTarget
8
+ , _readClickEvent
9
+ , mainDependencies
10
+ } = dependencies
11
+ const { listenOptions, currentContext } = state
12
+ const { mouseWait } = listenOptions
13
+
14
+ let
15
+ mouseTarget = null // Dom element or null
16
+ , mouseDomEvent = null
17
+ , mouseTimer = null // Timer for mouse sequence or null
18
+ , mouseIgnore = null // Timer for ignoring mouse clicks or null
19
+ , count = 0
20
+ ;
21
+
22
+ function mouseSequenceEnd () { // Execute when mouse sequence ends
23
+ const
24
+ mouseEvent = _readClickEvent ( mouseDomEvent, count )
25
+ , data = {
26
+ target : mouseTarget
27
+ , targetProps : mouseTarget ? mouseTarget.getBoundingClientRect() : null
28
+ , x : mouseDomEvent.clientX
29
+ , y : mouseDomEvent.clientY
30
+ , context : currentContext.name
31
+ , note : currentContext.note
32
+ , event : mouseDomEvent
33
+ , dependencies : mainDependencies.extra
34
+ , type : 'click'
35
+ }
36
+ ;
37
+
38
+ ev.emit ( mouseEvent, data )
39
+ // Reset:
40
+ mouseTimer = null
41
+ mouseIgnore = null
42
+ mouseTarget = null
43
+ mouseDomEvent = null
44
+ count = 0
45
+ } // mouseSequenceEnd func.
46
+
47
+
48
+
49
+ function listenLeftClick ( event ) {
50
+ let targetMax = listenOptions.maxClicks; // Maximum number of clicks per target
51
+ clearTimeout ( mouseTimer )
52
+ if ( mouseIgnore ) {
53
+ clearTimeout ( mouseIgnore )
54
+ mouseIgnore = setTimeout ( () => mouseIgnore=null, mouseWait )
55
+ return
56
+ }
57
+ mouseTarget = _findTarget ( dependencies, state, event.target )
58
+ if ( mouseTarget && mouseTarget.dataset.hasOwnProperty('quickClick')) targetMax = 1
59
+ if ( mouseTarget && mouseTarget.tagName === 'A' ) targetMax = 1
60
+ mouseDomEvent = event
61
+ count++
62
+ if ( count >= targetMax ) {
63
+ mouseSequenceEnd ()
64
+ if ( targetMax > 1 ) mouseIgnore = setTimeout ( () => mouseIgnore=null, mouseWait )
65
+ return
66
+ }
67
+ mouseTimer = setTimeout ( mouseSequenceEnd, mouseWait )
68
+ } // listenLeftClick func.
69
+
70
+
71
+
72
+ function listenRightClick ( event ) {
73
+ let targetMax = listenOptions.maxClicks; // Maximum number of clicks per target
74
+ clearTimeout ( mouseTimer )
75
+ if ( mouseIgnore ) {
76
+ clearTimeout ( mouseIgnore )
77
+ mouseIgnore = setTimeout ( () => mouseIgnore=null, mouseWait )
78
+ return
79
+ }
80
+ mouseTarget = _findTarget ( dependencies, state, event.target )
81
+ if ( mouseTarget && mouseTarget.dataset.hasOwnProperty('quickClick')) targetMax = 1
82
+ if ( mouseTarget && mouseTarget.tagName === 'A' ) targetMax = 1
83
+ mouseDomEvent = event
84
+ count++
85
+ if ( count >= targetMax ) {
86
+ mouseSequenceEnd ()
87
+ if ( targetMax > 1 ) mouseIgnore = setTimeout ( () => mouseIgnore=null, mouseWait )
88
+ return
89
+ }
90
+ mouseTimer = setTimeout ( mouseSequenceEnd, mouseWait )
91
+ } // listenRightClick func.
92
+
93
+
94
+
95
+
96
+ function start () {
97
+ if ( state.active ) return
98
+ window.addEventListener ( 'contextmenu', listenRightClick )
99
+ document.addEventListener ( 'click' , listenLeftClick )
100
+ state.active = true
101
+ } // start func.
102
+
103
+ function stop () {
104
+ if ( !state.active ) return
105
+ window.removeEventListener ( 'contextmenu', listenRightClick )
106
+ document.removeEventListener ( 'click' , listenLeftClick )
107
+ state.active = false
108
+ } // stop func.
109
+
110
+ return { start, stop }
111
+ } // _listenDOM func.
112
+
113
+
114
+
115
+ export default _listenDOM
116
+
117
+
@@ -0,0 +1,44 @@
1
+ 'use strict'
2
+
3
+ function _normalizeShortcutName ( name ) {
4
+ const
5
+ upperCase = name.toUpperCase ()
6
+ , regex = /CLICK\s*\:/i
7
+ , isClickShortcut = regex.test(upperCase)
8
+ , mouseNames = [ 'LEFT', 'MIDDLE', 'RIGHT' ]
9
+ , modifiers = [ 'ALT', 'SHIFT', 'CTRL' ]
10
+ ;
11
+ let
12
+ btn = null
13
+ , usedModifiers = []
14
+ , counter = 0
15
+ , sliceIndex = upperCase.indexOf ( ':' )
16
+ ;
17
+
18
+ // Click event format: CLICK:LEFT-2-ALT-SHIFT-CTRL
19
+
20
+ if ( !isClickShortcut ) return name
21
+ let shortcutArray = upperCase.slice(sliceIndex+1).trim().split('-').map ( x => x.trim() );
22
+ shortcutArray.forEach ( item => {
23
+ if ( mouseNames.includes ( item )) {
24
+ btn = item
25
+ return
26
+ }
27
+ if ( modifiers.includes ( item )) {
28
+ usedModifiers.push ( item )
29
+ return
30
+ }
31
+ if ( !isNaN ( item )) {
32
+ counter = item
33
+ return
34
+ }
35
+ }) // forEach
36
+
37
+ return `CLICK:${btn}-${counter}${usedModifiers.length>0?'-':''}${usedModifiers.sort().join('-')}`
38
+ } // _normalizeShortcutName func.
39
+
40
+
41
+
42
+ export default _normalizeShortcutName
43
+
44
+
@@ -0,0 +1,24 @@
1
+ 'use strict'
2
+
3
+ function _readClickEvent ( event, count ) {
4
+ let
5
+ { shiftKey, altKey, ctrlKey, key, button } = event
6
+ , mouseNames = [ 'LEFT', 'MIDDLE', 'RIGHT' ]
7
+ , mouseEvent = `CLICK:${mouseNames[button]}-${count}`
8
+ , mods = []
9
+ ;
10
+
11
+ // res.push ( mouseEvent )
12
+ if ( ctrlKey ) mods.push ( 'CTRL' )
13
+ if ( shiftKey ) mods.push ( 'SHIFT' )
14
+ if ( altKey ) mods.push ( 'ALT' )
15
+
16
+ if ( mods.length > 0 ) return `${mouseEvent}${mods.length>0?'-':''}${mods.sort().join('-')}`
17
+ else return `${mouseEvent}`
18
+ } // _readClickEvent func.
19
+
20
+
21
+
22
+ export default _readClickEvent
23
+
24
+
@@ -0,0 +1,30 @@
1
+ 'use strict'
2
+
3
+ function _registerShortcutEvents ( dependencies, pluginState ) {
4
+ let count = 0;
5
+ const
6
+ { regex } = dependencies
7
+ , {
8
+ listenOptions
9
+ , currentContext : { name:contextName }
10
+ , shortcuts
11
+ } = pluginState
12
+ ;
13
+
14
+ if ( contextName == null ) return 0
15
+ Object.entries ( shortcuts[contextName] ).forEach ( ([shortcutName, list ]) => { // Enable new context shortcuts and set a listenOptions 'maxSequence'
16
+ let isClickEv = regex.test ( shortcutName );
17
+ if ( !isClickEv ) return
18
+ count++
19
+
20
+ let [ ,numberClicks ] = shortcutName.slice(6).split('-');
21
+ if ( listenOptions.maxClicks < numberClicks ) listenOptions.maxClicks = numberClicks
22
+ })
23
+ return count
24
+ } // _registerShortcutEvents func.
25
+
26
+
27
+
28
+ export default _registerShortcutEvents
29
+
30
+