generated at
jumpy
atomやvscodeなどにあるカーソル移動を簡単にするプラグインjumpy
箇条書きを行ったり来たりできると、もしかしたら便利かも?と思って作ってみた

使い方
ctrl + j と入力すると目標になる文字列がでてくる

表示されているアルファベット2文字~3文字を打ち込むとその場所にカーソルが移動する

移動できる場所
タイトルになっている行の行頭と行末
箇条書きの行頭と行末
、。[]():,.「」 の文字の場所
文章の内容が別れていそうな地点?


余談
現状ページ内すべてに飛べるポイントを毎回作っているので情報量が多いページだと少し重い
プログラムががっつり書いてあるページだとなお重い
TODO: クリックで実装しているので、リンクが貼ってあるところだとクリックして開いてしまう

参考
クリック部分

script.js
let 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 } }