FuchsFan Version 152.0beta2. Im MultiRowTabs-Skript werden die Ziehpunkte (Punkt oder Emoji) nicht mehr angezeigt (per JS und CSS). Drag & Drop funktioniert weiterhin. Lässt sich das beheben?
Vielen Dank.
Mehrzeilige Tableiste für aktuelle Firefox-Versionen
-
BrokenHeart -
8. Dezember 2019 um 01:19 -
Erledigt
-
-
Version 152.0beta2. Im MultiRowTabs-Skript werden die Ziehpunkte (Punkt oder Emoji) nicht mehr angezeigt
Das Problem wurde gelöst, indem im Skript alle Vorkommen von ownerGlobal durch documentGlobal ersetzt wurden.
Vielen Dank für das wunderbare Script
-
Das Problem wurde gelöst, indem im Skript alle Vorkommen von ownerGlobal durch documentGlobal ersetzt wurden.
Sehr schön, das werde ich auch gleich mal ändern. Im Moment ist das ab 152 die erste Anlaufstelle, in der Regel funktioniert es. Danke!

-
Das Script wurde überarbeitet, alle Vorkommen von ownerGlobal durch documentGlobal ersetzt, damit es ab Version 152 wieder funktioniert.
JavaScript
Alles anzeigen// 'MultiRowTabs@BuF.uc.js' – Logik-Version mit MultiRow + DnD + Emoji-Marker // Styling (Farben, Tabhöhe, Breite, max. Zeilen) in userChrome.css "use strict"; MultiRowTabs(); function MultiRowTabs() { if (!window.gBrowser) { return; } // ---------------------------- // --- User-Settings: Start --- // ---------------------------- // Position der Tab-Leiste: // // [1] Tab-Leiste ist oberhalb aller Symbolleisten // [2] Tab-Leiste ist unterhalb aller Symbolleisten, aber über dem Inhaltsbereich // [6] Tab-Leiste ist unterhalb des Inhaltsbereichs var nTabbarPosition = 2; // MultiRow-Einstellungen (nur horizontale Positionen [1], [2], [6]) // Die tatsächliche Zeilenanzahl wird ausschließlich über CSS (max-height) begrenzt. var nTabLines = 3; // Dokumentationswert; in userChrome.css via max-height nachziehen var bTabScrollbar = true; // Scrollbar für Tab-Leiste anzeigen var bTabTooltips = false; // Tab-Tooltips (Tabvorschau) anzeigen? // Einstellungen für Maus-Bedienung var bTabWheel = false; // Tab per Mausrad wechseln var bPageScroll = true; // seitenweises Scrollen (statt zeilenweise) var bDblclickOnTabbarNewTab = true; // Doppelklick auf freie Tabbar -> neuer Tab var bDblclickOnTabReloadTab = true; // Doppelklick auf Tab -> Reload // ---------------------------- // --- User-Settings: Ende --- // ---------------------------- let strHomepageURL; try { strHomepageURL = Services.prefs.getCharPref("browser.startup.homepage"); } catch (e) { console.log("Error Homepage-String loading..."); } if (nTabbarPosition < 1 || (nTabbarPosition != 1 && nTabbarPosition != 2 && nTabbarPosition != 6)) { nTabbarPosition = 1; } // Tab-Leiste ganz unten if (nTabbarPosition == 6) { let tabbarBoxBottom = document.createXULElement("vbox"); tabbarBoxBottom.id = "tabbarboxbottom"; document .getElementById("navigator-toolbox") .parentNode.insertBefore(tabbarBoxBottom, null); let tabbar = document.getElementById("TabsToolbar"); tabbarBoxBottom.appendChild(tabbar); } // ------------------------------------------------------------- // Grund-CSS für Slot-Layout & Scrollbar (keine Farben!) // ------------------------------------------------------------- { let cssAgent = ` /* Scrollbars in der Tabbar sollen nicht als Fenster-Drag-Bereich dienen */ scrollbar, scrollcorner, scrollbar thumb, scrollbar scrollbarbutton { -moz-window-dragging: no-drag !important; } /* Slot-Inhalt (Tabs) direkt in den Flex-Container holen */ scrollbox[smoothscroll="true"] > slot { display: contents !important; } `; let sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService( Ci.nsIStyleSheetService ); let uriAgent = makeURI( "data:text/css;charset=UTF=8," + encodeURIComponent(cssAgent) ); if (!sss.sheetRegistered(uriAgent, sss.AGENT_SHEET)) { sss.loadAndRegisterSheet(uriAgent, sss.AGENT_SHEET); } } { // MultiRow-Layout: Wrap, keine Pfeile, „Alle Tabs“-Button entfernen let cssAuthor = ` #tabbrowser-tabs { --tab-overflow-pinned-tabs-width: 0px !important; } #alltabs-button, hbox.titlebar-spacer, #tabbrowser-arrowscrollbox::part(scrollbutton-up), #tabbrowser-arrowscrollbox::part(scrollbutton-down), #tabbrowser-arrowscrollbox::part(overflow-start-indicator), #tabbrowser-arrowscrollbox::part(overflow-end-indicator) { display: none !important; } tabs > arrowscrollbox::part(scrollbox) { flex-wrap: wrap !important; overflow-x: hidden !important; overflow-y: ${bTabScrollbar ? "auto" : "hidden"} !important; } `; let sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService( Ci.nsIStyleSheetService ); let uriAuthor = makeURI( "data:text/css;charset=UTF=8," + encodeURIComponent(cssAuthor) ); if (!sss.sheetRegistered(uriAuthor, sss.AUTHOR_SHEET)) { sss.loadAndRegisterSheet(uriAuthor, sss.AUTHOR_SHEET); } } // Tab-Leiste unterhalb der Symbolleisten (Position 2) if (nTabbarPosition == 2) { let tabbar = document.getElementById("TabsToolbar"); tabbar.parentNode.appendChild(tabbar); } //------------------------------------------------------------------------------------------ var tabsToolbar = document.getElementById("TabsToolbar"); var tabsscrollbox = document.getElementById("tabbrowser-arrowscrollbox"); var ScrollBox = tabsscrollbox.scrollbox; // ---------------------------------- // Load-Event: MultiRow aktivieren (keine Höhenberechnung mehr) // ---------------------------------- function onReady() { console.log("MultiRowTabs OnReady"); // Auswahl sichtbar halten gBrowser.selectedTab.scrollIntoView(); } if (document.readyState !== "loading") { setTimeout(onReady, 500); } else { window.addEventListener("DOMContentLoaded", onReady); } // ---------------------------------- // ToggleMenuObserver (Menüleiste ein/aus) – nur für Position 2/6 // ---------------------------------- if (nTabbarPosition == 2 || nTabbarPosition == 6) { let targetMenubar = document.getElementById("toolbar-menubar"); let titlebar = document.querySelector("#navigator-toolbox>vbox#titlebar"); const callback = (mutationList, observer) => { for (const mutation of mutationList) { if (mutation.type === "attributes") { let bInactive = targetMenubar.getAttribute("inactive"); if (bInactive == "true") { titlebar.style.display = "none"; } else { titlebar.style.display = "initial"; } } } }; let observerToggleMenu = new MutationObserver(callback); let configObserver = { attributes: true, attributeFilter: ["autohide","inactive"] }; observerToggleMenu.observe(targetMenubar, configObserver); } // ---------------------------------- // Middleclick auf Tab -> Close Tab // ---------------------------------- gBrowser.tabContainer.addEventListener( "click", function(event) { if (event.button == 1) { let element = event.target.parentNode; while (element) { if (element.localName == "tab") { gBrowser.removeTab(element, { animate: false }); event.preventDefault(); event.stopPropagation(); return; } element = element.parentNode; } } }, true ); // ---------------------------------- // Middleclick auf TabsToolbar -> New Tab // ---------------------------------- tabsToolbar.addEventListener( "click", function(event) { if (event.button == 1) { if (event.target.parentNode.id == "TabsToolbar") { if (strHomepageURL) { event.target.documentGlobal.openTrustedLinkIn(strHomepageURL,"tab"); } else { BrowserOpenTab(); } return; } } }, true ); // ---------------------------------- // Doubleclick auf TabsToolbar -> New Tab // ---------------------------------- tabsToolbar.addEventListener( "dblclick", function(event) { if (!bDblclickOnTabbarNewTab) return; if (event.button == 0) { if (event.target.parentNode.id == "TabsToolbar") { if (strHomepageURL) { event.target.documentGlobal.openTrustedLinkIn(strHomepageURL,"tab"); } else { BrowserOpenTab(); } event.preventDefault(); event.stopPropagation(); return; } } }, true ); // ---------------------------------- // Doubleclick auf leeren Bereich in TabContainer -> New Tab // ---------------------------------- gBrowser.tabContainer.addEventListener( "dblclick", function(event) { if (!bDblclickOnTabbarNewTab) return; if (event.button == 0) { let element = event.target.parentNode; if (element == gBrowser.tabContainer) { if (strHomepageURL) { event.target.documentGlobal.openTrustedLinkIn(strHomepageURL,"tab"); } else { BrowserOpenTab(); } event.preventDefault(); event.stopPropagation(); return; } } }, true ); // ---------------------------------- // Doubleclick auf Tab -> Reload Tab // ---------------------------------- gBrowser.tabContainer.addEventListener( "dblclick", function(event) { if (!bDblclickOnTabReloadTab) return; if (event.button == 0) { let element = event.target.parentNode; while (element) { if (element.localName == "tab") { element.linkedBrowser.reload(); return; } element = element.parentNode; } } }, true ); // ---------------------------------- // TabSelect -> Tab in Sicht bekommen // ---------------------------------- gBrowser.tabContainer.addEventListener( "TabSelect", function(event) { let bScroll = false; let bScrollTop = true; let scrollBoxY1 = event.target.parentElement.scrollbox.screenY; let scrollBoxHeight = event.target.parentElement.scrollbox.clientHeight; let scrollBoxY2 = scrollBoxY1 + scrollBoxHeight; let TabSelY1 = event.target.screenY; let TabSelHeight = event.target.clientHeight; let TabSelY2 = TabSelY1 + TabSelHeight; if (TabSelY2 > scrollBoxY2) { bScroll = true; bScrollTop = false; } if (TabSelY1 < scrollBoxY1) { bScroll = true; bScrollTop = true; } if (bScroll) { setTimeout(function() { event.target.scrollIntoView(bScrollTop); }, 0); } }, true ); // ---------------------------------- // Wheel-Event über Tab-Leiste // ---------------------------------- let tabsScrollbox2 = document.getElementById( "tabbrowser-arrowscrollbox" ).scrollbox; tabsScrollbox2.addEventListener( "wheel", function(event) { event.preventDefault(); event.stopPropagation(); let scrollUp = true; let wrap = false; let scrollBoxY1 = gBrowser.tabContainer._animateElement.scrollbox.scrollTop; let scrollHeight; if (bPageScroll) { scrollHeight = gBrowser.tabContainer._animateElement.scrollbox.clientHeight; } else { let firstTab = gBrowser.visibleTabs[0]; let h = firstTab ? firstTab.getBoundingClientRect().height : 24; scrollHeight = h; } let dir = (scrollUp ? 1 : -1) * Math.sign(event.deltaY); let bLastScrollLine = false; if ( gBrowser.tabContainer._animateElement.scrollbox.scrollTopMax == gBrowser.tabContainer._animateElement.scrollbox.scrollTop ) { bLastScrollLine = true; } if ( !bTabWheel || event.ctrlKey || event.originalTarget.localName == "thumb" || event.originalTarget.localName == "slider" || event.originalTarget.localName == "scrollbarbutton" ) { setTimeout(function() { let scrollBoxMod = scrollBoxY1 % scrollHeight; if (scrollBoxMod > 0) { if (dir == -1) { scrollBoxY1 -= scrollBoxMod; if (scrollBoxMod < scrollHeight && !bLastScrollLine) { scrollBoxY1 -= scrollHeight; } } else { scrollBoxY1 += scrollHeight - scrollBoxMod; if (scrollHeight - scrollBoxMod < scrollHeight) { scrollBoxY1 += scrollHeight; } } } else { if (dir == -1) { scrollBoxY1 -= scrollHeight; } else { scrollBoxY1 += scrollHeight; } } gBrowser.tabContainer._animateElement.scrollbox.scrollTo({ top: scrollBoxY1, left: 0, behavior: "auto" }); }, 20); } if (bTabWheel && !event.ctrlKey) { setTimeout(function() { if ( event.originalTarget.localName != "slider" && event.originalTarget.localName != "thumb" && event.originalTarget.localName != "scrollbarbutton" ) { gBrowser.tabContainer.advanceSelectedTab(dir, wrap); if ( gBrowser.tabContainer._firstTab == gBrowser.selectedTab || gBrowser.tabContainer._lastTab == gBrowser.selectedTab ) { gBrowser.selectedTab.scrollIntoView(); } } }, 50); } }, false ); //------------------------------------------------------------------------------------------- // Drag & Drop – Multirow-fähig, mit Emoji-Einfüge-Marker //------------------------------------------------------------------------------------------- // Einfüge-Markierung vorbereiten: Attribut "dnd-marker" statt Border if (!gBrowser.tabContainer.clearDropIndicator) { gBrowser.tabContainer.clearDropIndicator = function() { for (let tab of this.allTabs) { tab.removeAttribute("dnd-marker"); } }; gBrowser.tabContainer.addEventListener( "dragleave", function () { this.clearDropIndicator(); }, true ); } // _getDropIndex: ermittelt die Zielposition für den Drop gBrowser.tabContainer._getDropIndex = function(event) { let tabToDropAt = getTabFromEventTarget(event, false); if (tabToDropAt?.localName == "tab-group") { tabToDropAt = tabToDropAt.previousSibling; if (!tabToDropAt) { tabToDropAt = gBrowser.visibleTabs[0]; } } if (!tabToDropAt) { tabToDropAt = gBrowser.visibleTabs[gBrowser.visibleTabs.length - 1]; } const tabPos = gBrowser.tabContainer.getIndexOfItem(tabToDropAt); if (window.getComputedStyle(this).direction == "ltr") { let rect = tabToDropAt.getBoundingClientRect(); if (event.clientX < rect.x + rect.width / 2) { return tabPos; } return tabPos + 1; } let rect = tabToDropAt.getBoundingClientRect(); if (event.clientX > rect.x + rect.width / 2) { return tabPos; } return tabPos + 1; }; let listenersActive = false; gBrowser.tabContainer.addEventListener("dragstart", () => { gBrowser.visibleTabs.forEach(t => (t.style.transform = "")); if (!listenersActive) { gBrowser.tabContainer.getDropEffectForTabDrag = function() {}; gBrowser.tabContainer._getDropEffectForTabDrag = function() {}; gBrowser.tabContainer.on_dragover = dragoverEvent => performTabDragOver(dragoverEvent); gBrowser.tabContainer._onDragOver = dragoverEvent => performTabDragOver(dragoverEvent); gBrowser.tabContainer.ondrop = dropEvent => performTabDropEvent(dropEvent); listenersActive = true; } }); } // Ende MultiRowTabs() // ----------------------------------------------------------------------------- // Globale Hilfsfunktionen für Drag&Drop (mit Emoji-Einfüge-Marker) // ----------------------------------------------------------------------------- var lastKnownIndex = null; var lastGroupStart = null; var lastGroupEnd = null; function getTabFromEventTarget(event, ignoreTabSides = false) { let { target } = event; if (target.nodeType != Node.ELEMENT_NODE) { target = target.parentElement; } let tab = target?.closest("tab") || target?.closest("tab-group"); const selectedTab = gBrowser.selectedTab; if (tab && ignoreTabSides) { let { width, height } = tab.getBoundingClientRect(); if ( event.screenX < tab.screenX + width * 0.25 || event.screenX > tab.screenX + width * 0.75 || ((event.screenY < tab.screenY + height * 0.25 || event.screenY > tab.screenY + height * 0.25) && gBrowser.tabContainer.verticalMode) ) { return selectedTab; } } return tab; } function performTabDragOver(event) { event.preventDefault(); event.stopPropagation(); let tc = gBrowser.tabContainer; let ind = tc._tabDropIndicator; // Alte Marker entfernen if (tc.clearDropIndicator) { tc.clearDropIndicator(); } let effects = orig_getDropEffectForTabDrag(event); let tab; // Link-Drop (Links auf Tabs ziehen) – nur Auswahl, kein Marker if (effects == "link") { tab = getTabFromEventTarget(event, true); if (tab) { if (!tc._dragTime) { tc._dragTime = Date.now(); } if ( !tab.hasAttribute("pendingicon") && Date.now() >= tc._dragTime + tc._dragOverDelay ) { tc.selectedItem = tab; } if (ind) { ind.hidden = true; } return; } } if (!tab) { tab = getTabFromEventTarget(event, false); } let newIndex = tc._getDropIndex(event); if (newIndex == null) { return; } // eingebauten Indikator verstecken if (ind) { ind.hidden = true; } let tabs = gBrowser.tabs; // Am Ende der Tab-Leiste: Marker "right" am letzten Tab if (newIndex == tabs.length) { let lastTab = tabs[newIndex - 1]; if (lastTab) { lastTab.setAttribute("dnd-marker", "right"); } } else { // Sonst: Marker "left" am Tab an der Drop-Position let targetTab = tabs[newIndex]; if (targetTab) { targetTab.setAttribute("dnd-marker", "left"); } } } function performTabDropEvent(event) { let newIndex; let dt = event.dataTransfer; let dropEffect = dt.dropEffect; let draggedTab; if (dt.mozTypesAt(0)[0] == TAB_DROP_TYPE) { draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0); if (!draggedTab) { return; } } if ( draggedTab && dropEffect != "copy" && draggedTab.container == gBrowser.tabContainer ) { newIndex = gBrowser.tabContainer._getDropIndex(event); let selectedTabs = gBrowser.selectedTabs.length > 1 ? gBrowser.selectedTabs : [draggedTab]; let tabToMoveAt = gBrowser.tabContainer.getItemAtIndex(newIndex); let tab = getTabFromEventTarget(event, false); let tabgroup = tab?.closest("tab-group"); if (!tab) { newIndex = gBrowser.tabs.length; tabToMoveAt = null; } if (tabgroup && !tab.previousSibling) { newIndex = 0; selectedTabs.forEach(t => { gBrowser.moveTabTo(t, { tabIndex: newIndex++, forceUngrouped: true }); }); } else if ( !tab || (!tabgroup && !tabToMoveAt?.group) || (tabgroup && tabToMoveAt?.group) ) { selectedTabs.forEach(t => { gBrowser.moveTabBefore(t, tabToMoveAt); }); } else { tabToMoveAt = gBrowser.tabContainer.getItemAtIndex(newIndex - 1); selectedTabs.forEach(t => { gBrowser.moveTabAfter(t, tabToMoveAt); }); } lastKnownIndex = null; lastGroupStart = null; lastGroupEnd = null; } // Marker nach dem Drop entfernen if (gBrowser.tabContainer.clearDropIndicator) { gBrowser.tabContainer.clearDropIndicator(); } } function orig_getDropEffectForTabDrag(event) { let dt = event.dataTransfer; let isMovingTabs = dt.mozItemCount > 0; for (let i = 0; i < dt.mozItemCount; i++) { let types = dt.mozTypesAt(0); if (types[0] != TAB_DROP_TYPE) { isMovingTabs = false; break; } } if (isMovingTabs) { let sourceNode = dt.mozGetDataAt(TAB_DROP_TYPE, 0); if ( XULElement.isInstance(sourceNode) && sourceNode.localName == "tab" && sourceNode.documentGlobal.isChromeWindow && sourceNode.ownerDocument.documentElement.getAttribute("windowtype") == "navigator:browser" && sourceNode.documentGlobal.gBrowser.tabContainer == sourceNode.container ) { if ( PrivateBrowsingUtils.isWindowPrivate(window) != PrivateBrowsingUtils.isWindowPrivate(sourceNode.documentGlobal) ) { return "none"; } if ( window.gMultiProcessBrowser != sourceNode.documentGlobal.gMultiProcessBrowser ) { return "none"; } if (window.gFissionBrowser != sourceNode.documentGlobal.gFissionBrowser) { return "none"; } return dt.dropEffect == "copy" ? "copy" : "move"; } } if (Services.droppedLinkHandler.canDropLink(event, true)) { return "link"; } return "none"; } -
Mira_Belle Vielen Dank für den Hinweis. Das hört sich echt super an, was ich bisher gelesen habe. Wenn ich wieder etwas mehr Kraft für diese Umstellung habe, dann möchte ich das unbedingt auch umsetzen/probieren.
-
Das Script TabMoveOnly.uc.js funktionierte auch nicht mehr (jetzt erst festgestellt). Hier dann die bereinigte Version zur Verfügung.
JavaScript
Alles anzeigen// ==UserScript== // @name TabMoveOnly.uc.js // @namespace local // @description Nur das Verschieben von Tabs per Drag & Drop // @include main // @compatibility Firefox152+ // @version 2026-07-05 // ==/UserScript== "use strict"; TabMoveOnly(); function TabMoveOnly() { if (!window.gBrowser) return; const TAB_DROP_TYPE = window.TAB_DROP_TYPE || "application/x-moz-tabbrowser-tab"; // ========================================================= // FEINEINSTELLUNGEN FÜR DIE MARKER // ========================================================= // Links: Marker horizontal verschieben in px const LEFT_MARKER_SHIFT = 0; // Rechts: Marker horizontal verschieben in px const RIGHT_MARKER_SHIFT = 0; // Marker vertikal leicht nach oben/unten korrigieren in px const MARKER_TOP = -1; // ========================================================= // MARKER-CSS // ========================================================= const css = ` .tabbrowser-tab[dnd-marker]{ position: relative !important; } .tab-dnd-marker{ position: absolute !important; pointer-events: none !important; z-index: 1000 !important; content: "" !important; width: 14px !important; height: 18px !important; border-radius: 50% !important; background: radial-gradient(circle at center, #00ffff 0 35%, #1dacd6 36% 60%, rgba(255,255,255,0) 61%) !important; box-shadow: 0 0 3px rgba(255, 90, 82, 0.35) !important; } `; // ========================================================= // CSS EINBINDEN // ========================================================= const sss = Cc["@mozilla.org/content/style-sheet-service;1"] .getService(Ci.nsIStyleSheetService); const uri = Services.io.newURI( "data:text/css;charset=UTF-8," + encodeURIComponent(css) ); if (!sss.sheetRegistered(uri, sss.USER_SHEET)) { sss.loadAndRegisterSheet(uri, sss.USER_SHEET); } const tabContainer = gBrowser.tabContainer; // Listener nur einmal aktivieren let listenersActive = false; // Reserviert für Gruppen-/Drop-Zustand let lastGroupStart = null; let lastGroupEnd = null; // ========================================================= // MARKER-VERWALTUNG // ========================================================= function clearDndMarkers() { for (const tab of gBrowser.tabs) { tab.removeAttribute("dnd-marker"); tab.style.removeProperty("--tab-dnd-marker-top"); if (tab._dndMarkerEl) { tab._dndMarkerEl.remove(); tab._dndMarkerEl = null; } } } function setDndMarker(tab, side) { clearDndMarkers(); if (!tab || !side) return; // Nur zur Erkennung / CSS-Selektoren tab.setAttribute("dnd-marker", side); // Vertikale Feinkorrektur als Variable direkt am Tab tab.style.setProperty("--tab-dnd-marker-top", `${MARKER_TOP}px`); // Echtes Marker-Element, damit dein CSS sicher greift const marker = tab.ownerDocument.createXULElement("box"); marker.className = `tab-dnd-marker ${side}`; // Horizontale Feineinstellung pro Seite if (side === "left") { marker.style.setProperty("left", `${1 + LEFT_MARKER_SHIFT}px`, "important"); } else if (side === "right") { marker.style.setProperty("right", `${1 + RIGHT_MARKER_SHIFT}px`, "important"); } tab.appendChild(marker); tab._dndMarkerEl = marker; } // ========================================================= // HILFSFUNKTIONEN FÜR TAB / DROP // ========================================================= function getTabFromEventTarget(event, ignoreTabSides = false) { let { target } = event; if (!target) return null; if (target.nodeType !== Node.ELEMENT_NODE) { target = target.parentElement; } let tab = target?.closest("tab") || target?.closest("tab-group"); const selectedTab = gBrowser.selectedTab; // Falls der Cursor nur im Randbereich ist, nimm den aktuell ausgewählten Tab if (tab && ignoreTabSides) { const { width, height } = tab.getBoundingClientRect(); if ( event.screenX < tab.screenX + width * 0.25 || event.screenX > tab.screenX + width * 0.75 || ((event.screenY < tab.screenY + height * 0.25 || event.screenY > tab.screenY + height * 0.75) && gBrowser.tabContainer.verticalMode) ) { return selectedTab; } } return tab; } // Firefox-interne Drop-Index-Berechnung für Multirow / normales Tab-Layout gBrowser.tabContainer._getDropIndex = function (event) { let tabToDropAt = getTabFromEventTarget(event, false); if (tabToDropAt?.localName == "tab-group") { tabToDropAt = tabToDropAt.previousSibling; if (!tabToDropAt) { tabToDropAt = gBrowser.visibleTabs[0]; } } if (!tabToDropAt) { tabToDropAt = gBrowser.visibleTabs[gBrowser.visibleTabs.length - 1]; } if (!tabToDropAt) return null; const tabPos = gBrowser.tabContainer.getIndexOfItem(tabToDropAt); const rect = tabToDropAt.getBoundingClientRect(); const ltr = window.getComputedStyle(this).direction == "ltr"; if (ltr) { return event.clientX < rect.x + rect.width / 2 ? tabPos : tabPos + 1; } return event.clientX > rect.x + rect.width / 2 ? tabPos : tabPos + 1; }; // Prüft, ob der Drag wirklich ein Tab-Drag ist function orig_getDropEffectForTabDrag(event) { const dt = event.dataTransfer; let isMovingTabs = dt.mozItemCount > 0; for (let i = 0; i < dt.mozItemCount; i++) { const types = dt.mozTypesAt(0); if (types[0] != TAB_DROP_TYPE) { isMovingTabs = false; break; } } if (isMovingTabs) { const sourceNode = dt.mozGetDataAt(TAB_DROP_TYPE, 0); if ( XULElement.isInstance(sourceNode) && sourceNode.localName == "tab" && sourceNode.documentGlobal.isChromeWindow && sourceNode.ownerDocument.documentElement.getAttribute("windowtype") == "navigator:browser" && sourceNode.documentGlobal.gBrowser.tabContainer == sourceNode.container ) { if ( PrivateBrowsingUtils.isWindowPrivate(window) != PrivateBrowsingUtils.isWindowPrivate(sourceNode.documentGlobal) ) { return "none"; } if (window.gMultiProcessBrowser != sourceNode.documentGlobal.gMultiProcessBrowser) return "none"; if (window.gFissionBrowser != sourceNode.documentGlobal.gFissionBrowser) return "none"; return dt.dropEffect == "copy" ? "copy" : "move"; } } if (Services.droppedLinkHandler.canDropLink(event, true)) return "link"; return "none"; } function getMarkerInfo(event) { let tabToDropAt = getTabFromEventTarget(event, false); if (tabToDropAt?.localName == "tab-group") { tabToDropAt = tabToDropAt.previousSibling; if (!tabToDropAt) { tabToDropAt = gBrowser.visibleTabs[0]; } } if (!tabToDropAt) { const lastTab = gBrowser.visibleTabs[gBrowser.visibleTabs.length - 1]; return { tab: lastTab, side: "right" }; } const rect = tabToDropAt.getBoundingClientRect(); const ltr = window.getComputedStyle(gBrowser.tabContainer).direction == "ltr"; const side = ltr ? (event.clientX < rect.x + rect.width / 2 ? "left" : "right") : (event.clientX > rect.x + rect.width / 2 ? "left" : "right"); return { tab: tabToDropAt, side }; } // ========================================================= // DRAG OVER // ========================================================= function performTabDragOver(event) { const effects = orig_getDropEffectForTabDrag(event); // Nur echte Tab-Drags zulassen if (effects == "none" || effects == "link") { clearDndMarkers(); return; } event.preventDefault(); event.stopPropagation(); const tab = getTabFromEventTarget(event, true); // Kleine Starthilfe für Gruppen-Merker if (tab && tab.nodeName == "tab-group" && !lastGroupStart) { const first = tab.querySelector("tab:first-of-type"); const last = tab.querySelector("tab:last-of-type"); if (first && last) { lastGroupStart = first._tPos; lastGroupEnd = last._tPos; } } const newIndex = gBrowser.tabContainer._getDropIndex(event); if (newIndex == null) { clearDndMarkers(); return; } const markerInfo = getMarkerInfo(event); setDndMarker(markerInfo.tab, markerInfo.side); } // ========================================================= // DROP // ========================================================= function performTabDropEvent(event) { clearDndMarkers(); const dt = event.dataTransfer; const dropEffect = dt.dropEffect; let draggedTab; if (dt.mozTypesAt(0)[0] == TAB_DROP_TYPE) { draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0); if (!draggedTab) return; } if (draggedTab && dropEffect != "copy" && draggedTab.container == gBrowser.tabContainer) { let newIndex = gBrowser.tabContainer._getDropIndex(event); if (newIndex == null) return; const selectedTabs = gBrowser.selectedTabs.length > 1 ? gBrowser.selectedTabs : [draggedTab]; let tabToMoveAt = gBrowser.tabContainer.getItemAtIndex(newIndex); const tab = getTabFromEventTarget(event, false); const tabgroup = tab?.closest("tab-group"); if (!tab) { newIndex = gBrowser.tabs.length; tabToMoveAt = null; } if (tabgroup && !tab.previousSibling) { newIndex = 0; selectedTabs.forEach(t => { gBrowser.moveTabTo(t, { tabIndex: newIndex++, forceUngrouped: true }); }); } else if ( !tab || (!tabgroup && !tabToMoveAt?.group) || (tabgroup && tabToMoveAt?.group) ) { selectedTabs.forEach(t => { gBrowser.moveTabBefore(t, tabToMoveAt); }); } else { tabToMoveAt = gBrowser.tabContainer.getItemAtIndex(newIndex - 1); selectedTabs.forEach(t => { gBrowser.moveTabAfter(t, tabToMoveAt); }); } lastGroupStart = null; lastGroupEnd = null; } } // ========================================================= // EINMALIGE INITIALISIERUNG // ========================================================= tabContainer.addEventListener("dragstart", () => { if (listenersActive) return; tabContainer.on_dragover = e => performTabDragOver(e); tabContainer._onDragOver = e => performTabDragOver(e); tabContainer.ondrop = e => performTabDropEvent(e); tabContainer.addEventListener("dragend", clearDndMarkers, true); tabContainer.addEventListener("drop", clearDndMarkers, true); listenersActive = true; }); } -
Guten morgen

