承認コメントのグリーンマークの保持時間の設定

承認直後のコメントに、時間限定でマークを表示する機能を盛り込みました。 このマークにより、承認したコメントが何処に行ったか判らなくなる事が防げます。 また、複数のコメントに返信している間に、コメントを見ないまま見落とす事が、かなり防げると思います。

 

多数のコメントがある方は、コメントの見落しを避けるために、1コメントずつ「承認」→「返信」をされているのかも知れませんね。 私は、コメント数が少ないので、気付かなかったのですが、毎日何10件ものコメントをやりとりしている方は、どうされているのでしょう?

 

前ページのグリーンマークはプロトタイプで、更に色々なユーザーの場合に合わせた使い勝手を考慮すべきと思っています。 その最初の試みとして「マークの保持時間」の設定を変更出来る様にしました。

 

 

 

3種のマーク保持時間の選択 

「設定」ページのメニューに下の新しい選択メニューを追加しました。

 

 

◎「3分」の設定は、「承認」をしてすぐに「公開済み」を開いた場合に、「承認」したコメントがどれかを示す機能だけとして使う場合です。 すぐに3分は過ぎるので、このマークを余り必要としない場合には、マークが邪魔にならない設定です。

 

◎「1時間」の設定は、一般的な使用で適当な設定かと思います。 普通のユーザーはコメントを「承認」してから1時間も放置しないでしょうから。

 

◎「6時間」の設定を最長としました。 これ以上の時間を設定すると、次に「承認」操作があった場合に、それまでに放置していたデータが引き継がれる事が増えます。

 

「コメント管理」ではコメントを「承認」するだけで、「返信」はブログ画面で書くユーザーも居られるでしょう。 その使い方では「コメント管理」画面では未処理と同じなので、未処理コメントを大量に抱えた Cookieが出来上がります。 そういった場合を考えて Cookieの上限時間を「6時間」としました。 ユーザーが寝ている時間はあるだろうから、その間に Cookieをリセットするというわけです。

 

 

未だもっと練る必要があります 

現在は「返信する」「」「」「」のボタン操作で、グリーンマークがリセットされる仕様です。 これは少し操作しただけでマークが無くなります。 これに対して、「返信コメント」を実際に「送信」した場合だけマークが消え、「返信」せずにマークを消す場合は、何かの手段を用意するという仕様が考えられます。 つまり、もう少し確実なユーザー判断で消せるマークの仕様です。 これは、後の課題にします。

 

 

 

グリーンマークの Cookieによる管理 

「グリーンマーク」は、Cookieにコメント固有の「コメント番号」を記録して、それが記録されていたらマークを表示するコードで、実現しています。

 

下は、「承認」ボタンを押した時に、そのコメントの「コメント番号」を Cookieに保存する関数です。

 

function memo_app(){
    let app_button=document.querySelectorAll('[data-section-id="comment_approve"]');
    for(let k=0; k<app_button.length; k++){
        app_button[k].addEventListener('mousedown', function(){
            let comm_id=app_button[k].getAttribute('data-comment-id');
            let approve_id=get_cookie('new_comm_id');
            cookie_write(approve_id, comm_id); }); }

    function cookie_write(value0, value1){
        if(value0==0){
            document.cookie=
                  'new_comm_id='+value1+'; Max-Age='+save_t; }
        else{
            let arr=value0.split('%');
            arr.push(value1);
            let approve_id_n=arr.join('%');
            document.cookie=
                'new_comm_id='+approve_id_n+'; Max-Age='+save_t; }}}

 

主要な部分は後半のサブの関数で、2つの因数は「それまでの Cookie値」「追加するコメント番号」です。 登録に使用される Cookie名は「new_comm_id」で、その値はコメント番号の羅列した文字列です。

 

例えば、承認したコメントが3件の場合は、Cookieの記録には下の様になります。

 

 13112942018%13112590344%13104427389

 

コメント番号は11桁で、「%」は区切り文字として入れています。

後半のサブ関数は、これに新しい「コメント番号」を追加する関数で、青文字の部分で新しい Cookie値に書変えています。

 

上の例だと、「%」で繋いだ3個の「コメント番号」を一旦配列に分離して、配列に新しい「コメント番号」を追加し、配列をもう一度「%」の区切り文字で繋ぐという操作です。 まわりくどい方法ですが、これが一番問題のないコードです。

 

下は何かのボタンを押した場合に、操作したコメントの「コメント番号」を Cookieの値から削除する関数です。

 

