Add a "close all tabs to the left" button + fix compile error

This commit is contained in:
ownedbywuigi 2026-04-01 11:35:08 +01:00
commit 8bf148471c
5 changed files with 57 additions and 7 deletions

View file

@ -7441,6 +7441,12 @@ var TabContextMenu = {
document.getElementById("context_pinTab").hidden = this.contextTab.pinned; document.getElementById("context_pinTab").hidden = this.contextTab.pinned;
document.getElementById("context_unpinTab").hidden = !this.contextTab.pinned; document.getElementById("context_unpinTab").hidden = !this.contextTab.pinned;
// Disable "Close Tabs to the Left" if there are no tabs before it,
// and hide it when the user rightclicked on a pinned tab.
document.getElementById("context_closeTabsToTheStart").disabled =
gBrowser.getTabsToTheStartFrom(this.contextTab).length == 0;
document.getElementById("context_closeTabsToTheStart").hidden = this.contextTab.pinned;
// Disable "Close Tabs to the Right" if there are no tabs // Disable "Close Tabs to the Right" if there are no tabs
// following it and hide it when the user rightclicked on a pinned // following it and hide it when the user rightclicked on a pinned
// tab. // tab.

View file

@ -112,6 +112,8 @@
label="&bookmarkAllTabs.label;" label="&bookmarkAllTabs.label;"
accesskey="&bookmarkAllTabs.accesskey;" accesskey="&bookmarkAllTabs.accesskey;"
command="Browser:BookmarkAllTabs"/> command="Browser:BookmarkAllTabs"/>
<menuitem id="context_closeTabsToTheStart" label="&closeTabsToTheStart.label;" accesskey="&closeTabsToTheStart.accesskey;"
oncommand="gBrowser.removeTabsToTheStartFrom(TabContextMenu.contextTab, {animate: true});"/>
<menuitem id="context_closeTabsToTheEnd" label="&closeTabsToTheEnd.label;" accesskey="&closeTabsToTheEnd.accesskey;" <menuitem id="context_closeTabsToTheEnd" label="&closeTabsToTheEnd.label;" accesskey="&closeTabsToTheEnd.accesskey;"
oncommand="gBrowser.removeTabsToTheEndFrom(TabContextMenu.contextTab, {animate: true});"/> oncommand="gBrowser.removeTabsToTheEndFrom(TabContextMenu.contextTab, {animate: true});"/>
<menuitem id="context_closeOtherTabs" label="&closeOtherTabs.label;" accesskey="&closeOtherTabs.accesskey;" <menuitem id="context_closeOtherTabs" label="&closeOtherTabs.label;" accesskey="&closeOtherTabs.accesskey;"

View file

@ -55,7 +55,7 @@
]]></getter> ]]></getter>
</property> </property>
<field name="closingTabsEnum" readonly="true">({ ALL: 0, OTHER: 1, TO_END: 2 });</field> <field name="closingTabsEnum" readonly="true">({ ALL: 0, OTHER: 1, TO_START: 2, TO_END: 3 });</field>
<field name="_visibleTabs">null</field> <field name="_visibleTabs">null</field>
@ -2310,6 +2310,12 @@
case this.closingTabsEnum.OTHER: case this.closingTabsEnum.OTHER:
tabsToClose = this.visibleTabs.length - 1 - gBrowser._numPinnedTabs; tabsToClose = this.visibleTabs.length - 1 - gBrowser._numPinnedTabs;
break; break;
case this.closingTabsEnum.TO_START:
if (!aTab)
throw new Error("Required argument missing: aTab");
tabsToClose = this.getTabsToTheStartFrom(aTab).length;
break;
case this.closingTabsEnum.TO_END: case this.closingTabsEnum.TO_END:
if (!aTab) if (!aTab)
throw new Error("Required argument missing: aTab"); throw new Error("Required argument missing: aTab");
@ -2366,6 +2372,36 @@
</body> </body>
</method> </method>
<method name="getTabsToTheStartFrom">
<parameter name="aTab"/>
<body>
<![CDATA[
var tabsToStart = [];
let tabs = this.visibleTabs;
for (let i = 0; tabs[i] != aTab && i < tabs.length; ++i) {
if (!tabs[i].pinned)
tabsToStart.push(tabs[i]);
}
return tabsToStart;
]]>
</body>
</method>
<method name="removeTabsToTheStartFrom">
<parameter name="aTab"/>
<parameter name="aParams"/>
<body>
<![CDATA[
if (this.warnAboutClosingTabs(this.closingTabsEnum.TO_START, aTab)) {
let tabs = this.getTabsToTheStartFrom(aTab);
for (let i = tabs.length - 1; i >= 0; --i) {
this.removeTab(tabs[i], aParams);
}
}
]]>
</body>
</method>
<method name="getTabsToTheEndFrom"> <method name="getTabsToTheEndFrom">
<parameter name="aTab"/> <parameter name="aTab"/>
<body> <body>

