常に記事の最初から表示される「プレビュー」

編集画面が完全な「WYSIWYG」環境なら、プレビュー機能は不要です。 しかし、ブログスキンで表示要素の配置に微妙な調節を加えているものがあり、その修飾は編集画面上では働かず、「WYSIWYG」環境に綻びが出来ます。「WYSIWYG」を不完全にする要素は色々とあり、細部の確認にはプレビューが必要です。

 

さて、最新版エディタの「プレビュー」機能ですが、表示自体は正確ですが、毎回記事の先頭からの表示になります。 長文の記事や画像を沢山載せた記事を書いている場合など、記事末尾のプレビューは、プレビュー画面を表示してから末尾までスクロールする必要があります。 細部の表示に拘りがあるユーザーには、先頭からしか表示できないプレビューは扱い難い仕様です。

 

 

 

編集している場所をプレビュー表示する 

これを実現するには、編集画面の「編集枠」のスクロール位置を取得し、プレビュー画面でそのスクロール分を自動的にスクロールして表示すれば良いわけです。 しかし、このコードを作って見ると以下の原因で上手く動作しません。

 

◎「編集画面」「プレビュー画面」ともに、要素の取得がしづらい「iframe」。

◎「プレビュー画面」は、記事タイトル部分を先頭に表示する仕様。

 

特に後者のプログラムは、こちらが先にスクロール指定をすると、後から打ち消してしまいます。 この仕様が、とても邪魔になりました。 最初は「0.8sec」を待機してから、こちらのスクロールを実行していましたが、最終的に「interval」を使って待機監視するコードにしました。 この方が明らかに待機の無駄が減ります。

 

以下が、プレビューに関わるコードです。

 

function preview_line(){
    let native_line;

    let preview_button=document.querySelector('.p-header__tab__item__preview');
    preview_button.onclick=function(){

        let editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        if(editor_iframe){ // iframe読込みが実行条件
            let iframe_doc=editor_iframe.contentWindow.document;
            native_line=iframe_doc.querySelector('html').scrollTop; // 通常表示のスクロール位置を取得
            let retry=0;
            let interval=setInterval(wait_preview, 50);
            wait_preview();

            function wait_preview(){
                retry ++;
                if(retry>40){ // リトライ制限 40回 2sec
                    clearInterval(interval); }
                let target_iframe=document.querySelector('#js-preview-frame-pc'); // 監視 target
                if(target_iframe){
                    let target_html=target_iframe.contentWindow.document.querySelector('html');
                    if(target_iframe && target_html.scrollTop!=0){
                        clearInterval(interval);
                        target_html.style.scrollBehavior='initial';
                        setTimeout(()=>{
                            let entry=target_html.querySelector('[data-uranus-component="entryBody"]');
                            entry.scrollIntoView();
                        }, 100);
                        setTimeout(()=>{
                            target_html.scrollBy(0, native_line);
                        }, 200); }}}}}

        } // preview_line()

 

target_html.scrollTop!=0」となるのを「interval」で「50msec」間隔でチェックしています。 もしスクロール量が「0」で無くなれば、アメブロのスクロール操作が済んだ事になります。

 

これをトリガーにして、「entry.scrollIntoView();」を実行し、記事本文部が先頭になるまでスクロールし、更に「 target_html.scrollBy(0, native_line);」で、編集画面のスクロール分をスクロールします。

 

 

 

プレビューの自動スクロール機能の仕様 

● 各種の編集補助機能を持つ「Editor Keeper ⭐📛」にこの機能を統合しました。

 

● この機能は、プレビュー表示が「同じウインドウ」の場合にのみ動作します。

 

 

● 正確なスクロール量を取得するために「デザイン幅で表示」の選択が必要です。

 

●「Ameblo Writer」「Amebl Witer Compact」のスタイルを適用して、「編集画面のフォント種・サイズ」を「ブログ記事本文」と統一する事がお勧めの環境です。

 

● 記事内に配置された要素「iframeの動画」「リブログカード」「画像」「ツイッター埋込」などにより、プレビュー表示の位置が数行ズレる場合があります。

 

 

 

 「Editor Keeper ⭐📛」ver. 2.1

