generated at
scrapbox-selection
scriptからScrapboxの選択範囲を取得・操作するAPI

実装
機能一覧
現在表示されている選択範囲の情報を取得する
ts
type Return = { start: { line: HTMLDivElement; char?: HTMLSpanElement; }, end: { line: HTMLDivElement; char?: HTMLSpanElement; }, };
選択範囲の左端が末尾の場合は、 start.char === undefined になる
選択範囲の右端が先頭の場合は、 end.char === undefined になる
現在表示されている選択範囲の文字列を取得する
情報表示だけに絞るか?
その他の機能は別のclassやfunctionに任せるとか
選択範囲の追加
選択範囲の変更
選択範囲中のcursorの位置を変更する
表示されている選択範囲だけでなく、ある一定区間の文字の間を自由に取得したいな
{start: HTMLDivElement, end: HTMLDivElement} みたいな感じで
いや文字番号の方が良いか
DOMだと変更される可能性がある?
そうでもないか
その場の使い捨てとして扱えば問題ない
保持しなければいい
entityとして扱う
この間にある文字列を取得したり、実際の選択範囲をここに合わせたりする
任意の位置にcursorを移動する関数がほしいな

2020-12-26
07:15:55 正確に選択範囲を取得できるようにした
02:48:15 選択範囲が一行に収まるときの文字列取得に失敗していたのを直した

既知の問題
] など、cursorがあたっていないと見えない文字が選択範囲の端にある場合、 ] を選択していないつもりでも ] が含まれてしまう
こればっかりは対処できない

script.js
import {scrapboxDOM} from '/api/code/takker/scrapbox-dom-accessor/script.js'; import {getCharBorder} from '/api/code/takker/scrapbox-position/script.js'; import {char as c} from '/api/code/takker/scrapbox-char-info/script.js'; import {line as l} from '/api/code/takker/scrapbox-line-info-2/script.js'; class Selection { constructor() {} get exist() { return !!scrapboxDOM.selections?.getElementsByClassName('selection'); } get selection() { const selections = scrapboxDOM.selections?.getElementsByClassName('selection'); if (selections?.length === 0) return undefined; const startRect = selections[0].getBoundingClientRect(); const endRect = (selections[2] ?? selections[0]).getBoundingClientRect(); // 選択範囲の端の文字を取得する const start = getCharBorder({x: startRect.left, y: startRect.top}); const end = getCharBorder({x: endRect.right, y: endRect.bottom}); //console.log({start,end}); return { start: { line: start.line, char: start.right, }, end: { line: end.line, char: end.left, }, }; } get text() { const selection = this.selection; if (!selection) return []; const texts = scrapbox.Page.lines.map(line => line.text); const start = selection.start.char ? { index: c(selection.start.char).index, no: l(selection.start.line).index, } : { // 行末に選択範囲の左端があったときは、次行の最初の文字を選択範囲の開始位置とする index: 0, no: l(selection.start.line.nextElementSibling).index, type: 'LF', } const end = selection.end.char ? { index: c(selection.end.char).index, no: l(selection.end.line).index, } : { // 行頭に選択範囲の右端があったときは、前の行の最後の文字を選択範囲の終了位置とする index: l(selection.end.line.previousElementSibling).text.length - 1, no: l(selection.end.line.previousElementSibling).index, type: 'HEAD', } //console.log({start, end}); const middles = start.no === end.no ? // 選択範囲が一行に収まっているとき [texts[start.no].substring(start.index, 1 + end.index)] // 選択範囲が複数行にまたがるとき : [ texts[start.no].substring(start.index), ...texts.slice(start.no + 1, 1 + end.no - 1), texts[end.no].substring(0,1 + end.index), ]; return [ ...(start.type ? [''] : []), ...middles, ...(end.type ? [''] : []), ]; } moveBegin() {} moveEnd() {} } export const selection = new Selection();


テストコード
test.js
import {selection} from '/api/code/takker/scrapbox-selection/script.js'; document.addEventListener('keydown', () => { if (!selection.exist) return; console.log('[test:scrapbox-selection] %o', selection.selection); console.log('[test:scrapbox-selection] %o', '\n' + selection.text.join('\n')); });

#2020-12-28 09:47:24
#2020-12-26 02:48:07
#2020-12-25 11:06:52