編集画面の「Wysiwyg」環境を補強するツール

アメーバのPC編集画面は「デザイン幅で表示」にチェックを入れる事で、簡易な「Wysiwyg」環境になります。 しかし、スキンによっては行間隔が異なり、アメブロ絵文字の位置ズレ、画像と文字行の間隔が違う等の、気になる問題点があります。

 

これらの点は、「Stylus」で「編集枠内」にCSSを適用する事で改善が出来るので、編集画面のアレンジスタイル「Ameblo Writer(Compact)」には、「Wysiwyg」環境を補強するセクションを幾つか設けています。

 

 

しかし、ユーザーの編集環境は様々で、時には「Stylus」を使っていても「編集画面=iframe」のアレンジ指定が無効になる場合があります。 そこで「Wysiwyg」環境を確実に確保するために「Ameblo Wysiwyg ⭐」を制作しました。

 

「Ameblo Writer(Compact)」が機能していれば、このツールの半分以上の設定項目は不要で、「Ameblo Writer(Compact)」のアレンジに従います。 残りの項目では、このツールでしか設定できない便利な機能があります。 私は「Ameblo Writer Compact」を適用した上で「Ameblo Wysiwyg ⭐」を使っています。

 

 

 

 「Ameblo Wysiwyg ⭐」について

「Ameblo Wysiwyg ⭐」の指定項目は、全て設定パネルに表示されます。 ツールの設定パネルは「デザイン幅で表示」を「Ctrl+左Click」すると表示されます。

 

 

下は、設定パネルの内容です。( ver. 1.1 )

 

 

このツールの目的は、Wysiwyg環境を確実に維持することです。 ブログページはブログスキン等で本文デザインが指定されていますが、編集画面の「通常表示」の表示がそのデザインに一致する様に、このツールで調整するのが、本来の使用方法です。

 

もっとも、そういうWysiwygの目的は無視して、ツールを利用してもかまいません。

 

▪「選択文字列の反転色指定」

▪「選択した画像・アメブロ絵文字の透過反転色」

▪「YouTube動画 編集枠内で再生可能にする」

▪「Font Awesome の @import指定」

▪「編集枠への画像のドラッグ&ドロップを無効にする」

 

などの項目は、Wysiwygとは関係なく使える有効な機能です。

 

 

 

更新内容 

 

 編集画面起動時の「スクリプトエラー」を改善

編集画面には多くのスクリプトが動作しますが、この「Ameblo Wysiwyg ⭐」が多数の「スクリプトエラー」を出していました。 状況を調べると前ページのケースと同様に「MutationObserver」によるものです。 このツールの場合は、2個の「styleタグ」を編集画面に埋め込む事で、「Wysiwyg環境」を実現しますが、起動時にこの「styleタグ」を「更新型」で生成してエラーになっていました。

 

 

9個のエラー中 6個がこのツールによるもので、これより多い事もあります。

 

コードを修正し、起動時は「固定型」(タグが無い場合のみ生成)とし、ユーザー設定時は「更新型」(タグがあれば削除して生成)とする事で改善しました。

 

 

メニュー画面の修正 

上記のメニュー画面の末尾の表示を改めました。「Stylus」を使用している場合は、半分程の項目が「無効」に見えます。 これは同じ指定内容が「Stylus」によって既に指定されているためで、その事をなるべく判り易くしたつもりですが。

 

 

 

指定項目の説明 

以下のページにも、幾つかの指定項目の説明があります。

 

 

 

 

 

 

「Ameblo Wysiwyg ⭐」を利用するには 

このツールは Chrome / Edge / Firefox の拡張機能「Tampermonkey」上で動作します。

 

このツールは、Tampermonkey上で常にONにする常駐型ツールで、ブログ編集画面を開いた時に、自動的にその環境を最適化します。 ユーザーは、上記の環境設定を行った後は、何もする必要がありません。

 

以下に、このツールの導入手順を簡単に説明します。

 

❶「Tampermonkey」を導入します

使用しているブラウザに拡張機能「Tampermonkey」を導入する事が必要です。 以下のページに簡単な導入の説明があるので参照ください。

 

 

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

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

 

 

 

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

 

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

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

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

 

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

 

 

