【问题标题】:Firefox Add-on SDK getting the tab IDFirefox Add-on SDK 获取标签 ID
【发布时间】:2014-06-26 11:37:03
【问题描述】:

我正在尝试使用 SDK(1.6 版)构建一个 Firefox 插件,但我遇到了与扩展程序打开的选项卡有关的问题。

我想获取aContext(节点)所在的选项卡。为此,我一直在“获取”节点的窗口,然后使用 SDK 中的 Tab Utils,特别是 getTabForContentWindow()。这有时不起作用,从getTabForContentWindow() 返回的 Tab 为空。有没有更好、更健壮的方法来获取节点的 Tab?

另外,我在the Tab Utils page 上注意到它表示它“不稳定”。我应该避免使用 Tab Utils SDK 吗?

下面是 main.js 中的代码:

const {Cc, Ci, Cr, Cu, Cm, components} = require("chrome");
const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var winUtils = require('sdk/window/utils');
var tabUtils = require('sdk/tabs/utils');

let policy =
{
    classDescription: "my content policy",
    classID: components.ID("{2DA54ECA-FBDD-11E3-B3B1-695C1D5D46B0}"),
    contractID: "@www.com/policy;1",
    xpcom_categories: ["content-policy"],

    init: function()
    {
        let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
        registrar.registerFactory(this.classID, this.classDescription, this.contractID, this);

        let catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
        for each (let category in this.xpcom_categories)
            catMan.addCategoryEntry(category, this.contractID, this.contractID, false, true);
    },

    // nsIContentPolicy interface implementation
    shouldLoad: function(aContentType, aContentLocation, aRequestOrigin, aContext, aMimeTypeGuess, aExtra, aRequestPrincipal) {

        console.log("*****");
        console.log("aContentLocation.spec [" + aContentLocation.spec + "] ");
        console.log("aContentType [" + aContentType + "] ");
        if (aContext instanceof components.interfaces.nsIDOMNode) {            
            var node = aContext.QueryInterface(components.interfaces.nsIDOMNode);
            var win = getWindow(node);
            if (win) {
                console.log("window found" );
                var selectedTab = tabUtils.getTabForContentWindow(win);                
                if (selectedTab) {
                    console.log("tab found" );
                    var tabId = tabUtils.getTabId(selectedTab);
                    console.log("Node's tabId:" + tabId);
                } else {
                    console.log("tab undefined" );
                }
            } else {
                console.log("win undefined" );
            } 
        }
        return Ci.nsIContentPolicy.ACCEPT;

    },

    shouldProcess: function(contentType, contentLocation, requestOrigin, node, mimeTypeGuess, extra) {
        return Ci.nsIContentPolicy.ACCEPT;
    },

    // nsIFactory interface implementation
    createInstance: function(outer, iid) {
        if (outer)
            throw Cr.NS_ERROR_NO_AGGREGATION;
        return this.QueryInterface(iid);
    },

    // nsISupports interface implementation
    QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy, Ci.nsIFactory])
};

policy.init();

var scheduleCheckFilterUpdates = function() {
    var tabs = require("sdk/tabs");
    tabs.open("http://wikipedia.org");
}
require('sdk/timers').setTimeout(scheduleCheckFilterUpdates, 1000);

function getWindow(node) {
    if ("ownerDocument" in node && node.ownerDocument)
        node = node.ownerDocument;

    if ("defaultView" in node)
        return node.defaultView;

    return null;
}

