承認コメントのグリーンマークの保持時間の設定
承認直後のコメントに、時間限定でマークを表示する機能を盛り込みました。 このマークにより、承認したコメントが何処に行ったか判らなくなる事が防げます。 また、複数のコメントに返信している間に、コメントを見ないまま見落とす事が、かなり防げると思います。
多数のコメントがある方は、コメントの見落しを避けるために、1コメントずつ「承認」→「返信」をされているのかも知れませんね。 私は、コメント数が少ないので、気付かなかったのですが、毎日何10件ものコメントをやりとりしている方は、どうされているのでしょう?
前ページのグリーンマークはプロトタイプで、更に色々なユーザーの場合に合わせた使い勝手を考慮すべきと思っています。 その最初の試みとして「マークの保持時間」の設定を変更出来る様にしました。
3種のマーク保持時間の選択
「設定」ページのメニューに下の新しい選択メニューを追加しました。
◎「3分」の設定は、「承認」をしてすぐに「公開済み」を開いた場合に、「承認」したコメントがどれかを示す機能だけとして使う場合です。 すぐに3分は過ぎるので、このマークを余り必要としない場合には、マークが邪魔にならない設定です。
◎「1時間」の設定は、一般的な使用で適当な設定かと思います。 普通のユーザーはコメントを「承認」してから1時間も放置しないでしょうから。
◎「6時間」の設定を最長としました。 これ以上の時間を設定すると、次に「承認」操作があった場合に、それまでに放置していたデータが引き継がれる事が増えます。
「コメント管理」ではコメントを「承認」するだけで、「返信」はブログ画面で書くユーザーも居られるでしょう。 その使い方では「コメント管理」画面では未処理と同じなので、未処理コメントを大量に抱えた Cookieが出来上がります。 そういった場合を考えて Cookieの上限時間を「6時間」としました。 ユーザーが寝ている時間はあるだろうから、その間に Cookieをリセットするというわけです。
未だもっと練る必要があります
現在は「返信する」「▲」「▼」「…」のボタン操作で、グリーンマークがリセットされる仕様です。 これは少し操作しただけでマークが無くなります。 これに対して、「返信コメント」を実際に「送信」した場合だけマークが消え、「返信」せずにマークを消す場合は、何かの手段を用意するという仕様が考えられます。 つまり、もう少し確実なユーザー判断で消せるマークの仕様です。 これは、後の課題にします。
グリーンマークの Cookieによる管理
「グリーンマーク」は、Cookieにコメント固有の「コメント番号」を記録して、それが記録されていたらマークを表示するコードで、実現しています。
下は、「承認」ボタンを押した時に、そのコメントの「コメント番号」を Cookieに保存する関数です。
主要な部分は後半のサブの関数で、2つの因数は「それまでの Cookie値」「追加するコメント番号」です。 登録に使用される Cookie名は「new_comm_id」で、その値はコメント番号の羅列した文字列です。
例えば、承認したコメントが3件の場合は、Cookieの記録には下の様になります。
13112942018%13112590344%13104427389
コメント番号は11桁で、「%」は区切り文字として入れています。
後半のサブ関数は、これに新しい「コメント番号」を追加する関数で、青文字の部分で新しい Cookie値に書変えています。
上の例だと、「%」で繋いだ3個の「コメント番号」を一旦配列に分離して、配列に新しい「コメント番号」を追加し、配列をもう一度「%」の区切り文字で繋ぐという操作です。 まわりくどい方法ですが、これが一番問題のないコードです。
下は何かのボタンを押した場合に、操作したコメントの「コメント番号」を Cookieの値から削除する関数です。
青文字の部分で、それまでの 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"> 非表示 '+ '<input name="approved" type="radio" id="approved1"> 制限表示 '+ '<input name="approved" type="radio" id="approved2"> 全文表示</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"> 非表示 '+ '<input name="pending" type="radio" id="pending1"> 制限表示 '+ '<input name="pending" type="radio" id="pending2"> 全文表示</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"> 3分 '+ '<input name="save" type="radio" id="save1"> 1時間 '+ '<input name="save" type="radio" id="save2"> 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ツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。 最新バージョンへのリンクは、以下のページのリンクリストから探せます。