〔 Ameblo Wysiwyg 〕 ver. 1.1

 

// ==UserScript==
// @name         Ameblo Wysiwyg ⭐
// @namespace  http://tampermonkey.net/
// @version      1.1
// @description  Ameba編集画面とブログページの Wysiwygを管理
// @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 ua=0;
let agent=window.navigator.userAgent.toLowerCase();
if(agent.indexOf('firefox') > -1){ ua=1; } // Firefoxの場合のフラッグ

let menu_view=0; // メニューの表示・非表示

let wywg_set=[]; // Ameblo Wywg のユーザー設定

let read_json=localStorage.getItem('Wywg_set'); // ローカルストレージ 保存名
wywg_set=JSON.parse(read_json);
if(wywg_set==null){
    wywg_set=[0, 16, 1.6, 1, 1, 1, 1, "#3970b5", "#cccccc", 1, "#ffffff", "#2b5d75",
              1, 1, 1, 1, 1, 1, 1, 0, 0]; }
if(wywg_set.length<21){
    wywg_set[20]=0; }


let write_json=JSON.stringify(wywg_set);
localStorage.setItem('Wywg_set', write_json); // ローカルストレージ 保存


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){
        main(); }}



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

    insert_tag();
    stylus_active();

} // main()



function insert_tag(){
    let l_body=document.querySelector('.l-body');
    let bgc1=window.getComputedStyle(l_body, null).getPropertyValue('background-color');
    let cke_contents=document.querySelector('.cke_contents');
    let bgc2=window.getComputedStyle(cke_contents, null).getPropertyValue('background-color');
    let bdc1=window.getComputedStyle(cke_contents, null).getPropertyValue('border-color');

    let style_text='';

    style_text+='.cke_editable { ';

    if(wywg_set[0]==0){
        style_text+='font-family: Meiryo, sans-serif !important; '; }
    else if(wywg_set[0]==1){
        style_text+='font-family: "MS Pゴシック", sans-serif !important; '; }

    style_text+='font-size: '+ wywg_set[1] +'px !important; line-height: '+ wywg_set[2] +'; } ';

    if(wywg_set[3]==1){
        if(wywg_set[0]==0){
            style_text+=
                '.cke_editable img[src*="emoji.ameba.jp"] { vertical-align: -2px; } '+
                '.cke_editable img[src*=char2] { vertical-align: -2px; } '+
                '.cke_editable img[src*=char3], '+
                '.cke_editable img[src*=char4] { vertical-align: -3px; margin-top: -4px; } '; }
        else if(wywg_set[0]==1){
            style_text+=
                '.cke_editable img[src*="emoji.ameba.jp"], '+
                '.cke_editable img[src*=char2] { vertical-align: 0; margin: 0; } '+
                '.cke_editable img[src*=char3], '+
                '.cke_editable img[src*=char4] { vertical-align: -3px; margin-top: -4px; } '; }}

    if(wywg_set[4]==1){
        style_text+='video, img { vertical-align: middle; } '; }

    if(wywg_set[5]==1){
        style_text+=
            '.cke_editable h2, .cke_editable h3, .cke_editable h4 { font-weight: bold; } '; }

    if(wywg_set[6]==1){
        style_text+=
            'a, a:visited { color: '+ wywg_set[7] +
            '; text-decoration-color: '+ wywg_set[8] +'; } '; }

    if(wywg_set[9]==1){
        style_text+=
            'body :not(img)::selection { color: '+ wywg_set[10] +
            '; background: '+ wywg_set[11] +'; } '; }

    if(wywg_set[12]==1){
        style_text+=
            'body img[src*="/img/char/"]::selection { background: rgba(96, 125, 139, 0.2); } '+
            'body img[src*="/img/decoPeta/"]::selection { background: rgba(96, 125, 139, 0.2); } '+
            'body a > img::selection { background: transparent; } '+
            'body img:hover { outline: 1px solid #2196f3; opacity: 1; } '+
            '.ck-imgmask { border: 2px solid #2196f3; } '; }

    if(wywg_set[13]==1){
        style_text+=
            '.cke_editable iframe[src*="youtube"] { '+
            'display: block; margin: 0 auto; width: 80%; height: 320px; } '; }

    if(wywg_set[14]==1){
        style_text+=
            '.youtube_iframe { pointer-events: auto; } '; }

    if(wywg_set[15]==1){
        style_text+=
            '.cke_editable pre { font-size: 1em; font-family: inherit; } '; }

    if(wywg_set[16]==1){
        let style_text_head=
            '@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"); '
        style_text=style_text_head + style_text; }

    if(wywg_set[17]==1){
        style_text+=
            '.cke_editable { min-height: 100vh; overflow-y: scroll; '+
            'margin: 0 auto !important; padding: 12px 8px 0; color: #000; '+
            'box-shadow: #f8f8f8 0 -8px 0 8px inset, '+ bgc2 + ' 0 0 0 50vw; } '+
            '.cke_editable:focus { outline: none; } '+
            '.cke_editable_black { '+
            'box-shadow: inset 0 -8px 0 8px #3a3a3a, '+ bgc2 +' 0 0 0 50vw; '+
            'color: #fff; } '; }

    if(wywg_set[18]==1){
        style_text+=
            '::-webkit-scrollbar { width: 16px; } '+
            '::-webkit-scrollbar-track { background: ' + bgc2 + '; } '+
            '::-webkit-scrollbar-thumb { background: ' + bgc1 + '; '+
            'box-shadow: inset 0 0 0 .5px ' + bdc1 + '; } '; }


    let insert_style;
    let editor_iframe=document.querySelector('.cke_wysiwyg_frame');
    if(editor_iframe){ // iframe読込みが実行条件
        let iframe_doc=editor_iframe.contentWindow.document;
        if(iframe_doc){
            let iframe_body=iframe_doc.querySelector('body.cke_editable');
            let iframe_html=iframe_doc.querySelector('html');

            insert_style=iframe_doc.createElement("style");
            insert_style.appendChild(iframe_doc.createTextNode(style_text));
            insert_style.setAttribute("class", "iframe_style");

            if(!iframe_doc.querySelector('.iframe_style')){
                iframe_html.appendChild(insert_style); }}}



    let outer_style_text=''; // body側(iframe外)に適用するCSS
    if(wywg_set[16]==1){
        let outer_style_text_head=
            '@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"); ';
        outer_style_text+=outer_style_text_head; }

    if(wywg_set[20]==1){
        outer_style_text+='.p-photos-editorDropArea { display: none; } '; }

    let insert_outer_style=document.createElement("style");
    insert_outer_style.appendChild(document.createTextNode(outer_style_text));
    insert_outer_style.setAttribute("class", "outer_style");

    if(!document.querySelector('.outer_style')){
        document.documentElement.appendChild(insert_outer_style); }

} // insert_tag()



