2

ユーザーが「story」で始まるクラスを右クリックした場合にのみ、コンテキスト メニューのアクションを表示する方法はありますか。

例: ユーザーがクラス "story ...." のページ内のオブジェクトを右クリックすると、コンテキスト メニュー ボタンが表示されます。それ以外の場合は何も起こりません。

これが私のコードです(動作しませんが):

var divs = document.querySelectorAll("[class^=story]"); //get all classes that start with "Story"

    window.oncontextmenu = function() {

        for(var i=0; i < divs.length; i++)
        {
            divs[i].onclick = function() { 
            chrome.contextMenus.create
            (
                {"id": "butto1", "title": "1", "contexts":["all"], "onclick": genericOnClick}
            );
            chrome.contextMenus.create
            (
                {"id": "button2", "title": "2", "contexts":["all"], "onclick": genericOnClick}
            );
            chrome.contextMenus.create
            (
                {"id": "button3", "title": "3", "contexts":["all"], "onclick": genericOnClick}
            );

            };
        }

        return true; 
    };


function genericOnClick(info, tab) {
  //do some crap here
  chrome.contextMenus.removeAll();
}
4

2 に答える 2

10

この関連する回答では、イベントとコンテキスト メニュー項目の表示の間の時間は間に呼び出しcontextmenuを取得するのに十分ではないため、コンテキスト メニュー項目をオンザフライで作成できないことを説明しました。chrome.contextMenus.create

もう 1 つの回答では、コンテキスト メニュー エントリに選択したテキストが表示されるようにする方法を説明しています。これは、イベントを聞くことによって行われましたselectionchange。あなたの目的のために、希望するタイミングのイベントを使用したいと考えています。

mouseoverとイベントを使用しmouseoutます。マウス イベントによっては、JavaScript または Tab キーを使用して要素にフォーカスし、続いてコンテキスト メニュー キーを押すなど、キーボードを使用するときにコンテキスト メニューが機能しません。以下のソリューションでは実装しませんでした。

デモは 3 つのファイル (およびテスト用の HTML ページ) で構成されています。すべてのファイルをhttps://robwu.nl/contextmenu-dom.zipで入手できる zip ファイルに入れました。

manifest.json

すべての Chrome 拡張機能が機能するには、このファイルが必要です。このアプリケーションでは、背景ページとコンテンツ スクリプトが使用されます。また、contextMenus許可が必要です。

{
    "name": "Contextmenu based on activated element",
    "description": "Demo for https://stackoverflow.com/q/14829677",
    "version": "1",
    "manifest_version": 2,
    "background": {
        "scripts": ["background.js"]
    },
    "content_scripts": [{
        "run_at": "document_idle",
        "js": ["contentscript.js"],
        "matches": ["<all_urls>"]
    }],
    "permissions": [
        "contextMenus"
    ]
}

background.js

バックグラウンド ページは、コンテンツ スクリプトに代わってコンテキスト メニューを作成します。これは、イベント リスナーを にバインドすることによって実現されchrome.runtime.onConnectます。これは、コンテキスト メニュー エントリを置き換えるためのシンプルなインターフェイスを提供します。

chrome.contextMenus.createメッセージがこのポートを介して (コンテンツ スクリプトから) 受信されるたびに呼び出されます。を除くすべてのプロパティonclickは JSON シリアル化可能であるため、「onclick」ハンドラーのみが特別な処理を必要とします。文字列を使用して、辞書内の定義済み関数を識別しました ( var clickHandlers)。

var lastTabId;
// Remove context menus for a given tab, if needed
function removeContextMenus(tabId) {
    if (lastTabId === tabId) chrome.contextMenus.removeAll();
}
// chrome.contextMenus onclick handlers:
var clickHandlers = {
    'example': function(info, tab) {
        // This event handler receives two arguments, as defined at
        // https://developer.chrome.com/extensions/contextMenus#property-onClicked-callback

        // Example: Notify the tab's content script of something
        // chrome.tabs.sendMessage(tab.id, ...some JSON-serializable data... );

        // Example: Remove contextmenus for context
        removeContextMenus(tab.id);
    }
};

