0

I'm trying to convert my overlay add-on to restartless.
I can't access the bookmarks panel (on the sidebar) in SeaMonkey, in order to load my overlay UI.
Specifically, I need to do load my overlay to the bm-panel.xul similar to the following: myListener.document.loadOverlay("chrome://myBookmarksPanelOverlay.xul");

For that, I need the window of bm-panel.xul but I only have the main window of the browser.

SeaMonkey has a different structure from Firefox, so the following example
var sidebarPanels = window.document.getElementById('sidebar');
which is in documentation, does not work for SeaMonkey.

I can see the bm-panel.xul window in the Dom Inspector, but I can't get to it with Javascript.

I was able to access only the sidebar panels but that's as far as I can go:
var sidebarPanels = window.document.getElementById('sidebar-panels');

How do I access the bookmarksPanel page itself?

Laurel
  • 43
  • 5
  • A significant issue is that you should generally not be using `document.loadOverlay()` in a restartless extension. Instead, you should be dynamically adding and removing elements of the DOM. Remember, in a restartless add-on you need to be able to be able to cleanly *remove* all changes that you make to Firefox. If you can't cleanly remove them, then it is not a restartless add-on regardless of the fact that you can load the add-on without restarting. – Makyen Mar 28 '15 at 17:38
  • @Makyen, thanks. You're right of course, and I will change it accordingly. However, I still need the bm-panel.xul, to add the element (button). So the question still stands. – Laurel Mar 29 '15 at 04:47
  • It would be considerably easier to work on this if there was complete code (a [MCVE](http://stackoverflow.com/help/mcve)) available rather than having to roll my own SeaMonkey add-on prototype just to test code for this question. – Makyen Mar 29 '15 at 07:16
  • BTW: Thanks for changing the does not work example away from ID=`sidebar-panels`. Having it erroneously state that ID was in the MDN documentation like that and implying that the statement did not work in SeaMonkey, but did in Firefox, was one of the things that lead to my not being clear on your question, because as it was the opposite was true (it should have worked in SeaMonkey, but not in Firefox and was not part of the MDN sidebar documentation (i.e. that ID is not used in stock Firefox, but is in SeaMonkey)). – Makyen Mar 29 '15 at 07:23

2 Answers2

0

I'm not 100% certain if your question is really limited to just finding the bookmarksPanel. Thus, this answer contains generic information about accessing the bookmarksPanel, viewing the DOM, accessing the sidebar from an overlay or restartless extension, and obtaining a window reference.

Accessing the bookmarksPanel

The following should get you a reference to the <page id="bookmarksPanel">:

var sidebarDocument = document.getElementById("sidebar").contentDocument;
var bookmarksPanelElement = sidebarDocument.getElementById("bookmarksPanel")

Note that you need to use the getElementById() in the sidebarDocument, not the main window.document.getElementById() which will not search into the sidebar.

Viewing the DOM

If you are having issues with knowing what the DOM structure is for a particular element, I would suggest that you install DOM Inspector (for SeaMonkey) (to view the DOM) and Element Inspector (which allows you to shift-right-click on an element and open the DOM Inspector on that element).

This is an example of the DOM Inspector viewing a Bookmark Sidebar in Firefox: DOM Inspector viewing a Bookmark Sidebar in Firefox

Accessing the Sidebar From an Overlay or Restartless Extension

Quoting from MDN: "Sidebar: Accessing the sidebar from a browser.xul script":

Accessing the sidebar from a browser.xul script
The sidebar content is always in a document separate from the main browser document (the sidebar is actually implemented as a XUL browser element). This means you can't directly access the sidebar content from a script referenced from a browser.xul overlay.

To access your sidebar's window or document objects, you need to use the contentWindow or contentDocument properties of document.getElementById("sidebar") respectively. For example the code below calls a function defined in the sidebar's context:

var sidebarWindow = document.getElementById("sidebar").contentWindow;
// Verify that our sidebar is open at this moment:
if (sidebarWindow.location.href ==
      "chrome://yourextension/content/whatever.xul") {
  // call "yourNotificationFunction" in the sidebar's context:
  sidebarWindow.yourNotificationFunction(anyArguments);
}

Depending on how the current code you are running was started (e.g. UI button), you may need to obtain the current browser window.

Copying significantly from another answer of mine, you can obtain that by:

Obtaining a reference to the most recent window:

Firefox add-ons generally run in a scope where the global window object is not defined (if it is defined depends on how the portion of your code that is currently running was entered). Even if it is defined, it is often not defined as the window which you are expecting (the window of the current tab). You will probably need to obtain a reference to the window object for the most recently accessed window/tab.

If a browser window exists (in some instances you could be running where no browser window exists, yet, e.g. at start-up), you can obtain a reference to the most recent browser window, document, and gBrowser with:

if (window === null || typeof window !== "object") {
    //If you do not already have a window reference, you need to obtain one:
    //  Add/remove a "/" to comment/un-comment the code appropriate for your add-on type.
    /* Add-on SDK:
    var window = require('sdk/window/utils').getMostRecentBrowserWindow();
    //*/
    //* Overlay and bootstrap (from almost any context/scope):
    var window=Components.classes["@mozilla.org/appshell/window-mediator;1"]
                         .getService(Components.interfaces.nsIWindowMediator)
                         .getMostRecentWindow("navigator:browser");        
    //*/
}
if (typeof document === "undefined") {
    //If there is no document defined, get it
    var document = window.content.document;
}
if (typeof gBrowser === "undefined") {
    //If there is no gBrowser defined, get it
    var gBrowser = window.gBrowser;
}

If you are running the code in response to an event (e.g. a button command event), you can obtain the current window with:

var window = event.view

The lack of having the global window object available, or having it reference something other than what you are expecting, is something that many people encounter as a problem when writing Firefox add-ons.

Note: If you are wanting to be natively compatible with multi-process Firefox (Electrolysis, or e10s), then gaining access to the contents of the current document is more complex. There are shims in place which should make your code continue to work with multi-process Firefox for some time, but they may/will eventually go away.

References:

  1. nsIWindowMediator
  2. Working with windows in chrome code
  3. SDK: window/utils
  4. SDK: windows
  5. Multiprocess Firefox
  6. Working with multiprocess Firefox

Large portions of this were copied from my earlier answers, including this link.

Community
  • 1
  • 1
Makyen
  • 31,849
  • 12
  • 86
  • 121
  • I tried to clarify my request above. I specifically need the information for Seamonkey, and that's why I used the Seamonkey terms. The generic case and Mozilla documentation are about Firefox. – Laurel Mar 28 '15 at 15:35
0

This may not be the only way or the best, but here is what I am doing:

  1. Find the sidebar element (sidebar-panels)
  2. search the sidebar childNodes for the element with attribute src=chrome://communicator/content/bookmarks/bm-panel.xul

Searching the childNodes must be delayed until the relevant frames are loaded, and the search itself is a recursive iteration over all elements.

following is a minimal stripped code:

    var sidebarE =  domWindow.document.getElementById('sidebar-panels');
    setTimeout(function() {
        var sbPanelE = searchChildNodes(sidebarE);
    }, 350);

    function searchChildNodes (aElement) {
        var stackNew = [];
        var current;
        var i, lenArr;

        iterate(aElement); 
        function iterate(current) { 
            var childrenE = current.childNodes;
            for (var i = 0, lenArr = childrenE.length; i < lenArr; i++) {
                iterate(childrenE[i]);
                foundE = checkElement(childrenE[i]);
                if (e.nodeType == 1){ // Element node
                    if (e.getAttribute('src') == loc){
                        stackNew.push({ //pass args via object or array
                            element: childrenE[i],
                        });
                        return;
                    }
                }
            }
        }

        for (i=0;i<stackNew.length ;i++ ){
            var itm = stackNew[i].element;
            return itm;
        }
    } // searchChildNodes
Laurel
  • 43
  • 5