mirror of
https://github.com/zen-browser/desktop.git
synced 2026-08-20 13:40:50 +00:00
feat: Implement opacity changes to the drag image, b=no-bug, c=tabs, common, split-view
This commit is contained in:
@@ -20,6 +20,9 @@
|
||||
- name: zen.tabs.close-window-with-empty
|
||||
value: true
|
||||
|
||||
- name: zen.tabs.use-legacy-drag-and-drop
|
||||
value: false
|
||||
|
||||
- name: zen.tabs.folder-dragover-threshold-percent
|
||||
value: 20 # Percentage of folder height to trigger dragover
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include ../../../zen/common/jar.inc.mn
|
||||
#include ../../../zen/compact-mode/jar.inc.mn
|
||||
#include ../../../zen/drag-and-drop/jar.inc.mn
|
||||
#include ../../../zen/split-view/jar.inc.mn
|
||||
#include ../../../zen/mods/jar.inc.mn
|
||||
#include ../../../zen/workspaces/jar.inc.mn
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/tabbrowser/content/drag-and-drop.js b/browser/components/tabbrowser/content/drag-and-drop.js
|
||||
index 97b931c3c7385a52d20204369fcf6d6999053687..b028c923d24adf0e9dbe12f80deb3ad4fda535eb 100644
|
||||
index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79edfecd9117 100644
|
||||
--- a/browser/components/tabbrowser/content/drag-and-drop.js
|
||||
+++ b/browser/components/tabbrowser/content/drag-and-drop.js
|
||||
@@ -32,6 +32,9 @@
|
||||
@@ -217,24 +217,15 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..b028c923d24adf0e9dbe12f80deb3ad4
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1173,6 +1208,16 @@
|
||||
@@ -1173,6 +1208,7 @@
|
||||
if (tabStripItemElement.hasAttribute("dragtarget")) {
|
||||
return;
|
||||
}
|
||||
+ let { movingTabs: zenMovingTabs } = tab._dragData;
|
||||
+ for (let movingTab of zenMovingTabs.slice(zenMovingTabs.findIndex(t => t._tPos == tab._tPos))) {
|
||||
+ if (isTabGroupLabel(tab)) {
|
||||
+ movingTab = movingTab.parentElement;
|
||||
+ }
|
||||
+ // "dragtarget" contains the following rules which must only be set AFTER the above
|
||||
+ // elements have been adjusted. {z-index: 3 !important, position: absolute !important}
|
||||
+ movingTab.setAttribute("zen-dragtarget", "");
|
||||
+ }
|
||||
+ return;
|
||||
let isPinned = tab.pinned;
|
||||
let numPinned = gBrowser.pinnedTabCount;
|
||||
let allTabs = this._tabbrowserTabs.ariaFocusableItems;
|
||||
@@ -1624,10 +1669,7 @@
|
||||
@@ -1624,10 +1660,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -246,7 +237,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..b028c923d24adf0e9dbe12f80deb3ad4
|
||||
|
||||
let directionX = screenX > dragData.animLastScreenX;
|
||||
let directionY = screenY > dragData.animLastScreenY;
|
||||
@@ -1636,6 +1678,8 @@
|
||||
@@ -1636,6 +1669,8 @@
|
||||
|
||||
let { width: tabWidth, height: tabHeight } =
|
||||
draggedTab.getBoundingClientRect();
|
||||
@@ -255,7 +246,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..b028c923d24adf0e9dbe12f80deb3ad4
|
||||
let shiftSizeX = tabWidth * movingTabs.length;
|
||||
let shiftSizeY = tabHeight;
|
||||
dragData.tabWidth = tabWidth;
|
||||
@@ -1672,8 +1716,8 @@
|
||||
@@ -1672,8 +1707,8 @@
|
||||
let lastBoundX =
|
||||
lastTabInRow.screenX +
|
||||
lastTabInRow.getBoundingClientRect().width -
|
||||
@@ -266,7 +257,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..b028c923d24adf0e9dbe12f80deb3ad4
|
||||
translateX = Math.min(Math.max(translateX, firstBoundX), lastBoundX);
|
||||
translateY = Math.min(Math.max(translateY, firstBoundY), lastBoundY);
|
||||
|
||||
@@ -2417,6 +2461,7 @@
|
||||
@@ -2417,6 +2452,7 @@
|
||||
}
|
||||
|
||||
finishAnimateTabMove() {
|
||||
@@ -274,7 +265,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..b028c923d24adf0e9dbe12f80deb3ad4
|
||||
if (!this.#isMovingTab()) {
|
||||
return;
|
||||
}
|
||||
@@ -2457,7 +2502,7 @@
|
||||
@@ -2457,7 +2493,7 @@
|
||||
tab.style.left = "";
|
||||
tab.style.top = "";
|
||||
tab.style.maxWidth = "";
|
||||
@@ -283,7 +274,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..b028c923d24adf0e9dbe12f80deb3ad4
|
||||
}
|
||||
for (let label of draggedTabDocument.getElementsByClassName(
|
||||
"tab-group-label-container"
|
||||
@@ -2467,7 +2512,7 @@
|
||||
@@ -2467,7 +2503,7 @@
|
||||
label.style.left = "";
|
||||
label.style.top = "";
|
||||
label.style.maxWidth = "";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js
|
||||
index 6b6c04599fe80983d13d2069ca62b99d8ad70271..009a9c398e2434b8b6704ed2c75b0f09ecc22ca1 100644
|
||||
index 6b6c04599fe80983d13d2069ca62b99d8ad70271..6d5ae983446bc778f3075d79f8ff14748dd7756f 100644
|
||||
--- a/browser/components/tabbrowser/content/tabs.js
|
||||
+++ b/browser/components/tabbrowser/content/tabs.js
|
||||
@@ -235,7 +235,7 @@
|
||||
@@ -7,7 +7,7 @@ index 6b6c04599fe80983d13d2069ca62b99d8ad70271..009a9c398e2434b8b6704ed2c75b0f09
|
||||
)
|
||||
? new window.TabStacking(this)
|
||||
- : new window.TabDragAndDrop(this);
|
||||
+ : new window.ZenDragAndDrop(this);
|
||||
+ : Services.prefs.getBoolPref("zen.tabs.use-legacy-drag-and-drop") ? new window.TabDragAndDrop(this) : new window.ZenDragAndDrop(this);
|
||||
this.tabDragAndDrop.init();
|
||||
}
|
||||
|
||||
|
||||
47
src/widget/cocoa/nsDragService-mm.patch
Normal file
47
src/widget/cocoa/nsDragService-mm.patch
Normal file
@@ -0,0 +1,47 @@
|
||||
diff --git a/widget/cocoa/nsDragService.mm b/widget/cocoa/nsDragService.mm
|
||||
index f1614b823a859ff8fbc74982f205bb1f2ef29beb..897c24846a97c132babe3ad79da12ebfcec90484 100644
|
||||
--- a/widget/cocoa/nsDragService.mm
|
||||
+++ b/widget/cocoa/nsDragService.mm
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/DocumentInlines.h"
|
||||
+#include "mozilla/nsZenDragAndDrop.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
@@ -148,6 +149,10 @@
|
||||
bitsPerPixel:32];
|
||||
|
||||
uint8_t* dest = [imageRep bitmapData];
|
||||
+ auto drag_translucency = DRAG_TRANSLUCENCY;
|
||||
+ if (auto zenDragAndDrop = zen::nsZenDragAndDrop::GetZenDragAndDropInstance()) {
|
||||
+ drag_translucency = zenDragAndDrop->GetDragImageOpacity();
|
||||
+ }
|
||||
for (uint32_t i = 0; i < height; ++i) {
|
||||
uint8_t* src = map.mData + i * map.mStride;
|
||||
for (uint32_t j = 0; j < width; ++j) {
|
||||
@@ -155,15 +160,15 @@
|
||||
// is premultipled here. Also, Quartz likes RGBA, so do that translation
|
||||
// as well.
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
- dest[0] = uint8_t(src[1] * DRAG_TRANSLUCENCY);
|
||||
- dest[1] = uint8_t(src[2] * DRAG_TRANSLUCENCY);
|
||||
- dest[2] = uint8_t(src[3] * DRAG_TRANSLUCENCY);
|
||||
- dest[3] = uint8_t(src[0] * DRAG_TRANSLUCENCY);
|
||||
+ dest[0] = uint8_t(src[1] * drag_translucency);
|
||||
+ dest[1] = uint8_t(src[2] * drag_translucency);
|
||||
+ dest[2] = uint8_t(src[3] * drag_translucency);
|
||||
+ dest[3] = uint8_t(src[0] * drag_translucency);
|
||||
#else
|
||||
- dest[0] = uint8_t(src[2] * DRAG_TRANSLUCENCY);
|
||||
- dest[1] = uint8_t(src[1] * DRAG_TRANSLUCENCY);
|
||||
- dest[2] = uint8_t(src[0] * DRAG_TRANSLUCENCY);
|
||||
- dest[3] = uint8_t(src[3] * DRAG_TRANSLUCENCY);
|
||||
+ dest[0] = uint8_t(src[2] * drag_translucency);
|
||||
+ dest[1] = uint8_t(src[1] * drag_translucency);
|
||||
+ dest[2] = uint8_t(src[0] * drag_translucency);
|
||||
+ dest[3] = uint8_t(src[3] * drag_translucency);
|
||||
#endif
|
||||
src += 4;
|
||||
dest += 4;
|
||||
@@ -13,7 +13,6 @@
|
||||
content/browser/zen-components/ZenSessionStore.mjs (../../zen/common/modules/ZenSessionStore.mjs)
|
||||
content/browser/zen-components/ZenHasPolyfill.mjs (../../zen/common/modules/ZenHasPolyfill.mjs)
|
||||
content/browser/zen-components/ZenSidebarNotification.mjs (../../zen/common/modules/ZenSidebarNotification.mjs)
|
||||
content/browser/zen-components/ZenDragAndDrop.js (../../zen/common/ZenDragAndDrop.js)
|
||||
|
||||
content/browser/zen-components/ZenEmojisData.min.mjs (../../zen/common/emojis/ZenEmojisData.min.mjs)
|
||||
content/browser/zen-components/ZenEmojiPicker.mjs (../../zen/common/emojis/ZenEmojiPicker.mjs)
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
* @returns {MozTabbrowserTab|vbox}
|
||||
*/
|
||||
const elementToMove = (element) => {
|
||||
if (element.classList.contains('zen-current-workspace-indicator')) {
|
||||
if (element.closest('.zen-current-workspace-indicator')) {
|
||||
return element;
|
||||
}
|
||||
if (element.group?.hasAttribute('split-view-group')) {
|
||||
@@ -50,17 +50,28 @@
|
||||
window.ZenDragAndDrop = class extends window.TabDragAndDrop {
|
||||
#dragOverBackground = null;
|
||||
#lastDropTarget = null;
|
||||
originalDragImageArgs = [];
|
||||
|
||||
constructor(tabbrowserTabs) {
|
||||
super(tabbrowserTabs);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
'ZenDragAndDropService',
|
||||
'@mozilla.org/zen/drag-and-drop;1',
|
||||
Ci.nsIZenDragAndDrop
|
||||
);
|
||||
}
|
||||
|
||||
startTabDrag(event, tab, ...args) {
|
||||
this.ZenDragAndDropService.onDragStart(1);
|
||||
|
||||
super.startTabDrag(event, tab, ...args);
|
||||
const dt = event.dataTransfer;
|
||||
|
||||
const { offsetX, offsetY } = this.#getDragImageOffset(event, tab);
|
||||
dt.setDragImage(tab, offsetX, offsetY);
|
||||
this.originalDragImageArgs = [tab, offsetX, offsetY];
|
||||
dt.setDragImage(...this.originalDragImageArgs);
|
||||
}
|
||||
|
||||
_animateTabMove(event) {
|
||||
@@ -460,9 +471,11 @@
|
||||
}
|
||||
|
||||
handle_dragend(event) {
|
||||
this.ZenDragAndDropService.onDragEnd();
|
||||
super.handle_dragend(event);
|
||||
this.#removeDragOverBackground();
|
||||
gZenPinnedTabManager.removeTabContainersDragoverClass();
|
||||
this.originalDragImageArgs = [];
|
||||
}
|
||||
|
||||
#applyDragOverBackground(element) {
|
||||
@@ -488,6 +501,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
clearDragOverVisuals() {
|
||||
this.#removeDragOverBackground();
|
||||
gZenPinnedTabManager.removeTabContainersDragoverClass();
|
||||
}
|
||||
|
||||
#applyDragoverIndicator(event, tabs, movingTabs) {
|
||||
const separation = 4;
|
||||
const dropZoneSelector = ':is(.tabbrowser-tab, .zen-drop-target, .tab-group-label)';
|
||||
@@ -499,8 +517,7 @@
|
||||
const numPinned = gBrowser.pinnedTabCount - numEssentials;
|
||||
const tabToUse = event.target.closest(dropZoneSelector);
|
||||
if (!tabToUse) {
|
||||
this.#removeDragOverBackground();
|
||||
gZenPinnedTabManager.removeTabContainersDragoverClass();
|
||||
this.clearDragOverVisuals();
|
||||
return;
|
||||
}
|
||||
const isPinned = tabToUse.pinned;
|
||||
@@ -509,6 +526,10 @@
|
||||
dropElement = event.clientY > draggedTabRect.top ? relativeTabs.at(-1) : relativeTabs[0];
|
||||
}
|
||||
dropElement = elementToMove(dropElement);
|
||||
if (this._isContainerVerticalPinnedGrid(dropElement)) {
|
||||
this._animateExpandedPinnedTabMove(event);
|
||||
return;
|
||||
}
|
||||
if (this.#lastDropTarget !== dropElement) {
|
||||
shouldPlayHapticFeedback = this.#lastDropTarget !== null;
|
||||
this.#removeDragOverBackground();
|
||||
@@ -522,8 +543,8 @@
|
||||
// a folder label without dragging into the folder.
|
||||
let threshold = Services.prefs.getIntPref('zen.tabs.folder-dragover-threshold-percent') / 100;
|
||||
let dropIntoFolder =
|
||||
isZenFolder && !(overlapPercent < threshold || overlapPercent > 1 - threshold);
|
||||
if (isTab(dropElement) || !dropIntoFolder) {
|
||||
isZenFolder && (overlapPercent < threshold || overlapPercent > 1 - threshold);
|
||||
if (isTab(dropElement) || dropIntoFolder) {
|
||||
const indicator = gZenPinnedTabManager.dragIndicator;
|
||||
let top = 0;
|
||||
threshold =
|
||||
14
src/zen/drag-and-drop/components.conf
Normal file
14
src/zen/drag-and-drop/components.conf
Normal file
@@ -0,0 +1,14 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# 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/.
|
||||
|
||||
Classes = [
|
||||
{
|
||||
'cid': '{f8714110-1fb1-4129-abad-887a64e4085e}',
|
||||
'interfaces': ['nsIZenDragAndDrop'],
|
||||
'contract_ids': ['@mozilla.org/zen/drag-and-drop;1'],
|
||||
'type': 'zen::nsZenDragAndDrop',
|
||||
'headers': ['mozilla/nsZenDragAndDrop.h'],
|
||||
'processes': ProcessSelector.MAIN_PROCESS_ONLY,
|
||||
},
|
||||
]
|
||||
5
src/zen/drag-and-drop/jar.inc.mn
Normal file
5
src/zen/drag-and-drop/jar.inc.mn
Normal file
@@ -0,0 +1,5 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# 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/.
|
||||
|
||||
content/browser/zen-components/ZenDragAndDrop.js (../../zen/drag-and-drop/ZenDragAndDrop.js)
|
||||
31
src/zen/drag-and-drop/moz.build
Normal file
31
src/zen/drag-and-drop/moz.build
Normal file
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# 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/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
"nsIZenDragAndDrop.idl",
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
"nsZenDragAndDrop.h",
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
"nsZenDragAndDrop.cpp",
|
||||
]
|
||||
|
||||
XPCOM_MANIFESTS += [
|
||||
"components.conf",
|
||||
]
|
||||
|
||||
include("/ipc/chromium/chromium-config.mozbuild")
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
"/dom/base",
|
||||
"/layout/base",
|
||||
"/widget",
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
XPIDL_MODULE = "zen_dnd"
|
||||
25
src/zen/drag-and-drop/nsIZenDragAndDrop.idl
Normal file
25
src/zen/drag-and-drop/nsIZenDragAndDrop.idl
Normal file
@@ -0,0 +1,25 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* @brief Interface for Zen's drag and drop functionality.
|
||||
*/
|
||||
[scriptable, uuid(f8714110-1fb1-4129-abad-887a64e4085e)]
|
||||
interface nsIZenDragAndDrop : nsISupports {
|
||||
/**
|
||||
* @brief Indicate that a drag operation has started. Note
|
||||
* that this should only be called for zen's drag and drop
|
||||
* operations for the tabs.
|
||||
* @param opacity The opacity of the drag image.
|
||||
*/
|
||||
void onDragStart(in float opacity);
|
||||
|
||||
/**
|
||||
* @brief Indicate that a drag operation has ended.
|
||||
*/
|
||||
void onDragEnd();
|
||||
};
|
||||
|
||||
48
src/zen/drag-and-drop/nsZenDragAndDrop.cpp
Normal file
48
src/zen/drag-and-drop/nsZenDragAndDrop.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
#include "nsZenDragAndDrop.h"
|
||||
#include "nsBaseDragService.h"
|
||||
|
||||
namespace zen {
|
||||
namespace {
|
||||
|
||||
static constexpr auto kZenDefaultDragImageOpacity =
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
// For GTK, the default is 0.5 (DRAG_IMAGE_ALPHA_LEVEL) to match
|
||||
// the native behavior. Make sure its synced with the following variable:
|
||||
// https://searchfox.org/firefox-main/rev/14c08f0368ead8bfdddec62f43e0bb5c8fd61289/widget/gtk/nsDragService.cpp#75
|
||||
0.5f;
|
||||
#else
|
||||
// For other platforms, the default is whatever the value of DRAG_TRANSLUCENCY
|
||||
// is, defined in nsBaseDragService.h
|
||||
DRAG_TRANSLUCENCY;
|
||||
#endif
|
||||
|
||||
} // namespace: <empty>
|
||||
|
||||
// Use the macro to inject all of the definitions for nsISupports.
|
||||
NS_IMPL_ISUPPORTS(nsZenDragAndDrop, nsIZenDragAndDrop)
|
||||
|
||||
nsZenDragAndDrop::nsZenDragAndDrop() {
|
||||
(void)this->OnDragEnd();
|
||||
}
|
||||
|
||||
auto nsZenDragAndDrop::GetZenDragAndDropInstance() -> nsCOMPtr<nsZenDragAndDrop> {
|
||||
return do_GetService(ZEN_BOOSTS_BACKEND_CONTRACTID);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsZenDragAndDrop::OnDragStart(float opacity) {
|
||||
mDragImageOpacity = opacity;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsZenDragAndDrop::OnDragEnd() {
|
||||
mDragImageOpacity = kZenDefaultDragImageOpacity;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace: zen
|
||||
45
src/zen/drag-and-drop/nsZenDragAndDrop.h
Normal file
45
src/zen/drag-and-drop/nsZenDragAndDrop.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
#ifndef mozilla_ZenDragAndDrop_h__
|
||||
#define mozilla_ZenDragAndDrop_h__
|
||||
|
||||
#include "nsIZenDragAndDrop.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#define ZEN_BOOSTS_BACKEND_CONTRACTID "@mozilla.org/zen/drag-and-drop;1"
|
||||
|
||||
namespace zen {
|
||||
|
||||
/**
|
||||
* @brief Implementation of the nsIZenDragAndDrop interface.
|
||||
* When we want to do a drag and drop operation, web standards
|
||||
* don't really allow much customization of the drag image.
|
||||
* This class allows Zen to have more control over the drag
|
||||
* and drop operations for the tabs.
|
||||
*/
|
||||
class nsZenDragAndDrop final : public nsIZenDragAndDrop {
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIZENDRAGANDDROP
|
||||
|
||||
public:
|
||||
explicit nsZenDragAndDrop();
|
||||
auto GetDragImageOpacity() const { return mDragImageOpacity; }
|
||||
|
||||
/**
|
||||
* @brief Get the singleton instance of nsZenDragAndDrop. There may be occasions
|
||||
* where it won't be available (e.g. on the content process), so this may return
|
||||
* nullptr.
|
||||
* @return nsZenDragAndDrop* The singleton instance, or nullptr if not available
|
||||
*/
|
||||
static auto GetZenDragAndDropInstance() -> nsCOMPtr<nsZenDragAndDrop>;
|
||||
|
||||
private:
|
||||
~nsZenDragAndDrop() = default;
|
||||
float mDragImageOpacity{};
|
||||
};
|
||||
|
||||
} // namespace zen
|
||||
|
||||
#endif
|
||||
@@ -8,6 +8,7 @@ EXTRA_PP_COMPONENTS += [
|
||||
|
||||
DIRS += [
|
||||
"common",
|
||||
"drag-and-drop",
|
||||
"glance",
|
||||
"mods",
|
||||
"tests",
|
||||
|
||||
@@ -228,6 +228,24 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
||||
}
|
||||
}
|
||||
|
||||
#getDragImageForSplit(tab) {
|
||||
const element = window.MozXULElement.parseXULToFragment(
|
||||
`
|
||||
<vbox id="zen-split-view-drag-image">
|
||||
<image />
|
||||
<label />
|
||||
</vbox>
|
||||
`
|
||||
).querySelector('#zen-split-view-drag-image');
|
||||
const image = element.querySelector('image');
|
||||
const label = element.querySelector('label');
|
||||
image.src = tab.getAttribute('image');
|
||||
label.textContent = tab.label;
|
||||
document.documentElement.appendChild(element);
|
||||
this._dndElement = element;
|
||||
return element;
|
||||
}
|
||||
|
||||
onBrowserDragOverToSplit(event) {
|
||||
if (this.fakeBrowser) {
|
||||
this.onBrowserDragEndToSplit(event);
|
||||
@@ -285,6 +303,17 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
||||
return;
|
||||
}
|
||||
dt.mozCursor = 'default';
|
||||
if (!this._dndElement) {
|
||||
const originalDNDArgs = gBrowser.tabContainer.tabDragAndDrop.originalDragImageArgs;
|
||||
requestAnimationFrame(() => {
|
||||
dt.updateDragImage(
|
||||
this.#getDragImageForSplit(draggedTab),
|
||||
originalDNDArgs[1],
|
||||
originalDNDArgs[2]
|
||||
);
|
||||
});
|
||||
gBrowser.tabContainer.tabDragAndDrop.clearDragOverVisuals();
|
||||
}
|
||||
const oldTab = this._lastOpenedTab;
|
||||
this._canDrop = true;
|
||||
{
|
||||
@@ -330,11 +359,6 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
||||
this.fakeBrowser.setAttribute('has-split-view', 'true');
|
||||
}
|
||||
gBrowser.tabbox.appendChild(this.fakeBrowser);
|
||||
this.fakeBrowser.style.setProperty(
|
||||
'--zen-split-view-fake-icon',
|
||||
`url(${draggedTab.getAttribute('image')})`
|
||||
);
|
||||
draggedTab._visuallySelected = true;
|
||||
this.fakeBrowser.setAttribute('side', side);
|
||||
this._finishAllAnimatingPromise = Promise.all([
|
||||
gZenUIManager.motion.animate(
|
||||
@@ -377,7 +401,6 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
||||
.classList.remove('deck-selected');
|
||||
this.fakeBrowser.addEventListener('dragleave', this.onBrowserDragEndToSplit);
|
||||
this._canDrop = true;
|
||||
draggedTab._visuallySelected = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -390,12 +413,11 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
||||
const panelsRect = gBrowser.tabbox.getBoundingClientRect();
|
||||
const fakeBrowserRect = this.fakeBrowser && this.fakeBrowser.getBoundingClientRect();
|
||||
if (
|
||||
((event.target.closest('#tabbrowser-tabbox') && event.target != this.fakeBrowser) ||
|
||||
(fakeBrowserRect &&
|
||||
event.clientX > fakeBrowserRect.left &&
|
||||
event.clientX < fakeBrowserRect.left + fakeBrowserRect.width &&
|
||||
event.clientY > fakeBrowserRect.top &&
|
||||
event.clientY < fakeBrowserRect.top + fakeBrowserRect.height) ||
|
||||
((fakeBrowserRect &&
|
||||
event.clientX > fakeBrowserRect.left &&
|
||||
event.clientX < fakeBrowserRect.left + fakeBrowserRect.width &&
|
||||
event.clientY > fakeBrowserRect.top &&
|
||||
event.clientY < fakeBrowserRect.top + fakeBrowserRect.height) ||
|
||||
(event.screenX === 0 && event.screenY === 0)) && // It's equivalent to 0 if the event has been dropped
|
||||
!cancelled
|
||||
) {
|
||||
@@ -415,50 +437,47 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
||||
if (!this.fakeBrowser) {
|
||||
return;
|
||||
}
|
||||
this.fakeBrowser.classList.add('fade-out');
|
||||
const side = this.fakeBrowser.getAttribute('side');
|
||||
if (this._draggingTab) this._draggingTab.setAttribute('zen-has-splitted', 'true');
|
||||
this._lastOpenedTab = gBrowser.selectedTab;
|
||||
this._draggingTab = null;
|
||||
try {
|
||||
this._canDrop = false;
|
||||
Promise.all([
|
||||
gZenUIManager.motion.animate(
|
||||
gBrowser.tabbox,
|
||||
side === 'left'
|
||||
event.dataTransfer.updateDragImage(
|
||||
...gBrowser.tabContainer.tabDragAndDrop.originalDragImageArgs
|
||||
);
|
||||
this._canDrop = false;
|
||||
Promise.all([
|
||||
gZenUIManager.motion.animate(
|
||||
gBrowser.tabbox,
|
||||
side === 'left'
|
||||
? {
|
||||
paddingLeft: [`${halfWidth}px`, 0],
|
||||
}
|
||||
: {
|
||||
paddingRight: [`${halfWidth}px`, 0],
|
||||
},
|
||||
{
|
||||
duration: 0.1,
|
||||
easing: 'ease-out',
|
||||
}
|
||||
),
|
||||
gZenUIManager.motion.animate(
|
||||
this.fakeBrowser,
|
||||
{
|
||||
width: [`${halfWidth - padding * 2}px`, 0],
|
||||
...(side === 'left'
|
||||
? {
|
||||
paddingLeft: [`${halfWidth}px`, 0],
|
||||
marginLeft: [`${-halfWidth}px`, 0],
|
||||
}
|
||||
: {
|
||||
paddingRight: [`${halfWidth}px`, 0],
|
||||
},
|
||||
{
|
||||
duration: 0.1,
|
||||
easing: 'ease-out',
|
||||
}
|
||||
),
|
||||
gZenUIManager.motion.animate(
|
||||
this.fakeBrowser,
|
||||
{
|
||||
width: [`${halfWidth - padding * 2}px`, 0],
|
||||
...(side === 'left'
|
||||
? {
|
||||
marginLeft: [`${-halfWidth}px`, 0],
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
{
|
||||
duration: 0.1,
|
||||
easing: 'ease-out',
|
||||
}
|
||||
),
|
||||
]).then(() => {
|
||||
this._maybeRemoveFakeBrowser();
|
||||
});
|
||||
} catch {
|
||||
this._canDrop = false;
|
||||
: {}),
|
||||
},
|
||||
{
|
||||
duration: 0.1,
|
||||
easing: 'ease-out',
|
||||
}
|
||||
),
|
||||
]).finally(() => {
|
||||
this._maybeRemoveFakeBrowser();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1659,11 +1678,14 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
||||
_maybeRemoveFakeBrowser(select = true) {
|
||||
gBrowser.tabbox.removeAttribute('style');
|
||||
this.tabBrowserPanel.removeAttribute('dragging-split');
|
||||
if (this._dndElement) {
|
||||
this._dndElement.remove();
|
||||
delete this._dndElement;
|
||||
}
|
||||
if (this.fakeBrowser) {
|
||||
delete this._hasAnimated;
|
||||
this.fakeBrowser.remove();
|
||||
this.fakeBrowser = null;
|
||||
if (this._draggingTab) this._draggingTab._visuallySelected = false;
|
||||
if (select) {
|
||||
gBrowser.selectedTab = this._draggingTab;
|
||||
this._draggingTab = null;
|
||||
|
||||
@@ -210,31 +210,28 @@
|
||||
right: var(--zen-element-separation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 3.5rem;
|
||||
pointer-events: none;
|
||||
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;
|
||||
#zen-split-view-drag-image {
|
||||
width: 200px;
|
||||
height: 250px;
|
||||
border-radius: 16px;
|
||||
background: black;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
gap: 20px;
|
||||
position: relative;
|
||||
|
||||
@starting-style {
|
||||
opacity: 0;
|
||||
}
|
||||
& image {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
&.fade-out::after {
|
||||
opacity: 0;
|
||||
transition-delay: 0s;
|
||||
& label {
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1366,11 +1366,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.tabbrowser-tab[zen-dragtarget],
|
||||
.tab-group-label-container[zen-dragtarget] {
|
||||
z-index: 9 !important;
|
||||
}
|
||||
|
||||
#zen-dragover-background {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
|
||||
Reference in New Issue
Block a user