MrOtherGuy/fx-autoconfig

_ucUtils.startupFinished and contentDocument in TB 115

Frank-Steiner opened this issue · 6 comments

Hi,
after you pointed me to _ucUtils.startupFinished in this thread I'm now stuck trying to access the dom of a nested document. TB 115 has this structure:

<browser ... id="mail3PaneTabBrowser1"/>
  #document
    <html ...>
      <body...>
        <div id="threadPane">

and I'm trying to access threadPane inside a script. However, even if placed inside _ucUtils.startupFinished:

const bla=document.getElementById('mail3PaneTabBrowser1');
const blu=bla.contentWindow.document.getElementById('threadPane');

bla does return the object, bla.contentWindow is also available, but blu will be null. Likely because the inner document is not yet loaded. If I inspect bla.contenDocument, it will have a html child and inside a body child, but body has no more children, so the code inside body has not been loaded I guess.

Is there way to wait until such inner/nested documents are loaded, too, so that they can be accessed?

Thanks!
cu,
Frank

Seems to happen at some other places, too. E.g.:

var a = document.getElementById('unifiedToolbarContent');    
var b=a.getElementsByClassName('get-messages');
console.error(b);
console.error(b.item(0));

The output of console.error(b) is

HTMLCollection { 0: li.get-messages, length: 1 }

But b.item(0) (or b[0]) just returns null/undefined because the DOM is not fully loaded when the script executes. In a webpage I would use window.onload, but it seems _ucUtils.startupFinished fires earlier...

For these kinds of dynamically created elements you need to wait for what specifically causes those elements to be created. I don't know what that a.getElementsByClassName('get-messages') is supposed to return - because those things have not been created on my TB after it has been running for hours. So something is likely creating them dynamically as needed - thus you need to do something specific to that, it is not something the loader can help you with.

But for the previous thing - it seems you are trying to affect another document. So in that case I would suggest to just making your script be injected into that and not the TB main-window which is the default. So your script would then look like this:

// ==UserScript==
// @include           about:3pane
// ==/UserScript==

const blu = document.getElementById('threadPane');
console.log(blu)
// should log: <div id="threadPane">

Then, you don't need to wait for startup at all because your script is now injected and run when the about:3pane document's DOMContentLoaded event is fired.

Hi, thanks for your answer! I will try your proposal with injecting into the other document and see if that works!

About the 'get-messages': that's just the "Get Messages" button which is there from the beginning, and that's why it's so strange that it is not fully accessible. In TB 115 the inspector shows this structure:

<html:div id="unifiedToolbar" role="toolbar">
  <html:ul id="unifiedToolbarContent" class="unified-toolbar">
    <li class="get-messages" item-id="get-messages" is="customizable-element">
      <div class="live-content">
        <button is="unified-toolbar-button" ...

Thus, document.getElementById('unifiedToolbarContent').getElementsByClassName('get-messages').item(0); should return the li element that contains the "Get Messages" button in the main toolbar (or "unified toolbar") with all the other buttons (Write, Reply etc.) above or below the menu bar.
The unified toolbar with the menu bar and the buttons bar should be created at startup, and I can access the unifiedToolbarContent ul and print it in the console. But trying to access and print one of its li children, those are not loaded yet and return null...

Including the script into the inner document works, thanks for that hint! It doesn't help with my goal, though, because I tried to move some element from that inner document (the GetMessages button from the folderPane) into the UnifiedToolbar. For that, I would have to access elements from both, the inner and the global document, at the same time. But maybe that's just not possible with userScripts...

Ah, okay, .get-messages is just one of the toolbar items - my toolbar doesn't have any buttons except spaces menu at left and main menu on right. The unified toolbar rather looks like a custom element so I guess your script is run before the toolbar gets initialized which will probably end up creating the buttons and other customizable widgets only at that point.

So following that logic, it might work if you did something like this:

window.addEventListener("spaces-toolbar-ready",() => {
  requestAnimationFrame(() => {
    var a = document.getElementById('unifiedToolbarContent');    
    var b = a.getElementsByClassName('get-messages');
  })
},{once: true})

The requesAnimationFrame hackery is only added so that any synchronous initialization work TB might be doing should then definitely have been run before your callback.

For that, I would have to access elements from both, the inner and the global document, at the same time.

For that you can just reach to the ownerGlobar.top - so basically do window.parent. However, I don't think you can move elements across document boundaries. You can try, but I would be surprised if you can. What I would suggest you to try instead is to create your own element with same or similar functionality.

Hi,
thanks a lot for your support, I appreciate that very much! It does work indeed, i.e. I can now move the button from the threadPane into the UnifiedToolbar. It shows up there, but it won't work because now that this element has vanished in the threadPane, some other js scripts that expect this element to be there will fail, and e.g. the function attached to the button won't be there, too, as the script with this function is inside the other document.
So, moving GUI elements without functions will work, but for anything that has e.g. a click event attached, one will have to clone the element and re-attach events or create a similar element from scratch (as you proposed before).
Thus, moving does work in principal, it does not work for elements with functionality, but nevertheless, I've learned a lot trying to track this down with your help! Many thanks again!