function app_reset(item){
    let approve_id=get_cookie('new_comm_id');
    let menu_button=item.querySelector('.userList__menu');
    let sendbutton=item.querySelector('.commentList .sendButton');
    if(sendbutton){
        menu_button.classList.remove('co_menu');
        let id=sendbutton.getAttribute('data-comment-id');
        let arr=approve_id.split('%');
        let arr_d=arr.filter(function(value){
            return value!=id; });
        let approve_id_d=arr_d.join('%');
        document.cookie=
            'new_comm_id='+approve_id_d+'; Max-Age='+save_t; }}

 

青文字の部分で、それまでの Cookie値をいったん「%」を外して「コメント番号」の「配列」に変換し、そこから処理しているコメントの「コメント番号」を除外し、再び「%」を間に入れて繋いで、新しい Cookie値を得ています。 最後の行で、それを Cookieに保存して、マーク削除の処理が完了します。

 

以上の様に、1コメントあたり「11桁」の数が Cookieに追加され、余り沢山の未処理コメントを抱えると、ページの Cookieデータ制限が気になります。

 

調べると、Chromeの Cookieデータの制限は、「ドメインあたり180個、Cookieの1個は4096byte以下」の制限がある様です。 約4000byteを「11桁と%」で埋めたとすると、300程度のコメント数が記録できます。 6時間の制限を設けたので、未処理コメントが300も溜まる事は、スタブロでもなければ普通はないでしょう。

 

Cookieの個数では、現在のこのツールは、常用3個、一時的(短時間)2個、を使っていますが、これも全く問題ないでしょう。 DevToolsで見ると、このページで使われる Cookieは、他のプログラムを全て合わせても20個程度でした。

 

 

 

 

「Comment C-O」 ver. 0.6 

「Comment C-O」は「コメント管理」ページのコメントリストの操作性を改善するツールです。

 

◎ このツールの使用には「Ameblo Management  ver.2020.10.30」以降の適用が必須です。「Ameblo Management」の導入方法は以下のページを参照ください。

 

 

 

 

ツールを導入するには 

「Comment C-O」は Chrome / Edge / Firefox の拡張機能の「Tampermonkey」上で動作します。

 

❶「Tampermonkey」を導入します

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

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

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

 

 

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

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

 

 

 

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

 

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

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

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

 

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

 

 

〔 Comment C-O 〕 ver. 0.6

 

// ==UserScript==
// @name         Comment C-O
// @namespace    http://tampermonkey.net/
// @version      0.6
// @description  コメント管理画面のリスト開閉機能
// @author       Ameba Blog User
// @match        https://blog.ameba.jp/ucs/comment/comment*
// @noframes
// @run-at        document-start
// @grant        none
// ==/UserScript==

let save_t;