このツールは Chrome / 新Edge / Firefox の「Tampermonkey」で動作します。

このツールの他の機能については、以下のページを参照ください。

 

   編集画面を閉じずに「ブログトップ」「管理トップ」を開くスイッチ 

   画像貼り付け設定を記録する 

   絵文字タブの初期表示を保持 

   バナータブの初期表示を保持 

 

 

ツールの導入方法 

以下のコードを「Tampermonkey」の新規スクリプトの作成画面にコピー&ペーストして保存する事で、このツールを利用する事が出来ます。

 

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

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

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


 

〔 Editor Keeper ⭐📛 〕 ver. 2.1

 

// ==UserScript==
// @name         Editor Keeper ⭐📛
// @namespace    http://tampermonkey.net/
// @version      2.1
// @description  編集画面を閉じず「管理トップ」「ブログトップ」に移動する
// @author        Ameblo Writer 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.querySelector('.l-gHeaderLeft__link a'); // 監視 target
    if(target){
        clearInterval(interval);
        button_disp();
        keeper();
        environ();
        preview_line();
    }}



function button_disp(){
    let ua=0; // Chromeの場合のフラグ
    let agent=window.navigator.userAgent.toLowerCase();
    if(agent.indexOf('firefox') > -1){ ua=1; } // Firefoxの場合のフラグ
    if(agent.indexOf('edg') > -1){ ua=2; } // NEdgeの場合のフラグ

    // 以下 起動表示CSSを適用 📛
    let css;
    if(ua==0){
        css=
            '.l-gHeaderLeft__link a:before { content: "" !important; }'+
            '.l-gHeaderLeft__link a:after { content: "⏏" !important; font-size: 24px !important; '+
            'line-height: 16px !important; top: 2px !important; left: 6px !important; }'+
            '.l-gHeaderLeft__link a { text-indent: -6.3em !important; height: 31px !important; padding-top: 3px; }'+
            '.l-gHeaderLeft__link a:hover { text-indent: 0.4em !important; background: #fff !important; '+
            'width: calc(28px + 6.7em) !important; box-shadow: -10px 0 1px 0 var(--bgc1) !important; }'+
            '#globalHeader #gHeaderLeft { width: 280px; }'; }
    if(ua==1){
        css=
            '.l-gHeaderLeft__link a:before { content: "" !important; }'+
            '.l-gHeaderLeft__link a:after { content: "⏏" !important; font-size: 36px !important; '+
            'line-height: 4px !important; top: 7px !important; left: 2px !important; }'+
            '.l-gHeaderLeft__link a { text-indent: -6em !important; height: 30px !important; padding-top: 4px; }'+
            '.l-gHeaderLeft__link a:hover { text-indent: 0.7em !important; background: #fff !important; '+
            'width: calc(28px + 6.7em) !important; box-shadow: -10px 0 1px 0 var(--bgc1) !important; }'+
            '#globalHeader #gHeaderLeft { width: 280px; }'; }
    if(ua==2){
        css=
            '.l-gHeaderLeft__link a:before { content: "" !important; }'+
            '.l-gHeaderLeft__link a:after { content: "\\EA37" !important; '+
            'font: normal 30px/8px ameba-symbols !important; top: 10px !important; left: 3px !important; }'+
            '.l-gHeaderLeft__link a { text-indent: -6.3em !important; height: 31px !important; padding-top: 3px; }'+
            '.l-gHeaderLeft__link a:hover { text-indent: 0.4em !important; background: #fff !important; '+
            'width: calc(28px + 6.7em) !important; box-shadow: -10px 0 1px 0 var(--bgc1) !important; }'+
            '#globalHeader #gHeaderLeft { width: 280px; }'; }

    let style_tag=document.createElement("style"); // css設定styleタグ
    style_tag.type="text/css";
    style_tag.appendChild(document.createTextNode(css));
    document.querySelector('.l-body').appendChild(style_tag);

} // button_disp()



