1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

順序つきリストの行頭に連番を振るUserScript【Scrapbox】

Last updated at Posted at 2023-12-12

はじめに

EvernoteからScrapboxに移行するにあたり、使えなくて困った機能がありました。それは、Scrapboxでは「順序付きリスト」つまり、<ol>に自動で番号を振ってくれないことです。ということで、ネストに対応した番号を振るUserScriptを作成しました。

使い方

リストに含めたい行を選択して、ポップアップボタンを押して使います。選択行には必ず、行頭を含んでください。そうしないと変なところに番号が出力されます。
例えば、次の文字列に数字を振るとしましょう。

Before

	1行目
		2行目
		3行目
	4行目
5行目
		6. 6行目
		7行目
		24. 8行目
	-11. 9行目
	
	10行目
12行目

After

		1. 1行目
			1. 2行目
			2. 3行目
		2. 4行目
	1. 5行目
			6. 6行目
			7. 7行目
			8. 8行目
		-11. 9行目
		
		-10. 10行目
	2. 12行目

<ol>におけるstart属性にも対応しています。行頭(今回は6, 9行目)に"数字+ドット"の形式で数値を入力しておくと、その番号から連番を始めてくれます。

ただし、同じ数のインデントがついた最初の行のみを参照します。例えば、8行目には数値が入っていますが、すでに同じ数のインデントを持つ行が存在しているため、「24」という数字は無視され、代わりに「6+2=8」が代入されます。

空白行は単純に番号をつけずにスキップします。くわえて、値はマイナスにも対応していますが、Scrapboxの表示としては数字つきリストではなく、普通のリスト扱いになるようです。

ソースコード

script.js
	scrapbox.PopupMenu.addButton({
		title: 'Ordered list',
    		onClick: text => {
     		let result = formatOrderList(textToNestedList(text));
			if(/^\S/gm.test(result)) {// インデントが行頭にない行が存在する場合は追加する
				result = result.replace(/^/gm, "\t");
			}
     		return result;
     	}
	});
	
	function textToNestedList(text) {
		const reg = /(^\s*)(.*)/;
		return text.split("\n").reduce((result, line) => {
			const level = line.replace(reg, "$1").length;
			const content = line.replace(reg, "$2");
			let parent = result;
			for (let i = 0; i < level; i++) {
				if (parent.length === 0 || !Array.isArray(parent[parent.length - 1])) parent.push([]);
				parent = parent[parent.length - 1];
			}
			parent.push(content);
			return result;
		}, []);
	}
	
	function formatOrderList(list, indent = 0) {
		const blank = "\t".repeat(indent);
		const firstLine = list.find(value => !Array.isArray(value));
		const reg = /(^-?\d+)(\.\s*)/;
		const start = reg.test(firstLine) ? firstLine.split(".")[0] : 1;
		let index = 0;
		return list.map(item => {
			if (Array.isArray(item)) {
				return this.formatOrderList(item, indent + 1);
			}
			if(item.length === 0) {
				return blank;
			}
			return blank + `${Number(start) + index++}. ` + item.replace(reg, "");
		}).join("\n");
	}

textToNestedList()scrapbox.PopupMenu.addButtonにインライン化して平気ですが、formatOrderList()はインライン化はできません。なぜなら、値を入れ子にするために循環参照をしているからです。

テストはザックリしただけなので、バグがあったら教えてください。

参考資料

ネストに対応していない順序付きリストでいいなら、こちらの方が簡単。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?