window.addEventListener('DOMContentLoaded', function(){
    environ();
    set_items();
    list_mode();
    save_set();

    function environ(){
        let css=
            '.userList__item { position: relative; } '+
            '.userList__item:focus { outline: 2px solid #2196f3; } '+
            '.userList__text { display: none; } '+
            '.userList__information { top: 42px; right: 330px; } '+
            '.userList__buttons { top: 38px; right: 76px; } '+
            '.co_view { width: 29px; height: 29px; margin-left: 16px; color: #888; '+
            'font: 16px/30px Meiryo; padding: 0; border: 1px solid #aaa; '+
            'border-radius: 4px; background: #fff; cursor: pointer; } '+
            '.co_menu { '+
            'background: linear-gradient(#26c6da 0%, #009688 70%) !important; } '+
            '.co_menu:hover { '+
            'background: linear-gradient(#009688 0%, #26c6da 100%) !important; } '+
            '.co_menu svg { fill: #fff; } '+
            '.item_close { position: absolute; margin: 0 !important; } '+
            '.userList__tooltip { z-index: 1; }';

        let style=document.createElement('style');
        style.setAttribute('id', 'co_list');
        style.innerHTML=css;

        let target=document.querySelector('body');
        if(!target.querySelector('#co_list')){
            target.appendChild(style); }}


    function set_items(){
        let items=document.querySelectorAll('.userList__item');
        for(let k=0; k<items.length; k++){
            items[k].setAttribute('tabindex', '0');
            let information=items[k].querySelector('.userList__information');
            let buttons=items[k].querySelector('.userList__buttons');
            set_view(buttons);
            information.classList.add('item_close');
            buttons.classList.add('item_close'); }

        function set_view(elem){
            let view=document.createElement('button');
            view.setAttribute('type', 'button');
            view.setAttribute('class', 'co_view');
            view.textContent='▼';
            if(!elem.querySelector('.co_view')){
                elem.appendChild(view); }}}


    function list_mode(){
        let tab_item=document.querySelectorAll('.tabs .tabs__item');
        if(tab_item[0] && tab_item[0].classList.contains('is-active')){ // 公開済み画面
            let approved=get_cookie('approved');

            if(approved!=0){ // approved: 1:制限表示 2:全文表示
                let items=document.querySelectorAll('.userList__item');
                for(let k=0; k<items.length; k++){
                    let view_button=items[k].querySelector('.co_view');
                    let text=items[k].querySelector('.userList__text');
                    text.style.display='block';
                    height_g(text, approved);
                    view_button.textContent='▲'; }}
            document.cookie='approved='+approved+'; Max-Age=2592000'; }


        if(tab_item[1] && tab_item[1].classList.contains('is-active')){ // 承認待ち画面
            let pending=get_cookie('pending');
            if(pending!=0){ // pending: 1:制限表示 2:全文表示
                let items=document.querySelectorAll('.userList__item');
                for(let k=0; k<items.length; k++){
                    let view_button=items[k].querySelector('.co_view');
                    let text=items[k].querySelector('.userList__text');
                    text.style.display='block';
                    height_g(text, pending);
                    view_button.textContent='▲'; }}
            document.cookie='pending='+pending+'; Max-Age=2592000';

            let items=document.querySelectorAll('.userList__item');
            for(let k=0; k<items.length; k++){
                let menu_button=items[k].querySelector('.userList__menu');
                menu_button.classList.add('co_menu'); }}
    } // list_mode()


    function save_set(){ // 緑マークの保持時間はここで設定 🟩
        let save=get_cookie('save_time');
        if(save==0){
            save_t=180; }
        else if(save==1){
            save_t=3600; }
        else if(save==2){
            save_t=21600; }
        document.cookie='save_time='+save+'; Max-Age=2592000'; }

}); // window.addEventListener