function setup(){
    let bfont=document.getElementsByName('bfont');
    if(bfont.length==3){
        if(wywg_set[0]==0){
            bfont[0].checked=true; }
        else if(wywg_set[0]==1){
            bfont[1].checked=true; }
        else{
            bfont[2].checked=true; }}

    for(let k=0; k<bfont.length; k++){
        bfont[k].addEventListener('change', function(){
            if(bfont[k].checked){
                wywg_set[0]=k; }

            let write_json=JSON.stringify(wywg_set);
            localStorage.setItem('Wywg_set', write_json); // ローカルストレージ 保存

            renew_insert_tag();
        }); }


    input_value_setter(1);
    input_value_setter(2);
    checkbox_setter(3);
    checkbox_setter(4);
    checkbox_setter(5);
    checkbox_setter(6);
    input_value_setter(7);
    input_value_setter(8);
    checkbox_setter(9);
    input_value_setter(10);
    input_value_setter(11);
    checkbox_setter(12);
    checkbox_setter(13);
    checkbox_setter(14);
    checkbox_setter(15);
    checkbox_setter(16);
    checkbox_setter(17);
    checkbox_setter(18);
    checkbox_setter(19);
    checkbox_setter(20);

} // setup()



function checkbox_setter(k){
    let wywg=document.querySelector('#wywg'+k);
    if(wywg){
        if(wywg_set[k]==1){
            wywg.checked=true; }
        else{
            wywg.checked=false; }

        wywg.onclick=function(){
            if(wywg_set[k]==1){
                wywg.checked=false;
                wywg_set[k]=0; }
            else{
                wywg.checked=true;
                wywg_set[k]=1; }
            let write_json=JSON.stringify(wywg_set);
            localStorage.setItem('Wywg_set', write_json); // ローカルストレージ 保存
            renew_insert_tag(); }}}



