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_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
// following it and hide it when the user rightclicked on a pinned
// tab.

View file

@ -112,6 +112,8 @@
label="&bookmarkAllTabs.label;"
accesskey="&bookmarkAllTabs.accesskey;"
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;"
oncommand="gBrowser.removeTabsToTheEndFrom(TabContextMenu.contextTab, {animate: true});"/>
<menuitem id="context_closeOtherTabs" label="&closeOtherTabs.label;" accesskey="&closeOtherTabs.accesskey;"

View file

@ -55,7 +55,7 @@
]]></getter>
</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>
@ -2310,6 +2310,12 @@
case this.closingTabsEnum.OTHER:
tabsToClose = this.visibleTabs.length - 1 - gBrowser._numPinnedTabs;
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:
if (!aTab)
throw new Error("Required argument missing: aTab");
@ -2366,6 +2372,36 @@
</body>
</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">
<parameter name="aTab"/>
<body>

View file

@ -23,6 +23,11 @@
<!ENTITY reloadTab.accesskey "R">
<!ENTITY reloadAllTabs.label "Reload All Tabs">
<!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
direction in which tabs are closed, i.e. locales that use RTL mode should say
left instead of right. -->

View file

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