View file

@ -23,6 +23,11 @@
<!ENTITY reloadTab.accesskey "R"> <!ENTITY reloadTab.accesskey "R">
<!ENTITY reloadAllTabs.label "Reload All Tabs"> <!ENTITY reloadAllTabs.label "Reload All Tabs">
<!ENTITY reloadAllTabs.accesskey "A"> <!ENTITY reloadAllTabs.accesskey "A">
<!-- LOCALIZATION NOTE (closeTabsToTheStart.label): This should indicate the
direction in which tabs are closed, i.e. locales that use RTL mode should say
right instead of left. -->
<!ENTITY closeTabsToTheStart.label "Close Tabs to the Left">
<!ENTITY closeTabsToTheStart.accesskey "L">
<!-- LOCALIZATION NOTE (closeTabsToTheEnd.label): This should indicate the <!-- LOCALIZATION NOTE (closeTabsToTheEnd.label): This should indicate the
direction in which tabs are closed, i.e. locales that use RTL mode should say direction in which tabs are closed, i.e. locales that use RTL mode should say
left instead of right. --> left instead of right. -->

View file

@ -250,8 +250,9 @@ bool StreamFilterParent::RecvClose() {
void StreamFilterParent::Destroy() { void StreamFilterParent::Destroy() {
// Close the channel asynchronously so the actor is never destroyed before // Close the channel asynchronously so the actor is never destroyed before
// this message is fully processed. // this message is fully processed.
ActorThread()->Dispatch(NewRunnableMethod(this, ActorThread()->Dispatch(NS_NewRunnableFunction([self = RefPtr<StreamFilterParent>(this)]() {
&StreamFilterParent::Close), self->Close();
}),
NS_DISPATCH_NORMAL); NS_DISPATCH_NORMAL);
} }
@ -354,8 +355,8 @@ void StreamFilterParent::FinishDisconnect() {
bool StreamFilterParent::RecvWrite(Data&& aData) { bool StreamFilterParent::RecvWrite(Data&& aData) {
AssertIsActorThread(); AssertIsActorThread();
RunOnIOThread(NS_NewRunnableFunction([this, data = std::move(aData)]() mutable { RunOnIOThread(NS_NewRunnableFunction([self = RefPtr<StreamFilterParent>(this), data = std::move(aData)]() mutable {
WriteMove(std::move(data)); self->WriteMove(std::move(data));
})); }));
return true; return true;
} }
@ -612,8 +613,8 @@ StreamFilterParent::OnDataAvailable(nsIRequest* aRequest,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} else { } else {
ActorThread()->Dispatch( ActorThread()->Dispatch(
NS_NewRunnableFunction([this, data = std::move(data)]() mutable { NS_NewRunnableFunction([self = RefPtr<StreamFilterParent>(this), data = std::move(data)]() mutable {
DoSendData(std::move(data)); self->DoSendData(std::move(data));
}), }),
NS_DISPATCH_NORMAL); NS_DISPATCH_NORMAL);
} }