「PreBox Tools ⭐」とは 

「PreBox Tools ⭐」は、編集画面に配置した「コード表示枠」(pre枠)を扱う上で、必要な機能を統合したツールです。 この「pre枠」をアメーバブログで利用する方はそう多くないと思いますが、これはプログラムコードを掲載する際に必要です。

 

◎ プログラムコードである事を、一目で判り易く読者に表示する

◎ コードのインデントが正しく表示され、コード内容が判読し易い

◎ コードのコピーが可能で、コードテストやプログラムの利用が簡単にできる

◎ テキスト検索で、コード上の文字列も検索範囲に入る

 

といった要件は「pre枠」を使うことで、比較的簡単に可能になります。 ネット上でコードを掲載するページで、「pre枠」はとても多く使われています。

 

実際、このツールを必要とする方は稀と思いますが、ブログの可能性を拡張し、より有意義な場に高めるため、こういったツールの公開は決して無駄ではないでしょう。 他のブログでも、コードの移植・利用が可能な場合は多いですから。 

 

 

 

今回の更新内容 

このツールは2020年に制作し、幾つかのツールの分散・統合して、現在の形になりました。 その際、コーディングの未熟さから、マウス操作の選択肢が少なく、これまでのバージョンは、使える操作の中で選択した操作方法を不本意に利用していました。

 

「pre枠」をマウスでクリックする際に、「Ctrl」「Shift」「Alt」を同時押しする事で、機能を選択していますが、「右Click」「左Click」と組み合わせると、6通りの選択肢があるはずです。

 

ところが、実際に動かない組み合わせがありました。 今回、慣れた目でコードを見直すと、「Ctrl」「Shift」「Alt」の選択分岐を、2ヵ所で別々に書いていたので、この問題が生じている事に気付きました。 複数のツールを統合する際に、ありがちな事かも知れません。

 

これを1箇所で選択する様に、コードを書き直しました。 かなりの書換えで、変数、関数の整理などを経て、とても見通しの良いコードになりました。 一歩前進です。 そして、マウスによる機能選択が自由な組み合わせで可能になったので、これを一新しました。

 

 

 

 「PreBox Tools ⭐」の仕様と操作方法

●「通常表示」の編集画面で、「Ctrl+F7」を押すと下の「表示パネル」が出ます。 これはスイッチではなく単なる起動表示で、マウス操作をここに表示しています。

 

 

● この状態で、ツールの各機能が利用できます。「Ctrl+F7」をもう一度押すと「表示パネル」が消え、このツールが終了します。

 

このツールは3つの機能があります。 以下はその機能とそれを指定する操作です。

 

  起動する機能     機能を指定する操作
 To Space (nbsp)
 + zw_space
  コード枠を 「Ctrl+左Click
 Code Copy   コード枠を 「Ctrl+右Click
 Scroll Fix   コード枠を 「Alt+左Click

 

 

 To Space (nbsp)

●「pre枠」を「Ctrl+左Click」すると、コード内の「 」を「半角スペース」に変更する機能が起動します。

▪「 」は編集枠へのペースト時に大量に書き込まれ、文字数を増やします。

▪ コード上のリンク文字列は「a要素」と誤解釈され、コピーされたコードを無効にする場合があるので、これを単なる文字列に戻します。

 

 

 ●「OK」を押すと「pre枠」内のコードの整形処理が実行されます。

▪ 処理後の「pre枠」にはブルー枠が表示されます。

▪ 処理済の「pre枠」を「右クリック」すると処理をアンドゥできます。

▪ ブルー枠は、「Ctrl+F7」でツールを終了すると自動的に消えます。

 

●「To Space (nbsp)」のコード整形処理に続いて、自動的に特殊文字「\u200B」の混入をチェックします。 もしこの文字を発見した場合は、削除を確認するダイアログが表示されます。 このチェック機能は ver. 1.4 より追加しました。

 

 

Code Copy 

●「pre枠」を「Ctrl+右Click」すると、「pre枠」内のコードを全選択します。

▪「pre枠」内のコードだけを全コピーしたり、全削除する場合に利用します。

 

 

 

 Scroll Fix

●「pre枠」を「Alt+左クリック」すると、スクロール表示の「pre枠」を非スクロール表示に変更します。 これは一時的な変更で「pre枠」にグリーン枠を表示します。

