scrapbox-line-accessor
2021-06-08
2021-02-20
コードを少し整えた
2021-01-19
2021-01-17
12:38:34 折返し取得関数を削除した
12:01:11 行の折返し数の取得計算を間違えていたので直した
依存
code:script.js
import {char as c} from '/api/code/takker/scrapbox-char-accessor/script.js';
import {scrapboxDOM} from '/api/code/takker/scrapbox-dom-accessor/script.js';
本体
classでwrapして、便利な関数を提供するイメージ
code:script.js
class Line {
constructor({lineDOM}) {
if (!lineDOM?.classList?.contains?.('line')
|| lineDOM?.tagName !== 'DIV') throw Error(${lineDOM} is not div.line);
this.lineDOM = lineDOM;
}
情報の取得
行番号を取得する
code:script.js
get index() {
}
行IDを取得する
code:script.js
get id() {
return this.lineDOM.id;
}
行内の文字列を取得する
code:script.js
get text() {
}
行のインデントの数を取得する
span.indent-mark span.char-indexの数で判断する
code:script.js
get indent() {
return this.lineDOM.querySelectorAll('span.indent-mark span.char-index').length;
}
code:script.js
get indentBlockLength() {
const presentIndentLevel = this.indent;
const lineNo = this.index;
const nextTheSameIndentLineNo = scrapbox.Page.lines.findIndex((line, i) => {
const indentLevel = line.text.replace(/^(\s*).*$/,'$1').length;
return i > lineNo && indentLevel <= presentIndentLevel;
});
return nextTheSameIndentLineNo !== -1 ?
nextTheSameIndentLineNo - 1 - lineNo :
scrapbox.Page.lines.length - 1 - lineNo; // 見つからなければ、最後の行までインデントブロックだと判断する
}
行の折返し数を取得する
折返しがなければ0を返す
code:script.js_disabled
get breakNum() {
return Math.ceil(this.lineDOM.getBoundingClientRect().height
/ parseInt(window.getComputedStyle(this.lineDOM).lineHeight)) - 1;
}
文字情報の取得
任意の位置の文字
code:script.js
char(index) {
return c(this.id, index);
}
行頭文字/行末文字
code:script.js
get headChar() {
return this.char(0);
}
get lastChar() {
const index = this.text.length - 1;
// this.textが空行のときは span.c-0 を取得する
return this.char(index < 0 ? 0 : index);
}
空白を除いた行頭文字/行末文字
code:script.js
get headNonBlankChar() {
//this._log('enter "headNonBlankCharDOM".');
const text = this.text;
if (/^\s+$/.test(text)) return this.lastChar;
if (!/^\s+/.test(text)) return this.headChar;
const spaceNum = text.match(/^\s+/)?.0?.length; return this.char(spaceNum);
}
get lastNonBlankChar() {
//this._log('enter "lastNonBlankCharDOM".');
const text = this.text;
if (/^\s+$/.test(text)) return this.headChar;
if (!/\s+$/.test(text)) return this.lastChar;
const spaceNum = text.match(/\s+$/)?.0.length; return this.char(this.text.length - 1 - spaceNum);
}
行の取得
前の行
code:script.js
get prev() {
const lineDOM = this.prevDOM;
return lineDOM ? new Line({lineDOM}) : undefined;
}
次の行
code:script.js
get next() {
const lineDOM = this.nextDOM;
return lineDOM ? new Line({lineDOM}) : undefined;
}
位置の確認
先頭行かどうか
code:script.js
get isHead() {
return scrapbox.Page.lines0.id === this.id; }
EOFかどうか
code:script.js
get isLast() {
return scrapbox.Page.lines.pop().id === this.id;
}
DOMの取得
現在行
code:script.js
get DOM() {
return this.lineDOM;
}
前の行
code:script.js
get prevDOM() {
return this.lineDOM.previousElementSibling ?? undefined;
}
次の行
code:script.js
get nextDOM() {
return this.lineDOM.nextElementSibling ?? undefined;
}
Debug用
code:script.js
_log(msg, ...objects){
if (typeof msg !== 'object') {
console.log([scrapbox-line-info-2] ${msg}, ...objects);
return;
}
console.log([scrapbox-line-info-2] , msg, ...objects);
}
}
外部に公開する
以下のいずれかから、行情報を取得するinstanceを生成する
div.lineそのもの
内部ではdiv.lineを使う
行ID
行番号
内部で何を保持しているか知らなくても、外部から使えるようにする
code:script.js
export const line = (value) => {
// undefinedであればそのまま返す
if (value === undefined || value === null) return undefined;
let id = undefined;
let lineDOM = null;
switch(typeof value) {
// 行番号が渡されたとき
case 'number':
id = L${scrapbox.Page.lines[value]?.id};
if (id === undefined) {
console.error(${value} is out of range);
return undefined;
}
// そのまま次のcaseを実行する
// 行IDが渡されたとき
case 'string':
id = id ?? (/^L/.test(value) ? value : L${value});
lineDOM = document.getElementById(id);
if (!lineDOM) {
console.error(${id} is an invalid line id.);
return undefined;
}
// そのまま次のcaseを実行する
// 行のDOMが渡されたとき
default:
return new Line({lineDOM: lineDOM ?? value});
}
};