如何从XUL <browser>中运行的脚本中的当前活动浏览器窗口/选项卡中获取URL(例如,在侧边栏中)

时间:2016-09-02 19:38:10

标签: javascript firefox-addon sidebar firefox-addon-restartless

我正在为Firefox创建一个简单的bootstrapped插件。我需要通过单击按钮从浏览器捕获当前URL。

我的 bootstrap.js

const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import('resource://gre/modules/Services.jsm');
Cu.import("resource://gre/modules/NetUtil.jsm");  
Cu.import("resource://gre/modules/FileUtils.jsm");

/*start - windowlistener*/
var windowListener = {
    //DO NOT EDIT HERE
    onOpenWindow: function (aXULWindow) {
        // Wait for the window to finish loading
        let aDOMWindow =aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                                  .getInterface(Ci.nsIDOMWindowInternal||Ci.nsIDOMWindow);
        aDOMWindow.addEventListener("load", function () {
            aDOMWindow.removeEventListener("load", arguments.callee, false);
            windowListener.loadIntoWindow(aDOMWindow, aXULWindow);
        }, false);
    },
    onCloseWindow: function (aXULWindow) {},
    onWindowTitleChange: function (aXULWindow, aNewTitle) {},
    register: function () {
        // Load into any existing windows
        let XULWindows = Services.wm.getXULWindowEnumerator(null);
        while (XULWindows.hasMoreElements()) {
            let aXULWindow = XULWindows.getNext();
            let aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                                .getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
            windowListener.loadIntoWindow(aDOMWindow, aXULWindow);
        }
        // Listen to new windows
        Services.wm.addListener(windowListener);
    },
    unregister: function () {
        // Unload from any existing windows
        let XULWindows = Services.wm.getXULWindowEnumerator(null);
        while (XULWindows.hasMoreElements()) {
            let aXULWindow = XULWindows.getNext();
            let aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                                .getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
            windowListener.unloadFromWindow(aDOMWindow, aXULWindow);
        }
        //Stop listening so future added windows dont get this attached
        Services.wm.removeListener(windowListener);
    },
    //END - DO NOT EDIT HERE
    loadIntoWindow: function (aDOMWindow, aXULWindow) {
        if (!aDOMWindow) {
            return;
        }

        //START - EDIT BELOW HERE
        var browser = aDOMWindow.document.querySelector('#browser')
        if (browser) {
            var splitter = aDOMWindow.document.createElement('splitter');
            var propsToSet = {
                id: 'demo-sidebar-with-html_splitter',
                //I'm just copying what Mozilla does for their social sidebar splitter 
                //  I left it out, but you can leave it in to see how you can style
                //  the splitter
                class: 'sidebar-splitter'
            }
            for (var p in propsToSet) {
                splitter.setAttribute(p, propsToSet[p]);
            }

            var sidebar = aDOMWindow.document.createElement('vbox');
            var propsToSet = {
                id: 'demo-sidebar-with-html_sidebar',
                //Mozilla uses persist width here, I don't know what it does and can't
                //  see it how makes a difference so I left it out
                //persist: 'width' 
            }
            for (var p in propsToSet) {
                sidebar.setAttribute(p, propsToSet[p]);
            }
            var htmlVal = loadJsonHTML(0);
            var sidebarBrowser = aDOMWindow.document.createElement('browser');
            var propsToSet = {
                id: 'demo-sidebar-with-html_browser',
                type: 'content',
                context: 'contentAreaContextMenu',
                disableglobalhistory: 'true',
                tooltip: 'aHTMLTooltip',
                autoscrollpopup: 'autoscroller',
                flex: '1', //do not remove this
                //you should change these widths to how you want
                style: 'min-width: 14em; width: 18em; max-width: 36em;', 
                //or just set this to some URL like http://www.bing.com/
                src: 'data:text/html,'+ htmlVal
            }
            for (var p in propsToSet) {
                sidebarBrowser.setAttribute(p, propsToSet[p]);
            }

            browser.appendChild(splitter);

            sidebar.appendChild(sidebarBrowser);
            browser.appendChild(sidebar);
        }
        //END - EDIT BELOW HERE
    },
    unloadFromWindow: function (aDOMWindow, aXULWindow) {
        if (!aDOMWindow) {
            return;
        }
        //START - EDIT BELOW HERE
        var splitter = aDOMWindow.document
                                 .querySelector('#demo-sidebar-with-html_splitter');

        if (splitter) {
            var sidebar = aDOMWindow.document
                                    .querySelector('#demo-sidebar-with-html_sidebar');
            splitter.parentNode.removeChild(splitter);
            sidebar.parentNode.removeChild(sidebar);
        }
        //END - EDIT BELOW HERE
    }
};
/*end - windowlistener*/