function input_value_setter(k){
    let wywg=document.querySelector('#wywg'+k);
    if(wywg){
        wywg.value=wywg_set[k];

        wywg.onchange=function(){
            wywg_set[k]=wywg.value;
            let write_json=JSON.stringify(wywg_set);
            localStorage.setItem('Wywg_set', write_json); // ローカルストレージ 保存
            renew_insert_tag(); }}}



function renew_insert_tag(){
    let editor_iframe=document.querySelector('.cke_wysiwyg_frame');
    if(editor_iframe){ // iframe読込みが実行条件
        let iframe_doc=editor_iframe.contentWindow.document;
        if(iframe_doc){
            let iframe_body=iframe_doc.querySelector('body.cke_editable');
            let iframe_html=iframe_doc.querySelector('html');

            if(iframe_doc.querySelector('.iframe_style')){
                iframe_doc.querySelector('.iframe_style').remove(); }}}

    if(document.querySelector('.outer_style')){
        document.querySelector('.outer_style').remove(); }

    insert_tag(); }



function disp_panel(){
    let css=
        '.wywg_menu { position: absolute; top: 10px; right: 10px; font: 16px/32px Meiryo; '+
        'padding: 0.6em 1em; border: 1px solid #009688; border-radius: 4px; z-index: 15; '+
        'background: #f9fafa; box-shadow: 6px 6px 20px rgba(0, 0, 0, 0.3); } '+
        '#wywg_close { display: inline-block; padding: 0 3px; height: 19px; '+
        'line-height: 20px; border: 1px solid #aaa; border-radius: 2px; cursor: pointer; } '+
        '.wywg_menu input { height: 18px; font-family: system-ui; text-align: center; '+
        'margin-right: 6px; } '+
        '.wywg_menu input[type="radio"] { margin-right: 3px; vertical-align: -3px; } '+
        '.wywg_menu label { margin-left: 1em; } '+

        '#wywg1, #wywg2 { width: 50px; } '+
        '#wywg3, #wywg4, #wywg5, #wywg6, #wywg9, #wywg12, #wywg13, #wywg14, '+
        '#wywg15, #wywg16, #wywg17, #wywg18, #wywg19, #wywg20 { vertical-align: -3px; } '+
        '#wywg7, #wywg8, #wywg10, #wywg11 { height: 26px; width: 22px; margin: 0; '+
        'border: none; background: none; vertical-align: -3px; } ';

    if(ua==1){
        css+=
            '.wywg_menu input[type="radio"] { vertical-align: -1px; } '+
            '#wywg3, #wywg4, #wywg5, #wywg6, #wywg9, #wywg12, #wywg13, #wywg14, '+
            '#wywg15, #wywg16, #wywg17, #wywg18, #wywg20 { vertical-align: -1px; } '+
            '#wywg7, #wywg8, #wywg10, #wywg11 { height: 18px; width: 18px; }'; }

    let wywg_style=document.createElement('style');
    wywg_style.textContent=css;

    let menu=document.createElement('div');
    menu.setAttribute('class', "wywg_menu");
    // パネルの表示内容
    let menu_content=
        '      〔 Ameblo Wysiwyg Menu 〕     <b id="wywg_close">✖</b><br>'+
        '基本フォント <label><input type="radio" name="bfont" value="1">メイリオ</label>'+
        '<label><input type="radio" name="bfont" value="2">MS Pゴシック</label>'+
        '<label><input type="radio" name="bfont" value="3">無指定</label><br>'+
        '基本フォントサイズ   '+
        '<input id="wywg1" type="number" step="1" min="12" max="20">px<br>'+
        '基本行間隔       '+
        '<input id="wywg2" type="number" step=".1" min=".5" max="3"><br>'+
        '<input id="wywg3" type="checkbox">アメブロ絵文字 位置補正<br>'+
        '<input id="wywg4" type="checkbox">画像・動画の下側行との間隔補正<br>'+
        '<input id="wywg5" type="checkbox">h2・h3・h4 見出し 太字指定<br>'+
        '<input id="wywg6" type="checkbox">リンク文字列の色指定    '+
        '文字色 <input id="wywg7" type="color"> 下線色 <input id="wywg8" type="color"><br>'+
        '<input id="wywg9" type="checkbox">選択文字列の反転色指定   '+
        '文字色 <input id="wywg10" type="color"> 背景色 <input id="wywg11" type="color"><br>'+
        '<input id="wywg12" type="checkbox">選択範した画像・アメブロ絵文字の透過反転色<br>'+
        '<input id="wywg13" type="checkbox">Youtube動画 中央配置<br>'+
        '<input id="wywg14" type="checkbox">Youtube動画 編集枠内で再生可能にする<br>'+
        '<input id="wywg15" type="checkbox">PRE枠内を基本フォントで表示<br>'+
        '<input id="wywg16" type="checkbox">Font Awesome の @import指定<br>'+
        '== Ameblo Writer 適用時の編集枠内デザイン ==<br>'+
        '<input id="wywg17" type="checkbox">編集枠の余白部配色<br>'+
        '<input id="wywg18" type="checkbox">編集枠スクロールバー配色 (Chrome/Edgeで有効)<br>'+
        '== Ameblo Writer の編集枠の機能指定 =====<br>'+
        '<input id="wywg20" type="checkbox">編集枠への画像のドラッグ&ドロップを無効にする<br>'+
        '<br>'+
        'Ameblo Writer(Compact) と Ameblo Wysiwyg の指定<br>'+
        'が競合する項目は Ameblo Writer が優先になります<br>';


    let editor_iframe=document.querySelector('.cke_wysiwyg_frame');
    if(editor_iframe){
        let iframe_doc=editor_iframe.contentWindow.document;
        if(iframe_doc){
            let stylus_tag=iframe_doc.querySelector('.stylus');
            if(stylus_tag){
                menu_content+=
                    '<br>'+
                    '----------------------------------------------------------<br>'+
                    '📛 拡張機能「Stylus」の編集枠内のCSS修飾が有効です<br>'+
                    '<input id="wywg19" type="checkbox">編集起動時のこの警告を非表示にする'; }}}


    menu.innerHTML=menu_content;
    menu.appendChild(wywg_style);

    if(!document.querySelector('.wywg_menu')){
        document.querySelector('.l-body').appendChild(menu); }

    setup();

} // disp_panel()



