Ctrl-:でアイコンを挿入するUserScript
/iconsプロジェクトのアイコンをfetchして、保持する code:script.js
const icons = new Map()
fetch('/api/pages/icons?limit=1000').then(res => res.json()).then(prj => {
if (!prj.pages) { return }
for (const p of prj.pages) {
if (!p.image) { continue }
icons.set(p.title, p.image)
}
})
GyazoのURLを変換する
code:script.js
const toImgSrc = url => {
if (url.endsWith('.png') || url.endsWith('.gif') || url.endsWith('.jpg')) { return url }
return url
.replace(/\/raw$/, '')
.replace(/$/, '/raw#.png')
}
/iconsプロジェクトのアイコンをoverlayパネルに並べる code:script.js
const showIconsPanel = onClick => {
const $container = document.createElement('div')
$container.style.position = 'fixed'
$container.style.top = 0
$container.style.left = 0
$container.style.zIndex = 1000
$container.style.width = '100%'
$container.style.height = '100%'
$container.style.background = 'rgba(0, 0, 0, .7)'
$container.style.transition = '.3s linear'
const $panel = document.createElement('div')
$panel.style.position = 'absolute'
$panel.style.top = 0
$panel.style.bottom = 0
$panel.style.left = 0
$panel.style.right = 0
$panel.style.margin = 'auto'
$panel.style.width = '70%'
$panel.style.height = '70%'
$panel.style.background = 'white'
$panel.style.overflow = 'scroll'
for (const i of icons.entries()) {
const $btn = document.createElement('button')
$btn.style.margin = '3px'
const $img = document.createElement('img')
$img.style.height = '20px'
$img.style.objectFit = 'contain'
$btn.appendChild($img)
$panel.appendChild($btn)
$img.addEventListener('click', e => {
document.body.parentElement.style.margin = ''
document.body.parentElement.style.height = ''
document.body.parentElement.style.overflow = ''
document.body.style.margin = ''
document.body.style.height = ''
document.body.style.overflow = ''
document.body.removeChild($container)
onClick([/icons/${i[0]}.icon])
})
}
$container.appendChild($panel)
$container.addEventListener('click', e => {
document.body.parentElement.style.margin = ''
document.body.parentElement.style.height = ''
document.body.parentElement.style.overflow = ''
document.body.style.margin = ''
document.body.style.height = ''
document.body.style.overflow = ''
document.body.removeChild($container)
})
document.body.appendChild($container)
document.body.parentElement.style.margin = '0'
document.body.parentElement.style.height = '100%'
document.body.parentElement.style.overflow = 'hidden'
document.body.style.margin = '0'
document.body.style.height = '100%'
document.body.style.overflow = 'hidden'
}
Ctrl-:が発火したときのカーソル位置にあるDOM要素(.cursor-lineと.c-*)を探す
.cursor-line: 編集している行の<div/>
span[class^="c-"]: 編集している行の各文字の<span/>
.cursor: カーソルの|の<div><svg/></div>
code:script.js
const findCursorPosition = () => {
const cursor = document.querySelector('.cursor')
const line = document.querySelector('.cursor-line')
for (const c of chars) {
if (c.getBoundingClientRect().left <= cursor.getBoundingClientRect().left &&
cursor.getBoundingClientRect().left <= c.getBoundingClientRect().right) {
return { line: line, char: c }
} else if (c.getBoundingClientRect().right < cursor.getBoundingClientRect().left) {
return { line: line, char: c }
}
}
return null
}
キーバインドを登録する
code:script.js
document.addEventListener('keydown', e => {
if (e.key === ':' && e.ctrlKey && !e.shiftKey) {
let pos = findCursorPosition()
if (!pos) { return }
showIconsPanel(icon => {
if (!icon) { return }
const newMouseEvent = name => {
const evt = document.createEvent('MouseEvent')
evt.initMouseEvent(
name, true, true, window, 1, 0, 0,
pos.line.offsetWidth, pos.char.offsetTop,
false, false, false, false, 0, null
)
return pos.char.dispatchEvent(evt)
}
newMouseEvent('mousedown')
newMouseEvent('mouseup')
newMouseEvent('click')
pos = null
document.execCommand('insertText', null, icon)
})
}
})
参考
UserScript.icon
更新履歴
2019-08-17 公開