右クリックメニューの「新しいタブで画像を開く」 

ブラウザの「右クリックメニュー」(コンテキストメニュー)は、使い慣れると無くてはならない機能です。 これはブラウザに組込まれたプログラムで、同条件で同様に右クリックしても、ブラウザによってメニューが違う事があります。

 

「右クリックメニュー」は、右クリックした対象に合わせた適当で可能なメニューが表示される仕組みで、内容は対象によって変化します。 例えばページ上の「画像」には「リンクが設定された画像」と「リンクがない画像」があり、それによって「右クリックメニュー」の内容が違って来ます。

 

 

 対象によって「メニュー」が変化する例

下は「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行 

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 ~~~

 

これで、「styleタグ」が無効でも「なんとか見れる」様になりました。

 

 

「svg」画像の文字数節約のためにCSSの修飾をする場合は「height」「width」の属性指定を省く場合が多いのです。 しかし今回の様な場合を考えると、「CSSで上書き指定がある場合も「svg」のサイズ属性は省略しない方が安全かも知れません。

 

この処理で奇抜な崩れは解消しましたが、Lightboxのパーツが露出して、しかも正常な動作ができないのは、今回の様な特殊な仕様の画像では避けられません。

 

 

 「新しいタブで画像を開く」で起動させない

いっその事、「新しいタブで画像を開く」で開いた画面では「Uni Lightbox JS」が起動しない様にしようかと考えました。 これは、ある程度は可能な事で、以下のページの情報が使えます。

 

 

このページの下のサンプルコードをテストすると、少なくとも確実に「新しいタブで開く」で開いた画面を判定できます。

 

if (document.referrer) {
    if (history.length == 1) {
        alert('リンクから新しいウィンドウで開かれました。');
    } else {
        alert('リンクから同じウィンドウで開かれました。');
    }
} else {
    alert('アドレスバーにURLを打ち込んで開かれました。もしくはブックマークから開かれました。');
}

 

しかし、リンクを「新しいタブで開く」「新しいタブで画像を開く」のどちらにも反応し、「画像を開く」場合のみを判定できないと使えません。 切り分ける方法を探すと、 Chormeの場合は「画像を開く」の場合の「body要素」に特徴があります。

 

<body style="margin: 0px; background: #0e0e0e; height: 100%">

 

「#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」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。