window.addEventListener('load', function(){
    open_edit();
    open_read();
    close();
    text_focus();
    menu_read();
    read_memo();
    read_memo_app();
    memo();
    memo_app();


    function open_edit(){
        let items=document.querySelectorAll('.userList__item');
        for(let k=0; k<items.length; k++){
            let reply_button=items[k].querySelector('.js-comment-reply-button');
            if(reply_button){
                reply_button.addEventListener('click', function(){
                    let text=items[k].querySelector('.userList__text');
                    let information=items[k].querySelector('.userList__information');
                    let buttons=items[k].querySelector('.userList__buttons');

                    text.style.display='block';
                    information.classList.remove('item_close');
                    buttons.classList.remove('item_close');
                    height_g(text, 1);
                    app_reset(items[k]);

                    items[k].scrollIntoView({block: "center"});
                    items[k].setAttribute('tabindex', ''); }); }}}


    function open_read(){
        let items=document.querySelectorAll('.userList__item');
        for(let k=0; k<items.length; k++){
            let view_button=items[k].querySelector('.co_view');
            if(view_button){
                view_button.addEventListener('click', function(){
                    toggle(items[k], view_button);
                    app_reset(items[k]); }); }}


        function toggle(item, sw){
            let open_limit;
            let tab_item=document.querySelectorAll('.tabs .tabs__item');
            if(tab_item[0] && tab_item[0].classList.contains('is-active')){ // 公開済み画面
                open_limit=get_cookie('approved'); }
            else if(tab_item[1] && tab_item[1].classList.contains('is-active')){ // 承認待ち画面
                open_limit=get_cookie('pending'); }

            let text=item.querySelector('.userList__text');
            if(sw.textContent=='▼'){
                text.style.display='block';
                sw.textContent='▲';
                height_g(text, open_limit); }
            else{
                text.style.display='none';
                sw.textContent='▼';
                item.focus(); }}}


    function menu_read(){
        let items=document.querySelectorAll('.userList__item');
        for(let k=0; k<items.length; k++){
            let menu_button=items[k].querySelector('.userList__menu');
            menu_button.addEventListener('click', function(){
                app_reset(items[k]); }); }}


    function close(){
        let items=document.querySelectorAll('.userList__item');
        for(let k=0; k<items.length; k++){
            let reply_cancel=items[k].querySelector('.js-comment-reply-cancel');
            if(reply_cancel){
                reply_cancel.addEventListener('click', function(){
                    let text=items[k].querySelector('.userList__text');
                    let information=items[k].querySelector('.userList__information');
                    let buttons=items[k].querySelector('.userList__buttons');
                    text.style.display='none';
                    information.classList.add('item_close');
                    buttons.classList.add('item_close');
                    let view_button=items[k].querySelector('.co_view');
                    if(view_button.textContent=='▲'){
                        view_button.textContent='▼'; }
                    items[k].setAttribute('tabindex', '0');
                    items[k].focus(); }); }}}


    function text_focus(){
        let items=document.querySelectorAll('.userList__item');
        for(let k=0; k<items.length; k++){
            let text=items[k].querySelector('.userList__text');
            let resizeObserver=new ResizeObserver(recover_scroll);
            resizeObserver.observe(text);

            function recover_scroll(){
                let textarea=items[k].querySelector('.formGroup__textarea');
                if(textarea){
                    textarea.blur(); }}}}


    function memo(){
        let sendbutton=document.querySelectorAll('.commentList .sendButton');
        for(let k=0; k<sendbutton.length; k++){
            sendbutton[k].addEventListener('mousedown', function(){
                let comm_id=sendbutton[k].getAttribute('data-comment-id');
                document.cookie='comm_id='+comm_id+'; Max-Age=20'; }); }}


    function read_memo(){
        let comm_id=get_cookie('comm_id');
        let items=document.querySelectorAll('.userList__item');
        for(let k=0; k<items.length; k++){
            let sendbutton=items[k].querySelector('.commentList .sendButton');
            if(sendbutton){
                let id=sendbutton.getAttribute('data-comment-id');
                if(id==comm_id){
                    items[k].focus(); }}}}


    function memo_app(){
        let app_button=document.querySelectorAll('[data-section-id="comment_approve"]');
        for(let k=0; k<app_button.length; k++){
            app_button[k].addEventListener('mousedown', function(){
                let comm_id=app_button[k].getAttribute('data-comment-id');
                let approve_id=get_cookie('new_comm_id');
                cookie_write(approve_id, comm_id); }); }

        function cookie_write(value0, value1){
            if(value0==0){
                document.cookie='new_comm_id='+value1+'; Max-Age='+save_t; }
            else{
                let arr=value0.split('%');
                arr.push(value1);
                let approve_id_n=arr.join('%');
                document.cookie=
                    'new_comm_id='+approve_id_n+'; Max-Age='+save_t; }}}


    function read_memo_app(){
        let approve_id=get_cookie('new_comm_id');
        let items=document.querySelectorAll('.userList__item');
        for(let k=0; k<items.length; k++){
            let sendbutton=items[k].querySelector('.commentList .sendButton');
            if(sendbutton && approve_id!=0){
                let id=sendbutton.getAttribute('data-comment-id');
                if(approve_id.indexOf(id)!=-1){
                    let view_button=items[k].querySelector('.userList__menu');
                    view_button.classList.add('co_menu'); }}}}


    function app_reset(item){
        let approve_id=get_cookie('new_comm_id');
        let menu_button=item.querySelector('.userList__menu');
        let sendbutton=item.querySelector('.commentList .sendButton');
        if(sendbutton && approve_id!=0){
            menu_button.classList.remove('co_menu');
            let id=sendbutton.getAttribute('data-comment-id');
            let arr=approve_id.split('%');
            let arr_d=arr.filter(function(value){
                return value!=id; });
            let approve_id_d=arr_d.join('%');
            document.cookie='new_comm_id='+approve_id_d+'; Max-Age='+save_t; }}

}); // window.addEventListener



function height_g(elem, limit){
    let s_height=elem.scrollHeight;
    if(s_height<300){
        elem.style.height='auto'; }
    else{
        if(limit!=2){
            elem.style.height='300px'; }
        else if(limit==2){
            elem.style.height='auto'; }}}


function get_cookie(name){
    let cookie_req=document.cookie.split('; ').find(row=>row.startsWith(name));
    if(cookie_req){
        return cookie_req.split('=')[1]; }
    if(!cookie_req){
        return 0; }}