Mich hat Firefox heute morgen begrüßt mit Version 155 und mich wieder auf eine "einzeilige" Tab-Leiste zurückgeschleudert
Ich habe aus Beitrag #1.144 bereits das Script ausgetauscht und den Firefox mal neu gestartet, aber die Tab-Leiste bleibt einzeilig.
Ist die "Baustelle" um wieder auf eine mindestens 3-Zeilige Tab-Leiste zu kommen größer, oder habe ich etwas übersehen?
UPDATE: Ich war wohl wieder mal ein "dummer" User und habe den Beitrag Scripte funktionieren seit 155 nicht mehr nicht beachtet. Mit den Hinweisen dort und dem aktualisieren der ganzen Dateien, die für die Multi-Tab-Anzeige notwendig sind, habe ich die mehrzeiligen Tabs wieder aktivieren können mit dem Firefox 155
Jetzt muss ich nur wieder etwas "feintunig" betreiben, weil meine Lieblingsfarben für die Tab-Anzeige und die Position der Tab-Leiste etwas anders sind, aber das bekomme ich hin. -
Habe etwas Geduld, ich schaue es mir an, melde mich dann zurück.
Übrigens, hast du dich damit befasst (ab 155): https://github.com/Endor8/userChr…0155/userChrome
-
Das Skript funktioniert weiterhin einwandfrei, V156.0beta1.
-
Habe etwas Geduld, ich schaue es mir an, melde mich dann zurück.
Übrigens, hast du dich damit befasst (ab 155): https://github.com/Endor8/userChr…0155/userChrome
Ja, im Rahmen des Ereignisses, dass das Update von Firefox auf 155 erst mal alles wieder "kaputt" gemacht hat, habe ich Stück für Stück die Infos mir hier im Forum (und auch den Link zu github) angesehen.
Das "Fatale" ist ja, dass es über lange Zeit mit den mehrzeiligen Tabs sehr stabil funktionierte und man (ich) als User dann natürlich nicht so häufig hier im Forum reinschaut um die Weiterentwicklungen und Veränderungen zu verfolgen und dann kommt natürlich noch der Effekt der abbauenden grauen Zellen hinzu, dass man sich nicht mehr genau daran erinnert, wie das ganze System um mehrzeilige Tabs im Firefox zu aktivieren, in der Praxis funktioniert. Das braucht dann nach dem ersten Schock erst wieder ein paar Momente, bis man kapiert hat, was wichtig zu prüfen war
Sorry also, wenn ich hier für Unruhe gesorgt habe. -
Sorry also, wenn ich hier für Unruhe gesorgt habe.
Du musst/brauchst dich nicht zu entschuldigen, alles ist gut

