generated at
scrapbox-char-accessor
文字情報を取り出しやすくするScrapbox拡張API

追加したい機能
非空白文字を除いた先頭/末尾判定
(やれたらやる) 文字の種類
リンク
画像
コードブロック
etc.


依存

script.js
import {line as l} from '/api/code/programming-notes/scrapbox-line-accessor/script.js'; const charSelector = 'span[class^="c-"]'; class Char {

行idと文字番号を保持する
行idなら、アウトライン編集で行を入れ替えても追跡できる
script.js
constructor({id, index}) { this._id = id; if (!this.lineDOM) throw Error(`#L${id} is an invalid line id.`); this._index = index; }

提供する機能
文字の列番号
script.js
get index() { return this._index; }
中身の文字
表示上の文字ではなく、テキストとして記録されている方の文字を取得する
script.js
get text() { return scrapbox.Page.lines.find(line => line.id === this._id) ?.text?.[this.index] ?? ''; }
文字がある行
script.js
get line() { return l(this.lineDOM); }
行の先頭の文字か
script.js
get isHead() { return this.index === 0; }
行の末尾の文字か
script.js
get isEnd() { return this.text === '' || this.index === this.text.length - 1; }
前の文字
script.js
get next() { if (this.isHead) return undefined; return new Char({id: this._id, index: this.index - 1}); }
後ろの文字
script.js
get prev() { if (this.isEnd) return undefined; return new Char({id: this._id, index: this.index + 1}); }

(WIP)文字を囲むリンクを取得する
内部リンクと外部リンクのどちらかを取得する
2021-01-15 14:12:18 一応できたけど、設計が微妙だなtakker
script.js
get link() { const livingLink = this.DOM.closest('a'); if (livingLink) { const index = parseInt(livingLink .querySelector(charSelector).classList[0].slice(2)); return { type: livingLink.type, href: livingLink.href, text: livingLink.type === 'link' ? livingLink.textContent.slice(1, -1) : livingLink.textContent.slice(1), index, DOM: livingLink, } } // 記法がむき出しになり、リンクとしての機能を果たしていない外部リンク // URLしかないリンクだとバグる const deadLink = this.DOM.closest('span.link'); if (deadLink) { const [text, href] = deadLink.textContent.replace(/\[(.+?)\]/,'$1').split(/\s/); return { type: 'link', href, text, } } return undefined; }

DOMへのアクセス
基本は内部関数用
外部からはどうしても必要なときだけ使う
scrapboxのeditor構造に破壊的な変更が加わると使えなくなる恐れがある
文字のいる行のDOM
script.js
get lineDOM() { return document.getElementById(`L${this._id}`); }
文字のDOM
script.js
get DOM() { return this.lineDOM?.getElementsByClassName(`c-${this._index}`)?.[0]; }

外部公開用
文字のDOM, 行番号&文字番号, 行id&文字番号のいずれかで作成する
script.js
const linesDOM = document.getElementsByClassName('lines')?.[0]; export const char = (value1, value2) => { // 文字のDOMのとき if (value1?.matches?.('span[class^="c-"]')) { return new Char({ id: value1.closest('div.line').id.slice(1), index: parseInt(value1.classList[0].replace(/c-(\d+)/,'$1')), }); } // 行id&文字番号のとき if ((typeof value1) === 'string') { if ((typeof value2) !== 'number') return undefined; const id = /^L[abcdef\d]+$/.test(value1) ? value1.slice(1) : value1; return new Char({id, index: value2}); } // 行番号&文字番号のとき if ((typeof value1) === 'number') { const id = scrapbox.Page.lines[value1].id; if (!id || (typeof value2) !== 'number') return undefined; return new Char({id, index: value2}); } return undefined; }

#2021-01-15 17:57:15