Skip to content

Commit

Permalink
fix: multirows don't work after Firefox Nightly update (closes #322)
Browse files Browse the repository at this point in the history
followup bug 1913322 - Make arrowscrollbox use resizeobserver rather than overflow/underflow events
followup bug 1914332 - Consolidate arrowscrollbox horizontal & vertical property access
followup bug 1914519 - Consolidate vertical mode and rtl checks in tab bar code
followup bug 1914831 - Allow tiny differences in our values to not trigger our overflow state
followup bug 1914798 - Track both slot and scrollbox sizes for overflow tracking
  • Loading branch information
onemen committed Aug 28, 2024
1 parent e995346 commit 21288e5
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 28 deletions.
19 changes: 19 additions & 0 deletions addon/chrome/content/minit/minit.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ var TMP_tabDNDObserver = {
return width + tab.getBoundingClientRect().width;
}, 0);
};

if (Tabmix.isVersion(1310)) {
// create none private method in gBrowser.tabContainer
// we will use instead of #rtlMode in:
// gBrowser.tabContainer._animateTabMove
// gBrowser.tabContainer.on_dragover
Object.defineProperty(gBrowser.tabContainer, "_rtlMode", {
get() {
return !this.verticalMode && RTL_UI;
},
configurable: true,
enumerable: true,
});
}