Hauptsache es funktioniert jetzt wieder alles.
-
Das "Fatale" ist ja, dass es über lange Zeit mit den mehrzeiligen Tabs sehr stabil funktionierte und man (ich) als User dann natürlich nicht so häufig hier im Forum reinschaut um die Weiterentwicklungen und Veränderungen zu verfolgen
Das sollte man aber tun, wenn man Scripte einsetzt...

-
Bob spricht mir aus der Seele.
Ich habe mich vor einem guten Jahr auch relativ intensiv mit etlichen Skripten beschäftigt, und auch viel Spaß daran – und in jenem Zusammenhang auch andiesem Forum – gehabt. Nichtsdestotrotz bleibe ich ich letztlich ein Firefoxer mit vereinzeilt und isoliert angelerntem. Dann kam wieder eine Zeit, in der ich mich mehr auf Inhalte konzentriert habe.
Ich denke, die Intensivskripter hier sollten insbesondere, wenn FF einen solchen Sprung wie zu Version 155 macht, Geduld mit den Immer-wieder-mal-Skriptern aufbringen. So wäre heute Morgen ein kurzes Refresh a la "Dort findet man den Installationsordner" und "Dort findet man den Profil- und den Chrome-Ordner" und diese Dateien müssen ersetzt werden sehr hilfreich gewesen. Letztlich haben's die meisten aber hinbekommen, denke ich.
Endors wunderbares Video mit der Schritt-für-Schritt-Anleitung war für das Ersetzen dieser wenigen Dateien für mich z.B. etwas zu umfangreich. Dort sind ja vieles erklärt, was heute goanet nötig war...
GL
-
Dort findet man den Installationsordner" und "Dort findet man den Profil- und den Chrome-Ordner"
Naja, wer Skripte oder CSS-Codes nutzt, der sollte das schon selber wissen wo die Ordner sind