function keeper(){
    let target=document.querySelector('.l-gHeaderLeft__link a');
    target.setAttribute('target', '_blank');

    target.onclick=function(){
        if(event.shiftKey){
            event.preventDefault();
            let amebaId=document.querySelector('.amebaId').textContent;
            if(amebaId){
                let blogurl='https://ameblo.jp/' + amebaId + '/';
                window.open(blogurl, "_blank"); }}}

    window.addEventListener('keydown', function(event){
        if(event.shiftKey==true){
            target.textContent='ブログトップ';
            target.style.boxShadow='#00e2ff -14px 0 0 0 inset';
            window.addEventListener('keyup', function(event){
                target.textContent='管理トップへ';
                target.style.boxShadow='#79fbf6 -14px 0 0 0 inset'; });}});

    let editor_iframe=document.querySelector('.cke_wysiwyg_frame');
    if(editor_iframe){ // iframe読込みが実行条件
        let iframe_doc=editor_iframe.contentWindow.document;
        iframe_doc.addEventListener('keydown', function(event){
            if(event.shiftKey==true){
                target.textContent='ブログトップ';
                target.style.boxShadow='#00e2ff -14px 0 0 0 inset';
                iframe_doc.addEventListener('keyup', function(event){
                    target.textContent='管理トップへ';
                    target.style.boxShadow='#79fbf6 -14px 0 0 0 inset'; });}}); }
} // keeper()



