script.jslet isShow = false,
stack = "",
anc = {},
digits = 0;
const click = (el, left, top) => {
const genEvent = type => {
const event = document.createEvent("MouseEvents")
event.initMouseEvent(type, true, true, window, 1, 0, 0,
left, top, false, false, false, false, 0, null)
return event
}
el.dispatchEvent(genEvent("mousedown"))
el.dispatchEvent(genEvent("mouseup"))
el.dispatchEvent(genEvent("click"))
}
$('body').keydown( ev => {
const key = ev.key;
if( ev.ctrlKey && key === "j" ){
({anc, digits} = showAnchors())
isShow = true
return
}
if(!isShow) return
ev.stopPropagation()
ev.preventDefault()
if(!key.match(/^[a-z]$/)){
isShow = false
stack = ""
closeAnchors(anc)
return
}
stack += key
if( stack.length == digits ) {
isShow = false
if( !!anc[stack] ){
const target = anc[stack].el
const pad = (anc[stack].isHead)? 0 : 10
click(target[0], target.offset().left + pad, target.offset().top - $(document).scrollTop())
const cursor = $('#text-input')
cursor.blur()
cursor.focus()
}
closeAnchors(anc)
stack = ""
return
}
})
function closeAnchors(anc){
for(let tag in anc){
anc[tag].box.remove()
}
}
function showAnchors(){
const sepChars = '、。[]():,.「」'
let anchors = []
const lines = $('.line')
lines.map( (i, line) => {
const l = $(line),
isTitleLine = l.hasClass('section-title'),
isIndentLine = l.find('.text .indent').length === 1,
isIndexLine = isTitleLine || isIndentLine;
const chars = l.find('.text [class^=c-]')
if(!isIndexLine){
chars.filter((i, el) => sepChars.includes(el.innerText))
.map((i, el) => anchors.push({ el: $(el), isHead: false }))
return
}
const nest = l.find('span .pad').length,
headEl = l.find('.c-' + nest);
if( headEl.length >= 1)
anchors.push({ el: headEl, isHead: true })
chars.filter((i, el) => sepChars.includes(el.innerText) && i > nest && i < chars.length - 2)
.map((i, el) => anchors.push({ el: $(el), isHead: false } ))
const tailEl = l.find('.c-'+ (chars.length - 1))
if( tailEl.length >= 1 )
anchors.push({ el: tailEl, isHead: false })
})
const digits = Math.log(anchors.length) / Math.log(26) + 1 | 0
const editor = $("#editor"),
eTop = editor.offset().top,
eLeft = editor.offset().left;
let anc = {}
anchors.forEach( (anchor, index) => {
let tag = ""
let num = index;
for( let i = 0; i < digits; i++){
const n = num % 26
tag = String.fromCharCode(97 + n) + tag
num = Math.floor( num / 26 )
}
const boxcss = {
position: "absolute",
"background-color": "rgba(255,255,255,1)",
"border-radius": "0.5em",
border: "solid 0.5px #eee",
color : "#777",
width: "2em",
height: "1.5em",
top: anchor.el.offset().top - eTop - 15,
left: anchor.el.offset().left - eLeft,
"text-align": "center",
margin: "1px 1px",
"box-shadow": "3px 3px 3px rgba(0,0,0,0.1)",
"font-size" : "1em",
"z-index": "5",
}
const box = $('<div>').text(tag).css(boxcss)
editor.append(box)
anc[tag] = {
el: anchor.el,
box: box,
isHead: anchor.isHead,
}
})
return {
digits,
anc
}
}