Ansonsten wird das hier:
BeitragFunktionelle Änderungen am Firefox durch Skripte
Als Ersatz für einige Erweiterungen bzw. Funktionen daraus kann man auch diverse Skripte benutzen.
( damit sind nicht optische Änderungen am Firefox gemeint)
Diese werden mit einer userChrome.css Datei erstellt.
Skripte werden als .uc.js Datei im Unterordner chrome gespeichert.
Hinweise:
Ab Firefox Version 139 kann der neue Eintrag in about:config:
security.allow_unsafe_dangerous_privileged_evil_evalauf true umgestellt werden, damit manche Skripte wieder funktionieren.
Hier der Gund dafür:
RE:…
2002Andreas15. November 2017 um 16:49 oder auch hier:
BeitragFirefox 155 notwendige Änderung bei Skriptverwendung!
Hinweis:
Ab der Firefox Version 155 müssen Dateien im Installationsorder von Firefox ausgetauscht werden.
Die neuen Dateien gibt es hier zum Download:
https://github.com/Endor8/userChr…rChrome/Dateien
Oder hier der direkte Download der .zip Datei:
https://raw.githubusercontent.com/Endor8/userChr…anpassungen.zip
Und hier eine Erklärung, wohin die Dateien müssen:
https://github.com/Endor8/userChr…ster/userChrome
Oder auch hier mal lesen:
RE: JavaScript in der Nightly 155.0a1 (2026-07-28)
2002Andreas2. September 2026 um 11:41 alles beschrieben, mit Anleitung und Video.