【问题讨论】:

    标签: javascript firefox firefox-addon firefox-addon-sdk


    【解决方案1】:

    你应该记住:

    • 并非所有请求都源自窗口。 (后台请求)
    • 并非所有源自窗口的请求实际上都源自选项卡。当您运行代码时,您可以看到例如请求浏览器窗口本身加载的 chrome://browser/skin/tabbrowser/tab-separator.png 之类的东西(在这种情况下将在 UI 中使用)。另请注意,并非所有顶级窗口实际上都是浏览器窗口 (browser.xul)。
    • 即使是选项卡导航,那么初始加载 (aContentLocation.spec [http://wikipedia.org/]) 将源自正在构建的新的、未完全初始化的内容窗口,还没有与任何标签相关联。此时的选项卡仍然是about:blank,新窗口(@98​​7654326@)只有在明确可以完全构建此窗口时才会被换入:请求未被阻止,DNS 已解析,随后重定向和最终响应实际上产生了数据,并且可以将这些数据制成一个窗口。例如。如果我的网络出现故障,wikipedia 窗口将在分配给选项卡之前被放弃,而是会创建一个连接错误文档和窗口。

    最后一点也有点记录在the nsIContentPolicy interface本身:

     /**
       * Should the resource at this location be loaded?
       * ShouldLoad will be called before loading the resource at aContentLocation
       * to determine whether to start the load at all.
       *
       * @param aContentType      the type of content being tested. This will be one
       *                          one of the TYPE_* constants.
       *
       * @param aContentLocation  the location of the content being checked; must
       *                          not be null
       *
       * @param aRequestOrigin    OPTIONAL. the location of the resource that
       *                          initiated this load request; can be null if
       *                          inapplicable
       *
       * @param aContext          OPTIONAL. the nsIDOMNode or nsIDOMWindow that
       *                          initiated the request, or something that can QI
       *                          to one of those; can be null if inapplicable.
       *                          Note that for navigation events (new windows and
       *                          link clicks), this is the NEW window.
       *
       * @param aMimeTypeGuess    OPTIONAL. a guess for the requested content's
       *                          MIME type, based on information available to
       *                          the request initiator (e.g., an OBJECT's type
       *                          attribute); does not reliably reflect the
       *                          actual MIME type of the requested content
       *
       * @param aExtra            an OPTIONAL argument, pass-through for non-Gecko
       *                          callers to pass extra data to callees.
       *
       * @param aRequestPrincipal an OPTIONAL argument, defines the principal that
       *                          caused the load. This is optional only for
       *                          non-gecko code: all gecko code should set this
       *                          argument.  For navigation events, this is
       *                          the principal of the page that caused this load.
       *
       * @return ACCEPT or REJECT_*
       *
       * @note shouldLoad can be called while the DOM and layout of the document
       * involved is in an inconsistent state.  This means that implementors of
       * this method MUST NOT do any of the following:
       * 1)  Modify the DOM in any way (e.g. setting attributes is a no-no).
       * 2)  Query any DOM properties that depend on layout (e.g. offset*
       *     properties).
       * 3)  Query any DOM properties that depend on style (e.g. computed style).
       * 4)  Query any DOM properties that depend on the current state of the DOM
       *     outside the "context" node (e.g. lengths of node lists).
       * 5)  [JavaScript implementations only] Access properties of any sort on any
       *     object without using XPCNativeWrapper (either explicitly or
       *     implicitly).  Due to various DOM0 things, this leads to item 4.
       * If you do any of these things in your shouldLoad implementation, expect
       * unpredictable behavior, possibly including crashes, content not showing
       * up, content showing up doubled, etc.  If you need to do any of the things
       * above, do them off timeout or event.
       */
      short shouldLoad(in nsContentPolicyType aContentType,
                       in nsIURI        aContentLocation,
                       in nsIURI        aRequestOrigin,
                       in nsISupports   aContext,
                       in ACString      aMimeTypeGuess,
                       in nsISupports   aExtra,
                       [optional] in nsIPrincipal  aRequestPrincipal);
    

    结论

    据我所知,Tab Utils 按预期工作,@Notidart 答案中的代码也是如此。期望立即将新文档分配给错误的选项卡。

    另外,我在 Tab Utils 页面上注意到它声明它“不稳定”。我应该避免使用 Tab Utils SDK 吗?

    嗯,这取决于您的个人喜好。 不稳定本质上意味着 API 可以再次更改,甚至在更高版本的浏览器中再次被删除。替代方案,例如使用 window.gBrowser 至少与 SDK API 一样不稳定(也可以随时更改),因此恕我直言,避免使用此 SDK API 没有任何好处,只要它没有事实证明它在某些方面没有问题(但如果确实如此,您仍然可以切换到其他东西)。

    【讨论】:

    • 我无法竞争。书签天哪,这么好的东西。
    • 上面的第三个项目(关于选项卡未完全初始化)是我认为可能发生的。感谢您的确认。
    【解决方案2】:

    这是您可以尝试的方法。从内容窗口中,您将获得 dom 窗口。然后使用 dom 窗口执行 getTabForContentWindow:

    //var node = focused element?
    var contentWin = node.ownerDocument.defaultView;
    var DOMWin = contentWin.QueryInterface(Ci.nsIInterfaceRequestor)
        .getInterface(Ci.nsIWebNavigation)
        .QueryInterface(Ci.nsIDocShellTreeItem)
        .rootTreeItem
        .QueryInterface(Ci.nsIInterfaceRequestor)
        .getInterface(Ci.nsIDOMWindow);
    if (DOMWin.gBrowser && DOMWin.gBrowser.tabContainer) {
        var tab = DOMWin.gBrowser._getTabForContentWindow(contentWin);
    } else {
        //the node is in a firefox window with no tabs
    }
    

    它可能是一个没有标签的弹出窗口。

    【讨论】:

    • 感谢您的建议,但选项卡返回就行了: var tab = DOMWin.gBrowser._getTabForContentWindow(contentWin);初始文档为空。这与我在原始代码中看到的行为相同。
    • 什么是“初始文件”?我想重现来测试一下。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多