commit b6b652290eba0431c4a0e4f2ff0ad2e8a7f64622
parent 5a79798042f2fc1839f5f4ea6c16da601d40d644
Author: Sarah Clements <sclements@mozilla.com>
Date: Mon, 24 Nov 2025 11:55:17 +0000
Bug 1998199 - Create dragAndDropElements that account for splitview containers r=nsharpley,tabbrowser-reviewers,dao
* Create new dragAndDropElements array that includes splitview container but not its children
* Replace use of ariaFocusableItems in drag and drop modules and tabbrowser.js
* Update insertTabAtIndex to prevent tabs from inserted into a splitview container
Differential Revision: https://phabricator.services.mozilla.com/D271247
Diffstat:
6 files changed, 141 insertions(+), 63 deletions(-)
diff --git a/browser/components/tabbrowser/content/drag-and-drop.js b/browser/components/tabbrowser/content/drag-and-drop.js
@@ -8,19 +8,22 @@
{
const isTab = element => gBrowser.isTab(element);
const isTabGroupLabel = element => gBrowser.isTabGroupLabel(element);
+ const isSplitViewWrapper = element => gBrowser.isSplitViewWrapper(element);
/**
- * The elements in the tab strip from `this.ariaFocusableItems` that contain
+ * The elements in the tab strip from `this.dragAndDropElements` that contain
* logical information are:
*
* - <tab> (.tabbrowser-tab)
* - <tab-group> label element (.tab-group-label)
+ * - <tab-split-view-wrapper>
*
* The elements in the tab strip that contain the space inside of the <tabs>
* element are:
*
* - <tab> (.tabbrowser-tab)
* - <tab-group> label element wrapper (.tab-group-label-container)
+ * - <tab-split-view-wrapper>
*
* When working with tab strip items, if you need logical information, you
* can get it directly, e.g. `element.elementIndex` or `element._tPos`. If
@@ -32,7 +35,7 @@
* @returns {MozTabbrowserTab|vbox}
*/
const elementToMove = element => {
- if (isTab(element)) {
+ if (isTab(element) || isSplitViewWrapper(element)) {
return element;
}
if (isTabGroupLabel(element)) {
@@ -195,7 +198,7 @@
newMargin = pixelsToScroll > 0 ? maxMargin : minMargin;
} else {
let newIndex = this._getDropIndex(event);
- let children = this._tabbrowserTabs.ariaFocusableItems;
+ let children = this._tabbrowserTabs.dragAndDropElements;
if (newIndex == children.length) {
let itemRect = children.at(-1).getBoundingClientRect();
if (this._tabbrowserTabs.verticalMode) {
@@ -270,7 +273,7 @@
let duplicatedDraggedTab;
let duplicatedTabs = [];
let dropTarget =
- this._tabbrowserTabs.ariaFocusableItems[this._getDropIndex(event)];
+ this._tabbrowserTabs.dragAndDropElements[this._getDropIndex(event)];
for (let tab of movingTabs) {
let duplicatedTab = gBrowser.duplicateTab(tab);
duplicatedTabs.push(duplicatedTab);
@@ -307,7 +310,7 @@
newTranslateY -= tabHeight;
}
} else {
- let tabs = this._tabbrowserTabs.ariaFocusableItems.slice(
+ let tabs = this._tabbrowserTabs.dragAndDropElements.slice(
isPinned ? 0 : numPinned,
isPinned ? numPinned : undefined
);
@@ -532,8 +535,8 @@
// Restore tab selection
gBrowser.addRangeToMultiSelectedTabs(
- this._tabbrowserTabs.ariaFocusableItems[dropIndex],
- this._tabbrowserTabs.ariaFocusableItems[newIndex - 1]
+ this._tabbrowserTabs.dragAndDropElements[dropIndex],
+ this._tabbrowserTabs.dragAndDropElements[newIndex - 1]
);
} else {
// Pass true to disallow dropping javascript: or data: urls
@@ -579,7 +582,7 @@
}
}
- let nextItem = this._tabbrowserTabs.ariaFocusableItems[newIndex];
+ let nextItem = this._tabbrowserTabs.dragAndDropElements[newIndex];
let tabGroup = isTab(nextItem) && nextItem.group;
gBrowser.loadTabs(urls, {
inBackground,
@@ -786,7 +789,7 @@
_getDropIndex(event) {
let item = this._getDragTarget(event);
if (!item) {
- return this._tabbrowserTabs.ariaFocusableItems.length;
+ return this._tabbrowserTabs.dragAndDropElements.length;
}
let isBeforeMiddle;
@@ -1175,7 +1178,7 @@
}
let isPinned = tab.pinned;
let numPinned = gBrowser.pinnedTabCount;
- let allTabs = this._tabbrowserTabs.ariaFocusableItems;
+ let dragAndDropElements = this._tabbrowserTabs.dragAndDropElements;
let isGrid = this._isContainerVerticalPinnedGrid(tab);
let periphery = document.getElementById(
"tabbrowser-arrowscrollbox-periphery"
@@ -1219,7 +1222,7 @@
/** @type {Map<MozTabbrowserTab, DOMRect>} */
const pinnedTabsOrigBounds = new Map();
- for (let t of allTabs) {
+ for (let t of dragAndDropElements) {
t = elementToMove(t);
let tabRect = window.windowUtils.getBoundsWithoutFlushing(t);
@@ -1387,7 +1390,7 @@
// Update tabs in the same container as the dragged tabs so as not
// to fill the space when the dragged tabs become absolute
- for (let t of allTabs) {
+ for (let t of dragAndDropElements) {
let tabIsPinned = t.pinned;
t = elementToMove(t);
if (!t.hasAttribute("dragtarget")) {
@@ -1454,7 +1457,7 @@
let addAnimationData = (movingTab, isBeforeSelectedTab) => {
let lowerIndex = Math.min(movingTab.elementIndex, draggedTabIndex) + 1;
let higherIndex = Math.max(movingTab.elementIndex, draggedTabIndex);
- let middleItems = this._tabbrowserTabs.ariaFocusableItems
+ let middleItems = this._tabbrowserTabs.dragAndDropElements
.slice(lowerIndex, higherIndex)
.filter(item => !item.multiselected);
if (!middleItems.length) {
@@ -1551,7 +1554,7 @@
}
// Slide the relevant tabs to their new position.
- for (let item of this._tabbrowserTabs.ariaFocusableItems) {
+ for (let item of this._tabbrowserTabs.dragAndDropElements) {
item = elementToMove(item);
if (item._moveTogetherSelectedTabsData?.translatePos) {
let translatePos =
@@ -1596,7 +1599,7 @@
gBrowser.moveTabAfter(selectedTabs[i], tab);
}
- for (let item of this._tabbrowserTabs.ariaFocusableItems) {
+ for (let item of this._tabbrowserTabs.dragAndDropElements) {
item = elementToMove(item);
item.style.transform = "";
item.removeAttribute("multiselected-move-together");
@@ -1835,8 +1838,8 @@
let isPinned = draggedTab.pinned;
let numPinned = gBrowser.pinnedTabCount;
- let allTabs = this._tabbrowserTabs.ariaFocusableItems;
- let tabs = allTabs.slice(
+ let dragAndDropElements = this._tabbrowserTabs.dragAndDropElements;
+ let tabs = dragAndDropElements.slice(
isPinned ? 0 : numPinned,
isPinned ? numPinned : undefined
);
@@ -2092,14 +2095,14 @@
// logically drop the dragged element(s).
//
// It's tempting to set `dropElement` to
- // `this.ariaFocusableItems.at(oldDropElementIndex)`, and that is correct
+ // `this.dragAndDropElements.at(oldDropElementIndex)`, and that is correct
// for most cases, but there are edge cases:
//
// 1) the drop element index range needs to be one larger than the number of
// items that can move in the tab strip. The simplest example is when all
// tabs are ungrouped and unpinned: for 5 tabs, the drop element index needs
// to be able to go from 0 (become the first tab) to 5 (become the last tab).
- // `this.ariaFocusableItems.at(5)` would be `undefined` when dragging to the
+ // `this.dragAndDropElements.at(5)` would be `undefined` when dragging to the
// end of the tab strip. In this specific case, it works to fall back to
// setting the drop element to the last tab.
//
@@ -2128,7 +2131,7 @@
maxElementIndexForDropElement
);
let oldDropElementCandidate =
- this._tabbrowserTabs.ariaFocusableItems.at(index);
+ this._tabbrowserTabs.dragAndDropElements.at(index);
if (!movingTabsSet.has(oldDropElementCandidate)) {
dropElement = oldDropElementCandidate;
}
@@ -2218,7 +2221,7 @@
: dropElement.elementIndex < numPinned;
if (isOutOfBounds) {
// Drop after last pinned tab
- dropElement = this._tabbrowserTabs.ariaFocusableItems[numPinned - 1];
+ dropElement = this._tabbrowserTabs.dragAndDropElements[numPinned - 1];
dropBefore = false;
}
}
@@ -2423,7 +2426,7 @@
this.#setMovingTabMode(false);
- for (let item of this._tabbrowserTabs.ariaFocusableItems) {
+ for (let item of this._tabbrowserTabs.dragAndDropElements) {
this._resetGroupTarget(item);
item = elementToMove(item);
item.style.transform = "";
diff --git a/browser/components/tabbrowser/content/tab-stacking.js b/browser/components/tabbrowser/content/tab-stacking.js
@@ -8,19 +8,21 @@
{
const isTab = element => gBrowser.isTab(element);
const isTabGroupLabel = element => gBrowser.isTabGroupLabel(element);
-
+ const isSplitViewWrapper = element => gBrowser.isSplitViewWrapper(element);
/**
- * The elements in the tab strip from `this.ariaFocusableItems` that contain
+ * The elements in the tab strip from `this.dragAndDropElements` that contain
* logical information are:
*
* - <tab> (.tabbrowser-tab)
* - <tab-group> label element (.tab-group-label)
+ * - <tab-split-view-wrapper>
*
* The elements in the tab strip that contain the space inside of the <tabs>
* element are:
*
* - <tab> (.tabbrowser-tab)
* - <tab-group> label element wrapper (.tab-group-label-container)
+ * - <tab-split-view-wrapper>
*
* When working with tab strip items, if you need logical information, you
* can get it directly, e.g. `element.elementIndex` or `element._tPos`. If
@@ -32,7 +34,7 @@
* @returns {MozTabbrowserTab|vbox}
*/
const elementToMove = element => {
- if (isTab(element)) {
+ if (isTab(element) || isSplitViewWrapper(element)) {
return element;
}
if (isTabGroupLabel(element)) {
@@ -87,7 +89,7 @@
let duplicatedDraggedTab;
let duplicatedTabs = [];
let dropTarget =
- this._tabbrowserTabs.ariaFocusableItems[this._getDropIndex(event)];
+ this._tabbrowserTabs.dragAndDropElements[this._getDropIndex(event)];
for (let tab of movingTabs) {
let duplicatedTab = gBrowser.duplicateTab(tab);
duplicatedTabs.push(duplicatedTab);
@@ -110,7 +112,7 @@
let newTranslateY = oldTranslateY - translateOffsetY;
let isPinned = draggedTab.pinned;
let numPinned = gBrowser.pinnedTabCount;
- let tabs = this._tabbrowserTabs.ariaFocusableItems.slice(
+ let tabs = this._tabbrowserTabs.dragAndDropElements.slice(
isPinned ? 0 : numPinned,
isPinned ? numPinned : undefined
);
@@ -356,8 +358,8 @@
// Restore tab selection
gBrowser.addRangeToMultiSelectedTabs(
- this._tabbrowserTabs.ariaFocusableItems[dropIndex],
- this._tabbrowserTabs.ariaFocusableItems[newIndex - 1]
+ this._tabbrowserTabs.dragAndDropElements[dropIndex],
+ this._tabbrowserTabs.dragAndDropElements[newIndex - 1]
);
} else {
// Pass true to disallow dropping javascript: or data: urls
@@ -403,7 +405,7 @@
}
}
- let nextItem = this._tabbrowserTabs.ariaFocusableItems[newIndex];
+ let nextItem = this._tabbrowserTabs.dragAndDropElements[newIndex];
let tabGroup = isTab(nextItem) && nextItem.group;
gBrowser.loadTabs(urls, {
inBackground,
@@ -419,7 +421,7 @@
})();
}
- for (let tab of this._tabbrowserTabs.ariaFocusableItems) {
+ for (let tab of this._tabbrowserTabs.dragAndDropElements) {
delete tab.currentIndex;
}
@@ -494,7 +496,7 @@
// selected tabs have moved together. These values make the math in _animateTabMove and
// _animateExpandedPinnedTabMove possible and less prone to edge cases when dragging
// multiple tabs.
- for (let unmovingTab of this._tabbrowserTabs.ariaFocusableItems) {
+ for (let unmovingTab of this._tabbrowserTabs.dragAndDropElements) {
if (unmovingTab.multiselected) {
unmovingTab.currentIndex = tab.elementIndex;
// Skip because this multiselected tab should
@@ -539,7 +541,7 @@
// translation needed for the background tab with the new index to move there.
let unmovingTabRect = unmovingTab.getBoundingClientRect();
let oldTabRect =
- this._tabbrowserTabs.ariaFocusableItems[
+ this._tabbrowserTabs.dragAndDropElements[
newIndex
].getBoundingClientRect();
unmovingTab._moveTogetherSelectedTabsData.translateX =
@@ -571,7 +573,7 @@
// Slide the relevant tabs to their new position.
// non-moving tabs adjust for RTL
- for (let item of this._tabbrowserTabs.ariaFocusableItems) {
+ for (let item of this._tabbrowserTabs.dragAndDropElements) {
if (
!tab._dragData.movingTabsSet.has(item) &&
(item._moveTogetherSelectedTabsData?.translateX ||
@@ -625,7 +627,7 @@
gBrowser.moveTabAfter(selectedTabs[i], tab);
}
- for (let item of this._tabbrowserTabs.ariaFocusableItems) {
+ for (let item of this._tabbrowserTabs.dragAndDropElements) {
delete item._moveTogetherSelectedTabsData;
item = elementToMove(item);
item.style.transform = "";
@@ -647,7 +649,7 @@
return;
}
let isPinned = tab.pinned;
- let allTabs = this._tabbrowserTabs.ariaFocusableItems;
+ let dragAndDropElements = this._tabbrowserTabs.dragAndDropElements;
let isGrid = this._isContainerVerticalPinnedGrid(tab);
let periphery = document.getElementById(
"tabbrowser-arrowscrollbox-periphery"
@@ -692,7 +694,7 @@
const tabsOrigBounds = new Map();
- for (let t of allTabs) {
+ for (let t of dragAndDropElements) {
t = elementToMove(t);
let tabRect = window.windowUtils.getBoundsWithoutFlushing(t);
@@ -818,7 +820,7 @@
// Update tabs in the same container as the dragged tabs so as not
// to fill the space when the dragged tabs become absolute
- for (let t of allTabs) {
+ for (let t of dragAndDropElements) {
let tabIsPinned = t.pinned;
t = elementToMove(t);
if (!t.hasAttribute("dragtarget")) {
@@ -869,8 +871,8 @@
let isPinned = draggedTab.pinned;
let numPinned = gBrowser.pinnedTabCount;
- let allTabs = this._tabbrowserTabs.ariaFocusableItems;
- let tabs = allTabs.slice(
+ let dragAndDropElements = this._tabbrowserTabs.dragAndDropElements;
+ let tabs = dragAndDropElements.slice(
isPinned ? 0 : numPinned,
isPinned ? numPinned : undefined
);
@@ -1127,14 +1129,14 @@
// logically drop the dragged element(s).
//
// It's tempting to set `dropElement` to
- // `this.ariaFocusableItems.at(oldDropElementIndex)`, and that is correct
+ // `this.dragAndDropElements.at(oldDropElementIndex)`, and that is correct
// for most cases, but there are edge cases:
//
// 1) the drop element index range needs to be one larger than the number of
// items that can move in the tab strip. The simplest example is when all
// tabs are ungrouped and unpinned: for 5 tabs, the drop element index needs
// to be able to go from 0 (become the first tab) to 5 (become the last tab).
- // `this.ariaFocusableItems.at(5)` would be `undefined` when dragging to the
+ // `this.dragAndDropElements.at(5)` would be `undefined` when dragging to the
// end of the tab strip. In this specific case, it works to fall back to
// setting the drop element to the last tab.
//
@@ -1163,7 +1165,7 @@
oldDropElementIndex,
maxElementIndexForDropElement
);
- let oldDropElementCandidate = this._tabbrowserTabs.ariaFocusableItems
+ let oldDropElementCandidate = this._tabbrowserTabs.dragAndDropElements
.filter(t => !movingTabsSet.has(t) || t == draggedTab)
.at(index);
if (!movingTabsSet.has(oldDropElementCandidate)) {
@@ -1258,7 +1260,7 @@
: dropElement.elementIndex < numPinned;
if (isOutOfBounds) {
// Drop after last pinned tab
- dropElement = this._tabbrowserTabs.ariaFocusableItems[numPinned - 1];
+ dropElement = this._tabbrowserTabs.dragAndDropElements[numPinned - 1];
dropBefore = false;
}
}
diff --git a/browser/components/tabbrowser/content/tab.js b/browser/components/tabbrowser/content/tab.js
@@ -153,7 +153,7 @@
throw new Error("Tab is not visible, so does not have an elementIndex");
}
// Make sure the index is up to date.
- this.container.ariaFocusableItems;
+ this.container.dragAndDropElements;
return this.#elementIndex;
}
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
@@ -3176,10 +3176,10 @@
if (elementIndex < 0) {
return -1;
}
- if (elementIndex >= this.tabContainer.ariaFocusableItems.length) {
+ if (elementIndex >= this.tabContainer.dragAndDropElements.length) {
return this.tabs.length;
}
- let element = this.tabContainer.ariaFocusableItems[elementIndex];
+ let element = this.tabContainer.dragAndDropElements[elementIndex];
if (this.isTabGroupLabel(element)) {
element = element.group.tabs[0];
}
@@ -3235,6 +3235,11 @@
return null;
}
+ this.dispatchEvent(
+ new CustomEvent("SplitViewCreated", {
+ bubbles: true,
+ })
+ );
return splitview;
}
@@ -4338,6 +4343,11 @@
previousTab.pinned
) {
elementIndex = Infinity;
+ } else if (previousTab.visible && previousTab.splitview) {
+ elementIndex =
+ this.tabContainer.dragAndDropElements.indexOf(
+ previousTab.splitview
+ ) + 1;
} else if (previousTab.visible) {
elementIndex = previousTab.elementIndex + 1;
} else if (previousTab == FirefoxViewHandler.tab) {
@@ -4359,7 +4369,7 @@
let allItems;
let index;
if (typeof elementIndex == "number") {
- allItems = this.tabContainer.ariaFocusableItems;
+ allItems = this.tabContainer.dragAndDropElements;
index = elementIndex;
} else {
allItems = this.tabs;
@@ -4378,6 +4388,8 @@
if (pinned && !itemAfter?.pinned) {
itemAfter = null;
+ } else if (itemAfter?.splitview) {
+ itemAfter = itemAfter.splitview?.nextElementSibling || null;
}
// Prevent a flash of unstyled content by setting up the tab content
// and inherited attributes before appending it (see Bug 1592054):
@@ -4386,7 +4398,10 @@
this.tabContainer._invalidateCachedTabs();
if (tabGroup) {
- if (this.isTab(itemAfter) && itemAfter.group == tabGroup) {
+ if (
+ (this.isTab(itemAfter) && itemAfter.group == tabGroup) ||
+ this.isSplitViewWrapper(itemAfter)
+ ) {
// Place at the front of, or between tabs in, the same tab group
this.tabContainer.insertBefore(tab, itemAfter);
} else {
@@ -6432,7 +6447,7 @@
* The desired position, expressed as the index within the `tabs` array.
* @param {number} [options.elementIndex]
* The desired position, expressed as the index within the
- * `MozTabbrowserTabs::ariaFocusableItems` array.
+ * `MozTabbrowserTabs::dragAndDropElements` array.
* @param {boolean} [options.forceUngrouped=false]
* Force `element` to move into position as a standalone tab, overriding
* any possibility of entering a tab group. For example, setting `true`
@@ -6870,7 +6885,7 @@
let nextElement;
if (typeof elementIndex == "number") {
index = elementIndex;
- nextElement = this.tabContainer.ariaFocusableItems.at(elementIndex);
+ nextElement = this.tabContainer.dragAndDropElements.at(elementIndex);
} else {
index = tabIndex;
nextElement = this.tabs.at(tabIndex);
diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js
@@ -13,6 +13,7 @@
const isTab = element => gBrowser.isTab(element);
const isTabGroup = element => gBrowser.isTabGroup(element);
const isTabGroupLabel = element => gBrowser.isTabGroupLabel(element);
+ const isSplitViewWrapper = element => gBrowser.isSplitViewWrapper(element);
class MozTabbrowserTabs extends MozElements.TabsBase {
static observedAttributes = ["orient"];
@@ -38,6 +39,8 @@
this.addEventListener("TabGroupAnimationComplete", this);
this.addEventListener("TabGroupCreate", this);
this.addEventListener("TabGroupRemoved", this);
+ this.addEventListener("SplitViewCreated", this);
+ this.addEventListener("SplitViewRemoved", this);
this.addEventListener("transitionend", this);
this.addEventListener("dblclick", this);
this.addEventListener("click", this);
@@ -396,6 +399,14 @@
this._invalidateCachedTabs();
}
+ on_SplitViewCreated() {
+ this._invalidateCachedTabs();
+ }
+
+ on_SplitViewRemoved() {
+ this._invalidateCachedTabs();
+ }
+
/**
* @param {TransitionEvent} event
*/
@@ -915,6 +926,9 @@
/** @type {FocusableItem[]} */
#focusableItems;
+ /** @type {dragAndDropElements[]} */
+ #dragAndDropElements;
+
/**
* @returns {FocusableItem[]}
* @override
@@ -924,36 +938,25 @@
return this.#focusableItems;
}
- let elementIndex = 0;
-
let unpinnedChildren = Array.from(this.arrowScrollbox.children);
let pinnedChildren = Array.from(this.pinnedTabsContainer.children);
let focusableItems = [];
for (let child of pinnedChildren) {
if (isTab(child)) {
- child.elementIndex = elementIndex++;
focusableItems.push(child);
}
}
for (let child of unpinnedChildren) {
if (isTab(child) && child.visible) {
- child.elementIndex = elementIndex++;
focusableItems.push(child);
} else if (isTabGroup(child)) {
- child.labelElement.elementIndex = elementIndex++;
focusableItems.push(child.labelElement);
let visibleTabsInGroup = child.tabs.filter(tab => tab.visible);
- visibleTabsInGroup.forEach(tab => {
- tab.elementIndex = elementIndex++;
- });
focusableItems.push(...visibleTabsInGroup);
} else if (child.tagName == "tab-split-view-wrapper") {
let visibleTabsInSplitView = child.tabs.filter(tab => tab.visible);
- visibleTabsInSplitView.forEach(tab => {
- tab.elementIndex = elementIndex++;
- });
focusableItems.push(...visibleTabsInSplitView);
}
}
@@ -964,6 +967,55 @@
}
/**
+ * @returns {dragAndDropElements[]}
+ * Representation of every drag and drop element including tabs, tab group labels and split view wrapper.
+ * We keep this separate from ariaFocusableItems because not every element for drag n'drop also needs to be
+ * focusable (ex, we don't want the splitview container to be focusable, only its children).
+ */
+ get dragAndDropElements() {
+ if (this.#dragAndDropElements) {
+ return this.#dragAndDropElements;
+ }
+
+ let elementIndex = 0;
+ let dragAndDropElements = [];
+ let unpinnedChildren = Array.from(this.arrowScrollbox.children);
+ let pinnedChildren = Array.from(this.pinnedTabsContainer.children);
+
+ for (let child of [...pinnedChildren, ...unpinnedChildren]) {
+ if (
+ !(
+ (isTab(child) && child.visible) ||
+ isTabGroup(child) ||
+ isSplitViewWrapper(child)
+ )
+ ) {
+ continue;
+ }
+
+ if (isTabGroup(child)) {
+ child.labelElement.elementIndex = elementIndex++;
+ dragAndDropElements.push(child.labelElement);
+
+ let visibleChildren = Array.from(child.children).filter(
+ ele => ele.visible || ele.tagName == "tab-split-view-wrapper"
+ );
+
+ visibleChildren.forEach(tab => {
+ tab.elementIndex = elementIndex++;
+ });
+ dragAndDropElements.push(...visibleChildren);
+ } else {
+ child.elementIndex = elementIndex++;
+ dragAndDropElements.push(child);
+ }
+ }
+
+ this.#dragAndDropElements = dragAndDropElements;
+ return this.#dragAndDropElements;
+ }
+
+ /**
* Moves the ARIA focus in the tab strip left or right, as appropriate, to
* the next tab or tab group label.
*
@@ -1000,8 +1052,9 @@
this.#visibleTabs = null;
// Focusable items must also be visible, but they do not depend on
// this.#visibleTabs, so changes to visible tabs need to also invalidate
- // the focusable items cache
+ // the focusable items and dragAndDropElements cache.
this.#focusableItems = null;
+ this.#dragAndDropElements = null;
}
#isMovingTab() {
diff --git a/browser/components/tabbrowser/content/tabsplitview.js b/browser/components/tabbrowser/content/tabsplitview.js
@@ -64,6 +64,11 @@
this.#tabChangeObserver?.disconnect();
this.ownerGlobal.removeEventListener("TabSelect", this);
this.#deactivate();
+ this.dispatchEvent(
+ new CustomEvent("SplitViewRemoved", {
+ bubbles: true,
+ })
+ );
}
#observeTabChanges() {