各種の描画設定を自動保存
「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」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。