// Determine what tab we're dragging over.
// * In tabmix tabs can have different width
// * Point of reference is the start of the dragged tab/tabs when
Expand Down Expand Up @@ -91,6 +106,8 @@ var TMP_tabDNDObserver = {
)._replace(
/let lastTabCenter =.*;/,
`let lastTabCenter = firstMovingTabScreen + translate + (this.verticalMode ? tabSize / 2 : rightTabWidth / 2);`,
)._replace(
"this.#rtlMode", "this._rtlMode", {check: Tabmix.isVersion(1310), flags: "g"}
).toCode();
} else {
_animateTabMove._replace(
Expand Down Expand Up @@ -149,6 +166,8 @@ var TMP_tabDNDObserver = {
? "translateY(" + Math.round(newMargin) + "px)"
: "translate(" + Math.round(newMargin) + "px," + Math.round(newMarginY) + "px)";`,
{check: Tabmix.isVersion(1300)}
)._replace(
"this.#rtlMode", "this._rtlMode", {check: Tabmix.isVersion(1310), flags: "g"}
).toCode();

Tabmix.changeCode(tabBar, "gBrowser.tabContainer.on_drop")._replace(
Expand Down
14 changes: 7 additions & 7 deletions addon/chrome/content/overlay/multirow.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
margin-inline-end: 6px;
}

#tabmix-scrollbox:not([overflowing="true"]),
#tabmix-scrollbox:not([overflowing]),
#tabmix-scrollbox[flowing="singlebar"],
#tabmix-scrollbox[verticalTabs],
#tabmix-scrollbox[defaultScrollButtons] {
Expand Down Expand Up @@ -70,8 +70,8 @@
apply #tabbrowser-arrowscrollbox button style to our buttons
based on browser/themes/shared/toolbarbuttons.inc.css
*/
#tabmix-scrollbox[scrolledtostart=true]::part(scrollbutton-up),
#tabmix-scrollbox[scrolledtoend=true]::part(scrollbutton-down) {
#tabmix-scrollbox[scrolledtostart]::part(scrollbutton-up),
#tabmix-scrollbox[scrolledtoend]::part(scrollbutton-down) {
opacity: 0.4;
}

Expand Down Expand Up @@ -105,14 +105,14 @@
}
} */

#tabmix-scrollbox:not([scrolledtostart=true])::part(scrollbutton-up):hover,
#tabmix-scrollbox:not([scrolledtoend=true])::part(scrollbutton-down):hover {
#tabmix-scrollbox:not([scrolledtostart])::part(scrollbutton-up):hover,
#tabmix-scrollbox:not([scrolledtoend])::part(scrollbutton-down):hover {
background-color: var(--toolbarbutton-hover-background);
color: inherit;
}

#tabmix-scrollbox:not([scrolledtostart="true"])::part(scrollbutton-up):hover:active,
#tabmix-scrollbox:not([scrolledtoend="true"])::part(scrollbutton-down):hover:active {
#tabmix-scrollbox:not([scrolledtostart])::part(scrollbutton-up):hover:active,
#tabmix-scrollbox:not([scrolledtoend])::part(scrollbutton-down):hover:active {
background-color: var(--toolbarbutton-active-background, var(--toolbarbutton-hover-background));
color: inherit;
}
Expand Down
3 changes: 0 additions & 3 deletions addon/chrome/content/scripts/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -472,9 +472,6 @@ var TabmixClickEventHandler = {
// This might be middle mouse navigation, in which case pass this back:
if (ContentSvc.version(980)) {
if (!href && event.button == 1 && isFromMiddleMousePasteHandler) {
const g = docShell.domWindow.windowGlobalChild.getActor("MiddleMousePasteHandler");
console.log(g);

docShell.domWindow.windowGlobalChild.getActor("MiddleMousePasteHandler").onProcessedClick(json);
}
} else if (event.button == 1) {
Expand Down
99 changes: 82 additions & 17 deletions addon/chrome/content/tab/scrollbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ Tabmix.multiRow = {
}
this.tabmixInitialized = true;

this.blockUnderflow = false;
this._scrollButtonUpLeft = this.shadowRoot.getElementById("scrollbutton-up");
this._scrollButtonDownLeft = this.shadowRoot.getElementById("scrollbutton-down");
this.scrollboxPaddingTop = parseFloat(window.getComputedStyle(this.scrollbox).paddingTop);
Expand All @@ -43,10 +42,47 @@ Tabmix.multiRow = {
this.minOffset = 50;
this.firstVisible = {tab: null, x: 0, y: 0};

this.scrollbox.addEventListener("underflow", event => {
let overflowTarget = this.scrollbox;
if (Tabmix.isVersion(1310)) {
// eslint-disable-next-line consistent-this
overflowTarget = this;
const slot = this.shadowRoot.querySelector("slot");
// modify MozArrowScrollbox _overflowObserver to handle multi-row
const tabmixOverflowObserver1 = new ResizeObserver(_ => {
const contentSize =
slot.getBoundingClientRect()[this._verticalMode ? "height" : "width"];
// NOTE(emilio): This should be contentSize > scrollClientSize, but due
// to how Gecko internally rounds in those cases, we allow for some
// minor differences (the internal Gecko layout size is 1/60th of a
// pixel, so 0.02 should cover it).
const scrollClientSize =
this.scrollbox[this._verticalMode ? "clientHeightDouble" : "clientWidthDouble"];
const overflowing = contentSize - scrollClientSize > 0.02;
if (overflowing == this.hasAttribute("overflowing")) {
if (overflowing) {
// Update scroll buttons' disabled state when the slot or scrollbox
// size changes while we were already overflowing.
this._updateScrollButtonsDisabledState();
}
return;
}
window.requestAnimationFrame(() => {
this.toggleAttribute("overflowing", overflowing);
this._updateScrollButtonsDisabledState();
this.dispatchEvent(
new CustomEvent(overflowing ? "overflow" : "underflow")
);
});
});
tabmixOverflowObserver1.observe(slot);
tabmixOverflowObserver1.observe(this.scrollbox);
}

overflowTarget.addEventListener("underflow", event => {
// filter underflow events which were dispatched on nested scrollboxes
if (event.originalTarget !== this.scrollbox)
if (event.originalTarget !== overflowTarget) {
return;
}

// Ignore events that doesn't match our orientation.
// Scrollport event orientation:
Expand All @@ -57,8 +93,7 @@ Tabmix.multiRow = {
if (event.detail === 1) {
return;
}
} else if (event.detail === 0 && !this.isMultiRow || this.blockUnderflow) {
this.blockUnderflow = false;
} else if (event.detail === 0 && !this.isMultiRow) {
return;
}

Expand All @@ -75,10 +110,11 @@ Tabmix.multiRow = {
}
}, true);

this.scrollbox.addEventListener("overflow", event => {
overflowTarget.addEventListener("overflow", event => {
// filter overflow events which were dispatched on nested scrollboxes
if (event.originalTarget !== this.scrollbox)
if (event.originalTarget !== overflowTarget) {
return;
}

// Ignore events that doesn't match our orientation.
// Scrollport event orientation:
Expand Down Expand Up @@ -174,7 +210,7 @@ Tabmix.multiRow = {
} else $&`,
{check: !Tabmix.isVersion(1020)}
)._replace(
'if (scrolledToEnd) {',
Tabmix.isVersion(1310) ? 'this.toggleAttribute("scrolledtoend", scrolledToEnd);' : 'if (scrolledToEnd) {',
'let box = document.getElementById("tabmix-scrollbox");' + $LF +
' Tabmix.setItem(box, "scrolledtoend", scrolledToEnd || null);' + $LF +
' Tabmix.setItem(box, "scrolledtostart", scrolledToStart || null);' + $LF +
Expand All @@ -188,6 +224,15 @@ Tabmix.multiRow = {
}`
).defineProperty();

const codeToReplace = Tabmix.isVersion(1310) ? 'this.#verticalMode' : 'this.getAttribute("orient") == "vertical"';
Tabmix.changeCode(this, "scrollbox.on_touchstart")._replace(
codeToReplace, 'this._verticalMode'
).toCode();

Tabmix.changeCode(this, "scrollbox.on_touchmove")._replace(
codeToReplace, 'this._verticalMode'
).toCode();

this._scrollButtonUpLeft.addEventListener("contextmenu", this._createScrollButtonContextMenu, true);
this._scrollButtonDownLeft.addEventListener("contextmenu", this._createScrollButtonContextMenu, true);
Services.prefs.addObserver("toolkit.scrollbox.", this.tabmixPrefObserver);
Expand All @@ -199,15 +244,20 @@ Tabmix.multiRow = {
Services.prefs.removeObserver("toolkit.scrollbox.", this.tabmixPrefObserver);
}

/** @this {This} */
get _verticalMode() {
return this.isMultiRow || this.getAttribute("orient") === "vertical";
}

/** @this {This} */
get startEndProps() {
return this.isMultiRow || this.getAttribute("orient") === "vertical" ?
return this._verticalMode ?
["top", "bottom"] : ["left", "right"];
}

/** @this {This} */
get isRTLScrollbox() {
return this.isMultiRow || this.getAttribute("orient") === "vertical" ?
return this._verticalMode ?
false : Tabmix.rtl;
}

Expand All @@ -216,16 +266,30 @@ Tabmix.multiRow = {
return this.getAttribute("flowing") === "multibar";
}

/** @this {This} */
get scrollClientSize() {
if (
Tabmix.isVersion(1310) &&
this.isMultiRow &&
Tabmix.callerName().startsWith("MozArrowScrollbox/overflowObserver")
) {
// prevent MozArrowScrollbox/overflowObserver from changing overflowing state
// when we are in isMultiRow mode
return this.hasAttribute("overflowing") ? -Infinity : Infinity;
}
return this.scrollbox[this._verticalMode ? "clientHeightDouble" : "clientWidthDouble"];
}

/** @this {This} */
get scrollSize() {
return this.isMultiRow || this.getAttribute("orient") === "vertical" ?
return this._verticalMode ?
this.scrollbox.scrollHeight :
this.scrollbox.scrollWidth;
}

/** @this {This} */
get scrollPosition() {
return this.isMultiRow || this.getAttribute("orient") === "vertical" ?
return this._verticalMode ?
this.scrollbox.scrollTop :
this.scrollbox.scrollLeft;
}
Expand Down Expand Up @@ -295,7 +359,7 @@ Tabmix.multiRow = {
}

/** @this {This} */
_enterVerticalMode(blockUnderflow) {
_enterVerticalMode() {
// when widthFitTitle is false we enter vertical mode only after we are in overflow
// if first or last tab is not visible enter vertical mode
// we can get here from new tabs, window resize tabs change width
Expand Down Expand Up @@ -324,9 +388,6 @@ Tabmix.multiRow = {
if (multibar === null) {
TabmixTabbar._failedToEnterVerticalMode = true;
}
if (blockUnderflow && multibar) {
this.blockUnderflow = true;
}
this.updateOverflow(Tabmix.tabsUtils.overflow);
}
}
Expand Down Expand Up @@ -410,8 +471,12 @@ Tabmix.multiRow = {
}

Tabmix.setItem(this, "overflowing", overflow || null);

this._updateScrollButtonsDisabledState();
if (Tabmix.isVersion(1310) && !overflow) {
// we are here before tabmixOverflowObserver
this.dispatchEvent(new CustomEvent("underflow"));
}

if (!overflow) {
const childNodes = this._getScrollableElements();
if (childNodes && childNodes.length) {
Expand Down
7 changes: 7 additions & 0 deletions addon/chrome/content/tab/tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -1785,6 +1785,13 @@ window.gTMPprefObserver = {
);
}

if (Tabmix.isVersion(1310)) {
const htmlSlot = gBrowser.tabContainer.arrowScrollbox.scrollbox.firstChild;
if (htmlSlot) {
htmlSlot.style.flexWrap = "inherit";
}
}

this.dynamicProtonRules();
this.toolbarbuttonTopMargin();
this.overflowIndicator();
Expand Down
6 changes: 5 additions & 1 deletion types/general.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ interface HTMLElement {
}

interface CSSStyleDeclaration {
flexWrap: string;
height: string;
marginBottom: string;
marginLeft: string;
Expand Down Expand Up @@ -157,11 +158,13 @@ declare namespace MockedGeckoTypes {
};

_ensureElementIsVisibleAnimationFrame: number;
_overflowObserver: ResizeObserver;
_singleRowHeight: number;
_tabMarginLeft: number;
_tabMarginRight: number;
_verticalAnimation: number;
blockUnderflow: boolean;
// insteadof private getter in MozArrowScrollbox
_verticalMode: boolean;
firstTabInRowMargin: number;
firstVisible: {tab: BrowserTab; x: number; y: number};
firstVisibleRow: number;
Expand All @@ -179,6 +182,7 @@ declare namespace MockedGeckoTypes {

interface TabContainer extends Element {
_animateElement: ArrowScrollbox;
_animateTabMove: (event: MouseEvent) => void;
_backgroundTabScrollPromise?: Promise<void>;
_blockDblClick?: boolean;
_dragOverDelay: number;
Expand Down

0 comments on commit 21288e5

Please sign in to comment.