mirror of
https://github.com/zen-browser/desktop.git
synced 2025-10-14 05:46:26 +00:00
Merge branch 'dev' of https://github.com/zen-browser/desktop into dev
This commit is contained in:
@@ -311,6 +311,7 @@ zen-split-view-shortcut-grid = Toggle Split View Grid
|
|||||||
zen-split-view-shortcut-vertical = Toggle Split View Vertical
|
zen-split-view-shortcut-vertical = Toggle Split View Vertical
|
||||||
zen-split-view-shortcut-horizontal = Toggle Split View Horizontal
|
zen-split-view-shortcut-horizontal = Toggle Split View Horizontal
|
||||||
zen-split-view-shortcut-unsplit = Close Split View
|
zen-split-view-shortcut-unsplit = Close Split View
|
||||||
|
zen-new-empty-split-view-shortcut = New Empty Split View
|
||||||
zen-key-select-tab-1 = Select tab #1
|
zen-key-select-tab-1 = Select tab #1
|
||||||
zen-key-select-tab-2 = Select tab #2
|
zen-key-select-tab-2 = Select tab #2
|
||||||
zen-key-select-tab-3 = Select tab #3
|
zen-key-select-tab-3 = Select tab #3
|
||||||
|
@@ -7,6 +7,9 @@ zen-panel-ui-workspaces-create =
|
|||||||
zen-panel-ui-folder-create =
|
zen-panel-ui-folder-create =
|
||||||
.label = Create Folder
|
.label = Create Folder
|
||||||
|
|
||||||
|
zen-panel-ui-new-empty-split =
|
||||||
|
.label = New Split
|
||||||
|
|
||||||
zen-workspaces-panel-context-delete =
|
zen-workspaces-panel-context-delete =
|
||||||
.label = Delete Space
|
.label = Delete Space
|
||||||
.accesskey = D
|
.accesskey = D
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
<command id="cmd_zenSplitViewUnsplit" />
|
<command id="cmd_zenSplitViewUnsplit" />
|
||||||
<command id="cmd_zenSplitViewLinkInNewTab" />
|
<command id="cmd_zenSplitViewLinkInNewTab" />
|
||||||
<command id="cmd_zenSplitViewContextMenu" />
|
<command id="cmd_zenSplitViewContextMenu" />
|
||||||
|
<command id="cmd_zenNewEmptySplit" />
|
||||||
|
|
||||||
<!-- Workspace commands -->
|
<!-- Workspace commands -->
|
||||||
<command id="cmd_zenWorkspaceSwitch1" />
|
<command id="cmd_zenWorkspaceSwitch1" />
|
||||||
|
@@ -3,10 +3,11 @@
|
|||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
<menupopup id="zenCreateNewPopup">
|
<menupopup id="zenCreateNewPopup">
|
||||||
<menuitem data-l10n-id="tabs-toolbar-new-tab" command="cmd_newNavigatorTab" image="chrome://browser/skin/zen-icons/plus.svg" />
|
|
||||||
<menuseparator/>
|
|
||||||
<menuitem data-l10n-id="zen-panel-ui-folder-create" command="cmd_zenOpenFolderCreation" image="chrome://browser/skin/zen-icons/folder.svg" />
|
|
||||||
<menuitem data-l10n-id="zen-panel-ui-workspaces-create" command="cmd_zenOpenWorkspaceCreation" image="chrome://browser/skin/zen-icons/duplicate-tab.svg" />
|
<menuitem data-l10n-id="zen-panel-ui-workspaces-create" command="cmd_zenOpenWorkspaceCreation" image="chrome://browser/skin/zen-icons/duplicate-tab.svg" />
|
||||||
|
<menuitem data-l10n-id="zen-panel-ui-folder-create" command="cmd_zenOpenFolderCreation" image="chrome://browser/skin/zen-icons/folder.svg" />
|
||||||
|
<menuseparator/>
|
||||||
|
<menuitem data-l10n-id="zen-panel-ui-new-empty-split" command="cmd_zenNewEmptySplit" image="chrome://browser/skin/zen-icons/split.svg" />
|
||||||
|
<menuitem data-l10n-id="tabs-toolbar-new-tab" command="cmd_newNavigatorTab" image="chrome://browser/skin/zen-icons/plus.svg" />
|
||||||
</menupopup>
|
</menupopup>
|
||||||
|
|
||||||
<menupopup id="zenWorkspaceMoreActions">
|
<menupopup id="zenWorkspaceMoreActions">
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
|
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
|
||||||
index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010eedf8dcc29 100644
|
index 3204f253c23551650991d3385dd256d55892a012..e5a907a81526fde51087a0c33599fbb2948420ad 100644
|
||||||
--- a/browser/components/tabbrowser/content/tabbrowser.js
|
--- a/browser/components/tabbrowser/content/tabbrowser.js
|
||||||
+++ b/browser/components/tabbrowser/content/tabbrowser.js
|
+++ b/browser/components/tabbrowser/content/tabbrowser.js
|
||||||
@@ -427,15 +427,64 @@
|
@@ -427,15 +427,64 @@
|
||||||
@@ -395,10 +395,10 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
+ gZenWorkspaces._initialTab._shouldRemove = true;
|
+ gZenWorkspaces._initialTab._shouldRemove = true;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ }
|
}
|
||||||
+ else {
|
+ else {
|
||||||
+ gZenWorkspaces._tabToRemoveForEmpty = this.selectedTab;
|
+ gZenWorkspaces._tabToRemoveForEmpty = this.selectedTab;
|
||||||
}
|
+ }
|
||||||
+ this._hasAlreadyInitializedZenSessionStore = true;
|
+ this._hasAlreadyInitializedZenSessionStore = true;
|
||||||
|
|
||||||
if (tabs.length > 1 || !tabs[0].selected) {
|
if (tabs.length > 1 || !tabs[0].selected) {
|
||||||
@@ -522,17 +522,22 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
if (
|
if (
|
||||||
!this._beginRemoveTab(aTab, {
|
!this._beginRemoveTab(aTab, {
|
||||||
closeWindowFastpath: true,
|
closeWindowFastpath: true,
|
||||||
@@ -4796,7 +4937,9 @@
|
@@ -4796,7 +4937,13 @@
|
||||||
// We're not animating, so we can cancel the animation stopwatch.
|
// We're not animating, so we can cancel the animation stopwatch.
|
||||||
Glean.browserTabclose.timeAnim.cancel(aTab._closeTimeAnimTimerId);
|
Glean.browserTabclose.timeAnim.cancel(aTab._closeTimeAnimTimerId);
|
||||||
aTab._closeTimeAnimTimerId = null;
|
aTab._closeTimeAnimTimerId = null;
|
||||||
+ gZenVerticalTabsManager.animateTabClose(aTab, (animate && !gReduceMotion)).then(() => {
|
- this._endRemoveTab(aTab);
|
||||||
this._endRemoveTab(aTab);
|
+ if (animate && !gReduceMotion && !gZenUIManager.testingEnabled) {
|
||||||
+ });
|
+ gZenVerticalTabsManager.animateTabClose(aTab, (animate && !gReduceMotion)).then(() => {
|
||||||
|
+ this._endRemoveTab(aTab);
|
||||||
|
+ });
|
||||||
|
+ } else {
|
||||||
|
+ this._endRemoveTab(aTab);
|
||||||
|
+ }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4930,7 +5073,7 @@
|
@@ -4930,7 +5077,7 @@
|
||||||
closeWindowWithLastTab != null
|
closeWindowWithLastTab != null
|
||||||
? closeWindowWithLastTab
|
? closeWindowWithLastTab
|
||||||
: !window.toolbar.visible ||
|
: !window.toolbar.visible ||
|
||||||
@@ -541,7 +546,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
|
|
||||||
if (closeWindow) {
|
if (closeWindow) {
|
||||||
// We've already called beforeunload on all the relevant tabs if we get here,
|
// We've already called beforeunload on all the relevant tabs if we get here,
|
||||||
@@ -4954,6 +5097,7 @@
|
@@ -4954,6 +5101,7 @@
|
||||||
|
|
||||||
newTab = true;
|
newTab = true;
|
||||||
}
|
}
|
||||||
@@ -549,7 +554,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
aTab._endRemoveArgs = [closeWindow, newTab];
|
aTab._endRemoveArgs = [closeWindow, newTab];
|
||||||
|
|
||||||
// swapBrowsersAndCloseOther will take care of closing the window without animation.
|
// swapBrowsersAndCloseOther will take care of closing the window without animation.
|
||||||
@@ -4994,13 +5138,7 @@
|
@@ -4994,13 +5142,7 @@
|
||||||
aTab._mouseleave();
|
aTab._mouseleave();
|
||||||
|
|
||||||
if (newTab) {
|
if (newTab) {
|
||||||
@@ -564,7 +569,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
} else {
|
} else {
|
||||||
TabBarVisibility.update();
|
TabBarVisibility.update();
|
||||||
}
|
}
|
||||||
@@ -5133,6 +5271,7 @@
|
@@ -5133,6 +5275,7 @@
|
||||||
this.tabs[i]._tPos = i;
|
this.tabs[i]._tPos = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,7 +577,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
if (!this._windowIsClosing) {
|
if (!this._windowIsClosing) {
|
||||||
// update tab close buttons state
|
// update tab close buttons state
|
||||||
this.tabContainer._updateCloseButtons();
|
this.tabContainer._updateCloseButtons();
|
||||||
@@ -5345,6 +5484,7 @@
|
@@ -5345,6 +5488,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
let excludeTabs = new Set(aExcludeTabs);
|
let excludeTabs = new Set(aExcludeTabs);
|
||||||
@@ -580,7 +585,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
|
|
||||||
// If this tab has a successor, it should be selectable, since
|
// If this tab has a successor, it should be selectable, since
|
||||||
// hiding or closing a tab removes that tab as a successor.
|
// hiding or closing a tab removes that tab as a successor.
|
||||||
@@ -5357,13 +5497,13 @@
|
@@ -5357,13 +5501,13 @@
|
||||||
!excludeTabs.has(aTab.owner) &&
|
!excludeTabs.has(aTab.owner) &&
|
||||||
Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")
|
Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")
|
||||||
) {
|
) {
|
||||||
@@ -596,7 +601,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
);
|
);
|
||||||
|
|
||||||
let tab = this.tabContainer.findNextTab(aTab, {
|
let tab = this.tabContainer.findNextTab(aTab, {
|
||||||
@@ -5379,7 +5519,7 @@
|
@@ -5379,7 +5523,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tab) {
|
if (tab) {
|
||||||
@@ -605,7 +610,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If no qualifying visible tab was found, see if there is a tab in
|
// If no qualifying visible tab was found, see if there is a tab in
|
||||||
@@ -5400,7 +5540,7 @@
|
@@ -5400,7 +5544,7 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,7 +619,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
}
|
}
|
||||||
|
|
||||||
_blurTab(aTab) {
|
_blurTab(aTab) {
|
||||||
@@ -5802,10 +5942,10 @@
|
@@ -5802,10 +5946,10 @@
|
||||||
SessionStore.deleteCustomTabValue(aTab, "hiddenBy");
|
SessionStore.deleteCustomTabValue(aTab, "hiddenBy");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -627,7 +632,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
aTab.selected ||
|
aTab.selected ||
|
||||||
aTab.closing ||
|
aTab.closing ||
|
||||||
// Tabs that are sharing the screen, microphone or camera cannot be hidden.
|
// Tabs that are sharing the screen, microphone or camera cannot be hidden.
|
||||||
@@ -5864,6 +6004,7 @@
|
@@ -5864,6 +6008,7 @@
|
||||||
* @param {MozTabbrowserTab|MozTabbrowserTabGroup|MozTabbrowserTabGroup.labelElement} aTab
|
* @param {MozTabbrowserTab|MozTabbrowserTabGroup|MozTabbrowserTabGroup.labelElement} aTab
|
||||||
*/
|
*/
|
||||||
replaceTabWithWindow(aTab, aOptions) {
|
replaceTabWithWindow(aTab, aOptions) {
|
||||||
@@ -635,7 +640,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
if (this.tabs.length == 1) {
|
if (this.tabs.length == 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -5997,7 +6138,7 @@
|
@@ -5997,7 +6142,7 @@
|
||||||
* `true` if element is a `<tab-group>`
|
* `true` if element is a `<tab-group>`
|
||||||
*/
|
*/
|
||||||
isTabGroup(element) {
|
isTabGroup(element) {
|
||||||
@@ -644,7 +649,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -6073,8 +6214,8 @@
|
@@ -6073,8 +6218,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't allow mixing pinned and unpinned tabs.
|
// Don't allow mixing pinned and unpinned tabs.
|
||||||
@@ -655,7 +660,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
} else {
|
} else {
|
||||||
tabIndex = Math.max(tabIndex, this.pinnedTabCount);
|
tabIndex = Math.max(tabIndex, this.pinnedTabCount);
|
||||||
}
|
}
|
||||||
@@ -6100,10 +6241,16 @@
|
@@ -6100,10 +6245,16 @@
|
||||||
this.#handleTabMove(
|
this.#handleTabMove(
|
||||||
element,
|
element,
|
||||||
() => {
|
() => {
|
||||||
@@ -674,7 +679,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
if (neighbor && this.isTab(element) && tabIndex > element._tPos) {
|
if (neighbor && this.isTab(element) && tabIndex > element._tPos) {
|
||||||
neighbor.after(element);
|
neighbor.after(element);
|
||||||
} else {
|
} else {
|
||||||
@@ -6161,23 +6308,28 @@
|
@@ -6161,23 +6312,28 @@
|
||||||
#moveTabNextTo(element, targetElement, moveBefore = false, metricsContext) {
|
#moveTabNextTo(element, targetElement, moveBefore = false, metricsContext) {
|
||||||
if (this.isTabGroupLabel(targetElement)) {
|
if (this.isTabGroupLabel(targetElement)) {
|
||||||
targetElement = targetElement.group;
|
targetElement = targetElement.group;
|
||||||
@@ -709,7 +714,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
} else if (!element.pinned && targetElement && targetElement.pinned) {
|
} else if (!element.pinned && targetElement && targetElement.pinned) {
|
||||||
// If the caller asks to move an unpinned element next to a pinned
|
// If the caller asks to move an unpinned element next to a pinned
|
||||||
// tab, move the unpinned element to be the first unpinned element
|
// tab, move the unpinned element to be the first unpinned element
|
||||||
@@ -6190,14 +6342,34 @@
|
@@ -6190,14 +6346,34 @@
|
||||||
// move the tab group right before the first unpinned tab.
|
// move the tab group right before the first unpinned tab.
|
||||||
// 4. Moving a tab group and the first unpinned tab is grouped:
|
// 4. Moving a tab group and the first unpinned tab is grouped:
|
||||||
// move the tab group right before the first unpinned tab's tab group.
|
// move the tab group right before the first unpinned tab's tab group.
|
||||||
@@ -745,7 +750,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
element.pinned
|
element.pinned
|
||||||
? this.tabContainer.pinnedTabsContainer
|
? this.tabContainer.pinnedTabsContainer
|
||||||
: this.tabContainer;
|
: this.tabContainer;
|
||||||
@@ -6206,7 +6378,7 @@
|
@@ -6206,7 +6382,7 @@
|
||||||
element,
|
element,
|
||||||
() => {
|
() => {
|
||||||
if (moveBefore) {
|
if (moveBefore) {
|
||||||
@@ -754,7 +759,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
} else if (targetElement) {
|
} else if (targetElement) {
|
||||||
targetElement.after(element);
|
targetElement.after(element);
|
||||||
} else {
|
} else {
|
||||||
@@ -6252,10 +6424,10 @@
|
@@ -6252,10 +6428,10 @@
|
||||||
* @param {TabMetricsContext} [metricsContext]
|
* @param {TabMetricsContext} [metricsContext]
|
||||||
*/
|
*/
|
||||||
moveTabToGroup(aTab, aGroup, metricsContext) {
|
moveTabToGroup(aTab, aGroup, metricsContext) {
|
||||||
@@ -767,7 +772,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (aTab.group && aTab.group.id === aGroup.id) {
|
if (aTab.group && aTab.group.id === aGroup.id) {
|
||||||
@@ -6285,6 +6457,7 @@
|
@@ -6285,6 +6461,7 @@
|
||||||
|
|
||||||
let state = {
|
let state = {
|
||||||
tabIndex: tab._tPos,
|
tabIndex: tab._tPos,
|
||||||
@@ -775,7 +780,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
};
|
};
|
||||||
if (tab.visible) {
|
if (tab.visible) {
|
||||||
state.elementIndex = tab.elementIndex;
|
state.elementIndex = tab.elementIndex;
|
||||||
@@ -6311,7 +6484,7 @@
|
@@ -6311,7 +6488,7 @@
|
||||||
let changedTabGroup =
|
let changedTabGroup =
|
||||||
previousTabState.tabGroupId != currentTabState.tabGroupId;
|
previousTabState.tabGroupId != currentTabState.tabGroupId;
|
||||||
|
|
||||||
@@ -784,7 +789,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
tab.dispatchEvent(
|
tab.dispatchEvent(
|
||||||
new CustomEvent("TabMove", {
|
new CustomEvent("TabMove", {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
@@ -6348,6 +6521,10 @@
|
@@ -6348,6 +6525,10 @@
|
||||||
|
|
||||||
moveActionCallback();
|
moveActionCallback();
|
||||||
|
|
||||||
@@ -795,7 +800,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
// Clear tabs cache after moving nodes because the order of tabs may have
|
// Clear tabs cache after moving nodes because the order of tabs may have
|
||||||
// changed.
|
// changed.
|
||||||
this.tabContainer._invalidateCachedTabs();
|
this.tabContainer._invalidateCachedTabs();
|
||||||
@@ -7249,7 +7426,7 @@
|
@@ -7249,7 +7430,7 @@
|
||||||
// preventDefault(). It will still raise the window if appropriate.
|
// preventDefault(). It will still raise the window if appropriate.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -804,7 +809,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
window.focus();
|
window.focus();
|
||||||
aEvent.preventDefault();
|
aEvent.preventDefault();
|
||||||
break;
|
break;
|
||||||
@@ -7264,7 +7441,6 @@
|
@@ -7264,7 +7445,6 @@
|
||||||
}
|
}
|
||||||
case "TabGroupCollapse":
|
case "TabGroupCollapse":
|
||||||
aEvent.target.tabs.forEach(tab => {
|
aEvent.target.tabs.forEach(tab => {
|
||||||
@@ -812,7 +817,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "TabGroupCreateByUser":
|
case "TabGroupCreateByUser":
|
||||||
@@ -8199,6 +8375,7 @@
|
@@ -8199,6 +8379,7 @@
|
||||||
aWebProgress.isTopLevel
|
aWebProgress.isTopLevel
|
||||||
) {
|
) {
|
||||||
this.mTab.setAttribute("busy", "true");
|
this.mTab.setAttribute("busy", "true");
|
||||||
@@ -820,7 +825,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
gBrowser._tabAttrModified(this.mTab, ["busy"]);
|
gBrowser._tabAttrModified(this.mTab, ["busy"]);
|
||||||
this.mTab._notselectedsinceload = !this.mTab.selected;
|
this.mTab._notselectedsinceload = !this.mTab.selected;
|
||||||
}
|
}
|
||||||
@@ -9200,7 +9377,7 @@ var TabContextMenu = {
|
@@ -9200,7 +9381,7 @@ var TabContextMenu = {
|
||||||
);
|
);
|
||||||
contextUnpinSelectedTabs.hidden =
|
contextUnpinSelectedTabs.hidden =
|
||||||
!this.contextTab.pinned || !this.multiselected;
|
!this.contextTab.pinned || !this.multiselected;
|
||||||
@@ -829,7 +834,7 @@ index 3204f253c23551650991d3385dd256d55892a012..0285b0bcf1e5ba769011c82729e010ee
|
|||||||
// Build Ask Chat items
|
// Build Ask Chat items
|
||||||
TabContextMenu.GenAI.buildTabMenu(
|
TabContextMenu.GenAI.buildTabMenu(
|
||||||
document.getElementById("context_askChat"),
|
document.getElementById("context_askChat"),
|
||||||
@@ -9520,6 +9697,7 @@ var TabContextMenu = {
|
@@ -9520,6 +9701,7 @@ var TabContextMenu = {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -11,24 +11,21 @@ index fdbab8806fd320f4aacec46a42c8ef953580d00c..5501c329a9fd12bcc8e12de396113497
|
|||||||
// Try to reuse the cached top-sites context. If it's not cached, then
|
// Try to reuse the cached top-sites context. If it's not cached, then
|
||||||
// there will be a gap of time between when the input is focused and
|
// there will be a gap of time between when the input is focused and
|
||||||
// when the view opens that can be perceived as flicker.
|
// when the view opens that can be perceived as flicker.
|
||||||
@@ -823,6 +823,19 @@ export class UrlbarView {
|
@@ -823,7 +823,16 @@ export class UrlbarView {
|
||||||
// them, resembling tab-to-search. In that case, the input value is
|
// them, resembling tab-to-search. In that case, the input value is
|
||||||
// still associated with the first result.
|
// still associated with the first result.
|
||||||
this.input.setResultForCurrentValue(firstResult);
|
this.input.setResultForCurrentValue(firstResult);
|
||||||
+ } else if (firstResult.payload.zenAction) {
|
- }
|
||||||
+ this.#selectElement(this.getFirstSelectableElement(), {
|
+ }
|
||||||
+ updateInput: false,
|
+ this.window.setTimeout(() => {
|
||||||
+ setAccessibleFocus:
|
+ if (queryContext.results[0].payload.zenAction) {
|
||||||
+ this.controller._userSelectionBehavior == "arrow",
|
|
||||||
+ });
|
|
||||||
+ this.window.setTimeout(() => {
|
|
||||||
+ this.#selectElement(this.getFirstSelectableElement(), {
|
+ this.#selectElement(this.getFirstSelectableElement(), {
|
||||||
+ updateInput: false,
|
+ updateInput: false,
|
||||||
+ setAccessibleFocus:
|
+ setAccessibleFocus:
|
||||||
+ this.controller._userSelectionBehavior == "arrow",
|
+ this.controller._userSelectionBehavior == "arrow",
|
||||||
+ });
|
+ });
|
||||||
+ }, 150);
|
+ }
|
||||||
}
|
+ }, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3189,7 +3202,7 @@ export class UrlbarView {
|
@@ -3189,7 +3202,7 @@ export class UrlbarView {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/toolkit/components/extensions/parent/ext-runtime.js b/toolkit/components/extensions/parent/ext-runtime.js
|
diff --git a/toolkit/components/extensions/parent/ext-runtime.js b/toolkit/components/extensions/parent/ext-runtime.js
|
||||||
index 0d7a3e505b6bd30548c6dda1504dd343a517b083..71bab6f1562ef6ec43541e52573d2ed5c4e8e3af 100644
|
index 0d7a3e505b6bd30548c6dda1504dd343a517b083..54400def5e02e886765fab68c3854a6b3c24ef2b 100644
|
||||||
--- a/toolkit/components/extensions/parent/ext-runtime.js
|
--- a/toolkit/components/extensions/parent/ext-runtime.js
|
||||||
+++ b/toolkit/components/extensions/parent/ext-runtime.js
|
+++ b/toolkit/components/extensions/parent/ext-runtime.js
|
||||||
@@ -333,7 +333,7 @@ this.runtime = class extends ExtensionAPIPersistent {
|
@@ -333,7 +333,7 @@ this.runtime = class extends ExtensionAPIPersistent {
|
||||||
@@ -7,7 +7,7 @@ index 0d7a3e505b6bd30548c6dda1504dd343a517b083..71bab6f1562ef6ec43541e52573d2ed5
|
|||||||
getBrowserInfo: function () {
|
getBrowserInfo: function () {
|
||||||
const { name, vendor, version, appBuildID } = Services.appinfo;
|
const { name, vendor, version, appBuildID } = Services.appinfo;
|
||||||
- const info = { name, vendor, version, buildID: appBuildID };
|
- const info = { name, vendor, version, buildID: appBuildID };
|
||||||
+ const info = { name, vendor, version: AppConstants.ZEN_FIREFOX_VERSION, buildID: appBuildID };
|
+ const info = { name: 'firefox', vendor, version: AppConstants.ZEN_FIREFOX_VERSION, buildID: appBuildID };
|
||||||
return Promise.resolve(info);
|
return Promise.resolve(info);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@@ -111,7 +111,7 @@ export var ZenCustomizableUI = new (class {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const popup = window.document.getElementById('zenCreateNewPopup');
|
const popup = window.document.getElementById('zenCreateNewPopup');
|
||||||
popup.openPopup(button, 'after_start');
|
popup.openPopup(button, 'before_start');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -274,22 +274,23 @@ var gZenUIManager = {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
handleNewTab(werePassedURL, searchClipboard, where) {
|
handleNewTab(werePassedURL, searchClipboard, where, overridePreferance = false) {
|
||||||
// Validate browser state first
|
// Validate browser state first
|
||||||
if (!this._validateBrowserState()) {
|
if (!this._validateBrowserState()) {
|
||||||
console.warn('Browser state invalid for new tab operation');
|
console.warn('Browser state invalid for new tab operation');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.testingEnabled) {
|
if (this.testingEnabled && !overridePreferance) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldOpenURLBar =
|
const shouldOpenURLBar =
|
||||||
gZenVerticalTabsManager._canReplaceNewTab &&
|
overridePreferance ||
|
||||||
!werePassedURL &&
|
(gZenVerticalTabsManager._canReplaceNewTab &&
|
||||||
!searchClipboard &&
|
!werePassedURL &&
|
||||||
where === 'tab';
|
!searchClipboard &&
|
||||||
|
where === 'tab');
|
||||||
|
|
||||||
if (!shouldOpenURLBar) {
|
if (!shouldOpenURLBar) {
|
||||||
return false;
|
return false;
|
||||||
@@ -399,7 +400,10 @@ var gZenUIManager = {
|
|||||||
|
|
||||||
if (gURLBar.focused) {
|
if (gURLBar.focused) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
gURLBar.view.close({ elementPicked: onSwitch });
|
window.dispatchEvent(
|
||||||
|
new CustomEvent('ZenURLBarClosed', { detail: { onSwitch, onElementPicked } })
|
||||||
|
);
|
||||||
|
gURLBar.view.close({ elementPicked: onElementPicked });
|
||||||
gURLBar.updateTextOverflow();
|
gURLBar.updateTextOverflow();
|
||||||
|
|
||||||
// Ensure tab and browser are valid before updating state
|
// Ensure tab and browser are valid before updating state
|
||||||
|
@@ -502,21 +502,52 @@ button.popup-notification-dropmarker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.urlbarView-shortcutContent {
|
.urlbarView-shortcutContent {
|
||||||
border-radius: 4px;
|
|
||||||
padding: 6px 8px;
|
|
||||||
font-size: 10px;
|
|
||||||
font-weight: 600;
|
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-top: auto;
|
background-color: color-mix(in srgb, var(--zen-branding-bg-reverse), transparent 95%);
|
||||||
margin-bottom: auto;
|
padding: 6px 8px;
|
||||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
|
||||||
|
font-size: 10px;
|
||||||
|
|
||||||
&:empty {
|
&:empty {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.urlbarView-prettyName,
|
||||||
|
.urlbarView-shortcutContent {
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.urlbarView-prettyName {
|
||||||
|
padding: 4px 6px;
|
||||||
|
background-color: color-mix(in srgb, var(--zen-branding-bg-reverse), transparent 90%);
|
||||||
|
margin-left: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
display: flex;
|
||||||
|
color: color-mix(in srgb, var(--zen-primary-color), currentColor 95%);
|
||||||
|
|
||||||
|
& img {
|
||||||
|
-moz-context-properties: fill;
|
||||||
|
fill: currentColor;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
|
||||||
|
&[workspaceIcon] {
|
||||||
|
scale: 1.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[hidden] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.urlbarView-row[has-action]:is([type='switchtab'], [type='remotetab'], [type='clipboard']) {
|
.urlbarView-row[has-action]:is([type='switchtab'], [type='remotetab'], [type='clipboard']) {
|
||||||
& .urlbarView-action:last-child {
|
& .urlbarView-action:last-child {
|
||||||
margin-left: auto !important;
|
margin-left: auto !important;
|
||||||
@@ -575,14 +606,15 @@ button.popup-notification-dropmarker {
|
|||||||
--urlbarView-item-block-padding: 10px;
|
--urlbarView-item-block-padding: 10px;
|
||||||
color: light-dark(rgba(0, 0, 0, 0.7), rgba(255, 255, 255, 0.7)) !important;
|
color: light-dark(rgba(0, 0, 0, 0.7), rgba(255, 255, 255, 0.7)) !important;
|
||||||
|
|
||||||
&:hover.urlbarView-favicon,
|
&:hover {
|
||||||
&:hover,
|
&,
|
||||||
& .urlbarView-shortcutContent {
|
& .urlbarView-favicon {
|
||||||
background-color: color-mix(
|
background-color: color-mix(
|
||||||
in srgb,
|
in srgb,
|
||||||
var(--zen-branding-bg-reverse) 5%,
|
var(--zen-branding-bg-reverse) 5%,
|
||||||
transparent 95%
|
transparent 95%
|
||||||
) !important;
|
) !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&[selected] {
|
&[selected] {
|
||||||
@@ -612,6 +644,10 @@ button.popup-notification-dropmarker {
|
|||||||
fill: var(--zen-selected-color) !important;
|
fill: var(--zen-selected-color) !important;
|
||||||
background-color: rgba(255, 255, 255, 0.9) !important;
|
background-color: rgba(255, 255, 255, 0.9) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& .urlbarView-prettyName {
|
||||||
|
background-color: color-mix(in srgb, var(--zen-branding-bg-reverse), transparent 80%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -79,6 +79,11 @@ document.addEventListener(
|
|||||||
case 'cmd_zenSplitViewLinkInNewTab':
|
case 'cmd_zenSplitViewLinkInNewTab':
|
||||||
gZenViewSplitter.splitLinkInNewTab();
|
gZenViewSplitter.splitLinkInNewTab();
|
||||||
break;
|
break;
|
||||||
|
case 'cmd_zenNewEmptySplit':
|
||||||
|
setTimeout(() => {
|
||||||
|
gZenViewSplitter.createEmptySplit();
|
||||||
|
}, 0);
|
||||||
|
break;
|
||||||
case 'cmd_zenReplacePinnedUrlWithCurrent':
|
case 'cmd_zenReplacePinnedUrlWithCurrent':
|
||||||
gZenPinnedTabManager.replacePinnedUrlWithCurrent();
|
gZenPinnedTabManager.replacePinnedUrlWithCurrent();
|
||||||
break;
|
break;
|
||||||
|
@@ -816,7 +816,7 @@ class nsZenKeyboardShortcutsLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class nsZenKeyboardShortcutsVersioner {
|
class nsZenKeyboardShortcutsVersioner {
|
||||||
static LATEST_KBS_VERSION = 10;
|
static LATEST_KBS_VERSION = 11;
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
@@ -1078,6 +1078,21 @@ class nsZenKeyboardShortcutsVersioner {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (version < 11) {
|
||||||
|
// Migrate from version 10 to 11
|
||||||
|
data.push(
|
||||||
|
new KeyShortcut(
|
||||||
|
'zen-new-empty-split-view',
|
||||||
|
'+',
|
||||||
|
'',
|
||||||
|
ZEN_SPLIT_VIEW_SHORTCUTS_GROUP,
|
||||||
|
nsKeyShortcutModifiers.fromObject({ accel: true, alt: true }),
|
||||||
|
'cmd_zenNewEmptySplit',
|
||||||
|
'zen-new-empty-split-view-shortcut'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1362,6 +1377,9 @@ var gZenKeyboardShortcutsManager = {
|
|||||||
* @returns {string|null} The shortcut as a string or null if not found
|
* @returns {string|null} The shortcut as a string or null if not found
|
||||||
*/
|
*/
|
||||||
getShortcutDisplayFromCommand(command) {
|
getShortcutDisplayFromCommand(command) {
|
||||||
|
if (!command) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const shortcut = this.getShortcutFromCommand(command);
|
const shortcut = this.getShortcutFromCommand(command);
|
||||||
if (shortcut) {
|
if (shortcut) {
|
||||||
return shortcut.toUserString();
|
return shortcut.toUserString();
|
||||||
|
@@ -1008,6 +1008,15 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
tab.linkedBrowser.docShellIsActive = true;
|
tab.linkedBrowser.docShellIsActive = true;
|
||||||
}
|
}
|
||||||
this._maybeRemoveFakeBrowser();
|
this._maybeRemoveFakeBrowser();
|
||||||
|
{
|
||||||
|
const shouldDisableEmptySplits = tab.hasAttribute('zen-empty-tab') || tab.splitView;
|
||||||
|
const command = document.getElementById('cmd_zenNewEmptySplit');
|
||||||
|
if (shouldDisableEmptySplits) {
|
||||||
|
command.setAttribute('disabled', 'true');
|
||||||
|
} else {
|
||||||
|
command.removeAttribute('disabled');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1913,6 +1922,42 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createEmptySplit() {
|
||||||
|
const selectedTab = gBrowser.selectedTab;
|
||||||
|
const emptyTab = gZenWorkspaces._emptyTab;
|
||||||
|
const data = {
|
||||||
|
tabs: [selectedTab, emptyTab],
|
||||||
|
gridType: 'grid',
|
||||||
|
layoutTree: this.calculateLayoutTree([selectedTab, emptyTab], 'grid'),
|
||||||
|
};
|
||||||
|
this._data.push(data);
|
||||||
|
this.activateSplitView(data);
|
||||||
|
gBrowser.selectedTab = emptyTab;
|
||||||
|
window.addEventListener(
|
||||||
|
'ZenURLBarClosed',
|
||||||
|
(event) => {
|
||||||
|
const { onElementPicked } = event.detail;
|
||||||
|
const groupIndex = this._data.findIndex((group) => group.tabs.includes(emptyTab));
|
||||||
|
const newSelectedTab = gBrowser.selectedTab;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.removeTabFromGroup(emptyTab, groupIndex);
|
||||||
|
if (onElementPicked) {
|
||||||
|
if (newSelectedTab === emptyTab || newSelectedTab === selectedTab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.splitTabs([selectedTab, newSelectedTab], 'grid', 1);
|
||||||
|
} else {
|
||||||
|
gBrowser.selectedTab = selectedTab;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ once: true }
|
||||||
|
);
|
||||||
|
setTimeout(() => {
|
||||||
|
gZenUIManager.handleNewTab(false, false, 'tab', true);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.gZenViewSplitter = new nsZenViewSplitter();
|
window.gZenViewSplitter = new nsZenViewSplitter();
|
||||||
|
@@ -14,3 +14,4 @@ support-files = [
|
|||||||
["browser_split_browser_duplication.js"]
|
["browser_split_browser_duplication.js"]
|
||||||
["browser_split_view_with_glance.js"]
|
["browser_split_view_with_glance.js"]
|
||||||
["browser_split_view_with_folders.js"]
|
["browser_split_view_with_folders.js"]
|
||||||
|
["browser_split_view_empty.js"]
|
||||||
|
49
src/zen/tests/split_view/browser_split_view_empty.js
Normal file
49
src/zen/tests/split_view/browser_split_view_empty.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { UrlbarTestUtils } = ChromeUtils.importESModule(
|
||||||
|
'resource://testing-common/UrlbarTestUtils.sys.mjs'
|
||||||
|
);
|
||||||
|
|
||||||
|
add_task(async function test_Split_View_Empty() {
|
||||||
|
await BrowserTestUtils.withNewTab('https://example.com', async function () {
|
||||||
|
const originalTab = gBrowser.selectedTab;
|
||||||
|
const command = document.getElementById('cmd_zenNewEmptySplit');
|
||||||
|
command.doCommand();
|
||||||
|
await UrlbarTestUtils.promisePopupOpen(window, () => {});
|
||||||
|
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||||
|
window,
|
||||||
|
waitForFocus,
|
||||||
|
value: 'https://example.com',
|
||||||
|
});
|
||||||
|
const waitForActivationPromise = BrowserTestUtils.waitForEvent(
|
||||||
|
window,
|
||||||
|
'ZenViewSplitter:SplitViewActivated'
|
||||||
|
);
|
||||||
|
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
|
||||||
|
EventUtils.synthesizeMouseAtCenter(result.element.row, {});
|
||||||
|
await waitForActivationPromise;
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(async () => {
|
||||||
|
resolve();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
const selectedTab = gBrowser.selectedTab;
|
||||||
|
ok(
|
||||||
|
gBrowser.tabpanels.hasAttribute('zen-split-view'),
|
||||||
|
'The split view should not have crashed with two tabs in it'
|
||||||
|
);
|
||||||
|
ok(!gZenWorkspaces._emptyTab.splitView, 'The empty tab should not be in split view');
|
||||||
|
ok(!gZenWorkspaces._emptyTab.group, 'The empty tab should not be in a group');
|
||||||
|
ok(selectedTab.splitView, 'The selected tab should be in split view');
|
||||||
|
ok(originalTab.splitView, 'The original tab should be in split view');
|
||||||
|
Assert.equal(
|
||||||
|
gBrowser.tabpanels.querySelectorAll('[zen-split="true"]').length,
|
||||||
|
2,
|
||||||
|
'There should be two split views present'
|
||||||
|
);
|
||||||
|
await BrowserTestUtils.removeTab(selectedTab);
|
||||||
|
});
|
||||||
|
});
|
@@ -21,6 +21,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
|||||||
UrlbarTokenizer: 'resource:///modules/UrlbarTokenizer.sys.mjs',
|
UrlbarTokenizer: 'resource:///modules/UrlbarTokenizer.sys.mjs',
|
||||||
QueryScorer: 'resource:///modules/UrlbarProviderInterventions.sys.mjs',
|
QueryScorer: 'resource:///modules/UrlbarProviderInterventions.sys.mjs',
|
||||||
BrowserWindowTracker: 'resource:///modules/BrowserWindowTracker.sys.mjs',
|
BrowserWindowTracker: 'resource:///modules/BrowserWindowTracker.sys.mjs',
|
||||||
|
AddonManager: 'resource://gre/modules/AddonManager.sys.mjs',
|
||||||
});
|
});
|
||||||
|
|
||||||
XPCOMUtils.defineLazyPreferenceGetter(
|
XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
@@ -63,25 +64,81 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#getWorkspaceActions(window) {
|
||||||
|
if (window.gZenWorkspaces.privateWindowOrDisabled) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const workspaces = window.gZenWorkspaces._workspaceCache?.workspaces;
|
||||||
|
if (!workspaces?.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
let actions = [];
|
||||||
|
const activeSpaceUUID = window.gZenWorkspaces.activeWorkspace;
|
||||||
|
for (const workspace of workspaces) {
|
||||||
|
if (workspace.uuid !== activeSpaceUUID) {
|
||||||
|
const accentColor = window.gZenWorkspaces
|
||||||
|
.workspaceElement(workspace.uuid)
|
||||||
|
?.style.getPropertyValue('--zen-primary-color');
|
||||||
|
actions.push({
|
||||||
|
label: 'Focus on',
|
||||||
|
extraPayload: {
|
||||||
|
workspaceId: workspace.uuid,
|
||||||
|
prettyName: workspace.name,
|
||||||
|
prettyIcon: workspace.icon,
|
||||||
|
accentColor,
|
||||||
|
},
|
||||||
|
icon: 'chrome://browser/skin/zen-icons/forward.svg',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
async #getExtensionActions(window) {
|
||||||
|
const addons = await lazy.AddonManager.getAddonsByTypes(['extension']);
|
||||||
|
return addons
|
||||||
|
.filter(
|
||||||
|
(addon) =>
|
||||||
|
addon.isActive &&
|
||||||
|
!addon.isSystem &&
|
||||||
|
window.gUnifiedExtensions.browserActionFor(window.WebExtensionPolicy.getByID(addon.id))
|
||||||
|
)
|
||||||
|
.map((addon) => {
|
||||||
|
return {
|
||||||
|
icon: 'chrome://browser/skin/zen-icons/extension.svg',
|
||||||
|
label: 'Extension',
|
||||||
|
extraPayload: {
|
||||||
|
extensionId: addon.id,
|
||||||
|
prettyName: addon.name,
|
||||||
|
prettyIcon: addon.iconURL,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {Window} window The window to check available actions for.
|
||||||
* @returns All the available global actions.
|
* @returns All the available global actions.
|
||||||
*/
|
*/
|
||||||
get #availableActions() {
|
async #getAvailableActions(window) {
|
||||||
return globalActions.filter((a) =>
|
return globalActions
|
||||||
typeof a.isAvailable === 'function' ? a.isAvailable() : true
|
.filter((a) => a.isAvailable(window))
|
||||||
);
|
.concat(this.#getWorkspaceActions(window))
|
||||||
|
.concat(await this.#getExtensionActions(window));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a search query amongst the available global actions.
|
* Starts a search query amongst the available global actions.
|
||||||
*
|
*
|
||||||
* @param {string} queryContext The query context object
|
* @param {string} query The user's search query.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
#findMatchingActions(query) {
|
async #findMatchingActions(query) {
|
||||||
const actions = this.#availableActions;
|
const window = lazy.BrowserWindowTracker.getTopWindow();
|
||||||
|
const actions = await this.#getAvailableActions(window);
|
||||||
let results = [];
|
let results = [];
|
||||||
for (let action of actions) {
|
for (let action of actions) {
|
||||||
const label = action.label;
|
const label = action.extraPayload?.prettyName || action.label;
|
||||||
const score = this.#calculateFuzzyScore(label, query);
|
const score = this.#calculateFuzzyScore(label, query);
|
||||||
if (score > MINIMUM_QUERY_SCORE) {
|
if (score > MINIMUM_QUERY_SCORE) {
|
||||||
results.push({
|
results.push({
|
||||||
@@ -155,7 +212,7 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionsResults = this.#findMatchingActions(query);
|
const actionsResults = await this.#findMatchingActions(query);
|
||||||
if (!actionsResults.length) {
|
if (!actionsResults.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -173,6 +230,7 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
shortcutContent: ownerGlobal.gZenKeyboardShortcutsManager.getShortcutDisplayFromCommand(
|
shortcutContent: ownerGlobal.gZenKeyboardShortcutsManager.getShortcutDisplayFromCommand(
|
||||||
action.command
|
action.command
|
||||||
),
|
),
|
||||||
|
...action.extraPayload,
|
||||||
});
|
});
|
||||||
|
|
||||||
let result = new lazy.UrlbarResult(
|
let result = new lazy.UrlbarResult(
|
||||||
@@ -206,6 +264,9 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
* @returns {object} An object describing the view update.
|
* @returns {object} An object describing the view update.
|
||||||
*/
|
*/
|
||||||
getViewUpdate(result) {
|
getViewUpdate(result) {
|
||||||
|
const prettyIconIsSvg =
|
||||||
|
result.payload.prettyIcon &&
|
||||||
|
(result.payload.prettyIcon.endsWith('.svg') || result.payload.prettyIcon.endsWith('.png'));
|
||||||
return {
|
return {
|
||||||
icon: {
|
icon: {
|
||||||
attributes: {
|
attributes: {
|
||||||
@@ -219,6 +280,27 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
shortcutContent: {
|
shortcutContent: {
|
||||||
textContent: result.payload.shortcutContent || '',
|
textContent: result.payload.shortcutContent || '',
|
||||||
},
|
},
|
||||||
|
prettyName: {
|
||||||
|
attributes: {
|
||||||
|
hidden: !result.payload.prettyName,
|
||||||
|
style: `--zen-primary-color: ${result.payload.accentColor || 'currentColor'}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prettyNameStrong: {
|
||||||
|
textContent: result.payload.prettyName
|
||||||
|
? prettyIconIsSvg || !result.payload.prettyIcon
|
||||||
|
? result.payload.prettyName
|
||||||
|
: `${result.payload.prettyIcon} ${result.payload.prettyName}`
|
||||||
|
: '',
|
||||||
|
attributes: { dir: 'ltr' },
|
||||||
|
},
|
||||||
|
prettyNameIcon: {
|
||||||
|
attributes: {
|
||||||
|
src: result.payload.prettyIcon || '',
|
||||||
|
hidden: !prettyIconIsSvg || !result.payload.prettyIcon,
|
||||||
|
workspaceIcon: !!result.payload.workspaceId,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,6 +326,23 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
tag: 'span',
|
||||||
|
classList: ['urlbarView-prettyName'],
|
||||||
|
hidden: true,
|
||||||
|
name: 'prettyName',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
tag: 'img',
|
||||||
|
name: 'prettyNameIcon',
|
||||||
|
attributes: { hidden: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'prettyNameStrong',
|
||||||
|
tag: 'strong',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'shortcutContent',
|
name: 'shortcutContent',
|
||||||
tag: 'span',
|
tag: 'span',
|
||||||
@@ -257,10 +356,28 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
const result = details.result;
|
const result = details.result;
|
||||||
const payload = result.payload;
|
const payload = result.payload;
|
||||||
const command = payload.zenCommand;
|
const command = payload.zenCommand;
|
||||||
|
const ownerGlobal = details.element.ownerGlobal;
|
||||||
|
if (typeof command === 'function') {
|
||||||
|
command(ownerGlobal);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Switch workspace if theres a workspaceId in the payload.
|
||||||
|
if (payload.workspaceId) {
|
||||||
|
ownerGlobal.gZenWorkspaces.changeWorkspaceWithID(payload.workspaceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (payload.extensionId) {
|
||||||
|
const action = ownerGlobal.gUnifiedExtensions.browserActionFor(
|
||||||
|
ownerGlobal.WebExtensionPolicy.getByID(payload.extensionId)
|
||||||
|
);
|
||||||
|
if (action) {
|
||||||
|
action.openPopup(ownerGlobal, /* without user interaction = */ true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!command) {
|
if (!command) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ownerGlobal = details.element.ownerGlobal;
|
|
||||||
const commandToRun = ownerGlobal.document.getElementById(command);
|
const commandToRun = ownerGlobal.document.getElementById(command);
|
||||||
if (commandToRun) {
|
if (commandToRun) {
|
||||||
ownerGlobal.gBrowser.selectedBrowser.focus();
|
ownerGlobal.gBrowser.selectedBrowser.focus();
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
export const globalActions = [
|
const globalActionsTemplate = [
|
||||||
{
|
{
|
||||||
label: 'Toggle Compact Mode',
|
label: 'Toggle Compact Mode',
|
||||||
command: 'cmd_zenCompactModeToggle',
|
command: 'cmd_zenCompactModeToggle',
|
||||||
@@ -15,4 +15,44 @@ export const globalActions = [
|
|||||||
icon: 'chrome://browser/skin/zen-icons/edit-theme.svg',
|
icon: 'chrome://browser/skin/zen-icons/edit-theme.svg',
|
||||||
suggestedIndex: 4,
|
suggestedIndex: 4,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'New Split View',
|
||||||
|
command: 'cmd_zenNewEmptySplit',
|
||||||
|
icon: 'chrome://browser/skin/zen-icons/split.svg',
|
||||||
|
suggestedIndex: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'New Folder',
|
||||||
|
command: 'cmd_zenOpenFolderCreation',
|
||||||
|
icon: 'chrome://browser/skin/zen-icons/folder.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Copy Current URL',
|
||||||
|
command: 'cmd_zenCopyCurrentURL',
|
||||||
|
icon: 'chrome://browser/skin/zen-icons/edit-copy.svg',
|
||||||
|
suggestedIndex: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Settings',
|
||||||
|
command: (window) => window.openPreferences(),
|
||||||
|
icon: 'chrome://browser/skin/zen-icons/settings.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Open New Window',
|
||||||
|
command: 'cmd_newNavigator',
|
||||||
|
icon: 'chrome://browser/skin/zen-icons/window.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Open Private Window',
|
||||||
|
command: 'Tools:PrivateBrowsing',
|
||||||
|
icon: 'chrome://browser/skin/zen-icons/private-window.svg',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const globalActions = globalActionsTemplate.map((action) => ({
|
||||||
|
isAvailable: (window) => {
|
||||||
|
return window.document.getElementById(action.command)?.getAttribute('disabled') !== 'true';
|
||||||
|
},
|
||||||
|
extraPayload: {},
|
||||||
|
...action,
|
||||||
|
}));
|
||||||
|
Reference in New Issue
Block a user