▪コードの検索/置換では、全コードが見える非スクロール表示が必要になります。

 

● 変更した「pre枠」は「Alt+左クリック」で元に戻ります。 また、これはツールによる仮表示で、「Ctrl+F7」でツールを終了した場合は、自動的に元に戻ります。

 

 

 

ヘルプボタン 

ヘルブボタンを設置しました。 これは、このページを表示します。

 

 

 

 

 操作上の注意点

 

起動のショートカット 

ブラウザの「カーソルブラウジング」が「F7」キーに設定されている事により、このツールを起動する「Ctrl+F7」が効かない場合があります。 回避方法は、以下のいずれかの方法を試してください。

 

◎「Ctrl+Shift+F7」を押す。

◎ 漢字変換をOFFにしてから「Ctrl+F7」を押す。

◎ 編集枠余白部をクリックして、編集枠外にフォーカスを移し「Ctrl+F7」を押す。

 

 

 「通常表示」⇄「HTML表示」の移動

このツールを起動中で(パネルが表示)、 「To Space (nbsp)」処理後のブルー枠、 「Scroll Fix」のグリーン枠と拡張した「pre枠」などが表示された状態であっても、「HTML表示」を開くことに問題はありません。(特に「To Space 」の実際の動作は「HTML表示」を見ると良く判ります。) 元の「通常表示」に戻ると、「HTML表示」に移動した時の状態が再現されます。

 

「Ctrl+F7」でツールを終了すると、ブルー枠やグリーン枠は消え、記事の本来の表示になります。 非スクロール表示のグリーン枠の状態で「下書き保存」「投稿する」をした場合は、ボタンを押した瞬間に本来の表示に戻って保存されます。

 

なお、「HTML表示」の編集画面で「下書き保存」「投稿する」を押した場合は、ツールの枠線の除去が出来ないので、通常表示で終了する様に説明が出ます。

 

 

もとに戻す操作 

長期にわたり使用して来ましたが、「To Space (nbsp)」によるコードデータの損失は一度も経験がありません。 制作の初期は判らなかったので、「pre枠」内のデータをバックアップし、処理後に問題があれば元に戻す(アンドゥ)機能を実装しています。 これは余り使う事はないと思いますが、正常に使えます。

 

ただし、このバックアップは、ツールを「Ctrl+F7」で起動して、終了をするまでの間の保持だけで、「Ctrl+F7」で終了した時点でリセットされます。 編集画面を閉じてもう一度開いた所から、アンドゥで前の画面の状態に戻せないのと同じです。

 

 

 

「PreBox Tools ⭐」を利用するには

このツールは Chrome / Edge / Firefox版の拡張機能「Tampermonkey」上で動作します。 以下に、このツールの導入手順を簡単に説明します。

 

 

❶「Tampermonkey」を導入します

◎ 使用しているブラウザに拡張機能「Tampermonkey」を導入する事が必要です。

既に「Tampermonkey」を導入している場合は、この手順 ❶ は不要です。 

拡張機能の導入については、以下のページに簡単な説明があるので参照ください。

 

 

❷「Tampermonkey」にスクリプトを登録します

◎「Tampermonkey」の「」マークの「新規スクリプト」タブを開きます。

 

 

 

◎「新規スクリプト」には、最初からテンプレートが記入されています。 これは全て削除して、完全に空白の編集枠に 下のコードをコピー&ペーストします。

 

〔コピー方法〕 軽量シンプルなツール「PreBox Button   」を使うと

  コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」

  の操作で、掲載コードのコピーが可能になります。

 

◎ 最後に「ファイル」メニューの「保存」を押すと、ツールが使用可能になります。

 

 

〔 PreBox Tools ⭐ 〕 ver. 1.3 

 

// ==UserScript==
// @name         PreBox Tools ⭐
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  「pre枠」関連総合編集ツール 「Ctrl+F7」
// @author       Ameba Blog User
// @match        https://blog.ameba.jp/ucs/entry/srventry*
// @exclude      https://blog.ameba.jp/ucs/entry/srventrylist.do*
// @grant        none
// ==/UserScript==


