|
@@ -20,6 +20,7 @@
|
|
|
var value = document.getElementById("input").value;
|
|
|
var view = document.getElementById("view");
|
|
|
view.innerHTML = value;
|
|
|
+ cleanup_element(view);
|
|
|
|
|
|
// Generate TOC
|
|
|
var root = document.getElementById("view");
|
|
@@ -80,6 +81,154 @@
|
|
|
return toc;
|
|
|
}
|
|
|
|
|
|
+ // 改行除去処理でスキップする要素 (子孫含めスキップされる)
|
|
|
+ const element_skip_list = {
|
|
|
+ pre: true,
|
|
|
+ };
|
|
|
+
|
|
|
+ // 改行除去処理の対象要素 (子孫含め処理される)
|
|
|
+ const element_target_flags = {
|
|
|
+ a: true,
|
|
|
+ em: true,
|
|
|
+ strong: true,
|
|
|
+ p: true,
|
|
|
+ li: true,
|
|
|
+ td: true,
|
|
|
+ h1: true,
|
|
|
+ h2: true,
|
|
|
+ h3: true,
|
|
|
+ h4: true,
|
|
|
+ h5: true,
|
|
|
+ h6: true,
|
|
|
+ };
|
|
|
+
|
|
|
+ // DOMツリーの各要素から不要な改行/空白を除去
|
|
|
+ // in_target: 処理対象の要素に入るとtrueになる
|
|
|
+ // queue: 要素を跨いだ処理の空白で使用する作業用配列
|
|
|
+ function cleanup_element(element, in_target, queue) {
|
|
|
+ in_target = in_target || false; // 未指定ならfalse
|
|
|
+ queue = queue || []; // 未指定なら空配列
|
|
|
+
|
|
|
+ // 処理対象要素から出た時にqueueを空にする
|
|
|
+ if (!in_target) {
|
|
|
+ queue.length = '';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 子要素のリストを持たなければスキップ
|
|
|
+ if (!element.childNodes) { return; }
|
|
|
+
|
|
|
+ // 直下の子要素を処理
|
|
|
+ let list = element.childNodes;
|
|
|
+ for (let i = 0, length = list.length; i < length; i++) {
|
|
|
+ let child = list[i];
|
|
|
+ let nodename = child.nodeName.toLowerCase();
|
|
|
+
|
|
|
+ // 特定の要素(主にpre)をスキップ
|
|
|
+ if (element_skip_list[nodename] === true) { continue; }
|
|
|
+
|
|
|
+ // 対象要素又はその子孫なら改行/空白を除去
|
|
|
+ let next_in_target = (in_target || element_target_flags[nodename] === true);
|
|
|
+ if (next_in_target) {
|
|
|
+ cleanup_node(child, queue);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 子孫を処理するため再帰呼び出し
|
|
|
+ cleanup_element(child, next_in_target, queue);
|
|
|
+
|
|
|
+ // 子孫要素の最後の「日本語文字」以降の改行/空白を除去
|
|
|
+ if (!in_target && next_in_target) {
|
|
|
+ cleanup_queue(queue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // テキストノードから不要な改行/空白を除去
|
|
|
+ function cleanup_node(node, queue) {
|
|
|
+
|
|
|
+ // 正規表現のメモ:
|
|
|
+ // (?:[^\s\d\w]| )←日本語 (記号含む)
|
|
|
+ // [^\S ]←改行/空白 (\sから全角スペースを除いた物)
|
|
|
+ // [^\S\n ]←空白 (\sから全角スペース/改行文字を除いた物)
|
|
|
+ // [\[\]\(\)\{\}\<\>\|] ←括弧と「|」
|
|
|
+
|
|
|
+ // テキストノード以外はスキップ
|
|
|
+ if (node.nodeType !== document.TEXT_NODE) { return; }
|
|
|
+
|
|
|
+ let text = node.data;
|
|
|
+
|
|
|
+ // 前要素の末尾が日本語だった場合
|
|
|
+ if (queue.length > 0) {
|
|
|
+
|
|
|
+ // 改行/空白だけのテキストノードはqueueに追加 (次に日本語が出現したらまとめて除去)
|
|
|
+ if (text === '' || /^[^\S ]*$/.test(text)) {
|
|
|
+ queue.push(node);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 日本語又は開き括弧以外の記号が出現したらtrue
|
|
|
+ let jp_or_paren = /^[^\S ]*(?:[^\s\d\w\[\(\{\<\|]| )/.test(text);
|
|
|
+
|
|
|
+ // 前の要素の末尾が閉じ括弧ならtrue
|
|
|
+ let last_paren = (/[^\S ]*[\]\)\}\>\|][^\S ]*$/.test(queue[0].data));
|
|
|
+
|
|
|
+ // 日本語又は開き括弧以外の記号が出現したらqueueを使用して最後の日本語より後の改行/空白をまとめて除外
|
|
|
+ // 閉じ括弧の後に、。が来た場合も除外
|
|
|
+ if (jp_or_paren && (!last_paren || /^[^\S ]*[、。]/.test(text))) {
|
|
|
+ cleanup_queue(queue);
|
|
|
+ text = text.replace(/^[^\S ]*/, "");
|
|
|
+ } else {
|
|
|
+ // 上記以外ならqueueを破棄
|
|
|
+ queue.length = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 日本語と閉じ括弧以外の記号+改行+後続の空白+開き括弧以外
|
|
|
+ text = text.replace(/((?:[^\s\d\w\]\)\}\>\|]| ))\n[^\S ]*([^\[\(\{\<\|])/g, "$1$2");
|
|
|
+
|
|
|
+ // 閉じ括弧以外+改行+後続の空白+日本語と開き括弧以外の記号
|
|
|
+ text = text.replace(/([^\]\)\}\>\|])\n[^\S ]*((?:[^\s\d\w\[\(\{\<\|]| ))/g, "$1$2");
|
|
|
+
|
|
|
+ // 括弧+改行+後続の空白+、。
|
|
|
+ text = text.replace(/([\[\]\(\)\{\}\<\>\|])\n[^\S ]*([、。])/g, "$1$2");
|
|
|
+
|
|
|
+ if (/(?:[^\s\d\w]| )[^\S ]*$/.test(text)) {
|
|
|
+ // 末尾が日本語ならqueueに追加
|
|
|
+ queue.push(node);
|
|
|
+ } else {
|
|
|
+ // 上記以外ならqueueを使用して最後の日本語より後の改行/空白を除去
|
|
|
+ cleanup_queue(queue);
|
|
|
+ }
|
|
|
+
|
|
|
+ node.data = text;
|
|
|
+ }
|
|
|
+
|
|
|
+ // queueに溜まったテキストノードから末尾の改行/空白を削除
|
|
|
+ function cleanup_queue(queue) {
|
|
|
+
|
|
|
+ // 途中に改行文字を含むか?
|
|
|
+ let has_break = false;
|
|
|
+ for (let i = 1, length = queue.length; i < length; i++) { // 0番目は日本語が末尾なので1番目以降を調べる
|
|
|
+ let text = queue[i].data;
|
|
|
+ if (/\n/g.test(text)) {
|
|
|
+ has_break = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 途中に改行を含まないなら削除しない
|
|
|
+ if (!has_break) {
|
|
|
+ queue.length = 0;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (let i = 0, length = queue.length; i < length; i++) {
|
|
|
+ let text = queue[i].data;
|
|
|
+ text = text.replace(/[^\S ]*$/, "");
|
|
|
+ queue[i].data = text;
|
|
|
+ }
|
|
|
+ queue.length = 0;
|
|
|
+ }
|
|
|
+
|
|
|
function escape_html(unsafeText) {
|
|
|
if(typeof unsafeText !== 'string') {
|
|
|
return unsafeText;
|
|
@@ -816,4 +965,4 @@ href="#20170505T0118_Heading-1-2">Heading 1-2</a></li></ol>
|
|
|
<p> <small>Author: SENOO, Ken (<a href="https://twitter.com/senopen">@senopen</a>). License: CC0. Created date: <time>2017-05-06.</time></small></p>
|
|
|
</footer>
|
|
|
</body>
|
|
|
-</html>
|
|
|
+</html>
|