Create single-key shortcuts for any page. Press ctrl+alt+s to open manager.
// ==UserScript==
// @name SimpleShortcuts
// @namespace com.gmail.fujifruity.greasemonkey
// @version 2.4
// @description Create single-key shortcuts for any page. Press ctrl+alt+s to open manager.
// @author fujifruity
// @match *://*/*
// @grant GM.getValue
// @grant GM.setValue
// @grant GM.listValues
// @license MIT
// ==/UserScript==
(async () => {
'use strict';
// With Tampermonkey, you can directly modify shortcuts from Storage tab (Advance mode only) in the editor.
// Find the longest matching url from GM cache
let targetUrl; {
const urls = await GM.listValues()
console.log('urls', urls)
const foundUrl = urls.sort((a, b) => b.length - a.length).find(url => location.href.startsWith(url))
targetUrl = foundUrl ?? location.protocol + '//' + location.host + location.pathname
}
const getShortcuts = async () => {
const shortcuts = await GM.getValue(targetUrl) ?? '{}'
return JSON.parse(shortcuts)
}
const elem = selector => document.querySelector(selector)
const setShortcuts = async () => {
const shortcuts = await getShortcuts()
Object.keys(shortcuts).forEach(k => {
window.addEventListener('keydown', event => {
if (["INPUT", "TEXTAREA"].includes(event.target.tagName) ||
event.ctrlKey || event.altKey || event.metaKey || event.key != k) return
const button = elem(shortcuts[k])
button.focus()
button.click()
console.log('clicking', button);
})
})
}
// Set shortcuts if exist
setShortcuts()
const modalId = 'fujifruity-simpleshortcuts'
const modal = `
<style>
#${modalId} * { margin:4px; }
#${modalId} #modalTitle { font-weight:bold; }
#${modalId} {
z-index:99999; width:auto; max-height:90%; position:fixed;
margin:16px; padding:16px; border-radius:8px; overflow-y:auto;
box-shadow:rgba(0, 0, 0, 0.35) 0px 5px 15px; background-color:white
}
</style>
<div id=${modalId} >
<div id=modalTitle>SimpleShortcuts for</div>
<div id=targetUrl></div>
<hr class="solid">
<input id=keyInput size=3 placeholder=key maxlength=20>
<input id=valueInput size=16 placeholder="CSS selector">
<button id=saveButton>Save</button>
<div id=shortcutList></div>
</div> `
const createModal = async () => {
document.body.innerHTML = modal + document.body.innerHTML
// Init url input
elem('#targetUrl').textContent = targetUrl
// Init key input
const keyInput = elem('#keyInput')
keyInput.addEventListener('keyup', event => {
keyInput.value = event.key
keyInput.size = event.key.length
})
// Init shortcut list
const updateShortcutList = async () => {
const shortcuts = await getShortcuts()
const lines = Object.keys(shortcuts).map(k => `<div>${k ? k : '" "'} ➔ ${shortcuts[k]}</div>`).join('')
elem('#shortcutList').innerHTML = lines
}
updateShortcutList()
// Init save button
elem('#saveButton').onclick = async () => {
const key = elem('#keyInput').value
const value = elem('#valueInput').value
const shortcuts = await getShortcuts()
if (!key) return
if (value) {
shortcuts[key] = value
} else {
delete shortcuts[key]
}
await GM.setValue(targetUrl, JSON.stringify(shortcuts))
updateShortcutList()
setShortcuts()
}
return elem('#' + modalId)
}
window.addEventListener('keydown', async event => {
if (!event.altKey && !event.metaKey || !event.ctrlKey || event.key != 's') return
// Show modal
const modal = elem('#' + modalId) ?? await createModal()
modal.style.display = 'block'
modal.focus()
// Set event listeners to close modal
const closeModal = modal => { modal.style.display = 'none' }
const onKeydown = event => {
if (["INPUT", "TEXTAREA"].includes(event.target.tagName) || event.key != 'Escape') return
closeModal(modal)
window.removeEventListener('keydown', onKeydown)
}
const onClick = event => {
if (modal.contains(event.target)) return
closeModal(modal)
window.removeEventListener('click', onClick)
}
window.addEventListener('keydown', onKeydown)
window.addEventListener('click', onClick)
});
})()