diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index bb45aecb1..218478dc7 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -1148,8 +1148,20 @@ "description": "last focused" }, "commandSettingLabelTabClosePinned": { - "message": "Close pinned tabs", - "description": "Close pinned tabs" + "message": "Pinned tabs behavior", + "description": "Pinned tabs behavior" + }, + "commandSettingLabelTabClosePinnedNone": { + "message": "Do nothing", + "description": "Do nothing" + }, + "commandSettingLabelTabClosePinnedClose": { + "message": "Close", + "description": "Close" + }, + "commandSettingLabelTabClosePinnedDiscard": { + "message": "Discard", + "description": "Discard" }, "commandSettingLabelRestoreCurrentWindow": { "message": "Current window only", @@ -1345,8 +1357,8 @@ "description": "Determines which tab should be focused next." }, "commandSettingDescriptionTabClosePinned": { - "message": "Determines if pinned tabs can be closed or not.", - "description": "Determines if pinned tabs can be closed or not." + "message": "Determines how the close gesture handles pinned tabs: do nothing (ignore), close (remove tab), or discard (unload content but keep tab).", + "description": "Determines how the close gesture handles pinned tabs: do nothing (ignore), close (remove tab), or discard (unload content but keep tab)." }, "commandSettingDescriptionRestoreCurrentWindow": { "message": "Determines if only tabs which belong to the current window should be restored.", diff --git a/src/_locales/ja_JP/messages.json b/src/_locales/ja_JP/messages.json index b23ce1284..0c544fc3c 100644 --- a/src/_locales/ja_JP/messages.json +++ b/src/_locales/ja_JP/messages.json @@ -1132,8 +1132,20 @@ "description": "last focused" }, "commandSettingLabelTabClosePinned": { - "message": "ピン留めされたタブを閉じる", - "description": "Close pinned tabs" + "message": "ピン留めタブの動作", + "description": "Pinned tabs behavior" + }, + "commandSettingLabelTabClosePinnedNone": { + "message": "何もしない", + "description": "Do nothing" + }, + "commandSettingLabelTabClosePinnedClose": { + "message": "閉じる", + "description": "Close" + }, + "commandSettingLabelTabClosePinnedDiscard": { + "message": "アンロード", + "description": "Discard" }, "commandSettingLabelRestoreCurrentWindow": { "message": "現在のウィンドウのみ", @@ -1328,8 +1340,8 @@ "description": "Determines which tab should be focused next." }, "commandSettingDescriptionTabClosePinned": { - "message": "ピン留めされたタブを閉じるかどうかを指定します。", - "description": "Determines if pinned tabs can be closed or not." + "message": "閉じるジェスチャーがピン留めタブをどう処理するか:何もしない(無視)、閉じる(タブを削除)、またはアンロード(コンテンツをアンロードしてタブを保持)", + "description": "Determines how the close gesture handles pinned tabs: do nothing (ignore), close (remove tab), or discard (unload content but keep tab)." }, "commandSettingDescriptionRestoreCurrentWindow": { "message": "タブの復元を現在のウィンドウのみにするかどうかを指定します。", diff --git a/src/_locales/ko_KR/messages.json b/src/_locales/ko_KR/messages.json index 0d2a8589c..fd2348a4e 100644 --- a/src/_locales/ko_KR/messages.json +++ b/src/_locales/ko_KR/messages.json @@ -1132,8 +1132,20 @@ "description": "last focused" }, "commandSettingLabelTabClosePinned": { - "message": "고정 탭 닫기", - "description": "Close pinned tabs" + "message": "고정 탭 동작", + "description": "Pinned tabs behavior" + }, + "commandSettingLabelTabClosePinnedNone": { + "message": "아무것도 안 함", + "description": "Do nothing" + }, + "commandSettingLabelTabClosePinnedClose": { + "message": "닫기", + "description": "Close" + }, + "commandSettingLabelTabClosePinnedDiscard": { + "message": "언로드", + "description": "Discard" }, "commandSettingLabelRestoreCurrentWindow": { "message": "현재 창만", @@ -1328,8 +1340,8 @@ "description": "Determines which tab should be focused next." }, "commandSettingDescriptionTabClosePinned": { - "message": "고정된 탭의 닫기 여부를 정의합니다.", - "description": "Determines if pinned tabs can be closed or not." + "message": "닫기 제스처가 고정 탭을 처리하는 방법: 아무것도 안 함(무시), 닫기(탭 제거), 또는 언로드(내용을 언로드하지만 탭 유지)", + "description": "Determines how the close gesture handles pinned tabs: do nothing (ignore), close (remove tab), or discard (unload content but keep tab)." }, "commandSettingDescriptionRestoreCurrentWindow": { "message": "현재 창에 속한 탭만 복원할지 여부를 결정합니다.", diff --git a/src/_locales/zh_CN/messages.json b/src/_locales/zh_CN/messages.json index f320947be..7be39e05f 100644 --- a/src/_locales/zh_CN/messages.json +++ b/src/_locales/zh_CN/messages.json @@ -1132,8 +1132,20 @@ "description": "last focused" }, "commandSettingLabelTabClosePinned": { - "message": "关闭固定的标签页", - "description": "Close pinned tabs" + "message": "固定标签页的处理方式", + "description": "Pinned tabs behavior" + }, + "commandSettingLabelTabClosePinnedNone": { + "message": "不操作", + "description": "Do nothing" + }, + "commandSettingLabelTabClosePinnedClose": { + "message": "关闭", + "description": "Close" + }, + "commandSettingLabelTabClosePinnedDiscard": { + "message": "卸载", + "description": "Discard" }, "commandSettingLabelRestoreCurrentWindow": { "message": "仅当前窗口", @@ -1328,8 +1340,8 @@ "description": "Determines which tab should be focused next." }, "commandSettingDescriptionTabClosePinned": { - "message": "决定是否关闭固定的标签页。", - "description": "Determines if pinned tabs can be closed or not." + "message": "决定关闭手势对固定标签页的处理方式:不操作(忽略)、关闭(移除标签页)、或卸载(清空内容但保留标签页)", + "description": "Determines how the close gesture handles pinned tabs: do nothing (ignore), close (remove tab), or discard (unload content but keep tab)." }, "commandSettingDescriptionRestoreCurrentWindow": { "message": "决定是否只恢复属于当前窗口的标签页。", diff --git a/src/_locales/zh_TW/messages.json b/src/_locales/zh_TW/messages.json index 3e238f469..3e60aa017 100644 --- a/src/_locales/zh_TW/messages.json +++ b/src/_locales/zh_TW/messages.json @@ -1132,8 +1132,20 @@ "description": "last focused" }, "commandSettingLabelTabClosePinned": { - "message": "關閉釘選的分頁", - "description": "Close pinned tabs" + "message": "釘選分頁的處理方式", + "description": "Pinned tabs behavior" + }, + "commandSettingLabelTabClosePinnedNone": { + "message": "不操作", + "description": "Do nothing" + }, + "commandSettingLabelTabClosePinnedClose": { + "message": "關閉", + "description": "Close" + }, + "commandSettingLabelTabClosePinnedDiscard": { + "message": "卸載", + "description": "Discard" }, "commandSettingLabelRestoreCurrentWindow": { "message": "僅目前的視窗", @@ -1328,8 +1340,8 @@ "description": "Determines which tab should be focused next." }, "commandSettingDescriptionTabClosePinned": { - "message": "決定被釘選的分頁是否能被關閉", - "description": "Determines if pinned tabs can be closed or not." + "message": "決定關閉手勢對釘選分頁的處理方式:不操作(忽略)、關閉(移除分頁)、或卸載(清空內容但保留分頁)", + "description": "Determines how the close gesture handles pinned tabs: do nothing (ignore), close (remove tab), or discard (unload content but keep tab)." }, "commandSettingDescriptionRestoreCurrentWindow": { "message": "決定是否僅還原屬於目前視窗的分頁", diff --git a/src/core/commands.mjs b/src/core/commands.mjs index b5b2b1275..5bbd7c5db 100644 --- a/src/core/commands.mjs +++ b/src/core/commands.mjs @@ -78,8 +78,71 @@ export async function NewTab (sender, data) { export async function CloseTab (sender, data) { - // remove tab if not pinned or remove-pinned-tabs option is enabled - if (this.getSetting("closePinned") || !sender.tab.pinned) { + let closePinnedBehavior = this.getSetting("closePinned"); + + // Handle backward compatibility: convert boolean to string + if (typeof closePinnedBehavior === "boolean") { + closePinnedBehavior = closePinnedBehavior ? "close" : "none"; + } + + // If tab is pinned and behavior is "none", do nothing + if (sender.tab.pinned && closePinnedBehavior === "none") { + return; + } + + // If tab is pinned and behavior is "discard" + if (sender.tab.pinned && closePinnedBehavior === "discard") { + try { + const tabs = await browser.tabs.query({ + windowId: sender.tab.windowId, + active: false, + hidden: false + }); + + // if there are other tabs to focus + if (tabs.length > 0) { + let nextTab = null; + const nextFocusSetting = this.getSetting("nextFocus"); + + switch (nextFocusSetting) { + case "default": + case "next": + // get closest tab to the right (if not found it will return the closest tab to the left) + nextTab = tabs.reduce((acc, cur) => + (acc.index <= sender.tab.index && cur.index > acc.index) || (cur.index > sender.tab.index && cur.index < acc.index) ? cur : acc + ); + break; + + case "previous": + // get closest tab to the left (if not found it will return the closest tab to the right) + nextTab = tabs.reduce((acc, cur) => + (acc.index >= sender.tab.index && cur.index < acc.index) || (cur.index < sender.tab.index && cur.index > acc.index) ? cur : acc + ); + break; + + case "recent": + // get the previous tab + nextTab = tabs.reduce((acc, cur) => acc.lastAccessed > cur.lastAccessed ? acc : cur); + break; + } + + if (nextTab) { + await browser.tabs.update(nextTab.id, { active: true }); + // Discard the tab after switching focus (cannot discard active tab) + await browser.tabs.discard(sender.tab.id); + return true; + } + } + + return false; + } catch (error) { + console.error("Error discarding pinned tab:", error); + return false; + } + } + + // remove tab if not pinned or remove-pinned-tabs option is "close" + if (closePinnedBehavior === "close" || !sender.tab.pinned) { const tabs = await browser.tabs.query({ windowId: sender.tab.windowId, active: false, diff --git a/src/resources/json/commands.json b/src/resources/json/commands.json index 523bf8798..da166f621 100644 --- a/src/resources/json/commands.json +++ b/src/resources/json/commands.json @@ -37,7 +37,7 @@ "command": "CloseTab", "settings": { "nextFocus": "default", - "closePinned": true + "closePinned": "close" }, "group": "tabs" }, diff --git a/src/views/options/fragments/command-setting-templates.inc b/src/views/options/fragments/command-setting-templates.inc index 69c513cdb..38fb7e38a 100644 --- a/src/views/options/fragments/command-setting-templates.inc +++ b/src/views/options/fragments/command-setting-templates.inc @@ -81,8 +81,14 @@