opto/Expression-Search-NG

Can't move Expression Search to Mail Toolbar on macOS

Opened this issue · 12 comments

Hi Opto,

In Thunderbird 115 (currently 115.6.0, but it was like this since 115.0) on macOS 14.1.1, I can't move the extension (version 4.0.20) to the Mail Toolbar. When I select Mail Toolbar in the Settings, click Save, and restart Thunderbird, the extension doesn't appear anywhere (it still "works": I can activate its separate search popup window).

I have had this problem before, see Issue #47, but the workaround in that issue doesn't work this time.

The Extension Debugger shows no console messages at all. In the Error Console I did see something. When starting Thunderbird with Expression Search in the Mail Toolbar, there is one additional error message that does not appear when it's in the Quick Search bar:

TypeError: toolbar is null
refreshFilterBar resource://expressionsearch/modules/ExpressionSearchChrome.jsm:486
loadInto3pane resource://expressionsearch/modules/ExpressionSearchChrome.jsm:1366
Load resource://expressionsearch/modules/ExpressionSearchChrome.jsm:1551
initWindow jar:file:///[...my profile folder...]/extensions/expressionsearch@opto.one.xpi!/api/ExpressionSearch/implementation.js:246
result resource://gre/modules/ExtensionParent.sys.mjs:1144
withCallContextData resource://gre/modules/ExtensionParent.sys.mjs:627
result resource://gre/modules/ExtensionParent.sys.mjs:1143
withPendingBrowser resource://gre/modules/ExtensionParent.sys.mjs:637
result resource://gre/modules/ExtensionParent.sys.mjs:1142
callAndLog resource://gre/modules/ExtensionParent.sys.mjs:1095
recvAPICall resource://gre/modules/ExtensionParent.sys.mjs:1141
read resource:///modules/LineReader.jsm:60
_actionListResponse resource:///modules/Pop3Client.jsm:1033
_onData resource:///modules/Pop3Client.jsm:356

whereas with the extension in Quick Search bar, these warnings appear that don't show up in the other case:

unreachable code after return statement
ExpressionSearchFilter.jsm:135:6
unreachable code after return statement
ExpressionSearchFilter.jsm:142:6

In both cases I also see this error – I don't know whether it has any relevance:

Uncaught TypeError: this.delayConnectedCallback is not a function
connectedCallback chrome://global/content/elements/text.js:99
createTooltip resource://expressionsearch/modules/ExpressionSearchChrome.jsm:1193
initStatusBar resource://expressionsearch/modules/ExpressionSearchChrome.jsm:1210
loadInto3pane resource://expressionsearch/modules/ExpressionSearchChrome.jsm:1283
Load resource://expressionsearch/modules/ExpressionSearchChrome.jsm:1551
initWindow jar:file:///[...my profile folder...]/extensions/expressionsearch@opto.one.xpi!/api/ExpressionSearch/implementation.js:246
result resource://gre/modules/ExtensionParent.sys.mjs:1144
withCallContextData resource://gre/modules/ExtensionParent.sys.mjs:627
result resource://gre/modules/ExtensionParent.sys.mjs:1143
withPendingBrowser resource://gre/modules/ExtensionParent.sys.mjs:637
result resource://gre/modules/ExtensionParent.sys.mjs:1142
callAndLog resource://gre/modules/ExtensionParent.sys.mjs:1095
recvAPICall resource://gre/modules/ExtensionParent.sys.mjs:1141
read resource:///modules/LineReader.jsm:60
_actionListResponse resource:///modules/Pop3Client.jsm:1033
_onData resource:///modules/Pop3Client.jsm:356

As you're not on a Mac, if I can be of any help debugging this, I'm happy to do some digging – just tell me where to start (where to put breakpoints, what to do, etc.)

I did a little bit of 'digging', looking at the HTML structure of the Thunderbird window and at the file ExpressionSearchChrome.jsm.

First, the Mail Toolbar has the ID unifiedToolbarContent in macOS, in contrast with mail-bar3 as used in that module. For other toolbars, the IDs are correct.

Second, perhaps the high-level window structure is different in macOS than the extension expects. If I understand the code correctly, the function refreshFilterBar is called for each of the windows of type 3pane, and it searches in that window for a toolbar with the right ID and then puts the extension there. In my case, there's just one 3pane window, so the function is called once – but that 3pane doesn't contain most of the toolbars. It only contains the quick-filter bar; therefore, that is the only bar on which the extension works. When the function does document.getElementById(dest) it gets null for all the other bars.

