-
-
Notifications
You must be signed in to change notification settings - Fork 131
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Hotkeys for most tabs and resource creations
Closes #91 as well (by the Alt+F5) hotkey
- Loading branch information
1 parent
4c0c97c
commit 4d0554b
Showing
15 changed files
with
240 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/* From @github/hotkey | ||
see https://github.com/github/hotkey/ */ | ||
const isFormField = function(element) { | ||
if (!(element instanceof HTMLElement)) { | ||
return false; | ||
} | ||
var name = element.nodeName.toLowerCase(); | ||
var type = (element.getAttribute('type') || '').toLowerCase(); | ||
/* eslint no-mixed-operators: off*/ | ||
return name === 'select' || | ||
name === 'textarea' || | ||
name === 'input' && | ||
type !== 'submit' && | ||
type !== 'reset' && | ||
type !== 'checkbox' && | ||
type !== 'radio' || | ||
element.isContentEditable; | ||
}; | ||
|
||
const getCode = e => '' | ||
.concat(e.ctrlKey? 'Control+' : '') | ||
.concat(e.altKey? 'Alt+' : '') | ||
.concat(e.metaKey ? 'Meta+' : '') | ||
.concat(e.key); | ||
|
||
const listenerRef = Symbol('keydownListener'); | ||
const offDomEventsRef = Symbol('offDomEventsRef'); | ||
const hotkeyRef = Symbol('hotkey'); | ||
|
||
class Hotkeys { | ||
constructor(doc) { | ||
this.document = doc; | ||
this.document[hotkeyRef] = this; | ||
this.scopeStack = []; | ||
|
||
this[offDomEventsRef] = new Map(); | ||
|
||
this[listenerRef] = e => { | ||
const code = getCode(e); | ||
this.trigger(code); | ||
}; | ||
this.document.body.addEventListener('keydown', this[listenerRef]); | ||
} | ||
|
||
on(code, event) { | ||
if (!this[offDomEventsRef].has(code)) { | ||
this[offDomEventsRef].set(code, []); | ||
} | ||
if (this[offDomEventsRef].get(code).indexOf(event) === -1) { | ||
this[offDomEventsRef].get(code).push(event); | ||
} | ||
} | ||
off(code, event) { | ||
if (event) { | ||
const ind = this[offDomEventsRef].get(code).indexOf(event); | ||
if (ind !== -1) { | ||
this[offDomEventsRef].get(code).splice(ind, 1); | ||
} | ||
} else { | ||
this[offDomEventsRef].set(code, []); | ||
} | ||
} | ||
trigger(code) { | ||
const offDom = this[offDomEventsRef].get(code); | ||
if (offDom) { | ||
for (const event of offDom) { | ||
event(); | ||
} | ||
} | ||
const elts = this.document.querySelectorAll(`[data-hotkey="${code}"]`); | ||
if (this.scopeStack.length) { | ||
// walk from the most recent scope to the last one | ||
for (let i = this.scopeStack.length - 1; i >= 0; i--) { | ||
const scope = this.scopeStack[i]; | ||
for (const elt of elts) { | ||
if (!elt.closest(`[data-hotkey-scope="${scope}"]`)) { | ||
continue; | ||
} | ||
if (isFormField(elt)) { | ||
elt.focus(); | ||
} else { | ||
elt.click(); | ||
} | ||
return; | ||
} | ||
} | ||
} | ||
// Look for all the elements if no scope | ||
// is specified or no scoped elements were found | ||
for (const elt of elts) { | ||
if (isFormField(elt)) { | ||
elt.focus(); | ||
} else { | ||
elt.click(); | ||
} | ||
return; | ||
} | ||
} | ||
|
||
get scope() { | ||
return this.scopeStack[this.scopeStack.length - 1]; | ||
} | ||
set scope(val) { | ||
if (Array.isArray(val)) { | ||
this.scopeStack = val; | ||
} else { | ||
this.scopeStack = val.split(' '); | ||
} | ||
} | ||
push(val) { | ||
this.scopeStack.push(val); | ||
} | ||
pop() { | ||
return this.scopeStack.pop(); | ||
} | ||
remove(val) { | ||
const ind = this.scopeStack.indexOf(val); | ||
if (val !== -1) { | ||
this.scopeStack.splice(ind, 1); | ||
} | ||
return ind !== -1; | ||
} | ||
exit(val) { | ||
const ind = this.scopeStack.indexOf(val); | ||
if (val !== -1) { | ||
this.scopeStack.splice(ind); | ||
} | ||
return ind !== -1; | ||
} | ||
cleanScope() { | ||
this.scopeStack.length = 0; | ||
} | ||
inScope(val) { | ||
return this.scopeStack.indexOf(val) !== -1; | ||
} | ||
|
||
unmount() { | ||
this.document.body.removeEventListener('keydown', this[listenerRef]); | ||
} | ||
} | ||
|
||
module.exports = function (doc) { | ||
doc = doc || document; | ||
if (!doc) { | ||
throw new Error('Can\'t find the document object! Am I in a bare node.js context?!'); | ||
} | ||
if (hotkeyRef in doc) { | ||
return doc[hotkeyRef]; | ||
} | ||
return new Hotkeys(doc); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.