scrapboxのcursorの位置を計算する
タイトル通り
用途
先頭から何文字目なのかとか
あとはどの文字が何番目にあるのかも取得したい
実装するmethodは他の機能を実装しながら考える
必要になったものを順次実装する
参考にするcode
今まで作ってきたやつ
一旦文字列に変換してから比較しているが、それを変更して、直接DOMの座標を比較するようにした
文字列→DOM→文字列の二度手間を避ける
Referene
実装
classではなく関数で実装する
classにする意義を感じられなかった
cursorには.cursorの縦棒を送る
#text-inputだと選択範囲があるときにうまく認識できない
完成したので別なページに載せる
code:getCursorInfo.js
export function getCursorInfo({lines, cursor}) {
// cursorのいる行を取得する
const cursorLine = lines.getElementsByClassName('cursor-line')?.0; if (!cursorLine) return {error: 'The cursor doesn\'t has a focus.'};
// 行内の文字を<span>のまま取得する
const chars = [...cursorLine.querySelectorAll('spanclass^="c-"')]; developper toolで確認したところ、leftの値が同一だった
等号比較で行けるか?
findで簡単に検索したい
code:js
const targetChar = chars.find(char =>
cursor.getBoundingClientRect().left === char.getBoundingClientRect().left);
21:13:31 同一でない文字もあるみたい。
全部確認して、一番近いcharを取得するしかなさそう
21:20:20 cursor.getBoundingClientRect().leftがchar.getBoundingClientRect()のleftとrightの中に収まっているものを探すのならどうだ?
/icons/done.icon21:24:27 やった!
21:30:31 行先頭の文字番号がおかしい?
0, 0, 1, ...になる
調べる
どうやらcursor.getBoundingClientRect().leftよりも該当文字のgetBoundingClientRect().leftが左にずれている場合があるみたい
どれも小数点以下でずれている
整数値に丸めたらどうなんだろう?
21:46:52 うまくいった
判定は半開区間にした
[..., ...[
閉区間にすると、後ろの<span>とかぶってしまう
21:58:59 これでもだめなやつがあった
おそらく発生条件
indentあり
先頭が全角文字
半開区間に直すのを忘れてただけだった
22:06:57 最後にcursorが来たら、\nにcursorがあると解釈しよう
最後の.c-{number}に1足したものを返す
code:getCursorInfo.js
// cursorのいる<span>を検索する
const cursorLeft = Math.round(cursor.getBoundingClientRect().left);
const targetChar = chars.find(char => {
const {left, right} = char.getBoundingClientRect();
return Math.round(left) <= cursorLeft && cursorLeft < Math.round(right);});
return {
id: cursorLine.id,
column: targetChar?
parseInt(targetChar.className.replace(/c-(\d+)/,'$1')) :
chars.length, // 改行文字として、最後の文字より一つ後ろの番号を返す
};
}
テストコード
code:js
function getCursorInfo({lines, cursor}) {
// cursorのいる行を取得する
const cursorLine = lines.getElementsByClassName('cursor-line')?.0; if (!cursorLine) return {error: 'The cursor doesn\'t has a focus.'};
// 行内の文字を<span>のまま取得する
const chars = [...cursorLine.querySelectorAll('spanclass^="c-"')]; // cursorのいる<span>を検索する
console.log('char pos.: %o', chars
.map(char => char.getBoundingClientRect())
.map(rect => {return {left: Math.round(rect.left), right: Math.round(rect.right)}}));
const cursorLeft = Math.round(cursor.getBoundingClientRect().left);
console.log('cursor left: %o', cursorLeft);
const targetChar = chars.find(char => {
const {left, right} = char.getBoundingClientRect();
return Math.round(left) <= cursorLeft && cursorLeft < Math.round(right);});
return {
id: cursorLine.id,
column: targetChar?
parseInt(targetChar.className.replace(/c-(\d+)/,'$1')) :
chars.length, // 改行文字として、最後の文字より一つ後ろの番号を返す
};
}
addEventListener('keydown',e=>{
console.log(char info: %o,getCursorInfo({lines:document.getElementsByClassName('lines')0,cursor:document.getElementsByClassName('cursor')0})) })
/icons/hr.icon
classの名前でいい感じのが見つかったら、別のページに移す
code:computeCursor.js_disabled
export class cursorLocator {
constructor() {
this._editor = document.getElementById('editor');
this._lines = this._editor.getElementsByClassName('lines')0?.children; }
// cursorがどこかにいるかどうかを返す
hasFocus() {
return !!this._cursorLine;
}
// cursorがいる行の行番号と行idを返す
// タイトル行を0行目とする
// @return {index:number; id:string}?
get line() {
const currentLine = this._cursorLine;
return {index: ...this._lines.indexOf(currentLine), id: this.currentLine.id}; }
code:cumputeCursor.js_disabled
// cursorのいる行のDOMを取得する
get _cursorLine() {
return this._lines.getElementsByClassName('cursor-line')0; }
}
行から文字の座標を取得するのは別のclassに分離するか?
code:computeChar.js_disabled
export class charLocator {
constructor() {
this._editor = document.getElementById('editor');
}
code:computeChar.js_disabled
// 指定した文字に一致する<span>を探し、はじめに見つかった文字の位置を返す
// @return {index:number; position: {top,left,right,bottom}}?
findChar(char) {}
}