All the other bars – with IDs tabs-toolbar, toolbar-menubar and unifiedToolbarContent – are in the "main", top-level window, described as chrome://messenger/content/messenger.xhtml in the browser toolbox, which would be win.parent inside the refreshFilterBar function. (I hacked this into the function as a very crude attempt at a workaround, but it puts the extension in the bar above the Expression Search settings page instead of the main tab.)

I'm not sure how to modify the module to make this work. Hopefully there's enough information for you. Let me know if I can help find more information.

opto commented

sorry, this hasn't been re-implemented yet.
Thanks for finding the id. I will put that in for the next version.

opto commented

unfortunately, this needs a bit more work than just adding the correct id.
The reason is that TB has now two windows inserted into each other: one is the outer window with unified toolbar, menu etc., and the id is written into the wrong window, so it needs some more changes.

I think you're right. As I described above, getting to the right window DOM object seems to be more complicated than just using win.parent starting from the inner window.

opto commented

yes, I have it somewhere. I think it is something like windows.browsingContext.whatever ...

opto commented

this is somewhere in the code, could be this: win.browsingContext.topChromeWindow;

I think that returns the same thing as win.parent. If I go into a 3pane, select an element e, and do

 e.ownerGlobal.browsingContext.topChromeWindow === e.ownerGlobal.parent 

it evaluates to true, so presumably both versions give you the top-level window.

After doing this and making a change -

e.ownerGlobal.parent.document.querySelector('#unifiedToolbarContent').style.backgroundColor='green'

I noticed that it is the right bar, and it actually affects the bar in all of the tabs (main tab, Add-ons, Expression Search settings, and so on). So putting Expression Search in the toolbar should be possible, the question is how to make it show up on the main tab instead of the Settings tab.

In the Settings tab, all the toolbar buttons have attribute hidden="" and an additional element, the global-search-bar, is present. These changes are probably made automatically when the user switches from one tab to another. How to get Thunderbird to unhide the extension when the user switches to the main tab...?

opto commented

the main toolbar is in the same window as the statusbar, if I remember right. (the others may not be ...)

There, I have:
let win1 = Services.wm.getMostRecentWindow("mail:3pane");
let doc = win1.document;
let status_bar = doc.getElementById('status-bar');

you could try that with the unified toolbar and after:
let toolbar = document.getElementById(dest);
add an console.log("unifbar", toolbar)

if that is not null, we have at least the correct toolbar, whereas other stuff may still go wrong.

I tried this (but on the wrong window):
} else if (this.options.move2bar == 1) {
dest = 'unifiedToolbarContainer'; //was 'mail-bar3';
//102 reference = showFilterBarButton;
reference = document.getElementById('unifiedToolbar');

because, I think, your id is an unordered list now (ul), no toolbar, so my first go was to try it on a div.

opto commented

so depending on the toolbar, document in
let toolbar = document.getElementById(dest);

may be a different document for the various toolbars (definitely for the standard quickfilter bar, that is private now to each about:3pane (which is different from mail:3pane))

a lot of "confusion" in 115

A little experiment:

  1. in the main tab (the toolbar has buttons like "Create a new message"):
let dc = document;
let tb = dc.querySelector('#unifiedToolbarContent');
  1. click on the tab that holds the Expression Search Options. The toolbar content changes: the buttons are gone, there's now a global search bar
document === dc

evaluates to true, and tc still highlights the toolbar.

Conclusions: document in the top-level window is the same regardless of the active tab; the toolbar item is also the same individual DOM object for every tab. This window has the tabs-toolbar, toolbar-menubar, status-bar and unifiedToolbarContent bars, but not the query bar.

I guess the main challenge is to put Expression Search into the toolbar in such a way that it does not get attribute hidden="" on the main tab.

opto commented

correct, the quickfilterbar is multiple in each mailTab (about:3pane), the others (most or all) are in the outer window (mail:3pane)

opto commented

so this
let win1 = Services.wm.getMostRecentWindow("mail:3pane");
let doc = win1.document;

with this
let toolbar = doc.getElementById(dest);

finds the right toolbar and inserts the search box, but:

as the function is called for each mailTab, I now have three search boxes.

So more changes are needed to call this only once.