Ctrl-:でアイコンを挿入するUserScript
/iconsプロジェクトのアイコンを
fetch
して、保持する
script.jsconst 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
を変換する
script.jsconst toImgSrc = url => {
if (!url.startsWith('https://gyazo.com/')) { return url }
if (url.endsWith('.png') || url.endsWith('.gif') || url.endsWith('.jpg')) { return url }
return url
.replace('https://gyazo.com', 'https://i.gyazo.com')
.replace(/\/raw$/, '')
.replace(/$/, '/raw#.png')
}
/iconsプロジェクトのアイコンを
overlay
パネルに並べる
script.jsconst 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.src = toImgSrc(i[1])
$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>
script.jsconst findCursorPosition = () => {
const cursor = document.querySelector('.cursor')
const line = document.querySelector('.cursor-line')
const chars = line.querySelectorAll('span[class^="c-"]')
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
}
キーバインドを登録する
script.jsdocument.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)
})
}
})
参考
更新履歴
2019-08-17 公開