右クリックメニューの「新しいタブで画像を開く」
ブラウザの「右クリックメニュー」(コンテキストメニュー)は、使い慣れると無くてはならない機能です。 これはブラウザに組込まれたプログラムで、同条件で同様に右クリックしても、ブラウザによってメニューが違う事があります。
「右クリックメニュー」は、右クリックした対象に合わせた適当で可能なメニューが表示される仕組みで、内容は対象によって変化します。 例えばページ上の「画像」には「リンクが設定された画像」と「リンクがない画像」があり、それによって「右クリックメニュー」の内容が違って来ます。
対象によって「メニュー」が変化する例
下は「AbemaTV」の例で、「動画タイトル一覧画面」です。
この部分の3個の「画像」の「右クリックメニュー」は、全て内容が違います。
◎ブラウザによってメニューが異なりますが、ここは「Chrome」での説明です。
◎JavaScriptツール類は「メニュー」を乗っ取るので、全てOFFにしています。
❶
❷
❸
「新しいタブで開く」は、リンク先の画面を開くという意味です。 従って「リンク」が設定されていない画像は、このメニューは出ません。
❶ は「リンク」がないので、このメニューが無いわけです。
❷❸ は下の「動画再生画面」への「リンク」が設定されています。
「新しいタブで画像を開く」は画像ソースにアクセスして、画像のみを表示します。
この画面はブラウザ自身による演出で、❶❷ は下の様に右クリックした「画像」のみが表示されます。
ただし、この画像は少し特殊な画像で、通常の画像は黒背景でウインドウ中央に表示されます。 Firefoxは特殊条件の影響を受けず、下の様に通常の表示になります。
❸だけ「新しいタブで画像を開く」のメニューが無いのは、サイト側のスクリプトが関係して、ブラウザがメニューを出さないのだと思います。
まとめ
「右クリックメニュー」は、ブラウザが適当で可能なメニューを右クリックした対象に合わせて表示しています。 対象の条件やブラウザによってメニューは異なります。 その中で、画像表示のメニュー「新しいタブで画像を開く」は、ウインドウ内のレイアウト(黒背景・中央配置)をブラウザ自身が用意する点で少し特別です。
「Uni Lightbox JS」の特殊な画像への対応
そもそも、全てのネット上のページ(アメーバサイトを除く)を実行場所とするツールは、無理があって当然です。 サイトによって様々なHTMLがあり、想定外の画像や背景条件について、とても推し測れないからです。「Uni Lightbox JS」は、それを承知の上のツールですから、気付いた時点で対応するしかありません。
今回は、たまたま「Abama TV」で見つけた問題で、以前にもGoogle画像検索をしていて、同様の問題に出会っていました。 その原因が「Uni Lightbox JS」にある事が漸く判ったのですが。
問題というのは、このページ最初に書いた「新しいタブで画像を開く」の「右クリックメニュー」で稀に生じます。「Uni Lightbox JS」は「AbemaTV」では動作をしない設定ですが、「新しいタブで画像を開く」で開くタブは、画像のソースのURLにアクセスした状態で、そこでは「Uni Lightbox JS」が動作します。
上記のサンプル画像を右クリックすると、下の様な表示になります。
「Uni Lightbox JS」のデフォルトの起動ショートカットは「Ctrl+右Click」ですし、そもそも「AbemaTV」のページではこのショートカットは働きません。 つまり、この問題は、特別な画像を「新しいタブで画像を開く」で開いたタブ画面での問題で、しかも通常の画像の場合は生じないのです。
「AbemaTV」のサムネイル画像は、すべて「https://abm.hayabusa.media/」というサイトにソースがありますが、このサイト自体が特殊な画像の送り出し方をしている様です。
Chromeでは、白背景になって本来のセンター配置にならない。 Firefoxでは通常の画像と同様に黒背景・センター配置になるが、どちらの場合も「Uni Lightbox JS」は動作していても、挙動が正常ではありません。
通常の画像を「新しいタブで画像を開く」で開いた場合は、「画像」が黒背景・中央のデフォルト表示になり、更にその画像を「Ctrl+左Click」すれば「Uni Lightbox JS」が起動して、部分的な拡大表示も機能します。
原因は難解
「次のコンテンツ セキュリティポリシー ディレクティブに違反するため、インラインスタイルの適用が拒否されました: "default-src 'none'" 」というスクリプトのエラーが DevToolsに表示されます。 確かに Lightbox表示のための「styleタグ」の修飾が全く無効になっています。 色々と試しましたが「セキュリティポリシー」が出て来ると、手も足も出せません。
先ず、上の「巨大リンクマーク」は Lightboxのパーツで、「svg」のサイズ指定のCSSが無効になった結果で、「svg」のインラインのサイズ指定を追加しました。
ver. 0.6 102行
これで、「styleタグ」が無効でも「なんとか見れる」様になりました。
「svg」画像の文字数節約のためにCSSの修飾をする場合は「height」「width」の属性指定を省く場合が多いのです。 しかし今回の様な場合を考えると、「CSSで上書き指定がある場合も「svg」のサイズ属性は省略しない方が安全かも知れません。
この処理で奇抜な崩れは解消しましたが、Lightboxのパーツが露出して、しかも正常な動作ができないのは、今回の様な特殊な仕様の画像では避けられません。
「新しいタブで画像を開く」で起動させない
いっその事、「新しいタブで画像を開く」で開いた画面では「Uni Lightbox JS」が起動しない様にしようかと考えました。 これは、ある程度は可能な事で、以下のページの情報が使えます。
このページの下のサンプルコードをテストすると、少なくとも確実に「新しいタブで開く」で開いた画面を判定できます。
しかし、リンクを「新しいタブで開く」「新しいタブで画像を開く」のどちらにも反応し、「画像を開く」場合のみを判定できないと使えません。 切り分ける方法を探すと、 Chormeの場合は「画像を開く」の場合の「body要素」に特徴があります。
「#0e0e0e」で判定すれば、不完全ですが切り分け可能かも。 しかし、Firefoxではこの特徴はなく、まあ難しいです。
この様な特殊な仕様の画像はそう多くないし、そもそも一般のページで「新しいタブで画像を開く」で画像ソースを開き、更に「Uni Lightbox JS」を使うのは、変な使い方です。 最初から画像を「Ctrl+右Click」すれば良いのですから。(出来ない場合もありますが)
という事で、この問題の対策は、「svg」コードの修正だけとしました。
操作マニュアル
「Uni Lightbox JS」の全ての操作方法は以下のページに纏めています。
「Uni Lightbox JS」を利用するには
このツールは Chrome・Edge・Firefox版の拡張機能「Tampermonkey」上で動作します。 以下に、このツールの導入手順を簡単に説明します。
❶「Tampermonkey」を導入します
◎ 使用しているブラウザに拡張機能「Tampermonkey」を導入する事が必要です。
既に「Tampermonkey」を導入している場合は、この手順 ❶ は不要です。
拡張機能の導入については、以下のページに簡単な説明があるので参照ください。
❷「Tampermonkey」にスクリプトを登録します
◎「Tampermonkey」の「+」マークの「新規スクリプト」タブを開きます。
◎「新規スクリプト」には、最初からテンプレートが記入されています。 これは全て削除して、完全に空白の編集枠に 下のコードをコピー&ペーストします。
〔コピー方法〕 軽量シンプルなツール「PreBox Button 」を使うと
コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」
の操作で、掲載コードのコピーが可能になります。
◎ 最後に「ファイル」メニューの「保存」を押すと、ツールが使用可能になります。
〔 Uni Lightbox JS 〕 ver. 0.6
// ==UserScript== // @name Uni Lightbox JS // @namespace http://tampermonkey.net/ // @version 0.6 // @description ネット上の画像の高精細な暗転拡大表示 // @author personwritep // @match https://*/* // @match http://*/* // @exclude https://ameblo.jp/* // @exclude https://abema.tv/* // @exclude https://*.ameba.jp/* // @noframes // @grant none // ==/UserScript== let disp_mode=0; // 拡張ディスプレイモードの判別 let view_w; // 拡大率 let view_ac; // クリック操作 0: Ctrl+右Click 1: 右Click view_w=sessionStorage.getItem('UL_w')*1; if(!view_w){ view_w=200; // 🔴拡大率の初期値 sessionStorage.setItem('UL_w', view_w); } view_ac=sessionStorage.getItem('UL_ac')*1; if(!view_ac){ view_ac=0; // 🔴クリック動作の初期値 sessionStorage.setItem('UL_ac', view_ac); } let html_=document.documentElement; box_env(); document.addEventListener('contextmenu', function(event){ if(disp_mode==0){ if(view_ac==0){ if(event.ctrlKey){ event.preventDefault(); event.stopImmediatePropagation(); let elem=document.elementFromPoint(event.clientX, event.clientY); if(elem){ set_img(elem); set_link(elem); }}} if(view_ac==1){ if(!event.ctrlKey){ event.preventDefault(); event.stopImmediatePropagation(); let elem=document.elementFromPoint(event.clientX, event.clientY); if(elem){ set_img(elem); set_link(elem); }}}} else{ event.preventDefault(); event.stopImmediatePropagation(); ex_mag(event); }},true ); let lightbox=document.querySelector('#lightbox'); if(lightbox){ lightbox.onclick=(event)=>{ if(disp_mode!=0){ close_box(event); }}} let mag_sw=document.querySelector('#mag_sw'); if(mag_sw){ mag_sw.onclick=(event)=>{ event.preventDefault(); event.stopImmediatePropagation(); }} function box_env(){ let ud_SVG= '<svg height="20" width="20" viewBox="0 0 40 50">'+ '<path style="fill: #000;" d="M20 6L13 21L28 21C25.9 15.9 23.5 '+ '10.3 20 6M13 28L20 43C23.5 38.7 25.9 33.1 28 28L13 28z"></path>'+ '</svg>'; let help_SVG= '<svg height="28" width="28" viewBox="0 0 256 256">'+ '<path style="fill: #000;" d="M114 12C96 15 79 '+ '20 64 30C51 38 42 48 34 60C1 105 6 170 45 210C60 225 80 235 '+ '100 241C114 245 129 245 144 243C160 241 175 235 188 227C201 '+ '219 212 208 221 196C260 143 245 65 190 30C179 23 166 17 153 '+ '15C140 12 127 11 114 12z"></path>'+ '<path style="fill: #fff;" d="M115 26C100 29 85 34 72'+ ' 42C60 49 51 57 43 69C16 109 19 167 54 202C66 213 81 223 97 '+ '227C111 231 128 233 142 231C156 229 170 224 182 216C233 184 '+ '246 110 208 63C194 47 175 36 155 30C143 26 128 25 115 26z"></path>'+ '<path style="fill: #000;" d="M85 94C94 93 102 '+ '88 110 85C121 82 143 85 137 102C134 111 125 116 119 122C110 '+ '131 106 142 105 155L140 155C143 141 154 134 163 123C172 111 '+ '176 95 171 81C162 57 133 55 111 58C104 59 94 60 88 65C82 71 '+ '85 86 85 94M108 176L108 205C115 204 122 205 129 205C131 205 '+ '136 205 138 204C140 202 139 198 139 196L139 176L108 176z"></path>'+ '</svg>'; let link_SVG= '<svg class="link_UL" height="22" width="22" viewBox="0 0 512 512">'+ '<path d="M327 185c60 60 59 156.7.36 215-.11.12-.24.25-.36.37l-67 '+ '67c-59 59-156 59-215 0-59-59-59-156 0-215l37-37c10-10 27-3 27 '+ '10.6.6 18 4 36 10 53 2 5.8.6 12-4 17l-13 13c-28 28-29 74-1 102 28 '+ '29 74 29 102.3.5l67-67c28-28 28-74 0-102-4-4-7-7-10-9a16 16 0 0 '+ '1-7-13c-0-11 3-21 12-30l21-21c6-6 14-6 21-2a152 152 0 0 1 21 '+ '17zM468 44c-59-59-156-59-215 0l-67 67c-.1.1-.3.3-.4.4-59 59-59 '+ '154.8.4 215a152 152 0 0 0 21 17c6 4 15 4 21-2l21-21c8-8 12-19 '+ '12-30a16 16 0 0 0-7-13c-3-2-7-5-10-9-28-28-28-74 0-101l67-67c28-28 '+ '74-28 102.3.5 28 28 27 74-1 102l-13 13c-4 4-6 11-4 17 6 17 9 35 10 '+ '52.7.5 14 17 20 27 11l37-37c59-59 59-155.7.0-215z"></path></svg>'; let lightbox= '<div id="lightbox">'+ '<div id="photo_sw">'+ '<a id="photo_link">'+ link_SVG +' Linked Page</a>'+ '<div id="mag_sw">'+ '<p id="ws" class="bc" title="拡大率:マウスホイールで調節">Gz'+ ud_SVG + '<span id="wsv"></span></p>'+ '<p id="ac" class="bc" title="Lightboxの起動操作"></p>'+ '<a id="help_svg">'+ help_SVG +'</a>'+ '</div></div>'+ '<img id="box_img">'+ '<style>'+ '@keyframes fadeIn { 0% {opacity: 0} 100% {opacity: 1}} '+ '.fin { animation: fadeIn .5s ease 0s 1 normal; animation-fill-mode: both; } '+ '@keyframes fadeOut { 0% {opacity: 1} 100% {opacity: 0}} '+ '.fout { animation: fadeOut .2s ease 0s 1 normal; animation-fill-mode: both; } '+ '#lightbox { position: fixed; top: 0; left: 0; visibility: hidden; z-index: 3000000000; '+ 'display: grid; place-items: center; overflow: auto; user-select: none; '+ 'background: black; width: 100vw; height: 100vh; text-align: center; } '+ '#photo_sw { position: fixed; top: 0; width: 100%; height: 15%; } '+ '#photo_sw:hover #photo_link { opacity: 1; } '+ '#photo_link { font: bold 21px Meiryo; position: absolute; top: 16px; left: 30px; '+ 'padding: 4px 12px 1px 10px; color: #000; background: #fff; cursor: pointer; '+ 'border: 2px solid #000; border-radius: 6px; text-decoration: none; opacity: 0; } '+ '#photo_link:not([href]) { visibility: hidden; } '+ '.link_UL{ height: 22px; vertical-align: -3px; fill: red; } '+ '#mag_sw { position: fixed; top: 0; right: 20px; display: flex; padding: 20px; '+ 'width: auto; justify-content: flex-end; box-sizing: content-box; opacity: 0; } '+ '#photo_sw:hover #mag_sw { opacity: 1; } '+ '#help_svg { margin-left: 20px; cursor: pointer; } '+ '.bc { height: 24px; padding: 0 5px; margin: 0 4px; '+ 'font: bold 22px/28px Meiryo; border: 2px solid #000; border-radius: 4px; '+ 'background: #fff; cursor: pointer; box-sizing: content-box; overflow: hidden; } '+ '#ws svg { vertical-align: -3px; margin-right: 4px; } '+ '#box_img { width: 98vw; height: 98vh; padding: 1vh 1vw; object-fit: contain; '+ 'box-sizing: content-box; max-width: unset; max-height: unset; } '+ 'img { pointer-events: auto !important; } '+ '</style></div>'; if(!document.querySelector('#lightbox')){ document.body.insertAdjacentHTML('beforeend', lightbox); } let wsv=document.querySelector('#wsv'); if(wsv){ wsv.textContent=view_w; } zoom_set(); ctrl_act(); let help_svg=document.querySelector('#help_svg'); if(help_svg){ help_svg.onclick=(event)=>{ event.stopImmediatePropagation(); let help_url='https://ameblo.jp/personwritep/entry-12798649205.html'; window.open( help_url, null, '_blank'); }} } // box_env() function zoom_set(){ let wsv=document.querySelector('#wsv'); let mag_sw=document.querySelector('#mag_sw'); function ac_check(element){ let opa=window.getComputedStyle(element).getPropertyValue('opacity'); if(opa=='1' && disp_mode==2){ return true; }} if(wsv){ document.onwheel=function(event){ // マスウホイールで設定 if(event.deltaY<0 && ac_check(mag_sw) && view_w<381){ event.preventDefault(); event.stopImmediatePropagation(); view_w=view_w*1 +20; let box_img=document.querySelector('#box_img'); if(box_img){ box_img.style.width=view_w +'vw'; trim(view_w); } wsv.textContent=view_w; sessionStorage.setItem('UL_w', view_w); } else if(event.deltaY>0 && ac_check(mag_sw) && view_w>119){ event.preventDefault(); event.stopImmediatePropagation(); view_w=view_w*1 -20; let box_img=document.querySelector('#box_img'); if(box_img){ box_img.style.width=view_w +'vw'; trim(view_w); } wsv.textContent=view_w; sessionStorage.setItem('UL_w', view_w); } function trim(view_z){ let lightbox=document.querySelector('#lightbox'); let box_img=document.querySelector('#box_img'); let i_width=box_img.naturalWidth; let i_height=box_img.naturalHeight; let w_width= window.innerWidth; let w_height= window.innerHeight; let view_width=w_width*view_z/100; lightbox.scrollTo((view_width - w_width)/2, ((view_width*i_height)/i_width - w_height)/2); } }}} // zoom_set() function ctrl_act(){ let ac=document.querySelector('#ac'); if(ac){ if(view_ac==0){ ac.textContent='Ctrl+ R-Click'; } else{ ac.textContent='R-Click'; } ac.onclick=function(event){ event.stopImmediatePropagation(); if(view_ac==0){ view_ac=1; ac.textContent='R-Click'; } else{ view_ac=0; ac.textContent='Ctrl+R-Click'; } sessionStorage.setItem('UL_ac', view_ac); } // Storage更新 }} // ctrl_act() function set_link(target){ let photo_link=document.querySelector('#photo_link'); if(photo_link){ let link_a=target.closest('a'); if(link_a){ let url=link_a.getAttribute('href'); if(url){ photo_link.setAttribute('href', url); }} photo_link.onclick=function(event){ event.stopImmediatePropagation(); }}} function set_img(target){ let lightbox=document.querySelector('#lightbox'); let box_img=lightbox.querySelector('#box_img'); if(lightbox && box_img && target){ let img_url=target.getAttribute('src'); if(img_url){ disp_mode=1; // 拡張ディスプレイモードに入る disp_spm(); box_img.src=img_url; html_.style.overflow='hidden'; lightbox.style.visibility='visible'; lightbox.classList.remove('fout'); lightbox.classList.add('fin'); }}} function ex_mag(event){ let lightbox=document.querySelector('#lightbox'); let box_img=lightbox.querySelector('#box_img'); if(lightbox){ if(disp_mode==1){ disp_mode=2; // 拡張拡大 disp_spm(); lightbox.style.overflow='auto'; box_img.style.height='auto'; box_img.style.padding='0'; box_img.style.width=view_w +'vw'; mag_point(event); } else{ disp_mode=1; // 通常拡大 disp_spm(); lightbox.style.overflow='hidden'; box_img.style.height='98vh'; box_img.style.width='98vw'; box_img.style.padding='1vh 1vw'; }} function mag_point(event){ let actal_x; // Actual Pixels表示スクロールx値 let actal_y; // Actual Pixels表示スクロールy値 let nwidth=box_img.naturalWidth; let nhight=box_img.naturalHeight; let ratio=nwidth/nhight let top=event.offsetY; let left=event.offsetX; let ww=lightbox.clientWidth; let wh=lightbox.clientHeight; if(ww<wh*ratio){ actal_x=(left*view_w/100) - ww/2; actal_y=(2*top - wh + ww/ratio)*view_w/200 - wh/2; } else{ let zk=((2*left - ww)/wh/ratio + 1)/2; actal_x=(zk*view_w -50)*ww/100; actal_y=(top*ww*view_w)/(wh*ratio*100) - wh/2; } lightbox.scrollTo(actal_x, actal_y); } } // ex_mag() function disp_spm(){ let ws=document.querySelector('#ws'); if(ws){ if(disp_mode==1){ ws.style.display='none'; } else{ ws.style.display='block'; }}} function close_box(event){ let lightbox=document.querySelector('#lightbox'); let box_img=lightbox.querySelector('#box_img'); if(lightbox && box_img){ event.preventDefault(); event.stopImmediatePropagation(); disp_mode=0; // 拡張ディスプレイモード リセット html_.style.overflow='inherit'; lightbox.classList.remove('fin'); lightbox.classList.add('fout'); lightbox.style.overflow='hidden'; // overflowのリセット box_img.style.height='98vh'; box_img.style.width='98vw'; box_img.style.padding='1vh 1vw'; setTimeout(()=>{ lightbox.style.visibility='hidden'; box_img.src=''; }, 200); }}
(注)スマホからは上のコード枠が参照できない場合があります。
「Uni Lightbox JS」最新版について
旧いバージョンの JavaScriptツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。
●「Uni Lightbox JS」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。