mirror of
https://github.com/zen-browser/desktop.git
synced 2026-08-29 09:51:33 +00:00
Started working on folders implementation and better split view integration
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-urlbar.css" />
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-workspaces.css" />
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-decks.css" />
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-folders.css" />
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-glance.css" />
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-sidebar-panels.css" />
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-popup.css" />
|
||||
@@ -28,6 +29,7 @@
|
||||
</linkset>
|
||||
|
||||
# Scripts used all over the browser
|
||||
<script src="chrome://browser/content/zen-components/ZenFolders.mjs" />
|
||||
<script src="chrome://browser/content/zen-components/ZenThemesCommon.mjs" />
|
||||
<script src="chrome://browser/content/zen-components/ZenThemesImporter.mjs" />
|
||||
<script src="chrome://browser/content/zen-components/ZenCompactMode.mjs" />
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
content/browser/zen-components/ZenCommonUtils.mjs (zen-components/ZenCommonUtils.mjs)
|
||||
content/browser/zen-components/ZenGradientGenerator.mjs (zen-components/ZenGradientGenerator.mjs)
|
||||
content/browser/zen-components/ZenGlanceManager.mjs (zen-components/ZenGlanceManager.mjs)
|
||||
content/browser/zen-components/ZenFolders.mjs (zen-components/ZenFolders.mjs)
|
||||
content/browser/zen-components/ZenActorsManager.mjs (zen-components/ZenActorsManager.mjs)
|
||||
content/browser/zen-components/ZenRices.mjs (zen-components/ZenRices.mjs)
|
||||
content/browser/zen-components/ZenEmojies.mjs (zen-components/ZenEmojies.mjs)
|
||||
@@ -37,6 +38,7 @@
|
||||
content/browser/zen-styles/zen-sidebar.css (content/zen-styles/zen-sidebar.css)
|
||||
content/browser/zen-styles/zen-toolbar.css (content/zen-styles/zen-toolbar.css)
|
||||
content/browser/zen-styles/zen-decks.css (content/zen-styles/zen-decks.css)
|
||||
content/browser/zen-styles/zen-folders.css (content/zen-styles/zen-folders.css)
|
||||
content/browser/zen-styles/zen-glance.css (content/zen-styles/zen-glance.css)
|
||||
content/browser/zen-styles/zen-browser-container.css (content/zen-styles/zen-browser-container.css)
|
||||
content/browser/zen-styles/zen-workspaces.css (content/zen-styles/zen-workspaces.css)
|
||||
|
||||
@@ -85,18 +85,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes zen-deck-fadeIn {
|
||||
0% {
|
||||
transform: scale(0.9);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes better-sidebar-pinned-hide {
|
||||
0% {
|
||||
opacity: 1;
|
||||
|
||||
@@ -36,10 +36,6 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#tabbrowser-tabpanels[zen-split-view='true'] > [zen-split-anim='true'] {
|
||||
animation: zen-deck-fadeIn 0.2s forwards ease-in-out;
|
||||
}
|
||||
|
||||
#tabbrowser-tabpanels[zen-split-view='true']:not([zen-split-resizing]) > [zen-split-anim='true'] {
|
||||
transition: inset 0.09s ease-out !important;
|
||||
& browser {
|
||||
@@ -216,3 +212,46 @@
|
||||
#zenSplitViewModifier:not([has-enabled-realloc])[toast] #zenSplitViewModifierEnabledToast {
|
||||
display: revert;
|
||||
}
|
||||
|
||||
.zen-view-splitter-header {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
/*TODO: update with appropriate color*/
|
||||
background-color: var(--zen-colors-secondary);
|
||||
align-items: center;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.zen-view-splitter-drag-handle {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.zen-tab-unsplit-button {
|
||||
display: block;
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
border-radius: var(--tab-border-radius);
|
||||
/*TODO: update with appropriate color*/
|
||||
color: inherit;
|
||||
fill: currentColor;
|
||||
padding: var(--tab-close-button-padding);
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
appearance: none;
|
||||
outline: var(--toolbarbutton-outline);
|
||||
list-style-image: url('chrome://global/skin/icons/close-fill.svg') !important;
|
||||
&:hover {
|
||||
outline-color: var(--toolbarbutton-hover-outline-color);
|
||||
}
|
||||
|
||||
&:hover:active {
|
||||
outline-color: var(--toolbarbutton-active-outline-color);
|
||||
}
|
||||
}
|
||||
|
||||
108
src/browser/base/content/zen-styles/zen-folders.css
Normal file
108
src/browser/base/content/zen-styles/zen-folders.css
Normal file
@@ -0,0 +1,108 @@
|
||||
tab-group[split-view-group] {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(calc(var(--tab-pinned-min-width-expanded) + 20px), auto));
|
||||
gap: 1px;
|
||||
border-radius: var(--border-radius-medium);
|
||||
padding: 0;
|
||||
margin-inline: var(--tab-block-margin);
|
||||
margin-block: var(--tab-block-margin);
|
||||
min-height: var(--tab-min-height);
|
||||
outline: var(--tab-outline);
|
||||
outline-offset: var(--tab-outline-offset);
|
||||
outline-color: var(--tab-selected-outline-color);
|
||||
padding: 1px;
|
||||
transition: scale 0.1s ease;
|
||||
|
||||
& > * {
|
||||
--tab-min-height: 32px;
|
||||
--tab-selected-bgcolor: var(--zen-toolbar-element-bg);
|
||||
--tab-selected-shadow: none;
|
||||
--border-radius-medium: calc(2px + var(--tab-border-radius));
|
||||
--zen-active-tab-scale: 1;
|
||||
}
|
||||
|
||||
&:has(tab[visuallyselected]) {
|
||||
background-color: var(--tab-selected-bgcolor);
|
||||
box-shadow: var(--tab-selected-shadow);
|
||||
}
|
||||
|
||||
&:active {
|
||||
scale: var(--zen-active-tab-scale);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--zen-toolbar-element-bg);
|
||||
}
|
||||
|
||||
& .tab-close-button {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
tab-group[split-view-group] .tabbrowser-tab {
|
||||
width: 100%;
|
||||
max-width: unset;
|
||||
}
|
||||
|
||||
tab-group[split-view-group] .tab-group-label-container {
|
||||
display: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
tab-group[split-view-group] .tab-close-button {
|
||||
display: block;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
tab-group[split-view-group] .tab-group-line {
|
||||
display: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
tab-group:not([split-view-group]) {
|
||||
& .tab-group-label-container {
|
||||
min-width: fit-content;
|
||||
max-width: 100%;
|
||||
height: fit-content !important;
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
& .tab-group-label {
|
||||
text-align: start;
|
||||
flex-grow: 1 !important;
|
||||
min-width: fit-content;
|
||||
max-width: 100%;
|
||||
font-size: 14px !important;
|
||||
display: block !important;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
& .tab-group-line {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
&[collapsed] .tabbrowser-tab {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
&:not([collapsed]) .tabbrowser-tab {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
&:not([collapsed]) .tabbrowser-tab::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background-color: var(--tab-group-color);
|
||||
}
|
||||
}
|
||||
|
||||
.tab-group-line {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -265,7 +265,7 @@
|
||||
}
|
||||
|
||||
&:active {
|
||||
scale: 0.98;
|
||||
scale: var(--zen-active-tab-scale);
|
||||
}
|
||||
|
||||
max-width: unset;
|
||||
|
||||
@@ -172,6 +172,7 @@
|
||||
--arrowpanel-background: var(--zen-dialog-background) !important;
|
||||
|
||||
--zen-big-shadow: 0 0 9.73px 0px light-dark(rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.25));
|
||||
--zen-active-tab-scale: 0.98;
|
||||
|
||||
/* Nativity */
|
||||
--zen-native-content-radius: var(--zen-border-radius);
|
||||
|
||||
28
src/browser/base/zen-components/ZenFolders.mjs
Normal file
28
src/browser/base/zen-components/ZenFolders.mjs
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
{
|
||||
class ZenFolders {
|
||||
constructor() {
|
||||
this.#initEventListeners();
|
||||
}
|
||||
|
||||
#initEventListeners() {
|
||||
document.addEventListener('TabGrouped', this.#onTabGrouped.bind(this));
|
||||
document.addEventListener('TabUngrouped', this.#onTabUngrouped.bind(this));
|
||||
document.addEventListener('TabGroupRemoved', this.#onTabGroupRemoved.bind(this));
|
||||
}
|
||||
|
||||
#onTabGrouped(event) {
|
||||
const tab = event.target;
|
||||
const group = tab.group;
|
||||
group.pinned = tab.pinned;
|
||||
}
|
||||
|
||||
#onTabUngrouped(event) {
|
||||
}
|
||||
|
||||
#onTabGroupRemoved(event) {
|
||||
}
|
||||
}
|
||||
|
||||
window.gZenFolders = new ZenFolders();
|
||||
}
|
||||
@@ -840,7 +840,8 @@
|
||||
const pinnedTabsTarget = event.target.closest('#vertical-pinned-tabs-container');
|
||||
const essentialTabsTarget = event.target.closest('#zen-essentials-container');
|
||||
const tabsTarget = event.target.closest('#tabbrowser-arrowscrollbox');
|
||||
const targetTab = event.target.closest('.tabbrowser-tab');
|
||||
let targetTab = event.target.closest('.tabbrowser-tab');
|
||||
targetTab = targetTab?.group || targetTab;
|
||||
if (event.target.closest('.zen-current-workspace-indicator')) {
|
||||
this.removeTabContainersDragoverClass();
|
||||
ZenWorkspaces.activeWorkspaceIndicator.setAttribute('open', true);
|
||||
|
||||
@@ -120,8 +120,18 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
group.tabs.splice(tabIndex, 1);
|
||||
|
||||
this.resetTabState(tab, forUnsplit);
|
||||
|
||||
if (tab.group && tab.group.hasAttribute('split-view-group')) {
|
||||
gBrowser.ungroupTab(tab);
|
||||
}
|
||||
if (group.tabs.length < 2) {
|
||||
// We need to remove all remaining tabs from the group when unsplitting
|
||||
let remainingTabs = [...group.tabs]; // Copy array since we'll modify it
|
||||
for (let remainingTab of remainingTabs) {
|
||||
if (remainingTab.group && remainingTab.group.hasAttribute('split-view-group')) {
|
||||
gBrowser.ungroupTab(remainingTab);
|
||||
}
|
||||
this.resetTabState(remainingTab, forUnsplit);
|
||||
}
|
||||
this.removeGroup(groupIndex);
|
||||
} else {
|
||||
const node = this.getSplitNodeFromTab(tab);
|
||||
@@ -192,13 +202,14 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
|
||||
afterRearangeAction() {
|
||||
document.getElementById('zenSplitViewModifier').hidePopup();
|
||||
gZenUIManager.showToast('zen-split-view-modifier-enabled-toast', {
|
||||
ConfirmationHint.show(document.getElementById('zen-split-views-box'), 'zen-split-view-modifier-enabled-toast', {
|
||||
descriptionId: 'zen-split-view-modifier-enabled-toast-description',
|
||||
showDescription: true,
|
||||
});
|
||||
}
|
||||
|
||||
afterRearangeRemove() {
|
||||
gZenUIManager.showToast('zen-split-view-modifier-disabled-toast');
|
||||
ConfirmationHint.show(document.getElementById('zen-split-views-box'), 'zen-split-view-modifier-disabled-toast');
|
||||
}
|
||||
|
||||
toggleWrapperDisplay(value) {
|
||||
@@ -208,7 +219,7 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
wrapper.setAttribute('hidden', !value);
|
||||
}
|
||||
|
||||
enableTabRearrangeView() {
|
||||
enableTabRearrangeView(tabDrag = false) {
|
||||
if (this.rearrangeViewEnabled) return;
|
||||
this.rearrangeViewEnabled = true;
|
||||
this.rearrangeViewView = this.currentView;
|
||||
@@ -223,13 +234,19 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
b.style.pointerEvents = 'none';
|
||||
b.style.opacity = '.85';
|
||||
});
|
||||
this.tabBrowserPanel.addEventListener('dragstart', this.onBrowserDragStart);
|
||||
if (!tabDrag) {
|
||||
this.tabBrowserPanel.addEventListener('dragstart', this.onBrowserDragStart);
|
||||
this.tabBrowserPanel.addEventListener('dragend', this.onBrowserDragEnd);
|
||||
}
|
||||
|
||||
this.tabBrowserPanel.addEventListener('dragover', this.onBrowserDragOver);
|
||||
this.tabBrowserPanel.addEventListener('drop', this.onBrowserDrop);
|
||||
this.tabBrowserPanel.addEventListener('dragend', this.onBrowserDragEnd);
|
||||
|
||||
this.tabBrowserPanel.addEventListener('click', this.disableTabRearrangeView);
|
||||
window.addEventListener('keydown', this.disableTabRearrangeView);
|
||||
this.afterRearangeAction();
|
||||
if (!tabDrag) {
|
||||
this.afterRearangeAction();
|
||||
}
|
||||
}
|
||||
|
||||
disableTabRearrangeView = (event = null) => {
|
||||
@@ -257,21 +274,57 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
});
|
||||
this.rearrangeViewEnabled = false;
|
||||
this.rearrangeViewView = null;
|
||||
this.afterRearangeRemove();
|
||||
if (!event?.type === 'dragend') {
|
||||
// Don't show toast if exiting from drag
|
||||
this.afterRearangeRemove();
|
||||
}
|
||||
};
|
||||
|
||||
onBrowserDragStart = (event) => {
|
||||
if (!this.splitViewActive) return;
|
||||
let browser = event.target.querySelector('browser');
|
||||
if (!browser) {
|
||||
return;
|
||||
}
|
||||
browser.style.opacity = '.2';
|
||||
const browserContainer = browser.closest('.browserSidebarContainer');
|
||||
event.dataTransfer.setData('text/plain', browserContainer.id);
|
||||
this._draggingTab = gBrowser.getTabForBrowser(browser);
|
||||
|
||||
let dt = event.dataTransfer;
|
||||
let browser;
|
||||
let isSplitHeaderDrag = false;
|
||||
|
||||
const container = event.target.closest('.browserSidebarContainer[zen-split]');
|
||||
if (container && event.offsetY < 20) {
|
||||
// Split tab header drag case
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const clickX = event.clientX - containerRect.left;
|
||||
|
||||
// Only allow drag if click is NOT in right 20px (close button area)
|
||||
if (clickX > containerRect.width - 22) {
|
||||
return;
|
||||
}
|
||||
|
||||
browser = container.querySelector('browser');
|
||||
isSplitHeaderDrag = true;
|
||||
} else {
|
||||
// Regular browser drag case
|
||||
browser = event.target.querySelector('browser');
|
||||
}
|
||||
|
||||
if (!browser) return;
|
||||
|
||||
const tab = gBrowser.getTabForBrowser(browser);
|
||||
if (!tab) return;
|
||||
|
||||
// Store the necessary state for drag end
|
||||
this._dragState = {
|
||||
tab,
|
||||
browser,
|
||||
isSplitHeaderDrag,
|
||||
};
|
||||
|
||||
if (isSplitHeaderDrag) {
|
||||
this.enableTabRearrangeView(true);
|
||||
}
|
||||
|
||||
browser.style.opacity = '.2';
|
||||
event.dataTransfer.setData('text/plain', browser.closest('.browserSidebarContainer').id);
|
||||
this._draggingTab = tab;
|
||||
|
||||
// Canvas setup for drag image
|
||||
let scale = window.devicePixelRatio;
|
||||
let canvas = this._dndCanvas;
|
||||
if (!canvas) {
|
||||
@@ -294,8 +347,8 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
// On Windows and Mac we can update the drag image during a drag
|
||||
// using updateDragImage. On Linux, we can use a panel.
|
||||
if (platform === 'win' || platform === 'macosx') {
|
||||
captureListener = function () {
|
||||
dt.updateDragImage(canvas, dragImageOffset, dragImageOffset);
|
||||
captureListener = () => {
|
||||
event.dataTransfer.updateDragImage(canvas, dragImageOffset, dragImageOffset);
|
||||
};
|
||||
} else {
|
||||
// Create a panel to use it in setDragImage
|
||||
@@ -326,7 +379,7 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
PageThumbs.captureToCanvas(browser, canvas).catch((e) => console.error(e));
|
||||
dragImageOffset = dragImageOffset * scale;
|
||||
}
|
||||
dt.setDragImage(toDrag, dragImageOffset, dragImageOffset);
|
||||
event.dataTransfer.setDragImage(toDrag, dragImageOffset, dragImageOffset);
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -364,10 +417,28 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
};
|
||||
|
||||
onBrowserDragEnd = (event) => {
|
||||
this.dropZone.removeAttribute('enabled');
|
||||
const draggingBrowser = this._draggingTab.linkedBrowser;
|
||||
draggingBrowser.style.opacity = '.85';
|
||||
this.dropZone?.removeAttribute('enabled');
|
||||
|
||||
// If we don't have drag state, just clean up what we can
|
||||
if (!this._dragState) {
|
||||
this._draggingTab = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const { tab, browser, isSplitHeaderDrag } = this._dragState;
|
||||
|
||||
if (browser) {
|
||||
browser.style.opacity = isSplitHeaderDrag ? '1' : '.85';
|
||||
}
|
||||
|
||||
// Handle split view specific cleanup
|
||||
if (isSplitHeaderDrag) {
|
||||
this.disableTabRearrangeView(event);
|
||||
}
|
||||
|
||||
// Clear state
|
||||
this._draggingTab = null;
|
||||
this._dragState = null;
|
||||
};
|
||||
|
||||
_oppositeSide(side) {
|
||||
@@ -476,10 +547,12 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
*/
|
||||
resetTabState(tab, forUnsplit) {
|
||||
tab.splitView = false;
|
||||
tab.removeAttribute('split-view');
|
||||
tab.linkedBrowser.zenModeActive = false;
|
||||
const container = tab.linkedBrowser.closest('.browserSidebarContainer');
|
||||
this._removeHeader(container);
|
||||
this.resetContainerStyle(container);
|
||||
container.removeEventListener('click', this.handleTabEvent);
|
||||
container.removeEventListener('mousedown', this.handleTabEvent);
|
||||
container.removeEventListener('mouseover', this.handleTabEvent);
|
||||
if (!forUnsplit) {
|
||||
tab.linkedBrowser.docShellIsActive = false;
|
||||
@@ -631,7 +704,6 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
* @param {string} gridType - The type of grid layout.
|
||||
*/
|
||||
splitTabs(tabs, gridType) {
|
||||
tabs = tabs.filter((tab) => !tab.hasAttribute('zen-empty-tab'));
|
||||
if (tabs.length < 2) {
|
||||
return;
|
||||
}
|
||||
@@ -667,6 +739,16 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
};
|
||||
this._data.push(splitData);
|
||||
window.gBrowser.selectedTab = tabs[0];
|
||||
|
||||
// Add tabs to the split view group
|
||||
let splitGroup = this._getSplitViewGroup(tabs);
|
||||
if (splitGroup) {
|
||||
for (const tab of tabs) {
|
||||
if (!tab.group || tab.group !== splitGroup) {
|
||||
gBrowser.moveTabToGroup(tab, splitGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.activateSplitView(splitData);
|
||||
}
|
||||
|
||||
@@ -770,11 +852,45 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
applyGridToTabs(tabs) {
|
||||
tabs.forEach((tab, index) => {
|
||||
tab.splitView = true;
|
||||
const container = tab.linkedBrowser.closest('.browserSidebarContainer');
|
||||
tab.setAttribute('split-view', 'true');
|
||||
const container = tab.linkedBrowser.closest('.browserContainer');
|
||||
if (!container.querySelector('.zen-view-splitter-header')) {
|
||||
// insert a header into the container
|
||||
const header = this._createHeader(container);
|
||||
container.insertBefore(header, container.firstChild);
|
||||
}
|
||||
this.styleContainer(container);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a header for the tab.
|
||||
* @param container
|
||||
* @returns {*|!Element|HTMLElement|HTMLUnknownElement|HTMLDirectoryElement|HTMLFontElement|HTMLFrameElement|HTMLFrameSetElement|HTMLPreElement|HTMLMarqueeElement|HTMLParamElement}
|
||||
* @private
|
||||
*/
|
||||
_createHeader(container) {
|
||||
const header = document.createElement('div');
|
||||
header.classList.add('zen-view-splitter-header');
|
||||
const dragHandle = document.createElement('div');
|
||||
dragHandle.classList.add('zen-view-splitter-drag-handle');
|
||||
header.appendChild(dragHandle);
|
||||
const removeButton = document.createXULElement('toolbarbutton');
|
||||
removeButton.classList.add('zen-tab-unsplit-button');
|
||||
removeButton.addEventListener('click', () => {
|
||||
this.removeTabFromSplit(container);
|
||||
});
|
||||
header.appendChild(removeButton);
|
||||
return header;
|
||||
}
|
||||
|
||||
_removeHeader(container) {
|
||||
const header = container.querySelector('.zen-view-splitter-header');
|
||||
if (header) {
|
||||
header.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply grid layout to tabBrowserPanel
|
||||
*
|
||||
@@ -883,7 +999,7 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
*/
|
||||
styleContainer(container) {
|
||||
container.setAttribute('zen-split-anim', 'true');
|
||||
container.addEventListener('click', this.handleTabEvent);
|
||||
container.addEventListener('mousedown', this.handleTabEvent);
|
||||
container.addEventListener('mouseover', this.handleTabEvent);
|
||||
}
|
||||
|
||||
@@ -896,7 +1012,7 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
if (this.rearrangeViewEnabled || (event.type === 'mouseover' && !this.canChangeTabOnHover)) {
|
||||
return;
|
||||
}
|
||||
const container = event.currentTarget;
|
||||
const container = event.currentTarget.closest('.browserSidebarContainer');
|
||||
const tab = window.gBrowser.tabs.find((t) => t.linkedBrowser.closest('.browserSidebarContainer') === container);
|
||||
if (tab) {
|
||||
window.gBrowser.selectedTab = tab;
|
||||
@@ -977,9 +1093,15 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
const browser = tab.linkedBrowser.closest('.browserSidebarContainer');
|
||||
if (active) {
|
||||
browser.setAttribute('zen-split', 'true');
|
||||
|
||||
browser.addEventListener('dragstart', this.onBrowserDragStart);
|
||||
browser.addEventListener('dragend', this.onBrowserDragEnd);
|
||||
} else {
|
||||
browser.removeAttribute('zen-split');
|
||||
browser.removeAttribute('style');
|
||||
|
||||
browser.removeEventListener('dragstart', this.onBrowserDragStart);
|
||||
browser.removeEventListener('dragend', this.onBrowserDragEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1136,6 +1258,134 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
: [gBrowser.selectedTab, tabs[nextTabIndex]];
|
||||
this.splitTabs(selected_tabs, gridType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description removes the tab from the split
|
||||
* @param container - The container element
|
||||
*/
|
||||
removeTabFromSplit = (container) => {
|
||||
const browser = container.querySelector('browser');
|
||||
if (browser) {
|
||||
const tab = gBrowser.getTabForBrowser(browser);
|
||||
if (tab) {
|
||||
const groupIndex = this._data.findIndex((group) => group.tabs.includes(tab));
|
||||
if (groupIndex >= 0) {
|
||||
this.removeTabFromGroup(tab, groupIndex, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description moves the tab to the split view if dragged on a browser
|
||||
* @param event - The event
|
||||
* @param draggedTab - The dragged tab
|
||||
* @returns {boolean} true if the tab was moved to the split view
|
||||
*/
|
||||
moveTabToSplitView(event, draggedTab) {
|
||||
const dropTarget = document.elementFromPoint(event.clientX, event.clientY);
|
||||
const browser = dropTarget?.closest('browser');
|
||||
|
||||
if (!browser) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const droppedOnTab = gBrowser.getTabForBrowser(browser);
|
||||
if (droppedOnTab && droppedOnTab !== draggedTab) {
|
||||
// Calculate which side of the target browser the drop occurred
|
||||
const browserRect = browser.getBoundingClientRect();
|
||||
const hoverSide = this.calculateHoverSide(event.clientX, event.clientY, browserRect);
|
||||
|
||||
if (droppedOnTab.splitView) {
|
||||
// Add to existing split view
|
||||
const groupIndex = this._data.findIndex((group) => group.tabs.includes(droppedOnTab));
|
||||
const group = this._data[groupIndex];
|
||||
|
||||
if (!group.tabs.includes(draggedTab)) {
|
||||
// First move the tab to the split view group
|
||||
let splitGroup = droppedOnTab.group;
|
||||
if (splitGroup && (!draggedTab.group || draggedTab.group !== splitGroup)) {
|
||||
gBrowser.moveTabToGroup(draggedTab, splitGroup);
|
||||
}
|
||||
|
||||
const droppedOnSplitNode = this.getSplitNodeFromTab(droppedOnTab);
|
||||
const parentNode = droppedOnSplitNode.parent;
|
||||
|
||||
// Then add the tab to the split view
|
||||
group.tabs.push(draggedTab);
|
||||
|
||||
// If dropping on a side, create a new split in that direction
|
||||
if (hoverSide !== 'center') {
|
||||
const splitDirection = hoverSide === 'left' || hoverSide === 'right' ? 'row' : 'column';
|
||||
if (parentNode.direction !== splitDirection) {
|
||||
this.splitIntoNode(droppedOnSplitNode, new SplitLeafNode(draggedTab, 50), hoverSide, 0.5);
|
||||
} else {
|
||||
this.addTabToSplit(draggedTab, parentNode);
|
||||
}
|
||||
} else {
|
||||
this.addTabToSplit(draggedTab, group.layoutTree);
|
||||
}
|
||||
|
||||
this.activateSplitView(group, true);
|
||||
}
|
||||
} else {
|
||||
// Create new split view with layout based on drop position
|
||||
let gridType;
|
||||
switch (hoverSide) {
|
||||
case 'left':
|
||||
case 'right':
|
||||
gridType = 'vsep';
|
||||
break;
|
||||
case 'top':
|
||||
case 'bottom':
|
||||
gridType = 'hsep';
|
||||
break;
|
||||
default:
|
||||
gridType = 'grid';
|
||||
}
|
||||
|
||||
// Put tabs in correct order based on drop side
|
||||
const tabs = ['left', 'top'].includes(hoverSide) ? [draggedTab, droppedOnTab] : [droppedOnTab, draggedTab];
|
||||
|
||||
this.splitTabs(tabs, gridType);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or creates a tab group for split view tabs
|
||||
* @param {Array} tabs Initial tabs to add to the group if creating new
|
||||
* @returns {TabGroup} The tab group for split view tabs
|
||||
*/
|
||||
_getSplitViewGroup(tabs) {
|
||||
// if any of tabs is pinned, return null
|
||||
if (tabs.some((tab) => tab.pinned)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try to find an existing split view group
|
||||
let splitGroup = gBrowser.tabGroups.find(
|
||||
(group) => group.getAttribute('split-view-group') && group.tabs.some((tab) => tabs.includes(tab) && tab.splitView)
|
||||
);
|
||||
|
||||
if (splitGroup) {
|
||||
return splitGroup;
|
||||
}
|
||||
|
||||
// We can't create an empty group, so only create if we have tabs
|
||||
if (tabs?.length) {
|
||||
// Create a new group with the initial tabs
|
||||
const group = gBrowser.addTabGroup(tabs, {
|
||||
label: '',
|
||||
showCreateUI: false,
|
||||
});
|
||||
|
||||
group.setAttribute('split-view-group', true);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
window.gZenViewSplitter = new ZenViewSplitter();
|
||||
|
||||
@@ -2274,12 +2274,16 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||
const containers = [essentialsContainer, ...pinnedContainers, ...normalContainers];
|
||||
for (const container of containers) {
|
||||
for (const tab of container.children) {
|
||||
if (tab.tagName === 'tab' || tab.tagName == 'tab-group') {
|
||||
if (tab.tagName === 'tab') {
|
||||
tabs.push(tab);
|
||||
const glance = tab.querySelector('.tabbrowser-tab[glance-id]');
|
||||
if (glance) {
|
||||
tabs.push(glance);
|
||||
}
|
||||
} else if (tab.tagName == 'tab-group') {
|
||||
for (const groupTab of tab.tabs) {
|
||||
tabs.push(groupTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
diff --git a/browser/components/sessionstore/TabState.sys.mjs b/browser/components/sessionstore/TabState.sys.mjs
|
||||
index 8f7ed557e6aa61e7e16ed4a8d785ad5fe651b3d8..05dbb00375523819163bcd225074117ef02b8b37 100644
|
||||
index 8f7ed557e6aa61e7e16ed4a8d785ad5fe651b3d8..8b0781488e8f250666f1d542e3aa0cb34e018f24 100644
|
||||
--- a/browser/components/sessionstore/TabState.sys.mjs
|
||||
+++ b/browser/components/sessionstore/TabState.sys.mjs
|
||||
@@ -84,6 +84,14 @@ class _TabState {
|
||||
@@ -80,10 +80,18 @@ class _TabState {
|
||||
tabData.muteReason = tab.muteReason;
|
||||
}
|
||||
|
||||
- if (tab.group) {
|
||||
+ if (tab.group && !tab.group.hasAttribute("split-view-group")) {
|
||||
tabData.groupId = tab.group.id;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
|
||||
index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c7547437c9f 100644
|
||||
index 628aa6596627c85efe361fc1ece8fd58f7ee653e..490762fa04b9d37d8d7dee3e8dc22e220fe02955 100644
|
||||
--- a/browser/components/tabbrowser/content/tabbrowser.js
|
||||
+++ b/browser/components/tabbrowser/content/tabbrowser.js
|
||||
@@ -412,11 +412,50 @@
|
||||
@@ -194,7 +194,15 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
// Additionally send pinned tab events
|
||||
if (pinned) {
|
||||
this._notifyPinnedStatus(t);
|
||||
@@ -3367,6 +3431,24 @@
|
||||
@@ -2918,6 +2982,7 @@
|
||||
id = `${Date.now()}-${Math.round(Math.random() * 100)}`;
|
||||
}
|
||||
let group = this._createTabGroup(id, color, false, label);
|
||||
+ group.pinned = tabs.some(tab => tab.pinned);
|
||||
this.tabContainer.insertBefore(
|
||||
group,
|
||||
insertBefore?.group ?? insertBefore
|
||||
@@ -3367,6 +3432,24 @@
|
||||
) {
|
||||
tabWasReused = true;
|
||||
tab = this.selectedTab;
|
||||
@@ -219,7 +227,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
if (!tabData.pinned) {
|
||||
this.unpinTab(tab);
|
||||
} else {
|
||||
@@ -3380,6 +3462,7 @@
|
||||
@@ -3380,6 +3463,7 @@
|
||||
restoreTabsLazily && !select && !tabData.pinned;
|
||||
|
||||
let url = "about:blank";
|
||||
@@ -227,7 +235,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
if (tabData.entries?.length) {
|
||||
let activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
// Ensure the index is in bounds.
|
||||
@@ -3415,7 +3498,24 @@
|
||||
@@ -3415,7 +3499,24 @@
|
||||
skipLoad: true,
|
||||
preferredRemoteType,
|
||||
});
|
||||
@@ -253,7 +261,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
if (select) {
|
||||
tabToSelect = tab;
|
||||
}
|
||||
@@ -3428,8 +3528,8 @@
|
||||
@@ -3428,8 +3529,8 @@
|
||||
// inserted in the DOM. If the tab is not yet in the DOM,
|
||||
// just insert it in the right place from the start.
|
||||
if (!tab.parentNode) {
|
||||
@@ -264,7 +272,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
tab.toggleAttribute("pinned", true);
|
||||
this.tabContainer._invalidateCachedTabs();
|
||||
// Then ensure all the tab open/pinning information is sent.
|
||||
@@ -3693,7 +3793,7 @@
|
||||
@@ -3693,7 +3794,7 @@
|
||||
// Ensure we have an index if one was not provided.
|
||||
if (typeof index != "number") {
|
||||
// Move the new tab after another tab if needed, to the end otherwise.
|
||||
@@ -273,7 +281,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
if (
|
||||
!bulkOrderedOpen &&
|
||||
((openerTab &&
|
||||
@@ -3744,7 +3844,7 @@
|
||||
@@ -3744,7 +3845,7 @@
|
||||
}
|
||||
|
||||
/** @type {MozTabbrowserTab|undefined} */
|
||||
@@ -282,7 +290,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
this.tabContainer._invalidateCachedTabs();
|
||||
|
||||
if (tabGroup) {
|
||||
@@ -4059,6 +4159,9 @@
|
||||
@@ -4059,6 +4160,9 @@
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -292,7 +300,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
this.removeTabs(selectedTabs);
|
||||
}
|
||||
|
||||
@@ -4391,6 +4494,7 @@
|
||||
@@ -4391,6 +4495,7 @@
|
||||
skipSessionStore,
|
||||
} = {}
|
||||
) {
|
||||
@@ -300,7 +308,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
if (UserInteraction.running("browser.tabs.opening", window)) {
|
||||
UserInteraction.finish("browser.tabs.opening", window);
|
||||
}
|
||||
@@ -4407,6 +4511,12 @@
|
||||
@@ -4407,6 +4512,12 @@
|
||||
TelemetryStopwatch.start("FX_TAB_CLOSE_TIME_NO_ANIM_MS", aTab);
|
||||
}
|
||||
|
||||
@@ -313,7 +321,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
// Handle requests for synchronously removing an already
|
||||
// asynchronously closing tab.
|
||||
if (!animate && aTab.closing) {
|
||||
@@ -4421,7 +4531,9 @@
|
||||
@@ -4421,7 +4532,9 @@
|
||||
// frame created for it (for example, by updating the visually selected
|
||||
// state).
|
||||
let tabWidth = window.windowUtils.getBoundsWithoutFlushing(aTab).width;
|
||||
@@ -324,7 +332,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
if (
|
||||
!this._beginRemoveTab(aTab, {
|
||||
closeWindowFastpath: true,
|
||||
@@ -4435,7 +4547,6 @@
|
||||
@@ -4435,7 +4548,6 @@
|
||||
TelemetryStopwatch.cancel("FX_TAB_CLOSE_TIME_NO_ANIM_MS", aTab);
|
||||
return;
|
||||
}
|
||||
@@ -332,7 +340,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
let lockTabSizing =
|
||||
!this.tabContainer.verticalMode &&
|
||||
!aTab.pinned &&
|
||||
@@ -4574,14 +4685,14 @@
|
||||
@@ -4574,14 +4686,14 @@
|
||||
!!this.tabsInCollapsedTabGroups.length;
|
||||
if (
|
||||
aTab.visible &&
|
||||
@@ -349,7 +357,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
|
||||
if (closeWindow) {
|
||||
// We've already called beforeunload on all the relevant tabs if we get here,
|
||||
@@ -4605,6 +4716,7 @@
|
||||
@@ -4605,6 +4717,7 @@
|
||||
|
||||
newTab = true;
|
||||
}
|
||||
@@ -357,7 +365,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
aTab._endRemoveArgs = [closeWindow, newTab];
|
||||
|
||||
// swapBrowsersAndCloseOther will take care of closing the window without animation.
|
||||
@@ -4645,9 +4757,7 @@
|
||||
@@ -4645,9 +4758,7 @@
|
||||
aTab._mouseleave();
|
||||
|
||||
if (newTab) {
|
||||
@@ -368,7 +376,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
} else {
|
||||
TabBarVisibility.update();
|
||||
}
|
||||
@@ -4776,6 +4886,8 @@
|
||||
@@ -4776,6 +4887,8 @@
|
||||
this.tabs[i]._tPos = i;
|
||||
}
|
||||
|
||||
@@ -377,7 +385,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
if (!this._windowIsClosing) {
|
||||
if (wasPinned) {
|
||||
this.tabContainer._positionPinnedTabs();
|
||||
@@ -4994,7 +5106,7 @@
|
||||
@@ -4994,7 +5107,7 @@
|
||||
!excludeTabs.has(aTab.owner) &&
|
||||
Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")
|
||||
) {
|
||||
@@ -386,7 +394,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
}
|
||||
|
||||
// Try to find a remaining tab that comes after the given tab
|
||||
@@ -5016,7 +5128,7 @@
|
||||
@@ -5016,7 +5129,7 @@
|
||||
}
|
||||
|
||||
if (tab) {
|
||||
@@ -395,7 +403,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
}
|
||||
|
||||
// If no qualifying visible tab was found, see if there is a tab in
|
||||
@@ -5434,10 +5546,10 @@
|
||||
@@ -5434,10 +5547,10 @@
|
||||
SessionStore.deleteCustomTabValue(aTab, "hiddenBy");
|
||||
}
|
||||
|
||||
@@ -408,7 +416,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
aTab.selected ||
|
||||
aTab.closing ||
|
||||
// Tabs that are sharing the screen, microphone or camera cannot be hidden.
|
||||
@@ -5675,7 +5787,7 @@
|
||||
@@ -5675,7 +5788,7 @@
|
||||
|
||||
// Don't allow mixing pinned and unpinned tabs.
|
||||
if (aTab.pinned) {
|
||||
@@ -417,16 +425,27 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
} else {
|
||||
aIndex = Math.max(aIndex, this.pinnedTabCount);
|
||||
}
|
||||
@@ -5684,7 +5796,7 @@
|
||||
@@ -5684,8 +5797,8 @@
|
||||
}
|
||||
|
||||
this._handleTabMove(aTab, () => {
|
||||
- let neighbor = this.tabs[aIndex];
|
||||
- if (forceStandaloneTab && neighbor.group) {
|
||||
+ let neighbor = this.tabs.filter(tab => !tab.hasAttribute("zen-glance-tab"))[aIndex];
|
||||
if (forceStandaloneTab && neighbor.group) {
|
||||
+ if (forceStandaloneTab && neighbor.group || (neighbor.group && neighbor.group.hasAttribute("split-view-group"))) {
|
||||
neighbor = neighbor.group;
|
||||
}
|
||||
@@ -5721,6 +5833,8 @@
|
||||
if (neighbor && aIndex >= aTab._tPos) {
|
||||
@@ -5697,7 +5810,7 @@
|
||||
}
|
||||
|
||||
moveTabToGroup(aTab, aGroup) {
|
||||
- if (aTab.pinned) {
|
||||
+ if (aTab.pinned != !!aGroup.pinned && !aTab.hasAttribute("zen-essential")) {
|
||||
return;
|
||||
}
|
||||
if (aTab.group && aTab.group.id === aGroup.id) {
|
||||
@@ -5721,6 +5834,8 @@
|
||||
|
||||
moveActionCallback();
|
||||
|
||||
@@ -435,7 +454,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
// Clear tabs cache after moving nodes because the order of tabs may have
|
||||
// changed.
|
||||
this.tabContainer._invalidateCachedTabs();
|
||||
@@ -5771,7 +5885,7 @@
|
||||
@@ -5771,7 +5886,7 @@
|
||||
createLazyBrowser,
|
||||
};
|
||||
|
||||
@@ -444,7 +463,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
if (aIndex < numPinned || (aTab.pinned && aIndex == numPinned)) {
|
||||
params.pinned = true;
|
||||
}
|
||||
@@ -7415,6 +7529,7 @@
|
||||
@@ -7415,6 +7530,7 @@
|
||||
aWebProgress.isTopLevel
|
||||
) {
|
||||
this.mTab.setAttribute("busy", "true");
|
||||
@@ -452,7 +471,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
gBrowser._tabAttrModified(this.mTab, ["busy"]);
|
||||
this.mTab._notselectedsinceload = !this.mTab.selected;
|
||||
}
|
||||
@@ -8381,7 +8496,7 @@ var TabContextMenu = {
|
||||
@@ -8381,7 +8497,7 @@ var TabContextMenu = {
|
||||
);
|
||||
contextUnpinSelectedTabs.hidden =
|
||||
!this.contextTab.pinned || !multiselectionContext;
|
||||
@@ -461,7 +480,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
// Move Tab items
|
||||
let contextMoveTabOptions = document.getElementById(
|
||||
"context_moveTabOptions"
|
||||
@@ -8414,7 +8529,7 @@ var TabContextMenu = {
|
||||
@@ -8414,7 +8530,7 @@ var TabContextMenu = {
|
||||
let contextMoveTabToStart = document.getElementById("context_moveToStart");
|
||||
let isFirstTab =
|
||||
tabsToMove[0] == visibleTabs[0] ||
|
||||
@@ -470,7 +489,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..8bc9d9806ba6283bfa1b6b738b6c7c75
|
||||
contextMoveTabToStart.disabled = isFirstTab && allSelectedTabsAdjacent;
|
||||
|
||||
document.getElementById("context_openTabInWindow").disabled =
|
||||
@@ -8647,6 +8762,7 @@ var TabContextMenu = {
|
||||
@@ -8647,6 +8763,7 @@ var TabContextMenu = {
|
||||
if (this.contextTab.multiselected) {
|
||||
gBrowser.removeMultiSelectedTabs();
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js
|
||||
index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990d029cd67 100644
|
||||
index fa96568d366fd3608f9bd583fa793150bd815c8b..76b22ad907fe8b858300ec104af2b9b7b1d29a0e 100644
|
||||
--- a/browser/components/tabbrowser/content/tabs.js
|
||||
+++ b/browser/components/tabbrowser/content/tabs.js
|
||||
@@ -94,7 +94,7 @@
|
||||
@@ -91,7 +91,18 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
postTransitionCleanup();
|
||||
} else {
|
||||
let onTransitionEnd = transitionendEvent => {
|
||||
@@ -1285,7 +1297,8 @@
|
||||
@@ -1282,10 +1294,19 @@
|
||||
this._finishMoveTogetherSelectedTabs(draggedTab);
|
||||
this._finishAnimateTabMove();
|
||||
|
||||
+ if (event.ctrlKey && !dt.mozUserCancelled && dt.dropEffect == "none" && !this._isCustomizing) {
|
||||
+ const moved = gZenViewSplitter.moveTabToSplitView(event, draggedTab);
|
||||
+ if (moved) {
|
||||
+ delete draggedTab._dragData;
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (
|
||||
dt.mozUserCancelled ||
|
||||
dt.dropEffect != "none" ||
|
||||
@@ -101,7 +112,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
) {
|
||||
delete draggedTab._dragData;
|
||||
return;
|
||||
@@ -1517,7 +1530,7 @@
|
||||
@@ -1517,7 +1538,7 @@
|
||||
}
|
||||
|
||||
get newTabButton() {
|
||||
@@ -110,7 +121,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
}
|
||||
|
||||
get verticalMode() {
|
||||
@@ -1537,7 +1550,7 @@
|
||||
@@ -1537,7 +1558,7 @@
|
||||
if (this.#allTabs) {
|
||||
return this.#allTabs;
|
||||
}
|
||||
@@ -119,7 +130,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
// remove arrowScrollbox periphery element
|
||||
children.pop();
|
||||
|
||||
@@ -1551,14 +1564,29 @@
|
||||
@@ -1551,14 +1572,29 @@
|
||||
}
|
||||
|
||||
this.#allTabs = [
|
||||
@@ -151,7 +162,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
return children.filter(node => node.tagName == "tab-group");
|
||||
}
|
||||
|
||||
@@ -1579,7 +1607,7 @@
|
||||
@@ -1579,7 +1615,7 @@
|
||||
*/
|
||||
get visibleTabs() {
|
||||
if (!this.#visibleTabs) {
|
||||
@@ -160,7 +171,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
}
|
||||
return this.#visibleTabs;
|
||||
}
|
||||
@@ -1613,10 +1641,8 @@
|
||||
@@ -1613,10 +1649,8 @@
|
||||
return this.#focusableItems;
|
||||
}
|
||||
|
||||
@@ -173,7 +184,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
|
||||
let focusableItems = [];
|
||||
for (let child of children) {
|
||||
@@ -1632,6 +1658,7 @@
|
||||
@@ -1632,6 +1666,7 @@
|
||||
}
|
||||
|
||||
this.#focusableItems = [
|
||||
@@ -181,7 +192,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
...verticalPinnedTabsContainer.children,
|
||||
...focusableItems,
|
||||
];
|
||||
@@ -1642,6 +1669,7 @@
|
||||
@@ -1642,6 +1677,7 @@
|
||||
_invalidateCachedTabs() {
|
||||
this.#allTabs = null;
|
||||
this._invalidateCachedVisibleTabs();
|
||||
@@ -189,7 +200,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
}
|
||||
|
||||
_invalidateCachedVisibleTabs() {
|
||||
@@ -1656,8 +1684,8 @@
|
||||
@@ -1656,8 +1692,8 @@
|
||||
#isContainerVerticalPinnedExpanded(tab) {
|
||||
return (
|
||||
this.verticalMode &&
|
||||
@@ -200,7 +211,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1672,7 +1700,7 @@
|
||||
@@ -1672,7 +1708,7 @@
|
||||
|
||||
if (node == null) {
|
||||
// We have a container for non-tab elements at the end of the scrollbox.
|
||||
@@ -209,7 +220,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
}
|
||||
|
||||
node.before(tab);
|
||||
@@ -1772,7 +1800,7 @@
|
||||
@@ -1772,7 +1808,7 @@
|
||||
// There are separate "new tab" buttons for horizontal tabs toolbar, vertical tabs and
|
||||
// for when the tab strip is overflowed (which is shared by vertical and horizontal tabs);
|
||||
// Attach the long click popup to all of them.
|
||||
@@ -218,7 +229,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
const newTab2 = this.newTabButton;
|
||||
const newTabVertical = document.getElementById(
|
||||
"vertical-tabs-newtab-button"
|
||||
@@ -1855,7 +1883,7 @@
|
||||
@@ -1855,7 +1891,7 @@
|
||||
let rect = ele => {
|
||||
return window.windowUtils.getBoundsWithoutFlushing(ele);
|
||||
};
|
||||
@@ -227,7 +238,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
if (tab && rect(tab).width <= this._tabClipWidth) {
|
||||
this.setAttribute("closebuttons", "activetab");
|
||||
} else {
|
||||
@@ -1867,10 +1895,12 @@
|
||||
@@ -1867,10 +1903,12 @@
|
||||
|
||||
_handleTabSelect(aInstant) {
|
||||
let selectedTab = this.selectedItem;
|
||||
@@ -240,7 +251,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
selectedTab._notselectedsinceload = false;
|
||||
}
|
||||
|
||||
@@ -1882,7 +1912,7 @@
|
||||
@@ -1882,7 +1920,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -249,7 +260,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
if (!tabs.length) {
|
||||
return;
|
||||
}
|
||||
@@ -1918,7 +1948,7 @@
|
||||
@@ -1918,7 +1956,7 @@
|
||||
if (isEndTab && !this._hasTabTempMaxWidth) {
|
||||
return;
|
||||
}
|
||||
@@ -258,7 +269,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
// Force tabs to stay the same width, unless we're closing the last tab,
|
||||
// which case we need to let them expand just enough so that the overall
|
||||
// tabbar width is the same.
|
||||
@@ -1933,7 +1963,7 @@
|
||||
@@ -1933,7 +1971,7 @@
|
||||
let tabsToReset = [];
|
||||
for (let i = numPinned; i < tabs.length; i++) {
|
||||
let tab = tabs[i];
|
||||
@@ -267,7 +278,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
if (!isEndTab) {
|
||||
// keep tabs the same width
|
||||
tab.style.transition = "none";
|
||||
@@ -1999,16 +2029,15 @@
|
||||
@@ -1999,16 +2037,15 @@
|
||||
// Move pinned tabs to another container when the tabstrip is toggled to vertical
|
||||
// and when session restore code calls _positionPinnedTabs; update styling whenever
|
||||
// the number of pinned tabs changes.
|
||||
@@ -290,7 +301,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2016,9 +2045,7 @@
|
||||
@@ -2016,9 +2053,7 @@
|
||||
}
|
||||
|
||||
_resetVerticalPinnedTabs() {
|
||||
@@ -301,7 +312,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
|
||||
if (!verticalTabsContainer.children.length) {
|
||||
return;
|
||||
@@ -2031,8 +2058,8 @@
|
||||
@@ -2031,8 +2066,8 @@
|
||||
}
|
||||
|
||||
_positionPinnedTabs() {
|
||||
@@ -312,7 +323,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
let absPositionHorizontalTabs =
|
||||
this.overflowing && tabs.length > numPinned && numPinned > 0;
|
||||
|
||||
@@ -2042,6 +2069,7 @@
|
||||
@@ -2042,6 +2077,7 @@
|
||||
if (this.verticalMode) {
|
||||
this._updateVerticalPinnedTabs();
|
||||
} else if (absPositionHorizontalTabs) {
|
||||
@@ -320,7 +331,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
let layoutData = this._pinnedTabsLayoutCache;
|
||||
let uiDensity = document.documentElement.getAttribute("uidensity");
|
||||
if (!layoutData || layoutData.uiDensity != uiDensity) {
|
||||
@@ -2113,7 +2141,7 @@
|
||||
@@ -2113,7 +2149,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -329,7 +340,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
|
||||
let directionX = screenX > dragData.animLastScreenX;
|
||||
let directionY = screenY > dragData.animLastScreenY;
|
||||
@@ -2296,10 +2324,11 @@
|
||||
@@ -2296,10 +2332,11 @@
|
||||
}
|
||||
|
||||
let pinned = draggedTab.pinned;
|
||||
@@ -345,7 +356,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
);
|
||||
|
||||
if (this.#rtlMode) {
|
||||
@@ -2541,8 +2570,9 @@
|
||||
@@ -2541,8 +2578,9 @@
|
||||
);
|
||||
}
|
||||
|
||||
@@ -357,7 +368,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2604,7 +2634,7 @@
|
||||
@@ -2604,7 +2642,7 @@
|
||||
movingTab._moveTogetherSelectedTabsData.newIndex = movingTabNewIndex;
|
||||
movingTab._moveTogetherSelectedTabsData.animate = false;
|
||||
};
|
||||
@@ -366,7 +377,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
postTransitionCleanup();
|
||||
} else {
|
||||
let onTransitionEnd = transitionendEvent => {
|
||||
@@ -2707,9 +2737,9 @@
|
||||
@@ -2707,9 +2745,9 @@
|
||||
function newIndex(aTab, index) {
|
||||
// Don't allow mixing pinned and unpinned tabs.
|
||||
if (aTab.pinned) {
|
||||
@@ -378,7 +389,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..f92f3fba8deaebdc494a443de522e990
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2793,7 +2823,7 @@
|
||||
@@ -2793,7 +2831,7 @@
|
||||
}
|
||||
|
||||
_notifyBackgroundTab(aTab) {
|
||||
|
||||
Reference in New Issue
Block a user