generated at
Ctrl-:でアイコンを挿入するUserScript
/iconsプロジェクトのアイコンを fetch して、保持する
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 を変換する
script.js
const 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.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.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.js
const 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.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

更新履歴
2019-08-17 公開