let retry=0;
let interval=setInterval(wait_target, 100);
function wait_target(){
    retry++;
    if(retry>10){ // リトライ制限 10回 1sec
        clearInterval(interval); }
    let target=document.getElementById('cke_1_contents'); // 監視 target
    if(target){
        clearInterval(interval);
        main(); }}


function main(){
    let mode=0;
    let box_mode=0; // boxの状態
    let box_i; // boxの選択

    let editor_iframe;
    let iframe_doc;
    let iframe_body;
    let wysiwyg; // 通常表示の iframe内 html

    let buffer=[]; // box内データのバックアップ用配列


    let target=document.getElementById('cke_1_contents'); // 監視 target
    let monitor=new MutationObserver(catch_key);
    monitor.observe(target, {childList: true}); // ショートカット待受け開始

    catch_key();

    function catch_key(){
        editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        if(editor_iframe){
            iframe_doc=editor_iframe.contentWindow.document;

            when_back();
            right_select();

            document.addEventListener('keydown', check_key); // iframe外
            iframe_doc.addEventListener('keydown', check_key); // iframe内


            function check_key(event){
                if(event.ctrlKey && event.keyCode==118){ // ショートカット「Crtl+F7」
                    event.preventDefault();
                    event.stopImmediatePropagation();
                    if(mode==0){
                        mode=1;
                        sign();
                        right_select();
                        box_act(); }
                    else if(mode==1){
                        mode=0;
                        buffer=[]; // ツールOFF時にバッファークリア 🔵
                        sign_clear();
                        tospace_clear();
                        box_close(); }}}}

        before_end(); } // catch_key()


    function when_back(){ // HTML表示から戻った時に処理状態を再現表示
        editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        if(editor_iframe){
            iframe_doc=editor_iframe.contentWindow.document;
            if(iframe_doc){
                if(mode==1){
                    sign();
                    box_act(); }}}}



    // ********** Menu Display and additional function **************

    function sign(){
        monitor.disconnect(); // 起動時セットアップを MutationObserverに反応させない

        editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        if(editor_iframe){
            iframe_doc=editor_iframe.contentWindow.document;

            let style_sbf=
                '<style id="style_sbf">'+
                '.open_box { outline: 2px solid #009688 !important; height: auto !important; } '+
                '.clean_box { outline: 2px solid #03a9f4 !important; }'+
                '</style>';

            if(!iframe_doc.documentElement.querySelector('#style_sbf')){
                iframe_doc.documentElement.insertAdjacentHTML('beforeend', style_sbf); }}


        let SVG_h=
            '<svg id="help_pbt" viewBox="0 0 150 150">'+
            '<path  fill="#fff" d="M66 13C56 15 47 18 39 24C-12 60 18 146 82 137C92 '+
            '135 102 131 110 126C162 90 128 4 66 13M68 25C131 17 145 117 81 '+
            '125C16 133 3 34 68 25M69 40C61 41 39 58 58 61C66 63 73 47 82 57C84 '+
            '60 83 62 81 65C77 70 52 90 76 89C82 89 82 84 86 81C92 76 98 74 100 66'+
            'C105 48 84 37 69 40M70 94C58 99 66 118 78 112C90 107 82 89 70 94z">'+
            '</path></svg>';

        let disp_sf=
            '<div id="disp_sf">'+
            SVG_h+'   '+
            '■ To Space (nbsp): Ctrl+L-Click ■ Code Copy: Ctrl+R-Click ■ Scroll Fix: Alt+Click'+
            '</div>'+
            '<style>'+
            '#cke_1_contents { display: flex; flex-direction: column; } '+
            '#disp_sf { position: relative; margin: 0 0 5px; padding: 4px 0 1px; '+
            'font: 16px/24px Meiryo; color: #fff; background: #009688; white-space: nowrap; } '+
            '#help_pbt { position: absolute; top: 7px; left: 6px; height: 16px; width: 16px; '+
            'cursor: pointer; }'+
            '</style>';

        editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        if(editor_iframe){
            if(!document.querySelector('#disp_sf')){
                editor_iframe.insertAdjacentHTML('beforebegin', disp_sf); }}

        monitor.observe(target, {childList: true});


        document.querySelector('#disp_sf').style.display='block';
        let help=document.querySelector('#help_pbt');

        help.onclick=function(){
            window.open("https://ameblo.jp/personwritep/entry-12760312656.html", '_blank'); }

    } // sign()



    function sign_clear(){
        if(target.querySelector('#disp_sf')){
            target.querySelector('#disp_sf').style.display='none'; }} // 起動表示を非表示



    // *********** Pre Box Right Select ********************

    function right_select(){
        editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        if(editor_iframe){
            iframe_doc=editor_iframe.contentWindow.document;
            if(iframe_doc){
                let iframe_body=iframe_doc.querySelector('body');
                if(iframe_body){
                    let target_pre=iframe_body.querySelectorAll('pre');
                    for(let i=0; i<target_pre.length; i++){
                        target_pre[i].oncontextmenu=function(event){
                            if(event.ctrlKey){
                                event.preventDefault();
                                event.stopImmediatePropagation();
                                select_code(target_pre[i]); }}}

                    function select_code(box){
                        let selection=iframe_doc.getSelection();
                        let range=iframe_doc.createRange();
                        range.selectNodeContents(box);
                        selection.removeAllRanges();
                        selection.addRange(range); }
                }}}} // right_select()



    // ********** Scroll Fix & To Space (nbsp) **************

    function box_act(){
        let pre_box; // PRE枠のコンテナブロック

        editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        if(editor_iframe){
            iframe_doc=editor_iframe.contentWindow.document;
            if(iframe_doc){
                iframe_body=iframe_doc.querySelector('body');
                if(iframe_body){
                    pre_box=iframe_body.querySelectorAll('div');

                    for(let i=0; i<pre_box.length; i++){
                        pre_box[i].onclick=function(event){
                            if(event.altKey){
                                event.preventDefault();
                                event.stopImmediatePropagation();
                                scroll_fix(pre_box[i], i); }
                            if(event.ctrlKey){
                                event.preventDefault();
                                event.stopImmediatePropagation();
                                edit_box(pre_box[i], i); }}}



                    function scroll_fix(box, index){
                        if(box_mode==0 && mode==1){
                            box_mode=1; // boxのScroll設定を外す
                            let style_set=window.getComputedStyle(box, null);
                            if(style_set.getPropertyValue('overflow')){
                                if(style_set.getPropertyValue('overflow')=='scroll' ||
                                   style_set.getPropertyValue('overflow')=='auto' ||
                                   style_set.getPropertyValue('overflow')=='overlay'){
                                    box_i=index;
                                    box.classList.add('open_box'); }}
                            else if(style_set.getPropertyValue('overflow-y')){
                                if(style_set.getPropertyValue('overflow-y')=='scroll' ||
                                   style_set.getPropertyValue('overflow-y')=='auto' ||
                                   style_set.getPropertyValue('overflow-y')=='overlay'){
                                    box_i=index;
                                    box.classList.add('open_box'); }}}
                        else{
                            if(index==box_i){
                                box_mode=0; // boxのScroll設定を元に戻す
                                box.classList.remove('open_box'); }}
                    } // scroll_fix()



                    function edit_box(box, index){
                        let nbsp;
                        let a_count;

                        if(box.firstChild.tagName=='PRE' && mode==1){
                            let regex=new RegExp('\u00A0', 'g');
                            let nbsp=box.innerText.match(regex);
                            let pa_count=box.getElementsByTagName("a");

                            if(!box.classList.contains('clean_box')){
                                if(nbsp !=null || pa_count.length !=0){
                                    let ok;
                                    if(nbsp==null && pa_count.length !=0){
                                        ok=confirm(" ⏬  「&nbsp」 0 個\n"+
                                                   "    「a要素」 " + pa_count.length + " 個をテキストに置換えます"); }
                                    else if(nbsp !=null && pa_count.length==0){
                                        ok=confirm(" ⏬  「&nbsp」 " + nbsp.length + " 個を半角空白に変換します\n"+
                                                   "    「a要素」 0 個"); }
                                    else{
                                        ok=confirm(" ⏬  「&nbsp」 " + nbsp.length + " 個を半角空白に変換します\n"+
                                                   "    「a要素」 " + pa_count.length + " 個をテキストに置換えます"); }
                                    if(ok){
                                        if(buffer[index]==null){
                                            buffer[index]=box.firstChild.innerHTML; } // 選択pre枠のデータバックアップ 🔵
                                        box.classList.add('clean_box');
                                        to_space(box, index); }}
                                else{ box.classList.add('clean_box'); }}

                            else{
                                let ok=confirm(" ❎  変換前に戻しますか?");
                                if(ok){
                                    if(buffer[index]!=null){
                                        box.firstChild.innerHTML=buffer[index];
                                        buffer[index]=null; } // バッファークリア 🔵
                                    box.classList.remove('clean_box'); }}}


                        function to_space(box, index){
                            a_count=0;
                            let child_node=box.firstChild.childNodes;
                            for(let t=0; t<child_node.length; t++){
                                if(child_node[t].nodeType==3){
                                    child_node[t].nodeValue=child_node[t].nodeValue.replace(/\u00A0/g , '\u0020'); }
                                else if(child_node[t].nodeType==1 && child_node[t].tagName=="A"){
                                    let inner_node=child_node[t].childNodes;
                                    if(inner_node.length==1 && inner_node[0].nodeType==3){
                                        box.firstChild.replaceChild(inner_node[0], child_node[t]); } // text を a要素と入替え
                                    else{
                                        a_count +=1; }} // 子ノードが1個の textの条件に当てはまらない a要素
                                else{
                                    let child_node2=child_node[t].childNodes;
                                    if(child_node2){
                                        for(let t2=0; t2<child_node2.length; t2++){
                                            if(child_node2[t2].nodeType==3){
                                                child_node2[t2].nodeValue=
                                                    child_node2[t2].nodeValue.replace(/\u00A0/g , '\u0020'); }
                                            else{
                                                let child_node3=child_node2[t2].childNodes;
                                                if(child_node3){
                                                    for(let t3=0; t3<child_node3.length; t3++){
                                                        if(child_node3[t3].nodeType==3){
                                                            child_node3[t3].nodeValue=
                                                                child_node3[t3].nodeValue.replace(/\u00A0/g , '\u0020'); }
                                                    }}}}}}}


                            let regex=new RegExp('\u00A0', 'g');
                            nbsp=box.innerText.match(regex);
                            if(nbsp !=null){
                                alert("❌ 変換できなかった「&nbsp」の数 : " + nbsp.length );}
                            if(a_count !=0){
                                alert("❌ 置換えが出来ない「a要素」 : " + a_count); }

                        } // to_space()
                    } //edit_box()

                }}}} // box_act()



    // ********** Scroll Fix  additional function **************

    function box_close(){
        editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        if(editor_iframe){
            iframe_doc=editor_iframe.contentWindow.document;
            if(iframe_doc){
                box_mode=0;
                let open_box=iframe_body.querySelectorAll('.open_box');
                for(let i=0; i<open_box.length; i++){
                    open_box[i].classList.remove('open_box'); }}}} // 処理枠の outline を削除



    // ********** To Space (nbsp)  additional function **************

    function tospace_clear(){
        editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        if(editor_iframe){
            iframe_doc=editor_iframe.contentWindow.document;
            if(iframe_doc){
                let clear_box=iframe_doc.querySelectorAll('.clean_box');
                for(let i=0; i<clear_box.length; i++){
                    clear_box[i].classList.remove('clean_box'); }}}} // 処理枠の outline を削除



    // ********** Before End *********************************

    function before_end(){
        editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        let submitButton=document.querySelectorAll('.js-submitButton');
        submitButton[0].addEventListener("click", all_clear, false);
        submitButton[1].addEventListener("click", all_clear, false);

        function all_clear(){
            if(!editor_iframe){ //「HTML表示」編集画面の場合
                alert("⛔ PreBox Tools ⭐ の終了処理ができません\n\n"+
                      "   通常表示画面に戻り 編集を終了してください");
                event.stopImmediatePropagation();
                event.preventDefault(); }

            if(editor_iframe){ //「通常表示」編集画面の場合
                if(mode!=0){
                    mode=0;
                    box_mode=0;
                    tospace_clear();
                    box_close(); }}
        }} // before_end()


} // main()


 

 

 

「PreBox Tools ⭐」最新版について 

旧いバージョンの JavaScriptツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。

 

●「PreBox Tools ⭐」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。