-
Ich melde mich noch mal, weil ich erst jetzt Abends wieder dazu komme.
Ich stand jetzt vor der Aufgabe, dass ich mir eine neue UserChrome.css-Datei zusammenbauen musste, so wie mein Firefox bis Version 154 mit den dreizeiligen Browser-Tabs aussah, was Farbe, was Länge, Breite, Form, Tab-Verhalten anging.
Ich dachte, wow, das wird jetzt wieder Zeit kosten, weil ich vorher noch gar keine userChrome.css Datei hatte. Aber ich habe dafür jetzt eine AI genutzt und das hat jetzt drei Minuten gedauert, dass ich der AI meine alte Konfiguration (MultiRowTabs.uc.js) als Vorlage gegeben habe und von der AI wollte, dass sie das in die UserChrome.css-Datei so anpasst, dass der Firefox ab der Version 155 wieder so aussieht wie unter 154. Und wie gesagt, nach drei Minuten war es fertig. Ich bin begeistert. Dafür sind AIs echt geil
-
Sagt mal, was für Skripte nutzt ihr denn so als Mehrzeilige Tableiste? Das "Originale" wird ja nicht mehr "offiziell" weiter entwickelt, aber anscheinend hat hier trotzdem jeder sein eigenes. Gibts hierfür wieder neue Quellen ? Weil ich nutze auch mein eigenes. Das ist natürlich aufwendiger, wenn man immer alles selber fixen muss bei den neuen Firefox-Versionen

