各種の描画設定を自動保存
「Draw The Line ⭐」は、「アンダーライン」「マーカー線」「取り消し線」を自在に書き込めるツールです。 各種の装飾線の指定は HTMLに直接書き込まれるので、スマホでも表示されます。
(注)スマホで正確な描画位置を期待するには、インラインでフォント種を指定する事が最善の策と思われます。 以下の記事を参照ください。
このツールは実際は5種のモードで書き込みを行います。 各モードに「線幅」「開始位置」「線色」等の共通の設定があります。 しかし、アンダーラインとマーカー線の「線幅」は全く異なり、線描画の「開始位置」は単線・2重線で異なる場合が多く、ブログスキンのフォント種の違いで、適切な描画位置が異なります。 このため、モードごとに、全く独立した値の設定が必要です。
これまで「メイリオ 16px」を標準とした設定値を初期設定とした仕様でしたが、他のフォント種の場合や、独自設定を使う場合などは、ツールを起動する度に設定する必要があり、これは実用的とは言えない状態でした。
この使い勝手を改善するため、各種の設定をローカルストレージに自動登録する様にしました。 登録は以下の設定で、モードごとに独立した値が記録されます。
アンダーライン | ||||||
task1 | 単線 | 線幅px | 開始位置 | 線色 | MS | |
task2 | 2重線 | 線幅px | 開始位置 | 線色 | MS | |
マーカー線 | ||||||
task3 | 単線 | 線幅em | 開始位置 | (透過度) | 線色 | MS |
取り消し線 | ||||||
task4 | 単線 | 線幅px | 開始位置 | 線色 | ||
task5 | 2重線 | 線幅px | 開始位置 | 線色 |
「task」は書込みモードです。「透過度」は登録せず「線色」のアルファ値として登録されます。
これらの登録は、設定の変更時にリアルタイムで保存されます。 ツールのOFFや、ブラウザを閉じても、ツールを起動すると前回の設定が再現します。 登録データの初期値は「メイリオ 16px」を標準とした値にしていますが、一旦ユーザーが設定を変更すると、初期設定は更新され、ユーザーが設定したものに置換えられます。
カラー値の判定コードを更新
前ページのカラー値判定コードを導入しました。 表面上は判り難いのですが、線色の「カラー設定枠」と「透過度」の動作が柔軟になっています。 また実装に際して、「不適正」なカラー値は登録されない様にしました。
「Draw The Line」ver. 0.5
このツールは、Chrome / 新Edge / Firefox の「Tampermonkey」上で動作します。
現在のバージョンは実使用が可能です。 今後は、ファイル保存などの補足機能を追加して行きます。
各ブラウザの「Tampermonkey」の「新規スクリプト」の編集画面で、最初から登録されているテンプレートを削除して完全に空白にした上で、以下のコードをコピー&ペーストして「保存」してください。
〔コピー方法〕 軽量シンプルなツール「PreBox Button 」を使うと
コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」
の操作で、掲載コードのコピーが可能になります。
〔 Draw The Line 〕ver. 0.5
// ==UserScript== // @name Draw The Line ⭐ // @namespace http://tampermonkey.net/ // @version 0.5 // @description 各種の装飾線を記入するツール // @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 editor_iframe; let iframe_doc; let selection; let range; let task=0; // アンダーライン・マーカー線・消し線・終了 let add_padd; //「MS Pゴシック」のために padding-bottom追加フラグ let read_json; let setting; // 入力枠の設定とユーザー設定値登録 let ua=0; // Chromeの場合のフラグ let agent=window.navigator.userAgent.toLowerCase(); if(agent.indexOf('firefox') > -1){ ua=1; } // Firefoxの場合のフラグ read_json=localStorage.getItem('Draw_Line'); // ローカルストレージ 保存名 setting=JSON.parse(read_json); if(setting==null){ setting=[['DrawTheLine','0','0','0'],['1','1.23','#333','0'],['1','1.23','#333','0'], ['0.6','0.7','#ccc','0'],['1','0.66','#333','0'],['1','0.54','#333','0']]; } let write_json=JSON.stringify(setting); localStorage.setItem('Draw_Line', write_json); // ローカルストレージ 保存 let target=document.getElementById('cke_1_contents'); // 監視 target let monitor=new MutationObserver(catch_key); monitor.observe(target, {childList: true}); // ショートカット待受け開始 catch_key(); function catch_key(){ if(document.querySelector('.cke_wysiwyg_frame') !=null){ //「通常表示」から実行開始 editor_iframe=document.querySelector('.cke_wysiwyg_frame'); iframe_doc=editor_iframe.contentWindow.document; selection=iframe_doc.getSelection(); iframe_doc.addEventListener('keydown', check_key); document.addEventListener('keydown', check_key); function check_key(event){ let gate=-1; if(event.ctrlKey==true){ if(event.keyCode==114){ event.preventDefault(); gate=1; } if(gate==1){ event.stopImmediatePropagation(); do_task(); }}} function do_task(){ if(task==0){ task=1; panel_disp(); set_panel(); draw_line(); } else if(task==1 || task==2){ task=3; set_panel(); draw_line(); } else if(task==3){ task=4; set_panel(); draw_line(); } else if(task==4 || task==5){ task=0; panel_remove(); }} }} // catch_key() function draw_line(){ let insert_node; let style_text; show_color(); pick_color(); let l_type=document.querySelector('#l_type'); let single=document.querySelector('#single'); let double=document.querySelector('#double'); let pxem=document.querySelector('#pxem'); let l_width=document.querySelector('#l_width'); let l_base=document.querySelector('#l_base'); let l_trance=document.querySelector('#l_trance'); let l_color=document.querySelector('#l_color'); let ms=document.querySelector('#ms'); single.checked=true; double.onclick=function(){ double.checked=true; if(task==1){ task=2; l_width.disabled=true; l_width.value=1; // 固定値 pxem.classList.remove('wpx'); pxem.classList.add('wpxd'); l_base.value=setting[2][1]; l_color.value=setting[2][2]; add_padd=setting[2][3]; if(add_padd==1){ ms.style.boxShadow='inset 0 -5px 0 0 red'; } else{ ms.style.boxShadow='none'; }} if(task==4){ task=5; l_width.disabled=false; l_width.value=setting[5][0]; l_base.value=setting[5][1]; l_color.value=setting[5][2]; } show_color(); } single.onclick=function(){ single.checked=true; if(task==2){ task=1; l_width.disabled=false; pxem.classList.remove('wpxd'); pxem.classList.add('wpx'); l_width.value=setting[1][0]; l_base.value=setting[1][1]; l_color.value=setting[1][2]; add_padd=setting[1][3]; if(add_padd==1){ ms.style.boxShadow='inset 0 -5px 0 0 red'; } else{ ms.style.boxShadow='none'; }} if(task==5){ task=4; l_width.disabled=false; l_width.value=setting[4][0]; l_base.value=setting[4][1]; l_color.value=setting[4][2]; } show_color();} l_width.addEventListener('input', function(event){ event.preventDefault(); setting[task][0]=l_width.value; let write_json=JSON.stringify(setting); localStorage.setItem('Draw_Line', write_json); }); // ローカルストレージ 保存 l_base.addEventListener('input', function(event){ event.preventDefault(); setting[task][1]=l_base.value; let write_json=JSON.stringify(setting); localStorage.setItem('Draw_Line', write_json); }); // ローカルストレージ 保存 l_trance.addEventListener('input', function(event){ event.preventDefault(); if(!test_color(l_color.value) && l_color.value.length==9){ // 不適合な #付き9桁コードの場合 if(test_color(l_color.value.slice(0, -2))){ // アルファ―値のみ不適合なら修正 l_color.value=l_color.value.slice(0, -2); }} if(!test_color(l_color.value) && l_color.value.length==8){ // 不適合な #付き8桁コードの場合 if(test_color(l_color.value.slice(0, -1))){ // アルファ―値のみ不適合なら修正 l_color.value=l_color.value.slice(0, -1); }} if((test_color(l_color.value))){ trance(); l_color.style.boxShadow='inset -20px 0 ' + l_color.value; } else{ l_trance.value=1; } // 変換不能なコード, カラー名などは「1」を変更できない setting[task][2]=l_color.value; let write_json=JSON.stringify(setting); localStorage.setItem('Draw_Line', write_json); }); // ローカルストレージ 保存 if(add_padd==1){ ms.style.boxShadow='inset 0 -5px 0 0 red'; } else{ ms.style.boxShadow='none'; } ms.onclick=function(){ if(add_padd==0){ add_padd=1; ms.style.boxShadow='inset 0 -5px 0 0 red'; } else{ add_padd=0; ms.style.boxShadow='none'; } setting[task][3]=add_padd; let write_json=JSON.stringify(setting); localStorage.setItem('Draw_Line', write_json); } // ローカルストレージ 保存 l_type.onclick=function(){ range=selection.getRangeAt(0); get_param(); insert_node=document.createElement('span'); if(add_padd==1 && task!=4 && task!=5 ){ insert_node.style.paddingBottom='.4em'; } insert_node.style.background=style_text; try{ range.surroundContents(insert_node); } catch(e){;} range.collapse(); } function get_param(){ let l_w=l_width.value; let l_b= l_base.value; let l_c=l_color.value; if(task==1){ style_text= 'linear-gradient(transparent '+ l_b +'em, '+ l_c +' 0, '+ l_c +' calc('+ l_b +'em + '+ l_w +'px), transparent 0)'; } if(task==2){ style_text= 'linear-gradient('+ 'transparent '+ l_b +'em, '+ l_c +' 0, '+ l_c +' calc('+ l_b +'em + 1px), '+ 'transparent 0, transparent calc('+ l_b +'em + 2px), '+ l_c +' 0, '+ l_c +' calc('+ l_b +'em + 3px), '+ 'transparent 0)'; } if(task==3){ style_text= 'linear-gradient(transparent '+ l_b +'em, '+ l_c +' 0, '+ l_c +' calc('+ l_b +'em + '+ l_w +'em), transparent 0)'; } if(task==4){ style_text= 'linear-gradient(transparent '+ l_b +'em, '+ l_c +' 0, '+ l_c +' calc('+ l_b +'em + '+ l_w +'px), transparent 0)'; } if(task==5){ style_text= 'linear-gradient('+ 'transparent '+ l_b +'em, '+ l_c +' 0, '+ l_c +' calc('+ l_b +'em + '+ l_w +'px), '+ 'transparent 0, transparent calc('+ l_b +'em + '+ l_w +'px + 3px), '+ l_c +' 0, '+ l_c +' calc('+ l_b +'em + '+ 2*l_w +'px + 3px), '+ 'transparent 0)'; }} } // draw_line() function set_panel(){ let l_type=document.querySelector('#l_type'); let type_1=document.querySelector('#type_1'); let type_2=document.querySelector('#type_2'); let single=document.querySelector('#single'); let double=document.querySelector('#double'); let pxem=document.querySelector('#pxem'); let l_width=document.querySelector('#l_width'); let l_base=document.querySelector('#l_base'); let l_trance=document.querySelector('#l_trance'); let l_color=document.querySelector('#l_color'); let ms=document.querySelector('#ms'); if(task==1){ l_type.value="アンダーライン"; type_1.style.display='inline-block'; type_2.style.display='none'; l_width.disabled=false; l_width.value=setting[1][0]; l_base.value=setting[1][1]; l_color.value=setting[1][2]; add_padd=setting[1][3]; l_width.setAttribute('min', '1'); l_width.setAttribute('max', '50'); l_width.setAttribute('step', '1'); l_base.setAttribute('min', '0.9'); l_base.setAttribute('max', '1.5'); l_base.setAttribute('step', '0.01'); } else if(task==3){ l_type.value="マーカー線"; type_1.style.display='none'; type_2.style.display='inline-block'; l_width.classList.add('m'); pxem.classList.remove('wpx'); pxem.classList.add('wem'); l_width.disabled=false; l_width.value=setting[3][0]; l_base.value=setting[3][1]; l_color.value=setting[3][2]; add_padd=setting[3][3]; l_trance.value='1'; // 初期値 l_width.setAttribute('min', '0.1'); l_width.setAttribute('max', '1.5'); l_width.setAttribute('step', '0.1'); l_base.setAttribute('min', '0'); l_base.setAttribute('max', '1.3'); l_base.setAttribute('step', '0.1'); l_trance.setAttribute('min', '0.1'); l_trance.setAttribute('max', '1'); l_trance.setAttribute('step', '0.1'); } else if(task==4){ l_type.value="取り消し線"; type_1.style.display='inline-block'; type_2.style.display='none'; l_width.classList.remove('m'); pxem.classList.remove('wem'); pxem.classList.add('wpx'); l_width.disabled=false; l_width.value=setting[4][0]; l_base.value=setting[4][1]; l_color.value=setting[4][2]; l_width.setAttribute('min', '1'); l_width.setAttribute('max', '20'); l_width.setAttribute('step', '1'); l_base.setAttribute('min', '0'); l_base.setAttribute('max', '1'); l_base.setAttribute('step', '0.01'); add_padd=0; // 固定値 ms.style.display='none'; }} // set_panel() function panel_disp(){ let panel=document.createElement('div'); panel.setAttribute('id', 'l_panel'); panel.innerHTML= '<input id="l_type" type="submit">'+ '<div id="type_wrap">'+ '<div id="type_1">'+ '<input id="single" type="radio" name="s_d"><span class="l_label">単線</span>'+ '<input id="double" type="radio" name="s_d"><span class="l_label">2重線</span>'+ '</div>'+ '<span class="l_label label_w">線幅</span>'+ '<div id="pxem" class="wpx"><input id="l_width" type="number"></div>'+ '<span class="l_label">開始位置</span>'+ '<div class="wem"><input id="l_base" type="number"></div>'+ '<div id="type_2">'+ '<span class="l_label">透過度</span>'+ '<div class="wtr"><input id="l_trance" type="number"></div>'+ '</div>'+ '</div>'+ '<span class="l_label">線色</span>'+ '<input id="l_color" type="text" autocomplete="off">'+ '<input id="ms" type="submit" value="MS">'+ '<div id="test"></div>'; let css= '#l_panel { position: fixed; top: 15px; left: calc(50% - 490px); width: 784px; '+ 'padding: 6px 0 6px 15px; font-size: 14px; border: 1px solid #ccc; '+ 'border-radius: 4px; background: #eff5f6; z-index: 10; }'+ '#type_wrap { display: inline-block; text-align: right; width: 355px; }'+ '#type_1 { display: inline-block; } #type_2 { display: none; }'+ '#l_panel input { position: relative; margin-right: 10px; padding-top: 2px; }'+ '#l_panel input:hover { z-index: 1; }'+ '#l_panel input[type="radio"] { margin: 0 2px 0 8px; vertical-align: -2px; box-shadow: none; }'+ '.l_label { margin: 0 4px 0 0; } .label_w { margin: 0 4px 0 10px; }'+ '#l_type { width: 110px; margin-right: 4px !important; }'+ '.wpx, .wpxd, .wem, .wtr { position: relative; display: inline-block; }'+ '.wpx::after { content: "px"; position: absolute; right: 15px; top: 5px; background: #fff; }'+ '.wpxd::after { content: "px"; position: absolute; right: 15px; top: 5px; }'+ '.wem::after { content: "em"; position: absolute; right: 15px; top: 5px; background: #fff; }'+ '#l_width { width: 38px; text-align: center; padding: 2px 4px 0 0; }'+ '#l_width[disabled]:hover { z-index: 0; }'+ '#l_width.m { width: 45px; text-align: left; padding: 2px 4px 0 5px; }'+ '#l_base { width: 54px; padding: 2px 4px 0 3px; }'+ '#l_base.m { width: 45px; padding: 2px 4px 0 5px; }'+ '#l_trance { width: 40px; text-align: center; padding: 2px 0 0 4px; }'+ '#l_color { width: 90px; padding: 2px 24px 0 6px; border: thin solid #aaa; height: 23px; }'+ '#ms { margin-left: 5px; }'+ '#test { display: inline-block; }'+ '#cke_42 { top: 60px !important; left: calc( 50% - 45px) !important; }'; if(ua==1){ css=css + '#l_width, #l_base, #l_trance, #l_color { height: 24px; border: thin solid #aaa; }'+ '.wtr::after { content: " "; position: absolute; right: 11px; top: 5px; '+ 'background: #fff; width: 1.2em; }'+ '.wpxd::after { background: #e3e3e3; }'+ '#ms { border: thin solid #aaa; height: 28px; }'; } let style=document.createElement('style'); style.innerHTML=css; panel.appendChild(style); let l_panel=document.querySelector('#l_panel'); if(!l_panel){ document.querySelector('.l-body').appendChild(panel); }} // panel_disp() function panel_remove(){ let l_panel=document.querySelector('#l_panel'); l_panel.remove(); } function test_color(color){ return color.match( /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{8}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{4})$/)!==null; } function test_colorE(color){ // test_colorE ⏹ let test=document.querySelector('#test'); test.style.color='#000001'; if(color!=''){ test.style.color=color; } // 引数の入力がない場合 let colorR=window.getComputedStyle(test).color; if(colorR){ if(colorR!='rgb(0, 0, 1)'){ return true; } else{ if(color=='rgb(0, 0, 1)' || color=='#000001' || color=='#000001ff'){ return true; } else{ return false; }}} else{ return false; }} function show_color(){ let l_color=document.querySelector('#l_color'); l_color.style.boxShadow='inset -20px 0 ' + l_color.value; } function pick_color(){ let set_color; let color_input_selector; let color_label; let icon_button; editor_iframe=document.querySelector('.cke_wysiwyg_frame'); iframe_doc=editor_iframe.contentWindow.document; selection=iframe_doc.getSelection(); if(ua==0){ color_label=document.querySelector('#cke_16_label'); icon_button=document.querySelector('#cke_17'); } else if(ua==1){ color_label=document.querySelector('#cke_15_label'); icon_button=document.querySelector('#cke_16'); } let target_p=color_label; // 監視 アイコンのカラーラベル let monitor_p=new MutationObserver( get_copy ); let l_color=document.querySelector('#l_color'); l_color.onclick=function(event){ if(event.ctrlKey==true){ event.preventDefault(); icon_button.click(); selection.removeAllRanges(); // 反転選択がある場合に背景指定を防止する monitor_p.observe(target_p, {attributes: true}); }} // アイコンカラー取得開始 l_color.addEventListener('input', function(event){ event.preventDefault(); let l_trance=document.querySelector('#l_trance'); if(l_trance){ l_trance.value=1; } // 透過度をリセットする if(test_colorE(l_color.value)){ // test_colorEを実行 ⏹ l_color.style.boxShadow='inset -20px 0 ' + l_color.value; } else{ if(l_color.value==''){ l_color.style.boxShadow='inset 0 0 0 1px black'; } else{ l_color.style.boxShadow='inset 0 0 0 1px black'; // 担保コード l_color.style.boxShadow= 'inset 0 0 0 1px black, inset -20px 0 ' + l_color.value; }} if(test_colorE(l_color.value)){ // test_colorEを実行 ⏹ 不適正な入力は登録されない setting[task][2]=l_color.value; let write_json=JSON.stringify(setting); localStorage.setItem('Draw_Line', write_json); }}); // ローカルストレージ 保存 document.addEventListener('mousedown', function(){ monitor_p.disconnect(); }); // アイコンカラー取得終了 if(document.querySelector('.cke_wysiwyg_frame') !=null){ let editor_iframe=document.querySelector('.cke_wysiwyg_frame'); let iframe_doc=editor_iframe.contentWindow.document; iframe_doc.addEventListener('mousedown', function(){ monitor_p.disconnect(); }); } // アイコンカラー取得終了 function get_copy(){ let l_trance=document.querySelector('#l_trance'); if(l_trance){ l_trance.value=1; } // 透過度をリセットする set_color=color_label.getAttribute('data-color'); l_color.value='#'+ set_color; l_color.style.boxShadow= 'inset -20px 0 ' + l_color.value; monitor_p.disconnect(); // アイコンカラー取得終了 setting[task][2]=l_color.value; let write_json=JSON.stringify(setting); localStorage.setItem('Draw_Line', write_json); } // ローカルストレージ 保存 let target_body=document.querySelector('.l-body'); // 監視 target let monitor_generator=new MutationObserver(stealth); monitor_generator.observe(target_body, {childList: true, subtree: true}); function stealth(){ let color_generator=document.querySelector('.ck-l-colorGenerator'); if(color_generator){ color_generator.addEventListener('mousedown', function(event){ event.stopImmediatePropagation(); }); }} } // pick_color() function trance(){ let l_color_code; let l_color=document.querySelector('#l_color'); let l_trance=document.querySelector('#l_trance'); if(l_trance.value){ if(test_color(l_color.value)){ // #カラーコードは全て#+16進8桁に変更 if(l_color.value.length==4){ let ch=l_color.value.split(""); l_color_code='#'+ch[1]+ch[1]+ch[2]+ch[2]+ch[3]+ch[3]+'90'; } if(l_color.value.length==5){ let ch=l_color.value.split(""); l_color_code='#'+ch[1]+ch[1]+ch[2]+ch[2]+ch[3]+ch[3]+ch[4]+ch[4]; } if(l_color.value.length==7){ l_color_code=l_color.value+'90'; } if(l_color.value.length==9){ l_color_code=l_color.value; } if(l_trance.value!=1){ let ch=l_color_code.split(''); if(ch[7].match(/[A-Fa-f]/)){ // アルファ値の初桁が「9」を超える場合は「9」に ch[7]='9'; } if(Number(ch[7])<10*l_trance.value-1){ // 初桁とl_tranceの差が「2」以上は手入力 l_trance.value=Number(ch[7])/10; } // この場合はl_trance値を入力値に合わせる else{ ch[7]=10*l_trance.value.toString(); } // l_tranceの入力に合わせて増減操作 ch[8]='0'; l_color.value=ch.join(''); } else if(l_trance.value==1){ l_color.value=l_color_code.slice(0, -2); } }}} } // main()
「Draw The Line」最新版について
旧いバージョンの JavaScriptツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。
●「Draw The Line」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。