function environ(){
    let aw_preset=[]; // Ameblo Writer のユーザー設定
    set_db();

    function set_db(){
        let read_json=localStorage.getItem('AWriter_Preset'); // ローカルストレージ 保存名
        aw_preset=JSON.parse(read_json);
        if(aw_preset==null){
            aw_preset=[0,0,0,0,0]; }
        else{
            let db_length=aw_preset.length;
            for(let k=0; k<5-db_length; k++){ //「5」は配列指定数
                aw_preset.push(0); }}
        let write_json=JSON.stringify(aw_preset);
        localStorage.setItem('AWriter_Preset', write_json); } // ローカルストレージ 保存


    photo_size();

    function photo_size(){
        let ph_size=document.querySelectorAll('.js-photo-paste-size');
        if(ph_size.length>0){
            ph_size[aw_preset[0]].click(); } // サイズボタンをストレージ記録に従って押す

        for(let k=0; k<ph_size.length; k++){ // 押されたサイズボタンを記録する
            ph_size[k].onclick=function(){
                storage_w(0, k); }}} // サイズ選択をローカルストレージ 保存


    picto_select1();

    function picto_select1(){
        let pict_nav=document.querySelectorAll('.js-pictograph-nav');
        let pict_button=document.querySelector('button[data-side-content="pictograph"]');
        pict_button.onclick=function(){
            if(pict_nav.length>0){
                pict_nav[aw_preset[2]].click(); }}

        for(let k=0; k<pict_nav.length; k++){
            pict_nav[k].onclick=function(){
                if(k==1){
                    picto_select2(); } // 絵文字のパレットを記録に従って開く
                storage_w(2, k); }}} // 履歴・絵文字の選択をローカルストレージ 保存


    function picto_select2(){
        let pict_nav2=document.querySelectorAll('.js-pictograph-subNav');
        if(pict_nav2.length>0){
            pict_nav2[aw_preset[3]].click(); }

        for(let k=0; k<pict_nav2.length; k++){
            pict_nav2[k].onclick=function(){
                storage_w(3, k); }}} // 絵文字のパレット選択をローカルストレージ 保存


    coax_select();

    function coax_select(){
        let coax_nav=document.querySelectorAll('.js-coax-nav');
        let coax_button=document.querySelector('button[data-side-content="coax"]');
        coax_button.onclick=function(){
            if(coax_nav.length>0){
                coax_nav[aw_preset[4]].click(); }}

        for(let k=0; k<coax_nav.length; k++){
            coax_nav[k].onclick=function(){
                storage_w(4, k); }}} // おねだりバナーの選択をローカルストレージ 保存


    let p_images=document.querySelector('.p-images-imageList__body'); // 監視 target
    let monitor=new MutationObserver(photo_pos);
    monitor.observe(p_images, {childList: true, subtree: true}); // 画像リストの変化を監視開始

    function photo_pos(){
        let item=document.querySelectorAll('.p-images-imageList__item');
        for(let k=0; k<item.length; k++){
            set_pos(k); }

        function set_pos(k){ // 画像の挿入時に配置指定を実行
            item[k].addEventListener('mouseup', function(){
                let editor_iframe=document.querySelector('.cke_wysiwyg_frame');
                if(editor_iframe){ // iframe読込みが実行条件
                    let iframe_doc=editor_iframe.contentWindow.document;

                    let post_img_p=iframe_doc.getSelection().anchorNode;
                    if(aw_preset[1]==1){
                        post_img_p.setAttribute("style", "text-align: center;"); }
                    else if(aw_preset[1]==2){
                        post_img_p.setAttribute("style", "text-align: right;"); }

                    setTimeout(()=>{
                        dialogue(); }, 20); }});
        } // set_pos()
    } // photo_pos()


    dialogue();

    function dialogue(){
        let editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        if(editor_iframe){ // iframe読込みが実行条件
            let iframe_doc=editor_iframe.contentWindow.document;

            let post_img=iframe_doc.querySelectorAll('.cke_editable img');
            for(let k=0; k<post_img.length; k++){
                post_img[k].addEventListener('click', function(){
                    setTimeout(()=>{
                        get_set(); }, 20); }); }

            function get_set(){ // 画像ダイアログのサイズ・位置選択を取得
                let size_button=document.querySelectorAll('.js-image-size-button');
                for(let k=0; k<size_button.length; k++){
                    size_button[k].addEventListener('mouseup', function(){
                        storage_w(0, k); // サイズ選択をローカルストレージ 保存
                        photo_size(); }); } // 右パレットのサイズボタンを押す

                let pos_button=document.querySelectorAll('.ck-imgJustify');
                for(let k=0; k<pos_button.length; k++){
                    pos_button[k].addEventListener('mouseup', function(){
                        if(pos_button[k].classList.contains('ck-imgJustify--active')!=true){
                            storage_w(1, k); } // 位置選択をローカルストレージ 保存
                        else {
                            storage_w(1, 0); }}); } // 位置リセットをローカルストレージ 保存
            } // get_set()
        }} // dialogue()


    function storage_w(ele, val){ // 編集環境のローカルストレージ保存
        aw_preset[ele]=val;
        let write_json=JSON.stringify(aw_preset);
        localStorage.setItem('AWriter_Preset', write_json); }

} // environ()



function preview_line(){
    let native_line;

    let preview_button=document.querySelector('.p-header__tab__item__preview');
    preview_button.onclick=function(){

        let editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        if(editor_iframe){ // iframe読込みが実行条件
            let iframe_doc=editor_iframe.contentWindow.document;
            native_line=iframe_doc.querySelector('html').scrollTop; // 通常表示のスクロール位置を取得
            let retry0=0;
            let interval0=setInterval(wait_preview, 50);
            wait_preview();

            function wait_preview(){
                retry0 ++;
                if(retry0>40){ // リトライ制限 40回 2sec
                    clearInterval(interval0); }
                let target_iframe=document.querySelector('#js-preview-frame-pc'); // 監視 target
                if(target_iframe){
                    let target_html=target_iframe.contentWindow.document.querySelector('html');
                    target_html.style.scrollBehavior='initial';
                    if(target_iframe && target_html.scrollTop!=0){
                        clearInterval(interval0);
                        target_html.style.scrollBehavior='initial';
                        setTimeout(()=>{
                            let entry=target_html.querySelector('[data-uranus-component="entryBody"]');
                            entry.scrollIntoView();
                        }, 100);
                        setTimeout(()=>{
                            target_html.scrollBy(0, native_line);
                        }, 200); }}}}}

} // preview_line()


 

 

 

「Editor Keeper ⭐📛」最新版について 

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

 

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