mirror of
https://github.com/zen-browser/desktop.git
synced 2025-09-06 03:18:19 +00:00
Implement drag-and-drop functionality for split view and refine CSS styles for better layout and visibility
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
diff --git a/browser/base/content/main-popupset.inc.xhtml b/browser/base/content/main-popupset.inc.xhtml
|
diff --git a/browser/base/content/main-popupset.inc.xhtml b/browser/base/content/main-popupset.inc.xhtml
|
||||||
index e5f3424eaeeec0ba552537f167dd99e912216d94..4bdfcdb23fe9c44ad3d4de273c64f4cc31cb4034 100644
|
index 959c523b21c642f29353b9de37b3ce6b5505b01b..0d151ad345dde47467432196ed76f4320b4b92cc 100644
|
||||||
--- a/browser/base/content/main-popupset.inc.xhtml
|
--- a/browser/base/content/main-popupset.inc.xhtml
|
||||||
+++ b/browser/base/content/main-popupset.inc.xhtml
|
+++ b/browser/base/content/main-popupset.inc.xhtml
|
||||||
@@ -181,6 +181,10 @@
|
@@ -206,6 +206,10 @@
|
||||||
hidden="true"
|
hidden="true"
|
||||||
tabspecific="true"
|
tabspecific="true"
|
||||||
aria-labelledby="editBookmarkPanelTitle">
|
aria-labelledby="editBookmarkPanelTitle">
|
||||||
@@ -13,7 +13,7 @@ index e5f3424eaeeec0ba552537f167dd99e912216d94..4bdfcdb23fe9c44ad3d4de273c64f4cc
|
|||||||
<box class="panel-header">
|
<box class="panel-header">
|
||||||
<html:h1>
|
<html:h1>
|
||||||
<html:span id="editBookmarkPanelTitle"/>
|
<html:span id="editBookmarkPanelTitle"/>
|
||||||
@@ -206,6 +210,7 @@
|
@@ -231,6 +235,7 @@
|
||||||
class="footer-button"/>
|
class="footer-button"/>
|
||||||
</html:moz-button-group>
|
</html:moz-button-group>
|
||||||
</vbox>
|
</vbox>
|
||||||
@@ -21,7 +21,7 @@ index e5f3424eaeeec0ba552537f167dd99e912216d94..4bdfcdb23fe9c44ad3d4de273c64f4cc
|
|||||||
</panel>
|
</panel>
|
||||||
</html:template>
|
</html:template>
|
||||||
|
|
||||||
@@ -535,6 +540,8 @@
|
@@ -565,6 +570,8 @@
|
||||||
|
|
||||||
#include popup-notifications.inc.xhtml
|
#include popup-notifications.inc.xhtml
|
||||||
|
|
||||||
|
@@ -248,3 +248,34 @@
|
|||||||
outline-color: var(--toolbarbutton-active-outline-color);
|
outline-color: var(--toolbarbutton-active-outline-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#zen-split-view-fake-browser {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: var(--zen-native-inner-radius);
|
||||||
|
box-shadow: var(--zen-big-shadow);
|
||||||
|
pointer-events: none;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 3.5rem;
|
||||||
|
height: 3.5rem;
|
||||||
|
background: var(--zen-split-view-fake-icon);
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
opacity: 0.8;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
transition-delay: 0.1s;
|
||||||
|
|
||||||
|
@starting-style {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
font-size: x-small;
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
@@ -84,6 +84,10 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
|||||||
this.initializeContextMenu();
|
this.initializeContextMenu();
|
||||||
this.insertPageActionButton();
|
this.insertPageActionButton();
|
||||||
this.insertIntoContextMenu();
|
this.insertIntoContextMenu();
|
||||||
|
|
||||||
|
// Add drag over listener to the browser view
|
||||||
|
this.tabBrowserPanel.addEventListener('dragenter', this.onBrowserDragOverToSplit.bind(this));
|
||||||
|
this.tabBrowserPanel.addEventListener('dragleave', this.onBrowserDragEndToSplit.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
insertIntoContextMenu() {
|
insertIntoContextMenu() {
|
||||||
@@ -142,6 +146,111 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBrowserDragOverToSplit(event) {
|
||||||
|
var dt = event.dataTransfer;
|
||||||
|
var draggedTab;
|
||||||
|
if (dt.mozTypesAt(0)[0] == TAB_DROP_TYPE) {
|
||||||
|
// tab copy or move
|
||||||
|
draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||||
|
// not our drop then
|
||||||
|
if (!draggedTab || gBrowser.selectedTab.hasAttribute('zen-empty-tab')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
draggedTab.container._finishMoveTogetherSelectedTabs(draggedTab);
|
||||||
|
}
|
||||||
|
if (!draggedTab || this._canDrop || this._hasAnimated || this.fakeBrowser) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentView = this._data[this.currentView];
|
||||||
|
if (currentView?.tabs.length >= this.MAX_TABS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._canDrop = true;
|
||||||
|
// wait some time before showing the split view
|
||||||
|
this._showSplitViewTimeout = setTimeout(() => {
|
||||||
|
this._hasAnimated = true;
|
||||||
|
const panelsWidth = gBrowser.tabbox.getBoundingClientRect().width;
|
||||||
|
const halfWidth = panelsWidth / 2;
|
||||||
|
this.fakeBrowser = document.createXULElement('vbox');
|
||||||
|
const padding = Services.prefs.getIntPref('zen.theme.content-element-separation', 0);
|
||||||
|
this.fakeBrowser.setAttribute('flex', '1');
|
||||||
|
this.fakeBrowser.id = 'zen-split-view-fake-browser';
|
||||||
|
gBrowser.tabbox.appendChild(this.fakeBrowser);
|
||||||
|
this.fakeBrowser.style.setProperty('--zen-split-view-fake-icon', `url(${draggedTab.getAttribute('image')})`);
|
||||||
|
Promise.all([
|
||||||
|
gZenUIManager.motion.animate(
|
||||||
|
gBrowser.tabbox,
|
||||||
|
{
|
||||||
|
paddingLeft: [0, `${halfWidth}px`],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
duration: 0.1,
|
||||||
|
easing: 'ease-out',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
gZenUIManager.motion.animate(
|
||||||
|
this.fakeBrowser,
|
||||||
|
{
|
||||||
|
width: [0, `${halfWidth - padding * 2}px`],
|
||||||
|
marginLeft: [0, `${-(halfWidth - padding)}px`],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
duration: 0.1,
|
||||||
|
easing: 'ease-out',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]).then(() => {});
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
onBrowserDragEndToSplit(event) {
|
||||||
|
if (!this._canDrop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const panelsRect = gBrowser.tabbox.getBoundingClientRect();
|
||||||
|
// this event is fired even though we are still in the "allowed" area
|
||||||
|
if (event.target !== this.tabBrowserPanel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._canDrop = false;
|
||||||
|
if (this._showSplitViewTimeout) {
|
||||||
|
clearTimeout(this._showSplitViewTimeout);
|
||||||
|
}
|
||||||
|
if (!this._hasAnimated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
const panelsWidth = panelsRect.width;
|
||||||
|
const halfWidth = panelsWidth / 2;
|
||||||
|
const padding = Services.prefs.getIntPref('zen.theme.content-element-separation', 0);
|
||||||
|
Promise.all([
|
||||||
|
gZenUIManager.motion.animate(
|
||||||
|
gBrowser.tabbox,
|
||||||
|
{
|
||||||
|
paddingLeft: [`${halfWidth}px`, 0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
duration: 0.1,
|
||||||
|
easing: 'ease-out',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
gZenUIManager.motion.animate(
|
||||||
|
this.fakeBrowser,
|
||||||
|
{
|
||||||
|
width: [`${halfWidth - padding * 2}px`, 0],
|
||||||
|
marginLeft: [`${-(halfWidth - padding)}px`, 0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
duration: 0.1,
|
||||||
|
easing: 'ease-out',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]).then(() => {
|
||||||
|
this._mayabeRemoveFakeBrowser();
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a SplitNode from its tree and the view
|
* Remove a SplitNode from its tree and the view
|
||||||
* @param {SplitNode} toRemove
|
* @param {SplitNode} toRemove
|
||||||
@@ -699,6 +808,7 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
|||||||
this.updateSplitView(tab);
|
this.updateSplitView(tab);
|
||||||
tab.linkedBrowser.docShellIsActive = true;
|
tab.linkedBrowser.docShellIsActive = true;
|
||||||
}
|
}
|
||||||
|
this._mayabeRemoveFakeBrowser();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1282,6 +1392,16 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_mayabeRemoveFakeBrowser() {
|
||||||
|
if (this.fakeBrowser) {
|
||||||
|
this.fakeBrowser.remove();
|
||||||
|
this.fakeBrowser = null;
|
||||||
|
gBrowser.tabbox.removeAttribute('style');
|
||||||
|
delete this._canDrop;
|
||||||
|
delete this._hasAnimated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description moves the tab to the split view if dragged on a browser
|
* @description moves the tab to the split view if dragged on a browser
|
||||||
* @param event - The event
|
* @param event - The event
|
||||||
@@ -1289,6 +1409,8 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
|||||||
* @returns {boolean} true if the tab was moved to the split view
|
* @returns {boolean} true if the tab was moved to the split view
|
||||||
*/
|
*/
|
||||||
moveTabToSplitView(event, draggedTab) {
|
moveTabToSplitView(event, draggedTab) {
|
||||||
|
this._mayabeRemoveFakeBrowser();
|
||||||
|
|
||||||
const dropTarget = document.elementFromPoint(event.clientX, event.clientY);
|
const dropTarget = document.elementFromPoint(event.clientX, event.clientY);
|
||||||
const browser = dropTarget?.closest('browser');
|
const browser = dropTarget?.closest('browser');
|
||||||
|
|
||||||
@@ -1336,24 +1458,22 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create new split view with layout based on drop position
|
// Create new split view with layout based on drop position
|
||||||
let gridType;
|
let gridType = 'vsep';
|
||||||
switch (hoverSide) {
|
//switch (hoverSide) {
|
||||||
case 'left':
|
// case 'left':
|
||||||
case 'right':
|
// case 'right':
|
||||||
gridType = 'vsep';
|
// gridType = 'vsep';
|
||||||
break;
|
// break;
|
||||||
case 'top':
|
// case 'top':
|
||||||
case 'bottom':
|
// case 'bottom':
|
||||||
gridType = 'hsep';
|
// gridType = 'hsep';
|
||||||
break;
|
// break;
|
||||||
default:
|
// default:
|
||||||
gridType = 'grid';
|
// gridType = 'grid';
|
||||||
}
|
//}
|
||||||
|
|
||||||
// Put tabs in correct order based on drop side
|
// Put tabs always as if it was dropped from the left
|
||||||
const tabs = ['left', 'top'].includes(hoverSide) ? [draggedTab, droppedOnTab] : [droppedOnTab, draggedTab];
|
this.splitTabs([draggedTab, droppedOnTab], gridType);
|
||||||
|
|
||||||
this.splitTabs(tabs, gridType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@@ -1140,6 +1140,7 @@ menupopup > menuitem:is([type='checkbox']) .menu-iconic-left {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#toolbar-context-toggle-vertical-tabs,
|
#toolbar-context-toggle-vertical-tabs,
|
||||||
#toolbar-context-customize-sidebar {
|
#toolbar-context-customize-sidebar,
|
||||||
display: none;
|
#sidebarRevampSeparator {
|
||||||
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user