function startup(aData, aReason) {
    windowListener.register();
}

function shutdown(aData, aReason) {
    if (aReason == APP_SHUTDOWN) return;
    windowListener.unregister();
}

function loadJsonHTML(val=0){

    var fileContent = "";   
    var localFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);

    //full path is okay if directory exists     
    localFile.initWithPath("/Users/tinuy/Desktop/test_addodn/input.txt");

    //otherwise specify directory, create it if necessary, and append leaf.
    //localFile.initWithPath("C:\Users\tinuy\Documents\test\input.txt");

    if ( localFile.exists() == false ) {
        fileContent = "File does not exist";
    }
    var istream = Cc["@mozilla.org/network/file-input-stream;1"]
                  .createInstance(Ci.nsIFileInputStream);
    istream.init(localFile, 0x01, 4, null);
    var fileScriptableIO = Cc["@mozilla.org/scriptableinputstream;1"]
                           .createInstance(Ci.nsIScriptableInputStream); 
    fileScriptableIO.init(istream);
    // parse the XML into our internal document
    istream.QueryInterface(Ci.nsILineInputStream); 
    //fileContent = fileScriptableIO.read( '1' );
    var csize = 0; 
    while ((csize = fileScriptableIO.available()) != 0) {
        fileContent += fileScriptableIO.read( csize );
    }
    var array = fileContent.split("&");
    fileScriptableIO.close();   
    istream.close();

    return makeHTML(array[val], val);
}

function makeHTML(value, key){
    var arrValues = value.split(",");
    var htmlContent = '<div name="content" class="content">' +
        '<p> Name :' + arrValues[0] + '</p>';
    htmlContent += '<p> Price :' + arrValues[2] + '</p>';
    htmlContent += '<p> Color :' + arrValues[3] + '</p>';
    htmlContent += '<p> UID :' + arrValues[1] + '</p>';
    htmlContent += '<p><input type="radio" name="valid" value="yes" />Yes &nbsp;&nbsp; ' +
        '<input type="radio" name="valid" value="no" /> No</p>' +
        '<p><input type="text" placeholder="Reason" name="checkreason"></p>' +
        '<p><input type="text" placeholder="Feedback" name="feedback"></p>' +
        '</div><div><button name="load" type="button" id="loadit" onclick="loadHtml()" ' + 
        'loadurl="'+arrValues[4]+'">Load</button> <button name="save" type="button">' + 
        'Save </button> <button name="next" type="button" key="'+key+'">Next </button> ' +
        '</div> <script> function loadHtml() {' + 
            'var a = gBrowser.contentWindow.location.href ;alert(a);' + 
        '} </script>';
    return htmlContent;
}

function install() {}

function uninstall() {}

我尝试了Get current page URL from a firefox sidebar extension的所有建议但没有任何效果。

1 个答案:

答案 0 :(得分:1)

但是,你已经设置了这个事实:

var propsToSet = {
    id: 'demo-sidebar-with-html_browser',
    type: 'content', //<---------------------------This

<browser> type to content,我假设以下两件事之一:

  1. 您实际上并未尝试从正在加载到<browser>src属性的代码中获取有效标签的URI。
    • 如果是这种情况,请参阅我对#34; How to Get Active Tab Location by e10s add-on&#34;的回答。在这种情况下,您运行的上下文应该允许您使用该答案中的代码。
    • 这个可能的假设#1不适用于您的代码。
  2. 您希望获得对已加载到侧边栏的<browser>内的URI表单代码的访问权限,并且不知道将<browser> type to content设置为代码的限制加载到<browser>
    • 您似乎正在尝试从<browser>中的代码访问currant选项卡的URL。您应该考虑重构代码,以便<browser>中的内容不需要访问chrome权限。换句话说,如果可能的话,您应该编写代码,这样您就不需要直接从您插入的<browser>中运行的代码访问URL或其他信息。但是,这样做可能会变得更加复杂。
  3. 在您要添加的<browser>中获取Chrome权限:

    设置<browser> type to content适用于:

      

    内容浏览器。浏览器中加载的内容不允许访问其上方的镶边。

    <browser> type设置为chrome适用于:

      

    (默认行为):一种浏览器,用于使用chrome:// URI加载特权内容。 不要使用来自网络的内容,因为这可能会导致严重的安全问题!

    要将<browser> type设置为chrome,您可以这样做:

    var propsToSet = {
        id: 'demo-sidebar-with-html_browser',
        type: 'chrome', //<---------------------------This
    

    Noitidart提供的代码接近您的需求。但是,它需要稍微修改,如gBrowser.currentURI is a nsIURI, not a string)。因此,您需要使用gBrowser.currentURI.spec。您可以通过将makeHTML()更改为

    来使其正常运行
    function makeHTML(value, key){
        var arrValues = value.split(",");
        var htmlContent = '<html><head></head>'
            + '<body style="background-color: white;">'
            + '  <div name="content" class="content">'
            + '    <p> Name :' + arrValues[0] + '</p>';
        htmlContent += '<p> Price :' + arrValues[2] + '</p>';
        htmlContent += '<p> Color :' + arrValues[3] + '</p>';
        htmlContent += '<p> UID :' + arrValues[1] + '</p>';
        htmlContent += 
              '    <p><input type="radio" name="valid" value="yes" />Yes &nbsp;&nbsp; '
            + '    <input type="radio" name="valid" value="no" /> No</p>'
            + '    <p><input type="text" placeholder="Reason" name="checkreason" /></p>'
            + '    <p><input type="text" placeholder="Feedback" name="feedback" /></p>'
            + '  </div>'
            + '  <div>'
            + '    <button name="load" type="button" id="loadit" onclick="loadHtml()" '
            + '        loadurl="' + arrValues[4] + '">Load</button>'
            + '    <button name="save" type="button">Save </button>'
            + '    <button name="next" type="button" key="' + key + '">Next </button>'
            + '  </div>'
            + '  <script>'
            + '    function loadHtml() {' 
            + '      const Cu = Components.utils;'
            + '      Cu.import("resource://gre/modules/Services.jsm");'
            + '      var win = Services.wm.getMostRecentWindow("navigator:browser");'
            + '      if (win) {'
            + '        var url = win.gBrowser.currentURI.spec;'
            + '        alert("URL=" + url);'
            + '      }'
            + '    }'
            + '  </script>'
            + '</body></html>';
        return htmlContent;
    }
    

    安全问题:
    您可能遇到了一些非常重要的安全问题。仅仅因为您想要当前页面的URL意味着您可能正在快速接近这些是真正的问题。这将取决于您将要做什么完全。鉴于您没有提供这些信息,我不会深入探讨问题所在。但是,您应该阅读&#34; Firefox Security Basics for Developers&#34;和&#34; Security best practices in extensions&#34;

    有关侧边栏的其他信息:
    您应该认真考虑创建一个基于Add-on SDK的加载项,而不是一个自举加载项,并使用ui/sidebar API。

    如果您有兴趣,我创建了一些代码,可用于创建&#34;侧边栏&#34;它位于活动选项卡的顶部,左侧,右侧或底部,或位于单独的窗口中(类似于devtools面板将执行的操作)。创建的侧边栏与当前活动的选项卡相关联,而不是所有选项卡(我想我应该让它成为一个选项,让它与所有选项卡相关联,或者只是当前选项卡)在我的回答中:&#34; {{3 }}&#34;和&#34; How to create a bottom-docked panel with XUL in Firefox?&#34;