Bei mir siehts so aus (siehe Bildupload). Nutzt hier jemand auch ein Multirow-Tab Skript mit ähnlichdem Tab-Design (halbwegs modern aussehend) ?
Ps. ja, ich mag kompakt. Maximale Ausnutzung der Fläche
Ps2. Ja, das sind Lesezeichen direkt in der Nav-Bar. Ganz praktisch - ganz ohne zusätzliche Leiste.
Ps3: Ja, das ganz oben über der Tableiste ist Groupy von Stardock aus Steam und hat per se nichts mit Firefox zu tun. -
Platos Ich nutze es selber nicht, habe es nur mal angetestet und beafand es eigentlich ganz gelungen.
Alles anzeigenVersion 4.11 wurde veröffentlicht.
Dieses Update umfasst hauptsächlich kleinere Fehlerbehebungen, Code-Refaktorierung und Unterstützung für zukünftige Firefox-Versionen.
Darüber hinaus wurden auf der GitHub-Seite zu jedem Konfigurationspunkt kurze Beschreibungen ergänzt, wodurch die Lesbarkeit verbessert wurde. Die Installationsschritte wurden ebenfalls aktualisiert und enthalten nun Anleitungen zur Installation verschiedener Script-Loader, die bei Bedarf herangezogen werden können.
Um das Update sofort auszuführen, setzen Sie checkUpdate auf 1 zurück. Die Aktualisierungsprüfung wird dann sofort in einem neuen Fenster gestartet.
Bei Problemen oder Fragen ist Rückmeldung willkommen.
Vielen Dank.
Download und Changelog: https://github.com/Merci-chao/userChrome.js#changelog
Einführungsseite: https://merci-chao.github.io/userChrome.js/multitabrows/en
GitHub-Seite: https://github.com/Merci-chao/userChrome.js -
Ah, danke, das sieht ja mal gut aus. Das muss ich mal ausprobieren, danke!
-
das sieht ja mal gut aus.
Nur als Info: Der User ist auch regelmäßig hier im Forum, solltest du Fragen dazu haben.
-
Ok, gut zu wissen. Schön zu hören, dass hier jemand wieder "das Ruder" übernommen hat und hier so eine gute Version gemacht hat.
-