window.addEventListener('load', function(){

    let SettingsList=document.querySelector('.commentSettingsList');
    if(SettingsList){ // コメント設定メニューの画面でのみ動作

        let list1=document.createElement('li');
        list1.setAttribute('id', 'list1');
        list1.classList.add('commentSettingsList__item');
        list1.innerHTML=
            '<div class="commentSettingsList__link" style="justify-content: normal">'+
            '公開済みリスト 初期表示のコメント内容: '+
            '<input name="approved" type="radio" id="approved0">&#8196;非表示  '+
            '<input name="approved" type="radio" id="approved1">&#8196;制限表示  '+
            '<input name="approved" type="radio" id="approved2">&#8196;全文表示</div>';
        if(!SettingsList.querySelector('#list1')){
            SettingsList.appendChild(list1); }

        let list2=document.createElement('li');
        list2.setAttribute('id', 'list2');
        list2.classList.add('commentSettingsList__item');
        list2.innerHTML=
            '<div class="commentSettingsList__link"  style="justify-content: normal">'+
            '承認待ちリスト 初期表示のコメント内容: '+
            '<input name="pending" type="radio" id="pending0">&#8196;非表示  '+
            '<input name="pending" type="radio" id="pending1">&#8196;制限表示  '+
            '<input name="pending" type="radio" id="pending2">&#8196;全文表示</div>';
        if(!SettingsList.querySelector('#list2')){
            SettingsList.appendChild(list2); }

        let list3=document.createElement('li');
        list3.setAttribute('id', 'list3');
        list3.classList.add('commentSettingsList__item');
        list3.innerHTML=
            '<div class="commentSettingsList__link"  style="justify-content: normal">'+
            '承認したコメントの緑マーク 保持時間: '+
            '<input name="save" type="radio" id="save0">&#8196;3分  '+
            '<input name="save" type="radio" id="save1">&#8196;1時間  '+
            '<input name="save" type="radio" id="save2">&#8196;6時間</div>';
        if(!SettingsList.querySelector('#list3')){
            SettingsList.appendChild(list3); }


        set_radio();

        function set_radio(){
            let approved=get_cookie('approved');
            let approved0=document.querySelector('#approved0');
            let approved1=document.querySelector('#approved1');
            let approved2=document.querySelector('#approved2');
            if(approved==0){ // approved: 0:コメント非表示 1:制限表示 2:全文表示
                approved0.checked=true; }
            else if(approved==1){
                approved1.checked=true; }
            else if(approved==2){
                approved2.checked=true; }
            document.cookie='approved='+approved+'; Max-Age=2592000';

            let pending=get_cookie('pending');
            let pending0=document.querySelector('#pending0');
            let pending1=document.querySelector('#pending1');
            let pending2=document.querySelector('#pending2');
            if(pending==0){ // pending: 0:コメント非表示 1:制限表示 2:全文表示
                pending0.checked=true; }
            else if(pending==1){
                pending1.checked=true; }
            else if(pending==2){
                pending2.checked=true; }
            document.cookie='pending='+pending+'; Max-Age=2592000';

            let save=get_cookie('save_time'); // save: 0:3分 1:1時間 2:3時間
            let save0=document.querySelector('#save0');
            let save1=document.querySelector('#save1');
            let save2=document.querySelector('#save2');
            if(save==0){
                save0.checked=true; }
            else if(save==1){
                save1.checked=true; }
            else if(save==2){
                save2.checked=true; }
            document.cookie='save_time='+save+'; Max-Age=2592000'; }


        radio_select();

        function radio_select(){
            let approved0=document.querySelector('#approved0');
            approved0.onchange=function(){
                document.cookie='approved=0; Max-Age=2592000'; }

            let approved1=document.querySelector('#approved1');
            approved1.onchange=function(){
                document.cookie='approved=1; Max-Age=2592000'; }

            let approved2=document.querySelector('#approved2');
            approved2.onchange=function(){
                document.cookie='approved=2; Max-Age=2592000'; }

            let pending0=document.querySelector('#pending0');
            pending0.onchange=function(){
                document.cookie='pending=0; Max-Age=2592000'; }

            let pending1=document.querySelector('#pending1');
            pending1.onchange=function(){
                document.cookie='pending=1; Max-Age=2592000'; }

            let pending2=document.querySelector('#pending2');
            pending2.onchange=function(){
                document.cookie='pending=2; Max-Age=2592000'; }

            let save0=document.querySelector('#save0');
            save0.onchange=function(){
                document.cookie='save_time=0; Max-Age=2592000'; }

            let save1=document.querySelector('#save1');
            save1.onchange=function(){
                document.cookie='save_time=1; Max-Age=2592000'; }

            let save2=document.querySelector('#save2');
            save2.onchange=function(){
                document.cookie='save_time=2; Max-Age=2592000'; }}

    }}); // window.addEventListener


 

 

 

「Comment C-O」最新版について 

旧いバージョンの JavaScriptツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。 最新バージョンへのリンクは、以下のページのリンクリストから探せます。