サブパネルのデザイン更新
下は、「Fixed Format Palette」で画像を登録したBankを呼び出した所です。
この画像は細い縁線がある画像ですが、これを貼付けた時の正確な縦幅が判りません。 実際に貼付けられる範囲を調べて正確に表すと、下の赤枠の範囲になります。
このBankは、画像のある区画を「通常表示」で登録したので、画像の上下に1行ずつの余白を含んでいたわけです。 最初のスクリーンショットを見ただけでは、実際に貼付けられるデータの高さは、青いメニューバーとデータの間に余白があるので、推測し難い事が判ります。(横幅は正確ですが)
今回、この余白部に左右の枠部と同じグレーの背景色を着け、登録された実データの範囲が正確に判るデザインに改めました。
下は、ver. 5.7 で、画像を「HTML表示」の編集画面から登録する所です。
改善した ver. 5.8 で、同様に「HTML表示」の編集画面から登録する所で、余白なしの画像の範囲だけが取得できている事が判ります。
◎ グレーの部分が、データの正確な境界と考えれば良いわけです。
実用上では、上下の余白(余白行)の有無は大した問題になりませんが、区画の境界の行間隔が狭い場合などもあり、正確なデータ範囲を表示できるのがベストです。
スクロールバーの有無で移動しない
縦方向に長いデータを登録したBankだけスクロールバーが表示され、サブパネルが左にズレました。 これは少しガサツなので、パネル配置のコードを改めました。
これまでは「position: fixed」「right: 10px」で、ウインドウ右端から 10pxの配置でした。 これを「left: ~」の指定にすれば、スクロールバーの有無が配置に影響しなくなります。 しかし、これは簡単ではありません。 サブパネルの幅がブログ本文幅で変わるので、「left」値は、以下のコードでの指定が必要になります。
右側余白は「20px程度」の固定値ですが、パネル幅は毎回計算が必要です。
ver. 5.8 296行以降の関連コード
上側の関数「cke_style()」は、編集画面からブログ本文幅「width_m - 16」を計算し、Left値に指定する「100% - (width_m + 24) 」の値を計算して、CSSコードを出力します。
下側はこの関数で、サブパネルをデザインする「styleタグ」を生成・更新します。 今回は、「left値」を指定するコードを追加した形です。
操作方法
このツールの操作方法は、以下のマニュアルを参照ください。
「Fixed Format Palette ⭐」を利用するには
このツールは Chrome / Edge / Firefox 版の「Tampermonkey」上で動作します。「Tampermonkey」を導入し、ページ末尾の掲載コードを登録する事で、このツールを利用することが出来ます。
以下に、このツールの導入手順を簡単に説明します。
❶「Tampermonkey」を導入します
◎ 使用しているブラウザに拡張機能「Tampermonkey」を導入する事が必要です。
既に「Tampermonkey」を導入している場合は、この手順 ❶ は不要です。
拡張機能の導入については、以下のページに簡単な説明があるので参照ください。
❷「Tampermonkey」にスクリプトを登録します
◎「Tampermonkey」の「+」マークの「新規スクリプト」タブを開きます。
◎「新規スクリプト」には、最初からテンプレートが記入されています。 これは全て削除して、完全に空白の編集枠に 下のコードをコピー&ペーストします。
〔コピー方法〕 軽量シンプルなツール「PreBox Button 」を使うと
コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」
の操作で、掲載コードのコピーが可能になります。
◎ 最後に「ファイル」メニューの「保存」を押すと、ツールが使用可能になります。
〔 Fixed Format Palette ⭐ 〕 ver. 5.8
// ==UserScript==
// @name Fixed Format Palette ⭐
// @namespace http://tampermonkey.net/
// @version 5.8
// @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=document.querySelector('.cke_wysiwyg_frame');
let iframe_doc;
let iframe_html;
if(editor_iframe){
iframe_doc=editor_iframe.contentWindow.document;
iframe_html=iframe_doc.querySelector('html'); }
let format_data;
let bank;
let mode=-1; // 通常表示Write=0・Record=1 Html表示Record=2 Backup=3
let select_format;
let ua=0; // Chromeの場合のフラグ
let agent=window.navigator.userAgent.toLowerCase();
if(agent.indexOf('firefox') > -1){ ua=1; } // Firefoxの場合のフラグ
let read_json=localStorage.getItem('Format_Data'); // ローカルストレージ 保存名
format_data=JSON.parse(read_json);
if(format_data==null){
format_data=
[['0','FixedFormatPalette'],['1',''],['2',''],['3',''],['4',''],['5',''],['6',''],['7',''],['8',''],['9','']]; }
format_data[0][1]='FixedFormatPalette';
let write_json=JSON.stringify(format_data);
localStorage.setItem('Format_Data', 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('.l-gHeaderLeft__link a')){ // 起動を表示 📛
document.querySelector('.l-gHeaderLeft__link a')
.style.boxShadow='inset -14px 0 0 0 #79fbf6'; }
editor_iframe=document.querySelector('.cke_wysiwyg_frame');
if(editor_iframe){ // iframe がある「通常表示」の場合
mode=-1;
if(document.querySelector('.ffp_menu')){
document.querySelector('.ffp_menu').remove(); }
iframe_doc=editor_iframe.contentWindow.document;
iframe_doc.addEventListener("keydown", check_key);
function check_key(event){
if(event.ctrlKey && event.keyCode==122){ // 「Ctrl + F11」Bankから貼付
event.preventDefault();
mode=0;
setTimeout(()=>{
write_format(); }, 20); }
if(event.altKey && event.keyCode==122){ // 「Alt + F11」Bank登録
event.preventDefault();
mode=1;
setTimeout(()=>{
record_format(); }, 20); }
if(event.keyCode==122){ // ページ拡大の誤入力を抑止
event.preventDefault(); }
} // check_key()
} //「通常表示」の場合
else{ //「HTML表示」の場合
mode=-1;
if(document.querySelector('.ffp_menu')){
document.querySelector('.ffp_menu').remove(); }
document.addEventListener("keydown", check_key_h);
function check_key_h(event){
if(event.ctrlKey && event.keyCode==122){ // HTML表示で貼付操作をした場合
event.preventDefault();
event.stopImmediatePropagation();
unselect_h();
setTimeout(()=>{
alert(
" ⛔ 定型ブロックの記入は通常編集枠で行ってください\n"+
" == Fixed Format Palette =="); }, 20); }
if(event.altKey && event.keyCode==122){ //「Alt+F11」Bank登録(HTMLで登録)
if(ua==0){
event.preventDefault();
mode=2; // HTMLでの登録処理
setTimeout(()=>{
record_format_h(); }, 20); }
else if(ua==1){ // FirefoxはHTML編集でブロック登録が出来ない
event.preventDefault();
event.stopImmediatePropagation();
unselect_h();
setTimeout(()=>{
alert(
" ⛔ 定型ブロックの登録は通常編集枠で行ってください\n"+
" == Fixed Format Palette =="); }, 20); }}
if(event.keyCode==122){ // ページ拡大の誤入力を抑止
event.preventDefault(); }
} // check_key_h
} //「HTML表示」の場合
} // catch_key
function write_format(){
disp_menu();
document.addEventListener("keydown", menu_key_0);
iframe_doc.addEventListener("keydown", menu_key_0);
function menu_key_0(event){
if(event.keyCode==27 && mode==0){ //「Esc」
event.preventDefault();
mode=-1;
menu_end(); }
if(event.keyCode==13 && mode==0){ //「Enter」
event.preventDefault();
if(format_data[bank][1]!=''){
write_in(); } // ペースト処理
else{
mode=-1; }
setTimeout(()=>{
menu_end(); }, 20); }}
function write_in(){
let selection=iframe_doc.getSelection();
let range;
if(selection && selection.rangeCount>0){
range=selection.getRangeAt(0); }
let ac_node=selection.anchorNode;
let insert_node_d=iframe_doc.createElement('div');
insert_node_d.setAttribute('id', 'ffp_core');
if(ac_node && ac_node.parentNode){
// insert_node_d 生成の条件 親が div要素か BODYの場合
if(ac_node.parentNode.tagName=='DIV' ||
ac_node.parentNode.tagName=='BODY'){
ac_node.parentNode.insertBefore(insert_node_d, ac_node.nextSibling);
d_before_after(); }
// insert_node_d 生成の条件 ひとつ外の親が div要素か BODYの場合
else if(ac_node.parentNode.parentNode.tagName=='DIV' ||
ac_node.parentNode.parentNode.tagName=='BODY'){
ac_node.parentNode.parentNode.insertBefore(
insert_node_d, ac_node.parentNode.nextSibling);
d_before_after(); }}
let core=iframe_doc.querySelector('#ffp_core');
if(core){
core.outerHTML=format_data[bank][1];
mode=4; }
function d_before_after(){
range.setEnd(insert_node_d, 0);
range.collapse(); // レンジを閉じる
caret_back(); }}
} // write_format()
function record_format(){
let selection=iframe_doc.getSelection();
let range;
if(selection && selection.rangeCount>0){
range=selection.getRangeAt(0); }
select_format=document.createElement('div');
select_format.appendChild(range.cloneContents());
select_format=select_format.innerHTML;
disp_menu();
document.addEventListener("keydown", menu_key_1);
iframe_doc.addEventListener("keydown", menu_key_1);
function menu_key_1(event){
if(event.keyCode==27 && mode==1){ //「Esc」
event.preventDefault();
mode=-1;
menu_end(); }
else if(event.keyCode==13 && mode==1){ //「Enter」
event.preventDefault();
format_data[bank][1]=select_format;
let write_json=JSON.stringify(format_data);
localStorage.setItem('Format_Data', write_json);
mode=4;
menu_end(); }} // ローカルストレージ 保存
} // record_format()
function record_format_h(){
let result=new Promise( function(){
document.execCommand("copy"); })
navigator.clipboard.readText().then( function(clipText){
select_format=clipText; })
.then( function(){
disp_menu(); })
.then( function(){
document.querySelector('.CodeMirror textarea').blur(); })
document.addEventListener("keydown", menu_key_2);
function menu_key_2(event){
if(event.keyCode==27 && mode==2){ //「Esc」
event.preventDefault();
mode=-1;
unselect_h();
menu_end(); }
if(event.keyCode==13 && mode==2){ //「Enter」
event.preventDefault();
mode=4;
format_data[bank][1]=select_format;
let write_json=JSON.stringify(format_data);
localStorage.setItem('Format_Data', write_json); // ローカルストレージ 保存
unselect_h();
menu_end(); }}
} // record_format_h(}
function disp_subwin(){
let css=
'.ffp_menu_wrapp { position: fixed; top: 15px; left: calc(100% - 660px); '+
'max-height: 80vh; overflow: auto; z-index: 15; '+
'box-shadow: 20px 20px 60px 0 rgb(0 0 0 / 20%); } '+
'.ffp_menu { '+
'font-family: Meiryo; font-size: 16px; line-height: 1.6; width: 620px; '+
'padding: 8px 8px; border: 1px solid #009688; border-radius: 4px; '+
'background: #fff; box-shadow: inset 0 0 0 8px #eee; } '+
'.ffp_menu a { pointer-events: none; } '+
'.ffp_menu img { max-width: 99%; height: auto; } '+
'.ffp_menu h2, .ffp_menu h3, .ffp_menu h4 { '+
'font-weight: normal; line-height: 1.2; } '+
'.ffp_menu h2 { font-size: 1.96em; margin: 0.83em 0; } '+
'.ffp_menu h3 { font-size: 1.4em; margin: 1em 0; } '+
'.ffp_menu h4 { font-size: 1em; margin: 1.33em 0; } '+
'.ffp_menu iframe { max-width: 100%; } '+
'.ffp_menu .empty { '+
'font-size: 32px; color: #ccc; padding: 15px 0 5px; text-align: center; } '+
'.ffp_title { padding: 4px 15px 2px; border-bottom: 8px solid #eee; display: flex; '+
'color: #fff; font: 16px Meiryo; background: #2196f3; white-space: nowrap; } '+
'.ffp_title.btm { border-top: 8px solid #eee; } '+
'.ffp_title.fle { padding: 15px; border-bottom: none; } '+
'.ffp_title b { font-weight: bold; margin: 0 25px 0 4px; } '+
'.ffp_title .wrap { display: inline-block; } '+
'.ffp_title .wrap.r { margin: 0 20px 0 auto; } '+
'.ffp_sw { display: inline-block; padding: 0 6px; line-height: 24px; '+
'height: 22px; border: 1px solid #fff; border-radius: 3px; cursor: pointer; } '+
'.ffp_sw:hover { color: #2196f3; background: #fff; } '+
'#ffp_help { position: absolute; top: 16px; right: 15px; width: 18px; '+
'cursor: pointer; } '+
'.ffp_input { display: none; }';
if(ua==1){
css+='.ffp_menu_wrapp { overflow-y: scroll; overflow-x: auto; }'; }
let menu_style=
'<style class="style_ffp_menu">'+ css + '</style>';
if(!document.querySelector('.style_ffp_menu')){
document.querySelector('.l-body').insertAdjacentHTML('beforeend', menu_style); }
let style_ffp_menu=document.querySelector('.style_ffp_menu');
if(cke_style()){ // 本文幅の再取得
let width_ffp_menu=
'<style class="width_ffp_menu">'+ cke_style() +'</style>';
if(document.querySelector('.width_ffp_menu')){
document.querySelector('.width_ffp_menu').remove(); }
style_ffp_menu.insertAdjacentHTML('afterend', width_ffp_menu); }
let menu_wrapp=
'<div class="ffp_menu_wrapp"><div class="ffp_menu"></div></div>';
if(document.querySelector('.ffp_menu_wrapp')){
document.querySelector('.ffp_menu_wrapp').remove(); }
style_ffp_menu.insertAdjacentHTML('beforebegin', menu_wrapp); }
function cke_style(){
editor_iframe=document.querySelector('.cke_wysiwyg_frame');
if(editor_iframe){
iframe_doc=editor_iframe.contentWindow.document;
if(iframe_doc){
let cke=iframe_doc.querySelector('.cke_editable');
if(cke){
let cke_style=getComputedStyle(cke, null);
let width_c=cke_style.getPropertyValue("width").replace(/[^0-9\.]/g, '');
let width_m= Math.round(parseFloat(width_c));
let font_family=cke_style.getPropertyValue("font-family");
let font_size=cke_style.getPropertyValue("font-size");
return '.ffp_menu { width: '+ (width_m - 16) +
'px; font-family: '+ font_family +'; font-size: '+ font_size +'; } '+
'.ffp_menu_wrapp { left: calc(100% - '+ (width_m + 24) +'px); }'
}}}}
function disp_menu(){
disp_subwin();
let menu=document.querySelector('.ffp_menu');
setTimeout(()=>{
let selection=iframe_doc.getSelection();
if(selection){
let range=selection.getRangeAt(0);
range.collapse(); // 選択範囲がある時は反転を解除
}}, 40 ); // 登録の読取りの時間余裕
let out=0;
bank=1;
menu_change(1); // 初期表示Bank
if(ua==0){
menu.onmousewheel=function(event){
event.preventDefault();
event.stopImmediatePropagation();
let wd=event.wheelDelta/120;
out-=wd;
if(out>=0){
bank=out%9+1; }
else{
bank=(out+1)%9+9; }
menu_change(bank); }}
if(ua==1){
menu.addEventListener('DOMMouseScroll', function(event){
event.preventDefault();
event.stopImmediatePropagation();
let wd=- event.detail/3;
out-=wd;
if(out>=0){
bank=out%9+1; }
else{
bank=(out+1)%9+9; }
menu_change(bank); }); }
iframe_doc.addEventListener("keydown", menu_roll);
document.addEventListener("keydown", menu_roll);
function menu_roll(event){
if(event.keyCode==40 && mode>-1 && mode<3){ //「⇩」
event.preventDefault();
event.stopImmediatePropagation();
if(bank<9){
bank+=1; }
else{
bank=1; }
menu_change(bank); }
if(event.keyCode==38 && mode>-1 && mode<3){ //「⇧」
event.preventDefault();
event.stopImmediatePropagation();
if(bank>1){
bank-=1; }
else{
bank=9; }
menu_change(bank); }}
function menu_change(bank){
let SVG_h=
'<svg id="ffp_help" viewBox="0 0 150 150">'+
'<path fill="#fff" d="M66 13C56 15 47 18 39 24C-12 60 18 146 82 137C92 '+
'135 102 131 110 126C162 90 128 4 66 13M68 25C131 17 145 117 81 '+
'125C16 133 3 34 68 25M69 40C61 41 39 58 58 61C66 63 73 47 82 57C84 '+
'60 83 62 81 65C77 70 52 90 76 89C82 89 82 84 86 81C92 76 98 74 100 66'+
'C105 48 84 37 69 40M70 94C58 99 66 118 78 112C90 107 82 89 70 94z">'+
'</path></svg>';
let menu=document.querySelector('.ffp_menu');
let menu_str;
if(mode==0){ // Bankから貼付
menu_str=
'<div class="ffp_title">'+
'Bank<b>'+ bank +'</b>'+
'<span class="wrap">'+
'貼付:<span class="ffp_sw en">Enter</span> '+
'中止:<span class="ffp_sw es">Esc</span></span>'+
'<span class="wrap r">'+
'<span class="ffp_sw bk">File</span></span>'+ SVG_h +'</div>';
if(format_data[bank][1]==''){
menu_str+='<div class="empty">未登録</div>'; }
else{
menu_str+=format_data[bank][1] ; }}
if(mode==1 || mode==2){ // 通常表示でBank登録・HTML表示でBank登録
menu_str='<div id="check">'+ select_format + '</div>'; // テスト
menu.innerHTML=menu_str;
let check=document.querySelector('#check');
if(check){
if(getComputedStyle(check, null).getPropertyValue("height")=='0px'){
select_format=''; // 非表示要素は無入力に変換する:登録の削除
menu_str=
'<div class="ffp_title" style="background: #000;">'+
'Bank<b>'+ bank +'</b>'+
'<span class="wrap">'+
'登録削除:<span class="ffp_sw en">Enter</span> '+
'中止:<span class="ffp_sw es">Esc</span></span></div>';
if(format_data[bank][1]==''){
menu_str+='<div class="empty">未登録</div>'; }
else{
menu_str+=format_data[bank][1]; }}
else { // 登録データを更新する場合
menu_str=
'<div class="ffp_title">'+
'Bank<b>'+ bank +'</b>'+
'<span class="wrap">'+
'登録:<span class="ffp_sw en">Enter</span> '+
'中止:<span class="ffp_sw es">Esc</span></span>'+
'<span class="wrap r">'+
'<span class="ffp_sw bk">File</span></span>'+ SVG_h +'</div>'+
select_format +
'<div class="ffp_title btm" style="background: #000;">'+
'Bank<b>'+ bank +'</b>以下の登録内容は上書きで削除されます</div>';
if(format_data[bank][1]==''){
menu_str+='<div class="empty">未登録</div>'; }
else{
menu_str+=format_data[bank][1] ; }}}}
menu.innerHTML=menu_str;
let ffp_swbk=document.querySelector('.ffp_sw.bk');
if(ffp_swbk){
ffp_swbk.onclick=function(event){
event.stopImmediatePropagation();
caret_back();
unselect_h();
ffp_backup(); }}
let ffp_title=document.querySelector('.ffp_title');
if(ffp_title){
ffp_title.onclick=function(event){
event.stopImmediatePropagation();
caret_back(); }}
let ffp_swen=document.querySelector('.ffp_sw.en');
if(ffp_swen){
ffp_swen.onclick=function(event){
unselect_h();
caret_back();
key_in(13);
function key_in(key_Code){
let keyEvent=new KeyboardEvent('keydown', {keyCode: key_Code});
iframe_doc.dispatchEvent(keyEvent);
document.dispatchEvent(keyEvent); }}}
let ffp_swes=document.querySelector('.ffp_sw.es');
if(ffp_swes){
ffp_swes.onclick=function(event){
event.stopImmediatePropagation();
caret_back();
mode=-1;
unselect_h();
menu.remove(); }}
let ffp_help=document.querySelector('#ffp_help');
if(ffp_help){
ffp_help.onclick=function(event){
event.stopImmediatePropagation();
window.open('https://ameblo.jp/personwritep/entry-12783760034.html#manual',
null, 'width=820,height=800'); }}
} // menu_change()
} // disp_menu();
function menu_end(){
if(document.querySelector('.ffp_menu')){
document.querySelector('.ffp_menu').remove(); }}
function caret_back(){
let iframe_body=iframe_doc.querySelector('.cke_editable');
if(iframe_body){
iframe_body.focus(); }}
function unselect_h(){
let CodeMirror=document.querySelector('.CodeMirror');
if(CodeMirror){
key_in(36); //「Home」の入力で選択解除しコピー元の削除を防ぐ
function key_in(key_Code){
let keyEvent=new KeyboardEvent('keydown', {keyCode: key_Code});
document.querySelector('.CodeMirror textarea').dispatchEvent(keyEvent); }}}
function ffp_backup(){
let ffp_menu_wrapp=document.querySelector('.ffp_menu_wrapp');
let menu_wrapp=
'<div class="ffp_menu_wrapp" style="left: calc(100% - 635px)">'+
'<div class="ffp_menu" style="width: 595px">'+
'<div class="ffp_title fle"> '+
'<span class="ffp_button1 ffp_sw">登録データをファイルに保存</span> '+
'<span class="ffp_button2 ffp_sw">登録データファイルを読込む</span> '+
'<span class="ffp_button3 ffp_sw">✖</span>'+
'<input class="ffp_input" type="file"></div></div></div>';
ffp_menu_wrapp.outerHTML=menu_wrapp;
let button1=document.querySelector('.ffp_button1');
let button2=document.querySelector('.ffp_button2');
let ffp_input=document.querySelector('.ffp_input');
let button3=document.querySelector('.ffp_button3');
button1.onclick=function(){
let write_json=JSON.stringify(format_data); // 記録用配列 format_data を書出す
let blob=new Blob([write_json], {type: 'application/json'});
let a_elem=document.createElement('a');
a_elem.href=URL.createObjectURL(blob);
a_elem.download='FFP.json'; // 保存ファイル名
a_elem.click();
URL.revokeObjectURL(a_elem.href); }
button2.onclick=function(){
ffp_input.click(); }
ffp_input.addEventListener("change", function(){
if(!(ffp_input.value)) return; // ファイルが選択されない場合
let file_list=ffp_input.files;
if(!file_list) return; // ファイルリストが選択されない場合
let file=file_list[0];
if(!file) return; // ファイルが無い場合
let file_reader=new FileReader();
file_reader.readAsText(file);
file_reader.onload=function(){
if(file_reader.result.slice(0, 15)=='[["0","FixedFor'){ // FFP.jsonの確認
let data_in=JSON.parse(file_reader.result);
format_data=data_in; // 記録用配列 format_data を上書き
let write_json=JSON.stringify(format_data);
localStorage.setItem('Format_Data', write_json); // ローカルストレージに保存
}};});
button3.onclick=function(){
menu_end();
caret_back();
unselect_h(); }
} // ffp_backup()
} // main()
「Fixed Format Palette」最新版について
旧いバージョンの JavaScriptツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。
●「Fixed Format Palette」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。