on_off_panel();

function on_off_panel(){
    let l_form=document.querySelector('.l-form');
    let wywg_sw=document.querySelector('.p-editorStyle');
    let wywg_menu=document.querySelector('.wywg_menu');
    if(l_form && wywg_sw){
        wywg_sw.onclick=function(event){
            if(event.ctrlKey){
                event.preventDefault();
                event.stopImmediatePropagation();
                if(menu_view==0){
                    menu_view=1;
                    disp_panel();
                    l_form.style.marginLeft='10px';
                    l_form.style.marginRight='auto'; }
                else{
                    menu_view=0;
                    wywg_menu.remove();
                    l_form.style.marginLeft='auto';
                    l_form.style.marginRight='auto'; }

                on_off_panel(); }}}


    let close=document.querySelector('#wywg_close');
    if(l_form && close && wywg_menu){
        close.onclick=function(event){
            event.preventDefault();
            menu_view=0;
            wywg_menu.remove();
            l_form.style.marginLeft='auto';
            l_form.style.marginRight='auto'; }}

} //on_off_panel()



let once=0;

function stylus_active(){
    if(wywg_set[19]==0){
        let editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        if(editor_iframe){
            let iframe_doc=editor_iframe.contentWindow.document;
            if(iframe_doc){
                let stylus_tag=iframe_doc.querySelector('.stylus');
                if(stylus_tag && once==0){
                    once=1;
                    alert(
                        "📛 拡張機能「Stylus」の編集枠内のCSS修飾が有効になりました\n\n"+
                        "  Ameblo Writer(Compact)と Ameblo Wysiwyg の指定が\n"+
                        "  競合する修飾項目は Ameblo Writer の指定が優先になります");

                }}}}} // stylus_active()



 

 

 

「Ameblo Wysiwyg ⭐」最新版について 

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

 

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