HTML編集箇所へ案内するツール
「通常表示」で編集をしていてHTML編集が必要になった場合、先ず「HTML表示」のボタンをクリックし、次に「HTML表示」の編集枠の中で編集する箇所を探す必要があります。
記事の書き始めなら、「HTML表示」を開くとHTMLの先頭部が表示され、すぐに目的の場所がみつかります。 しかし、長い記事の途中の修正などでは、HTML上の問題の場所を探すのが、とても大変な事があります。 間違って、別の場所を修正してしまったという経験があるのは、きっと私だけではないでしょう。 この扱い難さを解決するツールが「Both-WH」です。
操作は単純です。「通常表示」編集枠内にカーソルがある状態で「Ctrl + F8」を押すと、「HTML表示」編集枠に切り替わり、元のカーソル位置のHTML部分にカーソルが表示されます。 記事の途中なら、その場所へスクロールしてHTMLが表示されます。
また、「HTML表示」で「Ctrl + F8」を押すと「通常表示」に戻り、最初にジャンプをした場所に戻ります。
改善した部分
これまで、両方の編集枠のカーソル位置を関連付けるため、マークとなる図形文字を仮記入していました。 記事中に同じ文字があると検索違いで誤動作するので、普通は使われない文字を利用していました。 この方式は検索コードが簡単ですが、誤動作でマーク文字が残った時は困ります。
そこで、今回からマーク文字を以下の「マークタグ」に改めました。
「•」は、Unicodeで「\u200B」「U+200B」「ゼロ幅スペース」などと呼ばれる文字で、表示されない機能文字です。 このマークタグは万が一削除に失敗しても、記事の表示には影響しません。 更に、タグ削除を考えて「i」というIDを付けています。
下は「HTML表示」で実際に表示させたマークタグです。 但し、通常はこのタグが目に触れる事はありません。
特殊な一部のWin10絵文字が及ぼす問題
Win10絵文字の中で「異体字」や「特殊文字」を含む行(段落)からジャンプを行うと、文字位置のカウントがズレて、マークタグの一部が残り、後方の記事の1~2文字が削除されたりします。 これに関しては「Both-WH」の開発時にとても苦労し、問題を生じるWin10絵文字を調べて感知フィルターを作りました。
今回もこのフィルターを引き継ぎ、問題が生じ得る場合は、以下のダイアログを表示し、「HTML表示」に移動した直後にタグ削除をしない仕様にしています。
下は「HTML表示」にジャンプした状態です。 普通は、ジャンプ直後にマークタグを削除しますが、特殊な絵文字が含まれた行なので残しています。
この場合に、従来は手作業でマーク文字の削除が必要でした。 今回のバージョンは、「通常表示」に戻った時点でタグを自動削除します。 マークタグをHTML編集で壊さない限り、「Ctrl + F8」で戻ればタグが残る事はありません。
私は特殊な絵文字を使う事がなく、これまでのバージョンでもマークが残る事は無かったのですが、Win10絵文字は少しずつ拡張されている様で、フィルターは不完全かも知れません。 特殊な絵文字がある行でジャンプした場合は、カーソル後方の1~2文字が消される可能性がある事は、理解してください。
問題を生じる絵文字はWin10絵文字の1/6程度です。 絵文字がある行(段落)であっても、絵文字より手前でジャンプすれば、問題は生じません。
特殊なWin10絵文字のフィルターに関しては以下を参照ください。
ジャンプ元のカーソル位置を正確に探せる
記事中に配置される各種の要素で、このツールの動作をテストしました。「リブログカード」の様なiframe構造は、その内部のHTMLにアクセスできませんが、カード型の「アフィリエイト」リンクは、カード内の文字の位置へもジャンプできます。 下は「通常表示」でカード内の「円」を反転させ、このHTMLを調べる例です。
「Ctrl + F8」で「HTML表示」が開いた状態です。
この様な「カード」、コード表記の「pre枠」、各種の「囲み枠」、などの内部のHTMLへも問題なくジャンプできます。
「Both-WH」の仕様
● アメブロの「最新版エディタ」で動作します。 デフォルトデザインの編集画面でも、Stylus等でアレンジした編集画面でも、正常に動作します。
●「通常表示」のカーソル位置で「Ctrl + F8」を押すと、「HTML表示」を開いて、その箇所にカーソルを自動的に表示します。
●「HTML表示」で「Ctrl + F8」を押すと、ショートカットで最後に離れた「通常表示」の位置を表示します。 但し、戻った通常表示枠にはカーソルを入れません。 これは、ショートカット連打によるミスを防ぐためです。
● 通常の記事では、HTMLへ1sec程度で移動出来ます。 ただし、実際のHTML文字数が見た目より大変に多い場合や、記事が長くて移動場所が文書の最後に近い場合などでは、「HTML表示」を開くまでに数秒かかる場合があります。
● 移動元の行中(正確には段落)に一部のWin10絵文字が使われている場合は、「HTML」表示のカーソル位置にマークタグが露出します。 再び「Ctrl +F8」で戻った時に、このマークタグは削除されます。
● 想定外の理由により、ジャンプ後のマークタグ削除処理によって、周辺の記事の1~2文字を不本意に削除する事が有り得ます。 重要な文書でのトラブルは、自己責任とお考えください。
● 旧バージョンがある場合は、「Tampermonkey」の管理画面で旧バージョンのスクリプトを削除するか無効にしてください。
「Both-WH」ver. 1.2
以下のコードを「Tampermonkey」にコピー&ペーストして登録する事で、このツールが使用出来ます。 このツールはChrome版 / Firefox版 の「Tampermonkey」で動作を確認しています。
〔コピー方法〕 軽量シンプルなツール「PreBox Button 」を使うと
コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」
の操作で、掲載コードのコピーが可能になります。
〔 Both-WH 〕ver. 1.2
// ==UserScript== // @name Both-WH // @namespace http://tampermonkey.net/ // @version 1.2 // @description 「通常表示」「HTML表示」のカーソル位置を「Ctrl+F8」で往復する // @author Ameba Blog User // @match https://blog.ameba.jp/ucs/entry/srventry* // @grant none // ==/UserScript== window.addEventListener('load', function(){ let editor_iframe; let iframe_doc; let wysiwyg; // 通常表示の iframe内 html let native_line; // 通常表示のスクロール位置 let selection; let range; let insert_node; let mark_regex; let activeline; let codemirror_scroll; let target=document.getElementById('cke_1_contents'); // 監視 target は3箇所で共用 let monitor1=new MutationObserver( catch_key ); monitor1.observe(target, {childList: true}); // ショートカット待受け開始 catch_key(); function catch_key(){ if(document.querySelector('.cke_wysiwyg_frame') !=null){ //「通常表示」から実行開始 editor_iframe=document.querySelector('.cke_wysiwyg_frame'); iframe_doc=editor_iframe.contentWindow.document; iframe_doc.addEventListener('keydown', check_key); function check_key(event){ if(event.which==17 || event.ctrlKey==true){ if(event.which==119 || event.keyCode==119){ set_mark(); }}} function set_mark(){ selection=iframe_doc.getSelection(); range=selection.getRangeAt(0); insert_node=iframe_doc.createElement("i"); // iタグ 空タグ insert_node.appendChild(iframe_doc.createTextNode("\u200B")); insert_node.setAttribute("id", "i"); range.insertNode(insert_node); // カーソル位置にマークタグを書き込む wysiwyg=iframe_doc.querySelector('html'); native_line=wysiwyg.scrollTop; // 通常表示のスクロール位置を記録 document.querySelector('button[data-mode="source"]').click( in_CodeMirror() ); // HTML表示に移動 function in_CodeMirror(){ let monitor2=new MutationObserver( task_CodeMirror ); monitor2.observe(target, {childList: true}); function task_CodeMirror(){ if(document.querySelector('.CodeMirror-activeline pre')){ // アクティブ行が条件 function key_in(key_Code){ let keyEvent=new KeyboardEvent('keydown', {keyCode: key_Code}); document.querySelector('.CodeMirror textarea').dispatchEvent(keyEvent); } mark_regex=RegExp('<i id="i">•</i>'); let line_count=0; for(let j=0; j<3000; j++){ activeline=document.querySelector('.CodeMirror-activeline pre'); if(mark_regex.test(activeline.textContent)==true ){ break; } else{ line_count +=1; key_in(40); }} // アクティブ行を下方へ移動 let zero_pattern=[ '\uD83C\uDFC3','\uD83C\uDFC4','\uD83C\uDFCA','\uD83C\uDFCB', '\uD83C\uDFCC','\uD83C\uDFF3','\uD83D\uDC31','\uD83D\uDC41', '\uD83D\uDC68','\uD83D\uDC69','\uD83D\uDC6E','\uD83D\uDC6F', '\uD83D\uDC71','\uD83D\uDC73','\uD83D\uDC81','\uD83D\uDC86', '\uD83D\uDC87','\uD83D\uDE45','\uD83D\uDE46','\uD83D\uDE47', '\uD83D\uDE4B','\uD83D\uDE4D','\uD83D\uDE4E','\uD83D\uDEA3', '\uD83D\uDEB4','\uD83D\uDEB5','\uD83D\uDEB6','\uD83E\uDD26', '\uD83E\uDD37','\uD83E\uDD38','\uD83E\uDD39','\uD83E\uDD3C', '\uD83E\uDD3D','\uD83E\uDD3E','\uD83E[\uDDD6-\uDDDF]', '\u0023\uFE0F\u20E3', '[\u002A]\uFE0F\u20E3', '[\u0030-\u0039]\uFE0F\u20E3', '\u26F9\uFE0F','\u26A0\uFE0F' ].join('|'); let zero_regex=RegExp(zero_pattern); let zero_stop=0; if(zero_regex.test(activeline.textContent)==true){ alert("位置マークの <i>タグ は 「通常表示」 に戻った時に削除されます"); zero_stop=1; } let index_uni=activeline.textContent.indexOf('<i id="i">•</i>'); // unicode16の文字数 let real=activeline.textContent.match(/./ug); // サロゲートペアも1文字に文字列を配列化 let dim=0; // サロゲートペア文字補正値 for(dim=0; dim<index_uni; dim++){ let str=real.slice(index_uni - dim, index_uni - dim +15).join(''); if(str=='<i id="i">•</i>'){ break; }} index_uni -=dim; // サロゲートペア文字のズレ補正 if(activeline.getElementsByClassName('cm-tab')){ index_uni -=4*(activeline.getElementsByClassName('cm-tab').length); } // タブ文字補正 key_in(36); for(let i=0; i<index_uni; i++){ key_in(39); } // アクティブ行内で右方へindex値だけ移動 if(zero_stop==1){ key_in(37); } // 特殊文字がある場合は左方へ1文字移動 削除なし else{ for(let i=0; i<15; i++){ key_in(46); }} // タグ文字列15文字<i id="i">•</i>を削除 codemirror_scroll=document.querySelector('.CodeMirror-scroll'); let win_height=codemirror_scroll.clientHeight; let styles=getComputedStyle(document.querySelector('.cm-bracket')); let line_height=parseFloat(styles.lineHeight); let scroll=0; if(line_count*line_height>=0.4*win_height){ if(line_count*line_height>=win_height){ scroll=0.6*win_height; } else{ scroll=line_count*line_height - 0.4*win_height; }} codemirror_scroll.scrollTop +=scroll; document.querySelector('.CodeMirror textarea').focus(); // 入力窓にカーソルを入れる monitor2.disconnect(); } // task_CodeMirrorの終了で監視ループを抜ける }} // in_CodeMirror } // set_mark } // WYSIWYG表示での場合 else if(document.querySelector('.CodeMirror') !=null){ //「HTML表示」から実行開始 document.querySelector('.CodeMirror').addEventListener('keydown', function(event){ if(event.which==17 || event.ctrlKey==true){ if(event.which==119 || event.keyCode==119){ to_native_line(); }}}); function to_native_line(){ document.querySelector('button[data-mode="wysiwyg"]').click( in_wysiwyg() ); // 通常表示に移動 function in_wysiwyg(){ let monitor3=new MutationObserver( task_wysiwyg ); monitor3.observe(target, {childList: true}); task_wysiwyg(); function task_wysiwyg(){ if(document.querySelector('.cke_wysiwyg_frame') !=null){ //「通常表示」が条件 editor_iframe=document.querySelector('.cke_wysiwyg_frame'); iframe_doc=editor_iframe.contentWindow.document; wysiwyg=iframe_doc.querySelector('html'); if(iframe_doc.querySelector('#i')){ iframe_doc.querySelector('#i').remove(); } wysiwyg.scrollTop=native_line; // 記録された通常表示のスクロール位置に移動 if(wysiwyg.scrollTop==native_line){ monitor3.disconnect(); }}} // task_wysiwyg の終了で監視ループを抜ける } // in_wysiwyg } // to_native_line } // HTML表示での場合 } // catch_key })();
「Both-WH ⭐」最新版について
旧いバージョンの JavaScriptツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。
●「Both-WH ⭐」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。