リンクカードのコンパクト化アレンジ機能
「リンクカード」の記事本文を遮ってしまうデザインが納得できず、これまでコンパクトにアレンジをして使って来ました。 具体的には Elements Palette にアレンジ機能を実装して利用して来ましたが、同等の機能を「LinkCard Editor」にも搭載する事にしました。
◎ コンパクト化アレンジの結果は、どちらのツールを使っても同じです。 余りない事ですが、「LinkCard Editor」でカバー画像を変更して「Elements Palette」でコンパクト化アレンジをしても問題はありません。 両方のアレンジを重ねても無問題です。
◎「Elements Palette」は記事上の「リンクカード」「リブログカード」を纏めてアレンジできますが、「LinkCard Editor」は「リンクカード」のみを、1個ずつ編集・アレンジする仕様です。
操作の実際
アレンジ機能の実装のために、ツール起動時の上部の帯に「リンクカード」の配置を指定するボタンを追加しました。
「Ctrl+F6」で「LinkCard Editor」を起動しカードリンクを「Ctrl+左クリック」して編集対象に指定します。 カードに「青枠」が表示されると、テキスト部にキャレットを入れて文字編集が可能です。 また「画像パレット」の登録画像をクリックして、クリックした画像をカードの「カバー画像」に設定できます。
下は「カバー画像」を変更した状態ですが、「記事タイトル」が "『』"で囲まれています。 これは「リンクカード」の仕様ですが、カッコが重なるのは不都合です。
● 3つの配置指定ボタンのどれを押しても、コンパクトアレンジが実行されます。
「 ▇ 」は「中央配置」、「◀」「▶」は、それぞれの方向にカードを寄せます。 下図は「中央配置」を指定したところです。
配置指定は後から変更が可能ですが、コンパクト化を元に戻す機能はありません。 元のデザインが必要な場合は、リンクカードを作りなおしてください。
● コンパクト化と同時に、不要な "『』" が自動的に削除されます。 キャレットを入れて「記事タイトル」を編集しても同じですが、その手間が省けます。
● デフォルトは「記事の出だし」が1行ですが、隠れていた文字を複数行で表示する仕様に変わります。 デフォルトよりコンパクトですが、逆に情報量が増えます。
● このアレンジは、インラインのアレンジなのでスマホ表示にも有効です。
● カードの編集が終了したら「Ctrl+F6」で「LinkCard Editor」を終了します。 編集画面上部の「帯表示」と、全ての「青枠」が非表示になります。
その他の操作上の注意
「LinkCard Editor」によって「リンクカード」上の「記事タイトル」「記事の出だし」などの文字が編集可能になります。「文字サイズ」「太字指定」「アンダーライン」「消し線」「文字色」「文字背景色」などの修飾変更・追加が可能ですが、編集内容によっては段落分けを生じて、カード全体が崩れてしまう場合があります。
この様な操作に至るのはスキルのあるユーザーでしょう。「リンクカード」は作り直しが出来ますから、どこまでアレンジするかはユーザーに委ねる事にします。
「LinkCard Editor」ver. 0.3
このツールは Chrome・Edge / Firefox 版の「Tampermonkey」で動作を確認しています。「Tampermonkey」に以下のコードを登録する事で、このツールを利用することが出来ます。
〔コピー方法〕 軽量シンプルなツール「PreBox Button 」を使うと
コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」
の操作で、掲載コードのコピーが可能になります。
〔 LinkCard Editor 〕ver. 0.3
// ==UserScript==
// @name LinkCard Editor ⭐
// @namespace http://tampermonkey.net/
// @version 0.3a
// @description 「通常表示」上のリンクカードを編集 「Ctrl+F6」
// @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 mode=0; // Card編集状態
let retry=0;
let interval=setInterval(wait_target, 100);
function wait_target(){
retry++;
if(retry>10){ // リトライ制限 10回 1sec
clearInterval(interval); }
let target=document.querySelector('#cke_1_contents'); // 監視 target
if(target){
clearInterval(interval);
main(); }}
function main(){
let editor_iframe;
let iframe_doc;
let iframe_body;
let wysiwyg; // 通常表示の iframe内 html
let target0=document.querySelector('#cke_1_contents'); // 監視 target
let monitor0=new MutationObserver( catch_key );
monitor0.observe(target0, {childList: true}); // ショートカット待受け開始
catch_key();
function catch_key(){
editor_iframe=document.querySelector('.cke_wysiwyg_frame');
if(editor_iframe){ // WYSIWYG表示が実行条件
when_back();
iframe_doc=editor_iframe.contentWindow.document;
iframe_doc.addEventListener('keydown', check_key); // iframe内
document.addEventListener('keydown', check_key); // iframe外
function check_key(event){
if(event.ctrlKey && event.keyCode==117){ // ショートカット「Crtl+F6」
event.stopImmediatePropagation();
if(mode==0 && editor_iframe){
mode=1;
sign();
card_edit(); }
else if(mode==1 && editor_iframe){
mode=0;
sign_clear();
card_close(); }}}}
before_end();
} // catch_key()
function when_back(){
if(mode==1){
sign();
card_edit_r();
card_edit(); }}
function card_close(){
editor_iframe=document.querySelector('.cke_wysiwyg_frame');
if(editor_iframe){ // WYSIWYG表示が実行条件
iframe_doc=editor_iframe.contentWindow.document;
if(iframe_doc){
let iframe_body=iframe_doc.querySelector('body');
if(iframe_body){
let target_card=iframe_body.querySelectorAll('.ogpCard_root');
for(let k=0; k<target_card.length; k++){
if(target_card[k].classList.contains('edit_card')){
target_card[k].classList.remove('edit_card');
let ogpCard_wrap=target_card[k].querySelector('.ogpCard_wrap');
if(ogpCard_wrap){
ogpCard_wrap.setAttribute('contenteditable', 'false'); }}}}}}}
function card_edit(){
editor_iframe=document.querySelector('.cke_wysiwyg_frame');
if(editor_iframe){ // WYSIWYG表示が実行条件
iframe_doc=editor_iframe.contentWindow.document;
if(iframe_doc){
let iframe_body=iframe_doc.querySelector('body');
if(iframe_body){
let target_card=iframe_body.querySelectorAll('.ogpCard_root');
for(let k=0; k<target_card.length; k++){
target_card[k].addEventListener('click', function(event){
event.preventDefault();
if(event.ctrlKey){
set_card(target_card[k]); }}); }
function set_card(card){
if(mode==1){
card_close();
card.classList.add('edit_card');
edit_in(card); }}
}}}} // card_edit()
function card_edit_r(){
editor_iframe=document.querySelector('.cke_wysiwyg_frame');
if(editor_iframe){ // WYSIWYG表示が実行条件
iframe_doc=editor_iframe.contentWindow.document;
if(iframe_doc){
let iframe_body=iframe_doc.querySelector('body');
if(iframe_body){
let target_card=iframe_body.querySelectorAll('.ogpCard_root');
for(let k=0; k<target_card.length; k++){
if(target_card[k].classList.contains('edit_card')){
edit_in(target_card[k]); }}}}}}
function edit_in(card){
if(mode==1){
let ogpCard_wrap=card.querySelector('.ogpCard_wrap');
if(ogpCard_wrap){
ogpCard_wrap.setAttribute('contenteditable', 'true'); } // 編集可能にする
let card_link=card.querySelector('.ogpCard_link');
if(!card.querySelector('.ogpCard_imageWrap')){
let imgw=document.createElement('span');
imgw.setAttribute('class', 'ogpCard_imageWrap');
imgw.setAttribute('style', 'position:relative;width:120px;height:120px;flex-shrink:0');
card_link.appendChild(imgw); } // カバー画像が無い場合に表示エリアを確保する
arrange_in(card);
item_setter(); }} // edit_in()
function item_setter(){
let target1=document.querySelector('#js-photos-imageList'); // 監視 target
let monitor1=new MutationObserver(item_select);
monitor1.observe(target1, {childList: true, subtree: true}); // 画像パレット監視
item_select();
function item_select(){
let item=document.querySelectorAll('.p-images-imageList__item');
for(let k=0; k<item.length; k++){
item[k].addEventListener('click', function(event){
set_img(event, item[k]); }); }}
function set_img(e, item){
if(mode==1){
e.stopImmediatePropagation();
let img_src=item.getAttribute('data-image');
let inner=
'<img alt="" class="ogpCard_image" data-ogp-card-image="" height="120" '+
'loading="lazy" data-cke-saved-src="' + img_src +
'" src="' + img_src +
'" style="position:absolute;top:50%;left:50%;object-fit:cover;'+
'min-height:100%;min-width:100%;'+
'transform:translate(-50%,-50%)" width="120">';
editor_iframe=document.querySelector('.cke_wysiwyg_frame');
if(editor_iframe){ // WYSIWYG表示が実行条件
iframe_doc=editor_iframe.contentWindow.document;
if(iframe_doc){
let iframe_body=iframe_doc.querySelector('body');
if(iframe_body){
let target_card=iframe_body.querySelectorAll('.ogpCard_root');
for(let k=0; k<target_card.length; k++){
if(target_card[k].classList.contains('edit_card')){
range_con(target_card[k]);
let card_imgw=target_card[k].querySelector('.ogpCard_imageWrap');
if(card_imgw){
card_imgw.innerHTML=inner; }}}
function range_con(card){
if(mode==1){
let selection=iframe_doc.getSelection(); //Selection取得
let range=iframe_doc.createRange(); //Range生成
range.setStart(card, 0);
range.setEnd(card, 0);
selection.removeAllRanges();
selection.addRange(range); }} // 選択Cardにselectionを指定
}}}}} // set_img()
} // item_setter()
function arrange_in(card){
let al=document.querySelector('#disp_le #al');
let ac=document.querySelector('#disp_le #ac');
let ar=document.querySelector('#disp_le #ar');
al.onclick=function(){ arrange_setting(0); }
ac.onclick=function(){ arrange_setting(1); }
ar.onclick=function(){ arrange_setting(2); }
function arrange_setting(n){
if(card.classList.contains('edit_card')){
if(n==0){
card.style.textAlign='left'; }
else if(n==1){
card.style.textAlign='center'; }
else if(n==2){
card.style.textAlign='right'; }
let link=card.querySelector('.ogpCard_link');
if(link){
link.style.width='500px';
link.style.height='108px';
link.style.margin='0 auto';
link.style.border='1px solid #009688'; }
let content=card.querySelector('.ogpCard_content');
if(content){
content.style.padding='8px 25px 4px 15px'; }
let title=card.querySelector('.ogpCard_title');
if(title){
title.style.flexShrink='0';
title.style.font='bold 16px/1.25 Meiryo';
slim_title(card); }
let description=card.querySelector('.ogpCard_description');
if(description){
description.style.whiteSpace='unset';
description.style.margin='0';
description.style.font='13px/1.4 Meiryo'; }
let imageW=card.querySelector('.ogpCard_imageWrap');
if(imageW){
imageW.style.width='98px';
imageW.style.height='98px';
imageW.style.top='3px';
imageW.style.right='15px';
imageW.style.border='1px solid #eee'; }
function slim_title(card){ // 先頭・末尾が『』の場合にカッコを削除
let link=card.querySelector('.ogpCard_link');
if(link.getAttribute('href').includes('https://ameblo.jp/')){
let title=card.querySelector('.ogpCard_title');
if(title){
let title_str=title.textContent;
if(title_str.slice(0, 1)=='『' && title_str.slice(-1)=='』'){
title_str=title_str.slice(1).slice(0, -1); }
title.textContent=title_str; }}}}}}
function sign(){
monitor0.disconnect(); // 起動時セットアップを MutationObserverに反応させない
let disp=document.createElement("div");
disp.setAttribute("id", "disp_le");
disp.innerHTML=
' ▢ LinkCard Editor カード編集指定:Ctrl+Click 小型化と配置:'+
'<span id="al">◀</span><span id="ac"> ▇ </span><span id="ar">▶</span>';
let css=
'#cke_1_contents { display: flex; flex-direction: column; } '+
'#disp_le { display: none; margin: 0 0 9px; padding: 4px 0 2px; '+
'font: normal 16px Meiryo; color: #fff; background: #607d8b; } '+
'#ac { font-size: 14px; vertical-align: 1px; } '+
'#al, #ac, #ar { cursor: pointer; }';
let style=document.createElement('style'); // disp_le のデザインを指定
style.setAttribute("id", "le_style");
style.innerHTML=css;
disp.appendChild(style);
editor_iframe=document.querySelector('.cke_wysiwyg_frame');
if(editor_iframe){
if(!target0.querySelector('#disp_le')){
target0.insertBefore(disp, editor_iframe); }}
editor_iframe=document.querySelector('.cke_wysiwyg_frame');
if(editor_iframe){
iframe_doc=editor_iframe.contentWindow.document;
if(iframe_doc){
let iframe_html=iframe_doc.querySelector('html');
iframe_body=iframe_doc.querySelector('body');
if(iframe_html && iframe_body){
let card_style= iframe_doc.createElement('style'); // 選択Card のデザインを指定
let css='.edit_card { outline: 2px solid #2196f3; }';
card_style.setAttribute("id", "card_style");
card_style.innerHTML=css;
if(!iframe_html.querySelector('#card_style')){
iframe_html.appendChild(card_style); }}}}
let disp_le=document.querySelector('#disp_le');
disp_le.style.display='block';
let photos_w=document.querySelector('#js-photos-wrapper');
photos_w.style.outline='2px solid #2196f3'; // 画像パレットに青枠表示
monitor0.observe(target0, {childList: true});
} // sign()
function sign_clear(){
if(target0.querySelector('#disp_le')){
target0.querySelector('#disp_le').style.display='none'; } // 起動表示を非表示
let photos_w=document.querySelector('#js-photos-wrapper');
photos_w.style.outline=''; } // 画像パレットの青枠を削除
function before_end(){
editor_iframe=document.querySelector('.cke_wysiwyg_frame');
let submitButton=document.querySelectorAll('.js-submitButton');
submitButton[0].addEventListener("click", all_close, false);
submitButton[1].addEventListener("click", all_close, false);
function all_close(){
if(mode==1){
if(!editor_iframe){ //「HTML表示」編集画面の場合
alert("⛔ LinkCard Editor が処理を終了していません\n\n"+
" 通常表示画面に戻り 編集を終了してください");
event.stopImmediatePropagation();
event.preventDefault(); }
else if(editor_iframe){ //「通常表示」編集画面の場合
mode=0;
card_close(); }}}
} // before_end()
} // main()
〔追記〕2020.12.09
「関数sign()」で「styleタグ」を記事中に書き込むコード上の間違いがあったので、修正しました。 ver. 0.3a は修正済です。
「LinkCard Editor ⭐」最新版について
旧いバージョンの「LinkCard Editor ⭐」は、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。 最新バージョンへのリンクは、以下のページのリンクリストから探せます。