chrome.runtime.onConnect.addListener(function(port) {
    if (!port.sender.tab || port.name != 'contextMenus') {
        // Unexpected / unknown port, do not interfere with it
        return;
    }
    var tabId = port.sender.tab.id;
    port.onDisconnect.addListener(function() {
        removeContextMenus(tabId);
    });
    // Whenever a message is posted, expect that it's identical to type
    // createProperties of chrome.contextMenus.create, except for onclick.
    // "onclick" should be a string which maps to a predefined function
    port.onMessage.addListener(function(newEntries) {
        chrome.contextMenus.removeAll(function() {
            for (var i=0; i<newEntries.length; i++) {
                var createProperties = newEntries[i];
                createProperties.onclick = clickHandlers[createProperties.onclick];
                chrome.contextMenus.create(createProperties);
            }
        });
    });
});

// When a tab is removed, check if it added any context menu entries. If so, remove it
chrome.tabs.onRemoved.addListener(removeContextMenus);

contentscript.js

このスクリプトの最初の部分では、コンテキスト メニューを作成するための簡単なメソッドを作成します。
最後の 5 行では、コンテキスト メニューのエントリが定義され、指定されたセレクターに一致する現在および将来のすべての要素にバインドされます。前のセクションで述べたように、引数の型は、バックグラウンド ページの関数にマップされる文字列である "onclick" を除いて、 のcreateProperties引数chrome.contextMenus.createと同じです。

// Port management
var _port;
var getPort = function() {
    if (_port) return _port;
    _port = chrome.runtime.connect({name: 'contextMenus'});
    _port.onDisconnect.addListener(function() {
        _port = null;
    });
    return _port;   
}

// listOfCreateProperties is an array of createProperties, which is defined at
// https://developer.chrome.com/extensions/contextMenus#method-create
// with a single exception: "onclick" is a string which corresponds to a function
// at the background page. (Functions are not JSON-serializable, hence this approach)
function addContextMenuTo(selector, listOfCreateProperties) {
    // Selector used to match an element. Match if an element, or its child is hovered
    selector = selector + ', ' + selector + ' *';
    var matches;
    ['matches', 'webkitMatchesSelector', 'webkitMatches', 'matchesSelector'].some(function(m) {
        if (m in document.documentElement) {
            matches = m;
            return true;
        }
    });
    // Bind a single mouseover+mouseout event to catch hovers over all current and future elements.
    var isHovering = false;
    document.addEventListener('mouseover', function(event) {
        if (event.target && event.target[matches](selector)) {
            getPort().postMessage(listOfCreateProperties);
            isHovering = true;
        } else if(isHovering) {
            getPort().postMessage([]);
            isHovering = false;
        }
    });
    document.addEventListener('mouseout', function(event) {
        if (isHovering && (!event.target || !event.target[matches](selector))) {
            getPort().postMessage([]);
            isHovering = false;
        }
    });
}

// Example: Bind the context menus to the elements which contain a class attribute starts with "story"
addContextMenuTo('[class^=story]', [
    {"id": "butto1", "title": "1", "contexts":["all"], "onclick": 'example'},
    {"id": "button2", "title": "2", "contexts":["all"], "onclick": 'example'},
    {"id": "button3", "title": "3", "contexts":["all"], "onclick": 'example'}
]);

前のコードは、すべてのコンテキスト メニューのクリックがバックグラウンド ページによって処理されることを前提としています。代わりにコンテンツ スクリプトでロジックを処理する場合は、コンテンツ スクリプトでメッセージ イベントをバインドする必要があります。このイベントがトリガーされる場所を示すためchrome.tabs.sendMessageに、例に (コメント付きの) のインスタンスを示しました。background.js

どの要素がイベントをトリガーしたかを特定する必要がある場合は、私の例に示すように (辞書で) 事前定義された関数を使用しないでください。インライン関数またはファクトリ関数を使用してください。要素を識別するには、メッセージを一意の識別子と組み合わせる必要があります。この実装を作成するタスクは読者に任せます (難しくありません)。

于 2013-03-08T22:29:53.397 に答える
0

これまで "all", "page", "frame", "selection", "link", "editable", "image", "video", "audio", "launcher"は、サポートされているコンテキストのみです。オブジェクトのクラスごとにカスタマイズすることはできません。

回避策

コンテキスト メニュー アクションを表示する場合は、ユーザーがページ上の特定の div.class を右クリックした場合にのみ、ここに示すようにマウス オーバー メニューを使用します。

ここに画像の説明を入力

于 2013-02-12T10:31:50.587 に答える