R.I.P.
Mfg.
Endor
R.I.P.
Mfg.
Endor
Schade, dass er sich nicht mal "persönlich" meldet.
Ja das finde ich auch.
Mfg.
Endor
Herzmann Der Autor hat wieder aktualisiert.
Hier die aktuelle Version:
// ==UserScript==
// @name zzzz-MultiRowTab_LiteforFx48.uc.js
// @namespace http://space.geocities.yahoo.co.jp/gl/alice0775
// @description Mehrzeilige Tableiste - Experimentelle CSS Version
// @include main
// @compatibility Firefox 128esr Firefox 131+
// @author Alice0775
// @version 2016/08/05 00:00 Firefox 48
// @version 2016/05/01 00:01 hide favicon if busy
// @version 2016/03/09 00:01 Bug 1222490 - Actually remove panorama for Fx45+
// @version 2016/02/09 00:01 workaround css for lwt
// @version 2016/02/09 00:00
// ==/UserScript==
"use strict";
MultiRowTabLiteforFx();
function MultiRowTabLiteforFx() {
if (!window.gBrowser) { return; }
// -- Config --
const // Anzahl der Tab-Leistenzeilen angeben, oder unbegrenzte Anzahl von Zeilen wählen.
TabBar_Rows = false ,// [false] = unbegrenzt
// true = Begrenzte Tabzeilen - Anzahl der Zeilen angeben
Max_Rows = 3 ,// Tabzeilen angeben (Standard: 3 Zeilen)
// ProtonUI Erscheinungsbild der Tabs ändern
ProtonUI = true ,// [true] = Darstellung ProtonUI
// Die Höhe der Tab-Leiste entspricht der Höhe der UI-Dichte plus dem Leerraum darüber und darunter.
// false = Darstellung wie bei browser.proton.enabled auf false, was man vor Firefox 90 noch einstellen konnte.
// Leerraum um die Tabs auf 0 anpassen, um der Höhe der UI-Dichte zu entsprechen.
// Position der Tab-Leiste.
TabBar_Position = 0 ,// [0] = Standard
// 1 = unter der Symbolleiste
// 2 = unter dem Fenster
// Standardposition der Tableiste Blenden Sie die Titelleistenschaltfläche [-□×]
// aus und verwenden Sie die Breite der Tableiste entsprechend
TitleBar_Button_Autohide = false ,// [false] = Aktiviert
// true = Deaktiviert
// Äußeren Rahmen der Titelleistenschaltfläche [-□×] reduzieren und transparent machen.
// Obere rechte Ecke der Tab-Leiste auf ihre ursprüngliche Größe zurücksetzen und Transparenz aufheben.
// Tab-Höhe „UI-Dichte“
UI_Density_Compact = 29 ,// Standard = 29 Pixel bei Kompakt
UI_Density_Normal = 36 ,// Standard = 36 Pixel bei Normal
UI_Density_Touch = 41 ,// Standard = 41 Pixel bei Touch
// Entsprechender CSS Code in UserChrome.css wird vorrangig behandelt!
// Tab-Breite
// Bei gleichen Werten bei Min und Max, wird Tabbreite fixiert!
Tab_Min_Width = 76 ,// Standard - Mindestwert = 76px
Tab_Max_Width = 225 ,// Standard - Maxwert = 225px
// Entsprechender CSS Code in UserChrome.css wird vorrangig behandelt!
// .Tab-Drop-Indikator-Icon-Ersetzung.
Tab_Drop_Indicator = false ,// [false] = Stecknadel Symbol 📍
// true = Rote Linie (2px × 29px) als Symbol
// Ränder auf der linken und rechten Seite der Tabs
Tab_Separators = false ,// [false] = Nicht anzeigen
// true = Anzeigen
// Rahmen CSS wurde extrahiert und angepasst, an Aussehen wie bei browser.proton.enabled
// auf false, was man vor Firefox 90 noch einstellen konnte.
// Tab-Leisten-Ziehbereich
Left_Drag_Area = 0 ,// Linker Ziehbereich Breite: Standard 40 Pixel
Right_Drag_Area = 0 ,// Rechter Ziehbereich Breite: Standard 40 Pixel
Window_Maximize_Left_Drag_Area = false ,// true = Linken Ziehbereich bei maximiertem Fenster anzeigen. Standardmäßig ausgeblendet.
Fullscreen_Drag_Area = false ,// true = Linken und rechten Ziehbereich bei Vollbild anzeigen. Standardmäßig ausgeblendet.
// Angeheftete Tabs neu positionieren
Separate_Tabs_and_PinnedTabs = false ,// [false] = Standard
// true = Angeheftete Tabs von der Tab-Leiste lösen und in die darüber liegende Zeile verschieben.
// „Tab schließen“ Schaltfläche .
Tab_Close_Button = 0 ,// [0] = Standard
// 1 = Ausgeblendet
// 2 = Auf allen Tabs anzeigen
// 3 = Nur bei Mausberührung anzeigen
// Alle Tabs Schaltfläche
All_Tabs_Button = false ,// [false] = ausblenden
// true = anzeigen
// -- Config End --
css = `
#TabsToolbar {
:root[uidensity="compact"] & { --tab-min-height: ${UI_Density_Compact}px; }
:root:not([uidensity]) & { --tab-min-height: ${UI_Density_Normal}px; }
:root[uidensity="touch"] & { --tab-min-height: ${UI_Density_Touch}px; }
${Tab_Drop_Indicator ? `
#tabbrowser-tabs > .tab-drop-indicator {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAAdCAIAAAAPVCo9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAASSURBVBhXY3growJEQ5+SUQEAOb1EM8kwskcAAAAASUVORK5CYII=) no-repeat center !important;
}
` : ``}
.titlebar-spacer[type="pre-tabs"] {
width: ${Left_Drag_Area}px !important;
}
.titlebar-spacer[type="post-tabs"] {
width: ${Right_Drag_Area}px !important;
}
${Window_Maximize_Left_Drag_Area ? `
.titlebar-spacer {
:root:not([sizemode="normal"], [inFullscreen]) &[type="pre-tabs"] {
display: block !important;
}
}
` : ``}
${Fullscreen_Drag_Area ? `
.titlebar-spacer {
:root[inFullscreen] &, :root:not([tabsintitlebar]) & {
display: block !important;
}
}
` : ``}
#tabbrowser-arrowscrollbox {
&::part(scrollbox) {
&:has(+ spacer) > slot,
.scrollbox-clip > & {
flex-wrap: wrap;
}
${TabBar_Rows ? `
max-height: calc((var(--tab-min-height) + ${ProtonUI ? 8 : 0}px) * ${Max_Rows});
overflow: hidden auto;
& scrollbar {
-moz-window-dragging: no-drag;
}
` : ``}
}
&::part(overflow-start-indicator),
&::part(overflow-end-indicator),
&::part(scrollbutton-up),
&::part(scrollbutton-down) {
display: none;
}
${Separate_Tabs_and_PinnedTabs ? `
&::part(scrollbox) {
&:has(+ spacer) > slot::after,
.scrollbox-clip > &::after {
display: flow-root list-item;
content: "";
flex-basis: -moz-available;
height: 0;
overflow: hidden;
}
}
.tabbrowser-tab:not([pinned]) {
#tabbrowser-tabs[haspinnedtabs] & {
&, & + :not(#tabs-newtab-button) {
order: 1;
}
}
}
` : ``}
.tabbrowser-tab[fadein]:not([pinned]) {
--tab-min-width: ${Tab_Min_Width}px;
--tab-max-width: ${Tab_Max_Width}px;
max-width: var(--tab-max-width);
${Tab_Close_Button !== 0 ? `
${Tab_Close_Button === 1 ? `
.tab-close-button {
display: none !important;
}
` : Tab_Close_Button === 2 ? `
.tab-close-button {
display: block !important;
}
` : Tab_Close_Button === 3 ? `
.tab-close-button {
opacity: 0;
}
&:hover .tab-close-button {
opacity: 1;
display: block !important;
}
` : ``}
` : ``}
}
#tabbrowser-tabs[haspinnedtabs]:not([positionpinnedtabs]):not([orient="vertical"]) > & > .tabbrowser-tab:nth-child(1 of :not([pinned], [hidden])) {
margin-inline-start: 0 !important;
}
}
${ProtonUI ? `` : `
.toolbarbutton-1 {
margin: 0 !important;
padding: 0 !important;
}
.tabbrowser-tab,
#tabs-newtab-button {
height: var(--tab-min-height);
padding: 0 !important;
}
.tab-background {
box-shadow: none !important;
margin-block: 0 !important;
}
.tabbrowser-tab[usercontextid] > .tab-stack > .tab-background > .tab-context-line {
margin: 1px 2px 0 !important;
}
`}
${Tab_Separators ? `
.titlebar-spacer[type="pre-tabs"] {
border-inline-end: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}
.tabbrowser-tab::after,
.tabbrowser-tab::before {
border-left: 1px solid color-mix(in srgb, currentColor 50%, transparent);
height: calc(var(--tab-min-height) - 15%);
margin-block: auto;
}
.tabbrowser-tab:hover::after,
.tabbrowser-tab[multiselected]::after,
#tabbrowser-tabs:not([movingtab]) .tabbrowser-tab:has(+ .tabbrowser-tab:hover)::after,
#tabbrowser-tabs:not([movingtab]) .tabbrowser-tab:has(+ [multiselected])::after {
height: 100%;
}
.tabbrowser-tab::after,
#tabbrowser-tabs[movingtab] .tabbrowser-tab[visuallyselected]::before {
content: "";
display: block;
}
` : ``}
${All_Tabs_Button ? `` : `
#alltabs-button {
display: none;
}
`}
}
${TabBar_Position === 0 ? `
#TabsToolbar {
.titlebar-buttonbox-container {
height: calc(var(--tab-min-height) + ${ProtonUI ? 8 : 0}px);
margin-bottom: 0 !important;
${TitleBar_Button_Autohide ? `
background-color: color-mix(in srgb, currentColor 20%, transparent);
height: 6px;
opacity: 0;
position: fixed;
right: 0;
z-index: 2147483647;
.titlebar-button {
opacity: 0;
padding: 0;
}
&:hover {
height: calc(var(--tab-min-height) + ${ProtonUI ? 8 : 0}px);
opacity: 1;
.titlebar-button {
opacity: 1;
padding: 8px 17px;
}
}
` : ``}
}
}
` : `
#nav-bar {
:root:not([inFullscreen]) #toolbar-menubar:not([inactive]) + & > .titlebar-buttonbox-container {
display: none;
}
.titlebar-button {
padding-block: 0 !important;
}
}
`}
${TabBar_Position !== 2 ? `` : `
body {
& > #fullscr-toggler[hidden] + tabbox,
:root[inFullscreen] & > tabbox:hover {
border-top: 0.5px solid var(--toolbar-bgcolor);
}
& > tabbox > #navigator-toolbox {
border-block: none !important;
}
:root[inFullscreen] & {
& > #navigator-toolbox {
transition: none;
&:has(~ tabbox:hover) {
margin-top: 0 !important;
}
&:hover ~ tabbox > #navigator-toolbox {
max-height: 100%;
}}
& > tabbox:not(:hover) {
border-top: .5px solid transparent;
& > #navigator-toolbox {
max-height: 0;
}
}
}
}
`}
`,
sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
uri = Services.io.newURI("data:text/css;charset=UTF=8," + encodeURIComponent(css));
if (TabBar_Rows == false) {
["0", "2"].find(type => {
if(sss.sheetRegistered(uri, type)) sss.unregisterSheet(uri, type); sss.loadAndRegisterSheet(uri, type);
});
} else {
["0", "2", "SSTabRestored", "TabMove", "TabOpen", "TabSelect"].find(type => {
if(sss.sheetRegistered(uri, type)) sss.unregisterSheet(uri, type); sss.loadAndRegisterSheet(uri, type);
gBrowser.tabContainer.addEventListener(type, (e) => { e.target.scrollIntoView({ block: "nearest" }); });
});
}
if (TabBar_Position !== 0) {
if (TabBar_Position === 1) {
document.getElementById("navigator-toolbox").prepend(
document.getElementById("toolbar-menubar"),
document.getElementById("nav-bar"),
document.getElementById("PersonalToolbar"),
document.getElementById("titlebar"),
);
} else {
document.getElementById("navigator-toolbox").prepend(
document.getElementById("toolbar-menubar"),
document.getElementById("nav-bar"),
document.getElementById("PersonalToolbar"),
);
}
document.getElementById("nav-bar").appendChild(
document.querySelector("#TabsToolbar > .titlebar-buttonbox-container")
);
}
if (TabBar_Position === 2) {
document.body.appendChild(
document.createXULElement("tabbox")
).appendChild(
document.importNode(document.getElementById("navigator-toolbox"))
).appendChild(
document.getElementById("titlebar")
);
}
gBrowser.tabContainer.addEventListener("dragover", function(event) { this._on_dragover(event); }, false)
gBrowser.tabContainer.addEventListener("drop", function(event) { this._on_drop(event); }, false)
gBrowser.tabContainer.on_dragover = function(event) { return false; }
gBrowser.tabContainer.on_drop = function(event) { return false; }
gBrowser.tabContainer._on_dragover = function(event) {
var effects = this.getDropEffectForTabDrag(event);
var ind = this._tabDropIndicator;
if (effects == "" || effects == "none") {
ind.hidden = true;
return;
}
event.preventDefault();
event.stopPropagation();
if (effects == "link") {
let tab = this._getDragTargetTab(event, { ignoreTabSides: true });
if (tab) {
if (!this._dragTime) {
this._dragTime = Date.now();
}
if (Date.now() >= this._dragTime + this._dragOverDelay) {
this.selectedItem = tab;
}
ind.hidden = true;
return;
}
}
let tabRect, rect = this.arrowScrollbox.getBoundingClientRect(),
newIndex = this._getDropIndex(event),
newMarginX = ind.clientWidth / 2 - rect.left +
((newIndex === this.allTabs.length)
? (tabRect = this._getVisibleTabs().at(-1).getBoundingClientRect()).right
: (tabRect = this.allTabs[newIndex].getBoundingClientRect()).left),
newMarginY = tabRect.top - rect.top + tabRect.height / 2 - rect.height / 2;
ind.hidden = false;
ind.style.transform = "translate(" + Math.round(newMarginX) + "px," + Math.round(newMarginY) + "px)";
}
gBrowser.tabContainer._on_drop = function(event) {
var dt = event.dataTransfer;
var dropEffect = dt.dropEffect;
var draggedTab;
let movingTabs;
if (dt.mozTypesAt(0)[0] == TAB_DROP_TYPE) {
// tab copy or move
draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
// not our drop then
if (!draggedTab) {
return;
}
movingTabs = draggedTab._dragData.movingTabs;
draggedTab.container._finishGroupSelectedTabs(draggedTab);
}
this._tabDropIndicator.hidden = true;
event.stopPropagation();
if (draggedTab && dropEffect == "copy") {
// copy the dropped tab (wherever it's from)
let newIndex = this._getDropIndex(event);
let draggedTabCopy;
for (let tab of movingTabs) {
let newTab = gBrowser.duplicateTab(tab);
gBrowser.moveTabTo(newTab, newIndex++);
if (tab == draggedTab) {
draggedTabCopy = newTab;
}
}
if (draggedTab.container != this || event.shiftKey) {
this.selectedItem = draggedTabCopy;
}
} else if (draggedTab && draggedTab.container == this) {
let oldTranslate = Math.round(draggedTab._dragData.translatePos);
let tabSize = Math.round(draggedTab._dragData.tabSize);
let translateOffset = oldTranslate % tabSize;
let newTranslate = oldTranslate - translateOffset;
if (oldTranslate > 0 && translateOffset > tabSize / 2) {
newTranslate += tabSize;
} else if (oldTranslate < 0 && -translateOffset > tabSize / 2) {
newTranslate -= tabSize;
}
let dropIndex;
if (draggedTab._dragData.fromTabList) {
dropIndex = this._getDropIndex(event);
} else {
dropIndex = this._getDropIndex(event);
// "animDropIndex" in draggedTab._dragData &&
// draggedTab._dragData.animDropIndex;
}
let incrementDropIndex = true;
if (dropIndex && dropIndex > movingTabs[0]._tPos) {
dropIndex--;
incrementDropIndex = false;
}
if (oldTranslate && oldTranslate != newTranslate && !gReduceMotion) {
for (let tab of movingTabs) {
tab.toggleAttribute("tabdrop-samewindow", true);
tab.style.transform = this.verticalMode
? "translateY(" + newTranslate + "px)"
: "translateX(" + newTranslate + "px)";
let postTransitionCleanup = () => {
tab.removeAttribute("tabdrop-samewindow");
this._finishAnimateTabMove();
if (dropIndex !== false) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
gBrowser.syncThrobberAnimations(tab);
};
if (gReduceMotion) {
postTransitionCleanup();
} else {
let onTransitionEnd = transitionendEvent => {
if (
transitionendEvent.propertyName != "transform" ||
transitionendEvent.originalTarget != tab
) {
return;
}
tab.removeEventListener("transitionend", onTransitionEnd);
postTransitionCleanup();
};
tab.addEventListener("transitionend", onTransitionEnd);
}
}
} else {
this._finishAnimateTabMove();
if (dropIndex !== false) {
for (let tab of movingTabs) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
}
}
} else if (draggedTab) {
// Move the tabs. To avoid multiple tab-switches in the original window,
// the selected tab should be adopted last.
const dropIndex = this._getDropIndex(event);
let newIndex = dropIndex;
let selectedTab;
let indexForSelectedTab;
for (let i = 0; i < movingTabs.length; ++i) {
const tab = movingTabs[i];
if (tab.selected) {
selectedTab = tab;
indexForSelectedTab = newIndex;
} else {
const newTab = gBrowser.adoptTab(tab, newIndex, tab == draggedTab);
if (newTab) {
++newIndex;
}
}
}
if (selectedTab) {
const newTab = gBrowser.adoptTab(
selectedTab,
indexForSelectedTab,
selectedTab == draggedTab
);
if (newTab) {
++newIndex;
}
}
// Restore tab selection
gBrowser.addRangeToMultiSelectedTabs(
gBrowser.tabs[dropIndex],
gBrowser.tabs[newIndex - 1]
);
} else {
// Pass true to disallow dropping javascript: or data: urls
let links;
try {
links = browserDragAndDrop.dropLinks(event, true);
} catch (ex) {}
if (!links || links.length === 0) {
return;
}
let inBackground = Services.prefs.getBoolPref(
"browser.tabs.loadInBackground"
);
if (event.shiftKey) {
inBackground = !inBackground;
}
let targetTab = this._getDragTargetTab(event, { ignoreTabSides: true });
let userContextId = this.selectedItem.getAttribute("usercontextid");
let replace = !!targetTab;
let newIndex = this._getDropIndex(event);
let urls = links.map(link => link.url);
let csp = browserDragAndDrop.getCsp(event);
let triggeringPrincipal =
browserDragAndDrop.getTriggeringPrincipal(event);
(async () => {
if (
urls.length >=
Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")
) {
// Sync dialog cannot be used inside drop event handler.
let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(
urls.length,
window
);
if (!answer) {
return;
}
}
gBrowser.loadTabs(urls, {
inBackground,
replace,
allowThirdPartyFixup: true,
targetTab,
newIndex,
userContextId,
triggeringPrincipal,
csp,
});
})();
}
if (draggedTab) {
delete draggedTab._dragData;
}
}
};
Alles anzeigen
Mfg.
Endor
So hier wieder eine Deutsche Version:
// ==UserScript==
// @name zzzz-MultiRowTab_LiteforFx48.uc.js
// @namespace http://space.geocities.yahoo.co.jp/gl/alice0775
// @description Experimentelle CSS Version für Mehrzeilige Tableiste
// @include main
// @compatibility Firefox 128esr Firefox 131+
// @author Alice0775
// @version 2016/08/05 00:00 Firefox 48
// @version 2016/05/01 00:01 hide favicon if busy
// @version 2016/03/09 00:01 Bug 1222490 - Actually remove panorama for Fx45+
// @version 2016/02/09 00:01 workaround css for lwt
// @version 2016/02/09 00:00
// ==/UserScript==
"use strict";
MultiRowTabLiteforFx();
function MultiRowTabLiteforFx() {
if (!window.gBrowser) { return; }
// -- Config --
const // Anzahl der Tab-Leistenzeilen angeben oder eine unbegrenzte Anzahl von Zeilen wählen.
TabBar_Rows = false ,// [false] = unbegrenzt
// true = Begrenzte Tabzeilen - Anzahl der Zeilen angeben
Maximum_Rows = 3 ,// Tabzeilen angeben (Standard: 3 Zeilen)
// ProtonUI Erscheinungsbild der Tabs ändern
ProtonUI = true ,// [true] = Darstellung ProtonUI
// Die Höhe der Tab-Leiste entspricht der Höhe der UI-Dichte plus dem Leerraum darüber und darunter.
// false = Darstellung = wie bei browser.proton.enabled auf false, was man vor Firefox 90 noch einstellen konnte.
// Leerraum um die Tabs auf 0 anpassen, um der Höhe der UI-Dichte zu entsprechen.
// Position der Tab-Leiste.
TabBar_Position = 0 ,// [0] = Standard
// 1 = unter der Symbolleiste
// 2 = unter dem Fenster
// Standardposition der Tableiste Blenden Sie die Titelleistenschaltfläche [-□×] aus und verwenden Sie die Breite der Tableiste entsprechend
TitleBar_Button_Autohide = false ,// [false] = Aktiviert
// true = Deaktiviert
// Außeren Rahmen der Titelleistenschaltfläche [-□×] reduzieren und transparent machen, obere rechte Ecke der Tab-Leiste auf ihre ursprüngliche Größe zurücksetzen und Transparenz aufheben.
// Tab-Höhe „UI-Dichte“
UI_Density_Compact = 29 ,// Standard = 29 Pixel bei Kompakt
UI_Density_Normal = 36 ,// Standard = 36 Pixel bei Normal
UI_Density_Touch = 41 ,// Standard = 41 Pixel bei Touch
// Entsprechender CSS Code in UserChrome.css wird vorrangig behandelt!
// Tab-Breite
// Bei gleichen Werten bei Min und Max, wird Tabbreite fixiert!
Tab_Min_Width = 76 ,// Standard - Mindestwert = 76px
Tab_Max_Width = 225 ,// Standard - Maxwert = 225px
// Entsprechender CSS Code in UserChrome.css wird vorrangig behandelt!
// .Tab-Drop-Indikator-Icon-Ersetzung.
Tab_Drop_Indicator = false ,// [false] = Stecknadel Symbol 📍
// true = Rote Linie (2px × 29px) als Symbol
// Ränder auf der linken und rechten Seite der Tabs
Tab_Separators = false ,// [false] = Nicht anzeigen
// true = Anzeigen
// Rahmen CSS wurde extrahiert und angepasst, an Aussehen wie bei browser.proton.enabled
// auf false, was man vor Firefox 90 noch einstellen konnte.
// Tab-Leisten-Ziehbereich
Left_Drag_Area = 0 ,// Linker Ziehbereich Breite: Standard 40 Pixel
Right_Drag_Area = 0 ,// Rechter Ziehbereich Breite: Standard 40 Pixel
Window_Maximize_Left_Drag_Area = false ,// true = Linken Ziehbereich bei maximiertem Fenster anzeigen. Standardmäßig ausgeblendet.
Fullscreen_Drag_Area = false ,// true = Linken und rechten Ziehbereich bei Vollbild anzeigen. Standardmäßig ausgeblendet.
// Angeheftete Tabs neu positionieren
Separate_Tabs_and_PinnedTabs = false ,// [false] = Standard
// true = Angeheftete Tabs von der Tab-Leiste lösen und in die darüber liegende Zeile verschieben.
// „Tab schließen“ Schaltfläche .
Tab_Close_Button = 0 ,// [0] = Standard
// 1 = Ausgeblendet
// 2 = Auf allen Tabs anzeigen
// 3 = Nur bei Mausberührung anzeigen
// Alle Tabs Schaltfläche
All_Tabs_Button = false ,// [false] = ausblenden
// true = anzeigen
// -- Config End --
css = `
#TabsToolbar {
:root[uidensity="compact"] & { --tab-min-height: ${UI_Density_Compact}px; }
:root:not([uidensity]) & { --tab-min-height: ${UI_Density_Normal}px; }
:root[uidensity="touch"] & { --tab-min-height: ${UI_Density_Touch}px; }
${Tab_Drop_Indicator ? `
#tabbrowser-tabs > .tab-drop-indicator {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAAdCAIAAAAPVCo9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAASSURBVBhXY3growJEQ5+SUQEAOb1EM8kwskcAAAAASUVORK5CYII=) no-repeat center !important;
}
` : ``}
.titlebar-spacer[type="pre-tabs"] {
width: ${Left_Drag_Area}px !important;
}
.titlebar-spacer[type="post-tabs"] {
width: ${Right_Drag_Area}px !important;
}
${Window_Maximize_Left_Drag_Area ? `
.titlebar-spacer {
:root:not([sizemode="normal"], [inFullscreen]) &[type="pre-tabs"] {
display: block !important;
}
}
` : ``}
${Fullscreen_Drag_Area ? `
.titlebar-spacer {
:root[inFullscreen] &, :root:not([tabsintitlebar]) & {
display: block !important;
}
}
` : ``}
#tabbrowser-arrowscrollbox {
&::part(scrollbox) {
&:has(+ spacer) > slot,
.scrollbox-clip > & {
flex-wrap: wrap;
}
${TabBar_Rows ? `
max-height: calc((var(--tab-min-height) + ${ProtonUI ? 8 : 0}px) * ${Maximum_Rows});
overflow: hidden auto;
& scrollbar {
-moz-window-dragging: no-drag;
}
` : ``}
}
&::part(overflow-start-indicator),
&::part(overflow-end-indicator),
&::part(scrollbutton-up),
&::part(scrollbutton-down) {
display: none;
}
${Separate_Tabs_and_PinnedTabs ? `
&::part(scrollbox) {
&:has(+ spacer) > slot::after,
.scrollbox-clip > &::after {
display: flow-root list-item;
content: "";
flex-basis: -moz-available;
height: 0;
overflow: hidden;
}
}
.tabbrowser-tab:not([pinned]) {
#tabbrowser-tabs[haspinnedtabs] & {
&, & + :not(#tabs-newtab-button) {
order: 1;
}
}
}
` : ``}
.tabbrowser-tab[fadein]:not([pinned]) {
--tab-min-width: ${Tab_Min_Width}px;
--tab-max-width: ${Tab_Max_Width}px;
max-width: var(--tab-max-width);
${Tab_Close_Button !== 0 ? `
${Tab_Close_Button === 1 ? `
.tab-close-button {
display: none !important;
}
` : Tab_Close_Button === 2 ? `
.tab-close-button {
display: block !important;
}
` : Tab_Close_Button === 3 ? `
.tab-close-button {
opacity: 0;
}
&:hover .tab-close-button {
opacity: 1;
display: block !important;
}
` : ``}
` : ``}
}
#tabbrowser-tabs[haspinnedtabs]:not([positionpinnedtabs]):not([orient="vertical"]) > & > .tabbrowser-tab:nth-child(1 of :not([pinned], [hidden])) {
margin-inline-start: 0 !important;
}
}
${ProtonUI ? `` : `
.toolbarbutton-1 {
margin: 0 !important;
padding: 0 !important;
}
.tabbrowser-tab,
#tabs-newtab-button {
height: var(--tab-min-height);
padding: 0 !important;
}
.tab-background {
box-shadow: none !important;
margin-block: 0 !important;
}
.tabbrowser-tab[usercontextid] > .tab-stack > .tab-background > .tab-context-line {
margin: 1px 2px 0 !important;
}
`}
${Tab_Separators ? `
.titlebar-spacer[type="pre-tabs"] {
border-inline-end: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}
.tabbrowser-tab::after,
.tabbrowser-tab::before {
border-left: 1px solid color-mix(in srgb, currentColor 50%, transparent);
height: calc(var(--tab-min-height) - 15%);
margin-block: auto;
}
.tabbrowser-tab:hover::after,
.tabbrowser-tab[multiselected]::after,
#tabbrowser-tabs:not([movingtab]) .tabbrowser-tab:has(+ .tabbrowser-tab:hover)::after,
#tabbrowser-tabs:not([movingtab]) .tabbrowser-tab:has(+ [multiselected])::after {
height: 100%;
}
.tabbrowser-tab::after,
#tabbrowser-tabs[movingtab] .tabbrowser-tab[visuallyselected]::before {
content: "";
display: block;
}
` : ``}
${All_Tabs_Button ? `` : `
#alltabs-button {
display: none;
}
`}
}
${TabBar_Position === 0 ? `
#TabsToolbar {
.titlebar-buttonbox-container {
height: calc(var(--tab-min-height) + ${ProtonUI ? 8 : 0}px);
margin-bottom: 0 !important;
${TitleBar_Button_Autohide ? `
background-color: color-mix(in srgb, currentColor 20%, transparent);
height: 6px;
opacity: 0;
position: fixed;
right: 0;
z-index: 2147483647;
.titlebar-button {
opacity: 0;
padding: 0;
}
&:hover {
height: calc(var(--tab-min-height) + ${ProtonUI ? 8 : 0}px);
opacity: 1;
.titlebar-button {
opacity: 1;
padding: 8px 17px;
}
}
` : ``}
}
}
` : `
#nav-bar {
:root:not([inFullscreen]) #toolbar-menubar:not([inactive]) + & > .titlebar-buttonbox-container {
display: none;
}
.titlebar-button {
padding-block: 0 !important;
}
}
`}
${TabBar_Position !== 2 ? `` : `
body {
& > #fullscr-toggler[hidden] + tabbox,
:root[inFullscreen] & > tabbox:hover {
border-top: 0.5px solid var(--toolbar-bgcolor);
}
& > tabbox > #navigator-toolbox {
border-block: none !important;
}
:root[inFullscreen] & {
& > #navigator-toolbox {
transition: none;
&:has(~ tabbox:hover) {
margin-top: 0 !important;
}
&:hover ~ tabbox > #navigator-toolbox {
max-height: 100%;
}}
& > tabbox:not(:hover) {
border-top: .5px solid transparent;
& > #navigator-toolbox {
max-height: 0;
}
}
}
}
`}
`,
sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
uri = Services.io.newURI("data:text/css;charset=UTF=8," + encodeURIComponent(css));
if (TabBar_Rows == false) {
["0", "2"].find(type => {
if(sss.sheetRegistered(uri, type)) sss.unregisterSheet(uri, type); sss.loadAndRegisterSheet(uri, type);
});
} else {
["0", "2", "SSTabRestored", "TabMove", "TabOpen", "TabSelect"].find(type => {
if(sss.sheetRegistered(uri, type)) sss.unregisterSheet(uri, type); sss.loadAndRegisterSheet(uri, type);
gBrowser.tabContainer.addEventListener(type, (e) => { e.target.scrollIntoView({ block: "nearest" }); });
});
}
if (TabBar_Position !== 0) {
if (TabBar_Position === 1) {
document.getElementById("navigator-toolbox").prepend(
document.getElementById("toolbar-menubar"),
document.getElementById("nav-bar"),
document.getElementById("PersonalToolbar"),
document.getElementById("titlebar"),
);
} else {
document.getElementById("navigator-toolbox").prepend(
document.getElementById("toolbar-menubar"),
document.getElementById("nav-bar"),
document.getElementById("PersonalToolbar"),
);
}
document.getElementById("nav-bar").appendChild(
document.querySelector("#TabsToolbar > .titlebar-buttonbox-container")
);
}
if (TabBar_Position === 2) {
document.body.appendChild(
document.createXULElement("tabbox")
).appendChild(
document.importNode(document.getElementById("navigator-toolbox"))
).appendChild(
document.getElementById("titlebar")
);
}
gBrowser.tabContainer.addEventListener("dragover", function(event) { this._on_dragover(event); }, false)
gBrowser.tabContainer.addEventListener("drop", function(event) { this._on_drop(event); }, false)
gBrowser.tabContainer.on_dragover = function(event) { return false; }
gBrowser.tabContainer.on_drop = function(event) { return false; }
gBrowser.tabContainer._on_dragover = function(event) {
var effects = this.getDropEffectForTabDrag(event);
var ind = this._tabDropIndicator;
if (effects == "" || effects == "none") {
ind.hidden = true;
return;
}
event.preventDefault();
event.stopPropagation();
var arrowScrollbox = this.arrowScrollbox;
if (effects == "link") {
let tab = this._getDragTargetTab(event, { ignoreTabSides: true });
if (tab) {
if (!this._dragTime) {
this._dragTime = Date.now();
}
if (Date.now() >= this._dragTime + this._dragOverDelay) {
this.selectedItem = tab;
}
ind.hidden = true;
return;
}
}
var tabRect, rect = arrowScrollbox.getBoundingClientRect();
var newMarginX, newMarginY;
let newIndex = this._getDropIndex(event);
let children = this.allTabs;
if (newIndex == children.length) {
tabRect = this._getVisibleTabs().at(-1).getBoundingClientRect();
newMarginX = tabRect.right - rect.left;
} else {
tabRect = children[newIndex].getBoundingClientRect();
newMarginX = tabRect.left - rect.left;
}
newMarginY = tabRect.top - rect.top + tabRect.height / 2 - rect.height / 2;
ind.hidden = false;
newMarginX += ind.clientWidth / 2;
ind.style.transform = "translate(" + Math.round(newMarginX) + "px," + Math.round(newMarginY) + "px)";
}
gBrowser.tabContainer._on_drop = function(event) {
var dt = event.dataTransfer;
var dropEffect = dt.dropEffect;
var draggedTab;
let movingTabs;
if (dt.mozTypesAt(0)[0] == TAB_DROP_TYPE) {
// tab copy or move
draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
// not our drop then
if (!draggedTab) {
return;
}
movingTabs = draggedTab._dragData.movingTabs;
draggedTab.container._finishGroupSelectedTabs(draggedTab);
}
this._tabDropIndicator.hidden = true;
event.stopPropagation();
if (draggedTab && dropEffect == "copy") {
// copy the dropped tab (wherever it's from)
let newIndex = this._getDropIndex(event);
let draggedTabCopy;
for (let tab of movingTabs) {
let newTab = gBrowser.duplicateTab(tab);
gBrowser.moveTabTo(newTab, newIndex++);
if (tab == draggedTab) {
draggedTabCopy = newTab;
}
}
if (draggedTab.container != this || event.shiftKey) {
this.selectedItem = draggedTabCopy;
}
} else if (draggedTab && draggedTab.container == this) {
let oldTranslate = Math.round(draggedTab._dragData.translatePos);
let tabSize = Math.round(draggedTab._dragData.tabSize);
let translateOffset = oldTranslate % tabSize;
let newTranslate = oldTranslate - translateOffset;
if (oldTranslate > 0 && translateOffset > tabSize / 2) {
newTranslate += tabSize;
} else if (oldTranslate < 0 && -translateOffset > tabSize / 2) {
newTranslate -= tabSize;
}
let dropIndex;
if (draggedTab._dragData.fromTabList) {
dropIndex = this._getDropIndex(event);
} else {
dropIndex = this._getDropIndex(event);
// "animDropIndex" in draggedTab._dragData &&
// draggedTab._dragData.animDropIndex;
}
let incrementDropIndex = true;
if (dropIndex && dropIndex > movingTabs[0]._tPos) {
dropIndex--;
incrementDropIndex = false;
}
if (oldTranslate && oldTranslate != newTranslate && !gReduceMotion) {
for (let tab of movingTabs) {
tab.toggleAttribute("tabdrop-samewindow", true);
tab.style.transform = this.verticalMode
? "translateY(" + newTranslate + "px)"
: "translateX(" + newTranslate + "px)";
let postTransitionCleanup = () => {
tab.removeAttribute("tabdrop-samewindow");
this._finishAnimateTabMove();
if (dropIndex !== false) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
gBrowser.syncThrobberAnimations(tab);
};
if (gReduceMotion) {
postTransitionCleanup();
} else {
let onTransitionEnd = transitionendEvent => {
if (
transitionendEvent.propertyName != "transform" ||
transitionendEvent.originalTarget != tab
) {
return;
}
tab.removeEventListener("transitionend", onTransitionEnd);
postTransitionCleanup();
};
tab.addEventListener("transitionend", onTransitionEnd);
}
}
} else {
this._finishAnimateTabMove();
if (dropIndex !== false) {
for (let tab of movingTabs) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
}
}
} else if (draggedTab) {
// Move the tabs. To avoid multiple tab-switches in the original window,
// the selected tab should be adopted last.
const dropIndex = this._getDropIndex(event);
let newIndex = dropIndex;
let selectedTab;
let indexForSelectedTab;
for (let i = 0; i < movingTabs.length; ++i) {
const tab = movingTabs[i];
if (tab.selected) {
selectedTab = tab;
indexForSelectedTab = newIndex;
} else {
const newTab = gBrowser.adoptTab(tab, newIndex, tab == draggedTab);
if (newTab) {
++newIndex;
}
}
}
if (selectedTab) {
const newTab = gBrowser.adoptTab(
selectedTab,
indexForSelectedTab,
selectedTab == draggedTab
);
if (newTab) {
++newIndex;
}
}
// Restore tab selection
gBrowser.addRangeToMultiSelectedTabs(
gBrowser.tabs[dropIndex],
gBrowser.tabs[newIndex - 1]
);
} else {
// Pass true to disallow dropping javascript: or data: urls
let links;
try {
links = browserDragAndDrop.dropLinks(event, true);
} catch (ex) {}
if (!links || links.length === 0) {
return;
}
let inBackground = Services.prefs.getBoolPref(
"browser.tabs.loadInBackground"
);
if (event.shiftKey) {
inBackground = !inBackground;
}
let targetTab = this._getDragTargetTab(event, { ignoreTabSides: true });
let userContextId = this.selectedItem.getAttribute("usercontextid");
let replace = !!targetTab;
let newIndex = this._getDropIndex(event);
let urls = links.map(link => link.url);
let csp = browserDragAndDrop.getCsp(event);
let triggeringPrincipal =
browserDragAndDrop.getTriggeringPrincipal(event);
(async () => {
if (
urls.length >=
Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")
) {
// Sync dialog cannot be used inside drop event handler.
let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(
urls.length,
window
);
if (!answer) {
return;
}
}
gBrowser.loadTabs(urls, {
inBackground,
replace,
allowThirdPartyFixup: true,
targetTab,
newIndex,
userContextId,
triggeringPrincipal,
csp,
});
})();
}
if (draggedTab) {
delete draggedTab._dragData;
}
}
};
Alles anzeigen
Es wurde nur eine weitere Option bei Tab-schließen Schaltfläche hinzugefügt.
Er hat auch ein paar Leerzeichen entfernt wo sie nicht hin gehörten.
Mfg.
Endor
Hallo Mira_Belle .
Ja du hast recht. Das ist heute schon die zweite neue Version.
Danke für die Info.
Deutsche Version folgt.
Mfg.
Endor
Genau. Dann öffnet sich eine neue Seite und ein paar Augenblicke später
startet automatisch der Download.
2002Andreas
vielen Dank!!
Mfg.
Endor
Hallo Herzmann.
Hier das japanische Original:
// ==UserScript==
// @name zzzz-MultiRowTab_LiteforFx48.uc.js
// @namespace http://space.geocities.yahoo.co.jp/gl/alice0775
// @description 多段タブもどき実験版 CSS入れ替えまくりLiteバージョン
// @include main
// @compatibility Firefox128esr Firefox131+
// @author Alice0775
// @version 2016/08/05 00:00 Firefox 48
// @version 2016/05/01 00:01 hide favicon if busy
// @version 2016/03/09 00:01 Bug 1222490 - Actually remove panorama for Fx45+
// @version 2016/02/09 00:01 workaround css for lwt
// @version 2016/02/09 00:00
// ==/UserScript==
"use strict";
MultiRowTabLiteforFx();
function MultiRowTabLiteforFx() {
if (!window.gBrowser) { return; }
// -- Config --
const // タブバーの段数
TabBar_Rows = false ,// [false] = 段数無制限
// true = 段数指定
Maximum_Rows = 3 ,// 段数指定 デフォルト3段
// ProtonUI タブの見た目
ProtonUI = true ,// [true] = ProtonUI デフォルト
// false = Firefox90以前は出来た設定で browser.proton.enabled を false にした時の見た目にする
// タブの周りにある空白を0にしてUI密度の高さにするので上下にあった空白の分-8px低くなります
// タブバーの位置
TabBar_Position = 0 ,// [0] = ツールバーの上 デフォルト
// 1 = ツールバーの下
// 2 = ウインドウの下
// タブバーの位置デフォルト用 タイトルバーボタン[-□×]を隠くしてその分タブバーの横幅を広く使う
TitleBar_Button_Autohide = false ,// [false] = 使用しない
// true = 使用する
// タイトルバーボタン[-□×]の外枠を小さくして透明化、タブバーの右上をマウスオーバーで元のサイズに戻して透明化を解除
// UI密度 タブの高さ
UI_Density_Compact = 29 ,// デフォルト29px コンパクト
UI_Density_Normal = 36 ,// デフォルト36px 通常
UI_Density_Touch = 41 ,// デフォルト41px タッチ
// 同じ様なCSSを書いた場合userChrome.cssが反映されます
// タブの横幅
Tab_Min_Width = 76 ,// デフォルト76px 最小値
Tab_Max_Width = 225 ,// デフォルト225px 最大値
// 指定する数値を両方同じにすると横幅が固定化します
// 同じ様なCSSを書いた場合userChrome.cssが反映されます
// タブをドラッグ&ドロップで移動中に表示されるアイコンの差し替え
Tab_Drop_Indicator = false ,// [false] = しない デフォルトアイコン
// true = する 赤線アイコン(2px×29px)
// タブの左右に境界線
Tab_Separators = false ,// [false] = 表示しない
// true = 表示する
// Firefox90以前は出来た設定で browser.proton.enabled を false にしたら表示されていた境界線のCSSを抽出して調整しています
// タブバーのドラッグ領域
Left_Drag_Area = 0 ,// デフォルト40px 左のドラッグ領域
Right_Drag_Area = 0 ,// デフォルト40px 右のドラッグ領域
Window_Maximize_Left_Drag_Area = false ,// [false] = デフォルト
// true = ウィンドウを最大化した時、非表示になる 左のドラッグ領域が表示出来ます
Fullscreen_Drag_Area = false ,// [false] = デフォルト
// true = フルスクリーンにした時、非表示になる 左右のドラッグ領域が表示出来ます
// ピン留めタブの位置
Separate_Tabs_and_PinnedTabs = false ,// [false] = デフォルト
// true = ピン留めタブをタブの行から分離して上に出来る行へ移動する
// タブを閉じるボタン
Tab_Close_Button = 0 ,// [0] = デフォルト
// 1 = すべてのタブに表示
// 2 = タブをマウスオーバーで表示
// タブを一覧表示するボタン
All_Tabs_Button = false ,// [false] = 非表示
// true = 表示
// -- Config End --
css = `
#TabsToolbar {
:root[uidensity="compact"] & { --tab-min-height: ${UI_Density_Compact}px; }
:root:not([uidensity]) & { --tab-min-height: ${UI_Density_Normal}px; }
:root[uidensity="touch"] & { --tab-min-height: ${UI_Density_Touch}px; }
${Tab_Drop_Indicator ? `
#tabbrowser-tabs > .tab-drop-indicator {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAAdCAIAAAAPVCo9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAASSURBVBhXY3growJEQ5+SUQEAOb1EM8kwskcAAAAASUVORK5CYII=) no-repeat center !important;
}
` : ``}
.titlebar-spacer[type="pre-tabs"] {
width: ${Left_Drag_Area}px !important;
}
.titlebar-spacer[type="post-tabs"] {
width: ${Right_Drag_Area}px !important;
}
${Window_Maximize_Left_Drag_Area ? `
.titlebar-spacer {
:root:not([sizemode="normal"], [inFullscreen]) &[type="pre-tabs"] {
display: block !important;
}
}
` : ``}
${Fullscreen_Drag_Area ? `
.titlebar-spacer {
:root[inFullscreen] &, :root:not([tabsintitlebar]) & {
display: block !important;
}
}
` : ``}
#tabbrowser-arrowscrollbox {
&::part(scrollbox) {
&:has(+ spacer) > slot,
.scrollbox-clip > & {
flex-wrap: wrap;
}
${TabBar_Rows ? `
max-height: calc((var(--tab-min-height) + ${ProtonUI ? 8 : 0}px) * ${Maximum_Rows});
overflow: hidden auto;
& scrollbar {
-moz-window-dragging: no-drag;
}
` : ``}
}
&::part(overflow-start-indicator),
&::part(overflow-end-indicator),
&::part(scrollbutton-up),
&::part(scrollbutton-down) {
display: none;
}
${Separate_Tabs_and_PinnedTabs ? `
&::part(scrollbox) {
&:has(+ spacer) > slot::after,
.scrollbox-clip > &::after {
display: flow-root list-item;
content: "";
flex-basis: -moz-available;
height: 0;
overflow: hidden;
}
}
.tabbrowser-tab:not([pinned]) {
#tabbrowser-tabs[haspinnedtabs] & {
&, & + :not(#tabs-newtab-button) {
order: 1;
}
}
}
` : ``}
.tabbrowser-tab[fadein]:not([pinned]) {
--tab-min-width: ${Tab_Min_Width}px;
--tab-max-width: ${Tab_Max_Width}px;
max-width: var(--tab-max-width);
${Tab_Close_Button !== 0 ? `
${Tab_Close_Button === 1 ? `
.tab-close-button {
display : block !important;
}
` : Tab_Close_Button === 2 ? `
.tab-close-button {
opacity: 0;
}
&:hover .tab-close-button {
opacity: 1;
display : block !important;
}
` : ``}
` : ``}
}
#tabbrowser-tabs[haspinnedtabs]:not([positionpinnedtabs]):not([orient="vertical"]) > & > .tabbrowser-tab:nth-child(1 of :not([pinned], [hidden])) {
margin-inline-start: 0 !important;
}
}
${ProtonUI ? `` : `
.toolbarbutton-1 {
margin: 0 !important;
padding: 0 !important;
}
.tabbrowser-tab,
#tabs-newtab-button {
height: var(--tab-min-height);
padding: 0 !important;
}
.tab-background {
box-shadow: none !important;
margin-block: 0 !important;
}
.tabbrowser-tab[usercontextid] > .tab-stack > .tab-background > .tab-context-line {
margin: 1px 2px 0 !important;
}
`}
${Tab_Separators ? `
.titlebar-spacer[type="pre-tabs"] {
border-inline-end: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}
.tabbrowser-tab::after,
.tabbrowser-tab::before {
border-left: 1px solid color-mix(in srgb, currentColor 50%, transparent);
height: calc(var(--tab-min-height) - 15%);
margin-block: auto;
}
.tabbrowser-tab:hover::after,
.tabbrowser-tab[multiselected]::after,
#tabbrowser-tabs:not([movingtab]) .tabbrowser-tab:has(+ .tabbrowser-tab:hover)::after,
#tabbrowser-tabs:not([movingtab]) .tabbrowser-tab:has(+ [multiselected])::after {
height: 100%;
}
.tabbrowser-tab::after,
#tabbrowser-tabs[movingtab] .tabbrowser-tab[visuallyselected]::before {
content: "";
display: block;
}
` : ``}
${All_Tabs_Button ? `` : `
#alltabs-button {
display: none;
}
`}
}
${TabBar_Position === 0 ? `
#TabsToolbar {
.titlebar-buttonbox-container {
height: calc(var(--tab-min-height) + ${ProtonUI ? 8 : 0}px);
margin-bottom: 0 !important;
${TitleBar_Button_Autohide ? `
background-color: color-mix(in srgb, currentColor 20%, transparent);
height: 6px;
opacity: 0;
position: fixed;
right: 0;
z-index: 2147483647;
.titlebar-button {
opacity: 0;
padding: 0;
}
&:hover {
height: calc(var(--tab-min-height) + ${ProtonUI ? 8 : 0}px);
opacity: 1;
.titlebar-button {
opacity: 1;
padding: 8px 17px;
}
}
` : ``}
}
}
` : `
#nav-bar {
:root:not([inFullscreen]) #toolbar-menubar:not([inactive]) + & > .titlebar-buttonbox-container {
display: none;
}
.titlebar-button {
padding-block: 0 !important;
}
}
`}
${TabBar_Position !== 2 ? `` : `
body {
& > #fullscr-toggler[hidden] + tabbox,
:root[inFullscreen] & > tabbox:hover {
border-top: 0.5px solid var(--toolbar-bgcolor);
}
& > tabbox > #navigator-toolbox {
border-block: none !important;
}
:root[inFullscreen] & {
& > #navigator-toolbox {
transition: none;
&:has(~ tabbox:hover) {
margin-top: 0 !important;
}
&:hover ~ tabbox > #navigator-toolbox {
max-height: 100%;
}}
& > tabbox:not(:hover) {
border-top: .5px solid transparent;
& > #navigator-toolbox {
max-height: 0;
}
}
}
}
`}
`,
sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
uri = Services.io.newURI("data:text/css;charset=UTF=8," + encodeURIComponent(css));
if (TabBar_Rows == false) {
["0", "2"].find(type => {
if(sss.sheetRegistered(uri, type)) sss.unregisterSheet(uri, type); sss.loadAndRegisterSheet(uri, type);
});
} else {
["0", "2", "SSTabRestored", "TabMove", "TabOpen", "TabSelect"].find(type => {
if(sss.sheetRegistered(uri, type)) sss.unregisterSheet(uri, type); sss.loadAndRegisterSheet(uri, type);
gBrowser.tabContainer.addEventListener(type, (e) => { e.target.scrollIntoView({ block: "nearest" }); });
});
}
if (TabBar_Position !== 0) {
if (TabBar_Position === 1) {
document.getElementById("navigator-toolbox").prepend(
document.getElementById("toolbar-menubar"),
document.getElementById("nav-bar"),
document.getElementById("PersonalToolbar"),
document.getElementById("titlebar"),
);
} else {
document.getElementById("navigator-toolbox").prepend(
document.getElementById("toolbar-menubar"),
document.getElementById("nav-bar"),
document.getElementById("PersonalToolbar"),
);
}
document.getElementById("nav-bar").appendChild(
document.querySelector("#TabsToolbar > .titlebar-buttonbox-container")
);
}
if (TabBar_Position === 2) {
document.body.appendChild(
document.createXULElement("tabbox")
).appendChild(
document.importNode(document.getElementById("navigator-toolbox"))
).appendChild(
document.getElementById("titlebar")
);
}
gBrowser.tabContainer.addEventListener("dragover", function(event) { this._on_dragover(event); }, false)
gBrowser.tabContainer.addEventListener("drop", function(event) { this._on_drop(event); }, false)
gBrowser.tabContainer.on_dragover = function(event) { return false; }
gBrowser.tabContainer.on_drop = function(event) { return false; }
gBrowser.tabContainer._on_dragover = function(event) {
var effects = this.getDropEffectForTabDrag(event);
var ind = this._tabDropIndicator;
if (effects == "" || effects == "none") {
ind.hidden = true;
return;
}
event.preventDefault();
event.stopPropagation();
var arrowScrollbox = this.arrowScrollbox;
if (effects == "link") {
let tab = this._getDragTargetTab(event, { ignoreTabSides: true });
if (tab) {
if (!this._dragTime) {
this._dragTime = Date.now();
}
if (Date.now() >= this._dragTime + this._dragOverDelay) {
this.selectedItem = tab;
}
ind.hidden = true;
return;
}
}
var tabRect, rect = arrowScrollbox.getBoundingClientRect();
var newMarginX, newMarginY;
let newIndex = this._getDropIndex(event);
let children = this.allTabs;
if (newIndex == children.length) {
tabRect = this._getVisibleTabs().at(-1).getBoundingClientRect();
newMarginX = tabRect.right - rect.left;
} else {
tabRect = children[newIndex].getBoundingClientRect();
newMarginX = tabRect.left - rect.left;
}
newMarginY = tabRect.top - rect.top + tabRect.height / 2 - rect.height / 2;
ind.hidden = false;
newMarginX += ind.clientWidth / 2;
ind.style.transform = "translate(" + Math.round(newMarginX) + "px," + Math.round(newMarginY) + "px)";
}
gBrowser.tabContainer._on_drop = function(event) {
var dt = event.dataTransfer;
var dropEffect = dt.dropEffect;
var draggedTab;
let movingTabs;
if (dt.mozTypesAt(0)[0] == TAB_DROP_TYPE) {
// tab copy or move
draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
// not our drop then
if (!draggedTab) {
return;
}
movingTabs = draggedTab._dragData.movingTabs;
draggedTab.container._finishGroupSelectedTabs(draggedTab);
}
this._tabDropIndicator.hidden = true;
event.stopPropagation();
if (draggedTab && dropEffect == "copy") {
// copy the dropped tab (wherever it's from)
let newIndex = this._getDropIndex(event);
let draggedTabCopy;
for (let tab of movingTabs) {
let newTab = gBrowser.duplicateTab(tab);
gBrowser.moveTabTo(newTab, newIndex++);
if (tab == draggedTab) {
draggedTabCopy = newTab;
}
}
if (draggedTab.container != this || event.shiftKey) {
this.selectedItem = draggedTabCopy;
}
} else if (draggedTab && draggedTab.container == this) {
let oldTranslate = Math.round(draggedTab._dragData.translatePos);
let tabSize = Math.round(draggedTab._dragData.tabSize);
let translateOffset = oldTranslate % tabSize;
let newTranslate = oldTranslate - translateOffset;
if (oldTranslate > 0 && translateOffset > tabSize / 2) {
newTranslate += tabSize;
} else if (oldTranslate < 0 && -translateOffset > tabSize / 2) {
newTranslate -= tabSize;
}
let dropIndex;
if (draggedTab._dragData.fromTabList) {
dropIndex = this._getDropIndex(event);
} else {
dropIndex = this._getDropIndex(event);
// "animDropIndex" in draggedTab._dragData &&
// draggedTab._dragData.animDropIndex;
}
let incrementDropIndex = true;
if (dropIndex && dropIndex > movingTabs[0]._tPos) {
dropIndex--;
incrementDropIndex = false;
}
if (oldTranslate && oldTranslate != newTranslate && !gReduceMotion) {
for (let tab of movingTabs) {
tab.toggleAttribute("tabdrop-samewindow", true);
tab.style.transform = this.verticalMode
? "translateY(" + newTranslate + "px)"
: "translateX(" + newTranslate + "px)";
let postTransitionCleanup = () => {
tab.removeAttribute("tabdrop-samewindow");
this._finishAnimateTabMove();
if (dropIndex !== false) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
gBrowser.syncThrobberAnimations(tab);
};
if (gReduceMotion) {
postTransitionCleanup();
} else {
let onTransitionEnd = transitionendEvent => {
if (
transitionendEvent.propertyName != "transform" ||
transitionendEvent.originalTarget != tab
) {
return;
}
tab.removeEventListener("transitionend", onTransitionEnd);
postTransitionCleanup();
};
tab.addEventListener("transitionend", onTransitionEnd);
}
}
} else {
this._finishAnimateTabMove();
if (dropIndex !== false) {
for (let tab of movingTabs) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
}
}
} else if (draggedTab) {
// Move the tabs. To avoid multiple tab-switches in the original window,
// the selected tab should be adopted last.
const dropIndex = this._getDropIndex(event);
let newIndex = dropIndex;
let selectedTab;
let indexForSelectedTab;
for (let i = 0; i < movingTabs.length; ++i) {
const tab = movingTabs[i];
if (tab.selected) {
selectedTab = tab;
indexForSelectedTab = newIndex;
} else {
const newTab = gBrowser.adoptTab(tab, newIndex, tab == draggedTab);
if (newTab) {
++newIndex;
}
}
}
if (selectedTab) {
const newTab = gBrowser.adoptTab(
selectedTab,
indexForSelectedTab,
selectedTab == draggedTab
);
if (newTab) {
++newIndex;
}
}
// Restore tab selection
gBrowser.addRangeToMultiSelectedTabs(
gBrowser.tabs[dropIndex],
gBrowser.tabs[newIndex - 1]
);
} else {
// Pass true to disallow dropping javascript: or data: urls
let links;
try {
links = browserDragAndDrop.dropLinks(event, true);
} catch (ex) {}
if (!links || links.length === 0) {
return;
}
let inBackground = Services.prefs.getBoolPref(
"browser.tabs.loadInBackground"
);
if (event.shiftKey) {
inBackground = !inBackground;
}
let targetTab = this._getDragTargetTab(event, { ignoreTabSides: true });
let userContextId = this.selectedItem.getAttribute("usercontextid");
let replace = !!targetTab;
let newIndex = this._getDropIndex(event);
let urls = links.map(link => link.url);
let csp = browserDragAndDrop.getCsp(event);
let triggeringPrincipal =
browserDragAndDrop.getTriggeringPrincipal(event);
(async () => {
if (
urls.length >=
Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")
) {
// Sync dialog cannot be used inside drop event handler.
let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(
urls.length,
window
);
if (!answer) {
return;
}
}
gBrowser.loadTabs(urls, {
inBackground,
replace,
allowThirdPartyFixup: true,
targetTab,
newIndex,
userContextId,
triggeringPrincipal,
csp,
});
})();
}
if (draggedTab) {
delete draggedTab._dragData;
}
}
};
Alles anzeigen
Die englische Übersetzung kannst Du gerne selbst machen.Den Link baue ich nachher gleich bei Github ein. Gute Idee.
Der Link ist doch auf der Hauptseite bei mir schon vorhanden.
Siehe hier ganz unten:
Mfg.
Endor
Hallo Herzmann.
Der Autor hat seine Version aktualisiert:
// ==UserScript==
// @name zzzz-MultiRowTab_LiteforFx48.uc.js
// @namespace http://space.geocities.yahoo.co.jp/gl/alice0775
// @description Experimentelle CSS Version für Mehrzeilige Tableiste
// @include main
// @compatibility Firefox 128esr Firefox 131+
// @author Alice0775
// @version 2016/08/05 00:00 Firefox 48
// @version 2016/05/01 00:01 hide favicon if busy
// @version 2016/03/09 00:01 Bug 1222490 - Actually remove panorama for Fx45+
// @version 2016/02/09 00:01 workaround css for lwt
// @version 2016/02/09 00:00
// ==/UserScript==
"use strict";
MultiRowTabLiteforFx();
function MultiRowTabLiteforFx() {
if (!window.gBrowser) { return; }
// -- Config --
const // Anzahl der Tab-Leistenzeilen angeben oder eine unbegrenzte Anzahl von Zeilen wählen.
TabBar_Rows = false ,// [false] = unbegrenzt
// true = Begrenzte Tabzeilen - Anzahl der Zeilen angeben
Maximum_Rows = 3 ,// Tabzeilen angeben (Standard: 3 Zeilen)
// ProtonUI Erscheinungsbild der Tabs ändern
ProtonUI = true ,// [true] = Darstellung ProtonUI
// Die Höhe der Tab-Leiste entspricht der Höhe der UI-Dichte plus dem Leerraum darüber und darunter.
// false = Darstellung = wie bei browser.proton.enabled auf false, was man vor Firefox 90 noch einstellen konnte.
// Leerraum um die Tabs auf 0 anpassen, um der Höhe der UI-Dichte zu entsprechen.
// Position der Tab-Leiste.
TabBar_Position = 0 ,// [0] = Standard
// 1 = unter der Symbolleiste
// 2 = unter dem Fenster
// Standardposition der Tableiste Blenden Sie die Titelleistenschaltfläche [-□×] aus und verwenden Sie die Breite der Tableiste entsprechend
TitleBar_Button_Autohide = false ,// [false] = Aktiviert
// true = Deaktiviert
// Außeren Rahmen der Titelleistenschaltfläche [-□×] redduzieren und transparent machen, obere rechte Ecke der Tab-Leiste auf ihre ursprüngliche Größe zurücksetzen und Transparenz aufheben.
// Tab-Höhe „UI-Dichte“
UI_Density_Compact = 29 ,// Standard = 29 Pixel bei Kompakt
UI_Density_Normal = 36 ,// Standard = 36 Pixel bei Normal
UI_Density_Touch = 41 ,// Standard = 41 Pixel bei Touch
// Entsprechender CSS Code in UserChrome.css wird vorrangig behandelt!
// Tab-Breite
// Bei gleichen Werten bei Min und Max, wird Tabbreite fixiert!
Tab_Min_Width = 76 ,// Standard - Mindestwert = 76px
Tab_Max_Width = 225 ,// Standard - Maxwert = 225px
// Entsprechender CSS Code in UserChrome.css wird vorrangig behandelt!
// .Tab-Drop-Indikator-Icon-Ersetzung.
Tab_Drop_Indicator = false ,// [false] = Stecknadel Symbol 📍
// true = Rote Linie (2px × 29px) als Symbol
// Ränder auf der linken und rechten Seite der Tabs
Tab_Separators = false ,// [false] = Nicht anzeigen
// true = Anzeigen
// Rahmen CSS wurde extrahiert und angepasst, an Aussehen wie bei browser.proton.enabled
// auf false, was man vor Firefox 90 noch einstellen konnte.
// Tab-Leisten-Ziehbereich
Left_Drag_Area = 0 ,// Linker Ziehbereich Breite: Standard 40 Pixel
Right_Drag_Area = 0 ,// Rechter Ziehbereich Breite: Standard 40 Pixel
Window_Maximize_Left_Drag_Area = false ,// true = Linken Ziehbereich bei maximiertem Fenster anzeigen. Standardmäßig ausgeblendet.
Fullscreen_Drag_Area = false ,// true = Linken und rechten Ziehbereich bei Vollbild anzeigen. Standardmäßig ausgeblendet.
// Angeheftete Tabs neu positionieren
Separate_Tabs_and_PinnedTabs = false ,// [false] = Standard
// true = Angeheftete Tabs von der Tab-Leiste lösen und in die darüber liegende Zeile verschieben.
// „Tab schließen“ Schaltfläche .
Tab_Close_Button = 0 ,// [0] = Standard
// 1 = Auf allen Tabs anzeigen
// 2 = Nur bei Mausberührung anzeigen
// Alle Tabs Schaltfläche
All_Tabs_Button = false ,// [false] = ausblenden
// true = anzeigen
// -- Config End --
css = `
#TabsToolbar {
:root[uidensity="compact"] & { --tab-min-height: ${UI_Density_Compact}px; }
:root:not([uidensity]) & { --tab-min-height: ${UI_Density_Normal}px; }
:root[uidensity="touch"] & { --tab-min-height: ${UI_Density_Touch}px; }
${Tab_Drop_Indicator ? `
#tabbrowser-tabs > .tab-drop-indicator {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAAdCAIAAAAPVCo9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAASSURBVBhXY3growJEQ5+SUQEAOb1EM8kwskcAAAAASUVORK5CYII=) no-repeat center !important;
}
` : ``}
.titlebar-spacer[type="pre-tabs"] {
width: ${Left_Drag_Area}px !important;
}
.titlebar-spacer[type="post-tabs"] {
width: ${Right_Drag_Area}px !important;
}
${Window_Maximize_Left_Drag_Area ? `
.titlebar-spacer {
:root:not([sizemode="normal"], [inFullscreen]) &[type="pre-tabs"] {
display: block !important;
}
}
` : ``}
${Fullscreen_Drag_Area ? `
.titlebar-spacer {
:root[inFullscreen] &, :root:not([tabsintitlebar]) & {
display: block !important;
}
}
` : ``}
#tabbrowser-arrowscrollbox {
&::part(scrollbox) {
&:has(+ spacer) > slot,
.scrollbox-clip > & {
flex-wrap: wrap;
}
${TabBar_Rows ? `
max-height: calc((var(--tab-min-height) + ${ProtonUI ? 8 : 0}px) * ${Maximum_Rows});
overflow: hidden auto;
& scrollbar {
-moz-window-dragging: no-drag;
}
` : ``}
}
&::part(overflow-start-indicator),
&::part(overflow-end-indicator),
&::part(scrollbutton-up),
&::part(scrollbutton-down) {
display: none;
}
${Separate_Tabs_and_PinnedTabs ? `
&::part(scrollbox) {
&:has(+ spacer) > slot::after,
.scrollbox-clip > &::after {
display: flow-root list-item;
content: "";
flex-basis: -moz-available;
height: 0;
overflow: hidden;
}
}
.tabbrowser-tab:not([pinned]) {
#tabbrowser-tabs[haspinnedtabs] & {
&, & + :not(#tabs-newtab-button) {
order: 1;
}
}
}
` : ``}
.tabbrowser-tab[fadein]:not([pinned]) {
--tab-min-width: ${Tab_Min_Width}px;
--tab-max-width: ${Tab_Max_Width}px;
max-width: var(--tab-max-width);
${Tab_Close_Button !== 0 ? `
${Tab_Close_Button === 1 ? `
.tab-close-button {
display : block !important;
}
` : Tab_Close_Button === 2 ? `
.tab-close-button {
opacity: 0;
}
&:hover .tab-close-button {
opacity: 1;
display : block !important;
}
` : ``}
` : ``}
}
#tabbrowser-tabs[haspinnedtabs]:not([positionpinnedtabs]):not([orient="vertical"]) > & > .tabbrowser-tab:nth-child(1 of :not([pinned], [hidden])) {
margin-inline-start: 0 !important;
}
}
${ProtonUI ? `` : `
.toolbarbutton-1 {
margin: 0 !important;
padding: 0 !important;
}
.tabbrowser-tab,
#tabs-newtab-button {
height: var(--tab-min-height);
padding: 0 !important;
}
.tab-background {
box-shadow: none !important;
margin-block: 0 !important;
}
.tabbrowser-tab[usercontextid] > .tab-stack > .tab-background > .tab-context-line {
margin: 1px 2px 0 !important;
}
`}
${Tab_Separators ? `
.titlebar-spacer[type="pre-tabs"] {
border-inline-end: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}
.tabbrowser-tab::after,
.tabbrowser-tab::before {
border-left: 1px solid color-mix(in srgb, currentColor 50%, transparent);
height: calc(var(--tab-min-height) - 15%);
margin-block: auto;
}
.tabbrowser-tab:hover::after,
.tabbrowser-tab[multiselected]::after,
#tabbrowser-tabs:not([movingtab]) .tabbrowser-tab:has(+ .tabbrowser-tab:hover)::after,
#tabbrowser-tabs:not([movingtab]) .tabbrowser-tab:has(+ [multiselected])::after {
height: 100%;
}
.tabbrowser-tab::after,
#tabbrowser-tabs[movingtab] .tabbrowser-tab[visuallyselected]::before {
content: "";
display: block;
}
` : ``}
${All_Tabs_Button ? `` : `
#alltabs-button {
display: none;
}
`}
}
${TabBar_Position === 0 ? `
#TabsToolbar {
.titlebar-buttonbox-container {
height: calc(var(--tab-min-height) + ${ProtonUI ? 8 : 0}px);
margin-bottom: 0 !important;
${TitleBar_Button_Autohide ? `
background-color: color-mix(in srgb, currentColor 20%, transparent);
height: 6px;
opacity: 0;
position: fixed;
right: 0;
z-index: 2147483647;
.titlebar-button {
opacity: 0;
padding: 0;
}
&:hover {
height: calc(var(--tab-min-height) + ${ProtonUI ? 8 : 0}px);
opacity: 1;
.titlebar-button {
opacity: 1;
padding: 8px 17px;
}
}
` : ``}
}
}
` : `
#nav-bar {
:root:not([inFullscreen]) #toolbar-menubar:not([inactive]) + & > .titlebar-buttonbox-container {
display: none;
}
.titlebar-button {
padding-block: 0 !important;
}
}
`}
${TabBar_Position !== 2 ? `` : `
body {
& > #fullscr-toggler[hidden] + tabbox,
:root[inFullscreen] & > tabbox:hover {
border-top: 0.5px solid var(--toolbar-bgcolor);
}
& > tabbox > #navigator-toolbox {
border-block: none !important;
}
:root[inFullscreen] & {
& > #navigator-toolbox {
transition: none;
&:has(~ tabbox:hover) {
margin-top: 0 !important;
}
&:hover ~ tabbox > #navigator-toolbox {
max-height: 100%;
}}
& > tabbox:not(:hover) {
border-top: .5px solid transparent;
& > #navigator-toolbox {
max-height: 0;
}
}
}
}
`}
`,
sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
uri = Services.io.newURI("data:text/css;charset=UTF=8," + encodeURIComponent(css));
if (TabBar_Rows == false) {
["0", "2"].find(type => {
if(sss.sheetRegistered(uri, type)) sss.unregisterSheet(uri, type); sss.loadAndRegisterSheet(uri, type);
});
} else {
["0", "2", "SSTabRestored", "TabMove", "TabOpen", "TabSelect"].find(type => {
if(sss.sheetRegistered(uri, type)) sss.unregisterSheet(uri, type); sss.loadAndRegisterSheet(uri, type);
gBrowser.tabContainer.addEventListener(type, (e) => { e.target.scrollIntoView({ block: "nearest" }); });
});
}
if (TabBar_Position !== 0) {
if (TabBar_Position === 1) {
document.getElementById("navigator-toolbox").prepend(
document.getElementById("toolbar-menubar"),
document.getElementById("nav-bar"),
document.getElementById("PersonalToolbar"),
document.getElementById("titlebar"),
);
} else {
document.getElementById("navigator-toolbox").prepend(
document.getElementById("toolbar-menubar"),
document.getElementById("nav-bar"),
document.getElementById("PersonalToolbar"),
);
}
document.getElementById("nav-bar").appendChild(
document.querySelector("#TabsToolbar > .titlebar-buttonbox-container")
);
}
if (TabBar_Position === 2) {
document.body.appendChild(
document.createXULElement("tabbox")
).appendChild(
document.importNode(document.getElementById("navigator-toolbox"))
).appendChild(
document.getElementById("titlebar")
);
}
gBrowser.tabContainer.addEventListener("dragover", function(event) { this._on_dragover(event); }, false)
gBrowser.tabContainer.addEventListener("drop", function(event) { this._on_drop(event); }, false)
gBrowser.tabContainer.on_dragover = function(event) { return false; }
gBrowser.tabContainer.on_drop = function(event) { return false; }
gBrowser.tabContainer._on_dragover = function(event) {
var effects = this.getDropEffectForTabDrag(event);
var ind = this._tabDropIndicator;
if (effects == "" || effects == "none") {
ind.hidden = true;
return;
}
event.preventDefault();
event.stopPropagation();
var arrowScrollbox = this.arrowScrollbox;
if (effects == "link") {
let tab = this._getDragTargetTab(event, { ignoreTabSides: true });
if (tab) {
if (!this._dragTime) {
this._dragTime = Date.now();
}
if (Date.now() >= this._dragTime + this._dragOverDelay) {
this.selectedItem = tab;
}
ind.hidden = true;
return;
}
}
var tabRect, rect = arrowScrollbox.getBoundingClientRect();
var newMarginX, newMarginY;
let newIndex = this._getDropIndex(event);
let children = this.allTabs;
if (newIndex == children.length) {
tabRect = this._getVisibleTabs().at(-1).getBoundingClientRect();
newMarginX = tabRect.right - rect.left;
} else {
tabRect = children[newIndex].getBoundingClientRect();
newMarginX = tabRect.left - rect.left;
}
newMarginY = tabRect.top - rect.top + tabRect.height / 2 - rect.height / 2;
ind.hidden = false;
newMarginX += ind.clientWidth / 2;
ind.style.transform = "translate(" + Math.round(newMarginX) + "px," + Math.round(newMarginY) + "px)";
}
gBrowser.tabContainer._on_drop = function(event) {
var dt = event.dataTransfer;
var dropEffect = dt.dropEffect;
var draggedTab;
let movingTabs;
if (dt.mozTypesAt(0)[0] == TAB_DROP_TYPE) {
// tab copy or move
draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
// not our drop then
if (!draggedTab) {
return;
}
movingTabs = draggedTab._dragData.movingTabs;
draggedTab.container._finishGroupSelectedTabs(draggedTab);
}
this._tabDropIndicator.hidden = true;
event.stopPropagation();
if (draggedTab && dropEffect == "copy") {
// copy the dropped tab (wherever it's from)
let newIndex = this._getDropIndex(event);
let draggedTabCopy;
for (let tab of movingTabs) {
let newTab = gBrowser.duplicateTab(tab);
gBrowser.moveTabTo(newTab, newIndex++);
if (tab == draggedTab) {
draggedTabCopy = newTab;
}
}
if (draggedTab.container != this || event.shiftKey) {
this.selectedItem = draggedTabCopy;
}
} else if (draggedTab && draggedTab.container == this) {
let oldTranslate = Math.round(draggedTab._dragData.translatePos);
let tabSize = Math.round(draggedTab._dragData.tabSize);
let translateOffset = oldTranslate % tabSize;
let newTranslate = oldTranslate - translateOffset;
if (oldTranslate > 0 && translateOffset > tabSize / 2) {
newTranslate += tabSize;
} else if (oldTranslate < 0 && -translateOffset > tabSize / 2) {
newTranslate -= tabSize;
}
let dropIndex;
if (draggedTab._dragData.fromTabList) {
dropIndex = this._getDropIndex(event);
} else {
dropIndex = this._getDropIndex(event);
// "animDropIndex" in draggedTab._dragData &&
// draggedTab._dragData.animDropIndex;
}
let incrementDropIndex = true;
if (dropIndex && dropIndex > movingTabs[0]._tPos) {
dropIndex--;
incrementDropIndex = false;
}
if (oldTranslate && oldTranslate != newTranslate && !gReduceMotion) {
for (let tab of movingTabs) {
tab.toggleAttribute("tabdrop-samewindow", true);
tab.style.transform = this.verticalMode
? "translateY(" + newTranslate + "px)"
: "translateX(" + newTranslate + "px)";
let postTransitionCleanup = () => {
tab.removeAttribute("tabdrop-samewindow");
this._finishAnimateTabMove();
if (dropIndex !== false) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
gBrowser.syncThrobberAnimations(tab);
};
if (gReduceMotion) {
postTransitionCleanup();
} else {
let onTransitionEnd = transitionendEvent => {
if (
transitionendEvent.propertyName != "transform" ||
transitionendEvent.originalTarget != tab
) {
return;
}
tab.removeEventListener("transitionend", onTransitionEnd);
postTransitionCleanup();
};
tab.addEventListener("transitionend", onTransitionEnd);
}
}
} else {
this._finishAnimateTabMove();
if (dropIndex !== false) {
for (let tab of movingTabs) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
}
}
} else if (draggedTab) {
// Move the tabs. To avoid multiple tab-switches in the original window,
// the selected tab should be adopted last.
const dropIndex = this._getDropIndex(event);
let newIndex = dropIndex;
let selectedTab;
let indexForSelectedTab;
for (let i = 0; i < movingTabs.length; ++i) {
const tab = movingTabs[i];
if (tab.selected) {
selectedTab = tab;
indexForSelectedTab = newIndex;
} else {
const newTab = gBrowser.adoptTab(tab, newIndex, tab == draggedTab);
if (newTab) {
++newIndex;
}
}
}
if (selectedTab) {
const newTab = gBrowser.adoptTab(
selectedTab,
indexForSelectedTab,
selectedTab == draggedTab
);
if (newTab) {
++newIndex;
}
}
// Restore tab selection
gBrowser.addRangeToMultiSelectedTabs(
gBrowser.tabs[dropIndex],
gBrowser.tabs[newIndex - 1]
);
} else {
// Pass true to disallow dropping javascript: or data: urls
let links;
try {
links = browserDragAndDrop.dropLinks(event, true);
} catch (ex) {}
if (!links || links.length === 0) {
return;
}
let inBackground = Services.prefs.getBoolPref(
"browser.tabs.loadInBackground"
);
if (event.shiftKey) {
inBackground = !inBackground;
}
let targetTab = this._getDragTargetTab(event, { ignoreTabSides: true });
let userContextId = this.selectedItem.getAttribute("usercontextid");
let replace = !!targetTab;
let newIndex = this._getDropIndex(event);
let urls = links.map(link => link.url);
let csp = browserDragAndDrop.getCsp(event);
let triggeringPrincipal =
browserDragAndDrop.getTriggeringPrincipal(event);
(async () => {
if (
urls.length >=
Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")
) {
// Sync dialog cannot be used inside drop event handler.
let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(
urls.length,
window
);
if (!answer) {
return;
}
}
gBrowser.loadTabs(urls, {
inBackground,
replace,
allowThirdPartyFixup: true,
targetTab,
newIndex,
userContextId,
triggeringPrincipal,
csp,
});
})();
}
if (draggedTab) {
delete draggedTab._dragData;
}
}
};
Alles anzeigen
Müsste soweit alles auf Deutsch übersetzt sein.
Mfg.
Endor
Dear Japanese Autor, you are absolutely welcome to joy in to this forum.
Thank you for this new Version. It would be great if we could communicate with you.
Kind regards
Endor
Hallo Herzmann.
Hier die auf Deutsch übersetzte Version:
// ==UserScript==
// @name zzzz-MultiRowTab_LiteforFx48.uc.js
// @namespace http://space.geocities.yahoo.co.jp/gl/alice0775
// @description Experimentelle CSS Version für Mehrzeilige Tableiste
// @include main
// @compatibility Firefox 128esr Firefox 131+
// @author Alice0775
// @version 2016/08/05 00:00 Firefox 48
// @version 2016/05/01 00:01 hide favicon if busy
// @version 2016/03/09 00:01 Bug 1222490 - Actually remove panorama for Fx45+
// @version 2016/02/09 00:01 workaround css for lwt
// @version 2016/02/09 00:00
// ==/UserScript==
"use strict";
MultiRowTabLiteforFx();
function MultiRowTabLiteforFx() {
// -- Config --
const // Anzahl der Tab-Leistenzeilen angeben oder eine unbegrenzte Anzahl von Zeilen wählen.
TabBar_Rows = false ,// [false] = unbegrenzt
// true = Begrenzte Tabzeilen - Anzahl der Zeilen angeben
Maximum_Rows = 3 ,// Tabzeilen angeben (Standard: 3 Zeilen)
// ProtonUI Erscheinungsbild der Tabs ändern
ProtonUI = true ,// [true] = Darstellung ProtonUI
// Die Höhe der Tab-Leiste entspricht der Höhe der UI-Dichte plus dem Leerraum darüber und darunter.
// false = Darstellung = wie bei browser.proton.enabled auf false, was man vor Firefox 90 noch einstellen konnte.
// Leerraum um die Tabs auf 0 anpassen, um der Höhe der UI-Dichte zu entsprechen.
// Position der Tab-Leiste.
TabBar_Position = 0 ,// [0] = Standard
// 1 = unter der Symbolleiste
// 2 = unter dem Fenster
// Tab-Höhe „UI-Dichte“
UI_Density_Compact = 29 ,// Standard = 29 Pixel bei Kompakt
UI_Density_Normal = 36 ,// Standard = 36 Pixel bei Normal
UI_Density_Touch = 41 ,// Standard = 41 Pixel bei Touch
// Entsprechender CSS Code in UserChrome.css wird vorrangig behandelt!
// Tab-Breite
// Bei gleichen Werten bei Min und Max, wird Tabbreite fixiert!
Tab_Min_Width = 76 ,// Standard - Mindestwert = 76px
Tab_Max_Width = 225 ,// Standard - Maxwert = 225px
// Entsprechender CSS Code in UserChrome.css wird vorrangig behandelt!
// .Tab-Drop-Indikator-Icon-Ersetzung.
Tab_Drop_Indicator = false ,// [false] = Stecknadel Symbol 📍
// true = Rote Linie (2px × 29px) als Symbol
// Ränder auf der linken und rechten Seite der Tabs
Tab_Separators = false ,// [false] = Nicht anzeigen
// true = Anzeigen
// Rahmen CSS wurde extrahiert und angepasst, an Aussehen wie bei browser.proton.enabled
// auf false, was man vor Firefox 90 noch einstellen konnte.
// Tab-Leisten-Ziehbereich
Left_Drag_Area = 0 ,// Linker Ziehbereich Breite: Standard 40 Pixel
Right_Drag_Area = 0 ,// Rechter Ziehbereich Breite: Standard 40 Pixel
Window_Maximize_Left_Drag_Area = false ,// true = Linken Ziehbereich bei maximiertem Fenster anzeigen. Standardmäßig ausgeblendet.
Fullscreen_Drag_Area = false ,// true = Linken und rechten Ziehbereich bei Vollbild anzeigen. Standardmäßig ausgeblendet.
// Angeheftete Tabs neu positionieren
Separate_Tabs_and_PinnedTabs = false ,// [false] = Standard
// true = Angeheftete Tabs von der Tab-Leiste lösen und in die darüber liegende Zeile verschieben.
// Alle Tabs Schaltfläche
All_Tabs_Button = false ,// [false] = ausblenden
// true = anzeigen
// -- Config End --
css = `
#TabsToolbar {
/* Tab-Höhe „UI-Dichte“ */
:root[uidensity="compact"] & { --tab-min-height: ${UI_Density_Compact}px; }
:root:not([uidensity]) & { --tab-min-height: ${UI_Density_Normal}px; }
:root[uidensity="touch"] & { --tab-min-height: ${UI_Density_Touch}px; }
${Tab_Drop_Indicator ? `
/* .tab-drop-indicator Symbol ersetzen. background: url() no-repeat center !important; Es wird nur eine rote Linie hinzugefügt (2px × 29px), als Base64 konvertierte PNG-Datei. */
#tabbrowser-tabs > .tab-drop-indicator {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAAdCAIAAAAPVCo9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAASSURBVBhXY3growJEQ5+SUQEAOb1EM8kwskcAAAAASUVORK5CYII=) no-repeat center !important;
}` : ``}
/* Ziehbereich der Tab-Leiste */
.titlebar-spacer[type="pre-tabs"] {
width: ${Left_Drag_Area}px !important;
}
.titlebar-spacer[type="post-tabs"] {
width: ${Right_Drag_Area}px !important;
}
${Window_Maximize_Left_Drag_Area ? `
.titlebar-spacer {
@media (-moz-platform: windows) {
:root:not([sizemode="normal"], [inFullscreen]) &[type="pre-tabs"] {
display: block !important;
}}}` : ``}
${Fullscreen_Drag_Area ? `
.titlebar-spacer {
:root[inFullscreen] &, :root:not([tabsintitlebar]) & {
display: block !important;
}}` : ``}
/* Tab-Tab-Leiste Bildlaufleiste */
#tabbrowser-arrowscrollbox {
&::part(scrollbox) {
${TabBar_Rows ? `
max-height: calc((var(--tab-min-height) + ${ProtonUI ? 8 : 0}px) * ${Maximum_Rows});
overflow: hidden auto;
& scrollbar {
-moz-window-dragging: no-drag;
}
/* Wenn Maximale Tabzeilen auf 1 gesetzt war, wurde eine Bildlaufleiste ohne Schieberegler angezeigt, was mich störte,
also habe ich sie unsichtbar gemacht. Die Bildlaufleiste wird ausgeblendet, funktioniert aber weiterhin.
Wenn die Tab-Leiste also zwei oder mehr Zeile enthält, kann man vertikal scrollen. */
${Maximum_Rows !== 1 ? `` : `scrollbar-width: none;`}
` : ``}}
&::part(overflow-start-indicator),
&::part(overflow-end-indicator),
&::part(scrollbutton-up),
&::part(scrollbutton-down) {
display: none;
}
.tabbrowser-tab[fadein]:not([pinned]) {
--tab-min-width: ${Tab_Min_Width}px;
--tab-max-width: ${Tab_Max_Width}px;
max-width: var(--tab-max-width);
}}
/* Abstand zwischen angehefteten Tabs auf 0 einstellen. */
#tabbrowser-tabs[haspinnedtabs]:not([positionpinnedtabs]):not([orient="vertical"]) > #tabbrowser-arrowscrollbox > .tabbrowser-tab:nth-child(1 of :not([pinned], [hidden])) {
margin-inline-start: 0px !important; /* Standard = 12px */
}
${ProtonUI ? `` : `
/* Leerraum um die Tabs auf 0 setzen und Höhe der UI-Dichte anpassen */
.toolbarbutton-1 {
margin: 0 !important;
padding: 0 !important;
}
.tabbrowser-tab,
#tabs-newtab-button {
height: var(--tab-min-height);
padding: 0 !important;
}
.tab-background {
box-shadow: none !important;
margin-block: 0 !important;
}
/* Tab-Umgebungen */
.tabbrowser-tab[usercontextid] > .tab-stack > .tab-background > .tab-context-line {
/* Freiraum um Tabs auf 0 setzen um den Farbbalken darüber auszublenden. Wenn Farbbalken gewünscht Wert höher den 0 verwenden. */
margin: 1px 2px 0; /* Standard margin: -3px 2px 0; */
}`}
${Tab_Separators ? `
.titlebar-spacer[type="pre-tabs"] {
border-inline-end: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}
.tabbrowser-tab::after,
.tabbrowser-tab::before {
border-left: 1px solid color-mix(in srgb, currentColor 50%, transparent);
height: calc(var(--tab-min-height) - 16.5%);
margin-block: auto;
}
.tabbrowser-tab:hover::after,.tabbrowser-tab[multiselected]::after,
#tabbrowser-tabs:not([movingtab]) .tabbrowser-tab:has(+ .tabbrowser-tab:hover)::after,
#tabbrowser-tabs:not([movingtab]) .tabbrowser-tab:has(+ [multiselected])::after {
height: 100%;
}
.tabbrowser-tab::after,
#tabbrowser-tabs[movingtab] .tabbrowser-tab[visuallyselected]::before {
content: "";
display: block;
}` : ``}
${All_Tabs_Button ? `` : `
/* Alle Tabs Schaltfläche */
#alltabs-button {
display: none;
}`}
}
/* Mehrzeilige Tableiste */
scrollbox[part][orient="horizontal"] {
&:has(+ spacer) > slot,
.scrollbox-clip > & {
flex-wrap: wrap;
}}
${Separate_Tabs_and_PinnedTabs ? `
/* Angeheftete Tabs von der Tab-Leiste lösen und in die darüber liegende Zeile verschieben. */
scrollbox[part][orient="horizontal"] {
&:has(+ spacer) > slot::after,
.scrollbox-clip > &::after {
display: flow-root list-item;
content: "";
flex-basis: -moz-available;
height: 0;
overflow: hidden;
}}
#TabsToolbar {
#tabbrowser-tabs[haspinnedtabs] {
.tabbrowser-tab:not([pinned]) {
&, & + :not(#tabs-newtab-button) {
order: 1;
}}}}` : ``}
${TabBar_Position === 0 ? `
/* Titelleistenschaltfläche [-□×] */
#TabsToolbar {
.titlebar-buttonbox-container {
height: calc(var(--tab-min-height) + ${ProtonUI ? 8 : 0}px);
margin-bottom: 0 !important;
}}` : `
#nav-bar {
:root:not([inFullscreen]) #toolbar-menubar:not([inactive]) + & > .titlebar-buttonbox-container {
display: none;
}
.titlebar-button {
padding-block: 0 !important;
}}`}
${TabBar_Position !== 2 ? `` : `
/* Tab-Leiste im Vollbildmodus ausblenden und mit Symbolleiste anzeigen, indem Sie den Mauszeiger über den oberen oder unteren Bildschirmrand bewegen. */
body {
& > #fullscr-toggler[hidden] + tabbox,
:root[inFullscreen] & > tabbox:hover {
border-top: 0.5px solid var(--toolbar-bgcolor);
}
& > tabbox > #navigator-toolbox {
border-block: none !important;
}
:root[inFullscreen] & {
& > #navigator-toolbox {
transition: none;
&:has(~ tabbox:hover) {
margin-top: 0 !important;
}
&:hover ~ tabbox > #navigator-toolbox {
max-height: 100%;
}}
& > tabbox:not(:hover) {
border-top: .5px solid transparent;
& > #navigator-toolbox {
max-height: 0;
}}}}`}
`,
sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
uri = Services.io.newURI("data:text/css;charset=UTF=8," + encodeURIComponent(css));
if (TabBar_Rows == false) {
["0", "2"].find(type => {
if(sss.sheetRegistered(uri, type)) sss.unregisterSheet(uri, type); sss.loadAndRegisterSheet(uri, type);
});
} else {
["0", "2", "SSTabRestored", "TabMove", "TabOpen", "TabSelect"].find(type => {
if(sss.sheetRegistered(uri, type)) sss.unregisterSheet(uri, type); sss.loadAndRegisterSheet(uri, type);
gBrowser.tabContainer.addEventListener(type, (e) => { e.target.scrollIntoView({ block: "nearest" }); });
});
}
if (TabBar_Position !== 0) {
if (TabBar_Position === 1) {
document.getElementById("navigator-toolbox").prepend(
document.getElementById("toolbar-menubar"),
document.getElementById("nav-bar"),
document.getElementById("PersonalToolbar"),
document.getElementById("titlebar"),
);
} else {
document.getElementById("navigator-toolbox").prepend(
document.getElementById("toolbar-menubar"),
document.getElementById("nav-bar"),
document.getElementById("PersonalToolbar"),
);
}
document.getElementById("nav-bar").appendChild(
document.querySelector("#TabsToolbar > .titlebar-buttonbox-container")
);
}
if (TabBar_Position === 2) {
document.body.appendChild(
document.createXULElement("tabbox")
).appendChild(
document.importNode(document.getElementById("navigator-toolbox"))
).appendChild(
document.getElementById("titlebar")
);
}
gBrowser.tabContainer.addEventListener("dragover", function(event) { this._on_dragover(event); }, false)
gBrowser.tabContainer.addEventListener("drop", function(event) { this._on_drop(event); }, false)
gBrowser.tabContainer.on_dragover = function(event) { return false; }
gBrowser.tabContainer.on_drop = function(event) { return false; }
gBrowser.tabContainer._on_dragover = function(event) {
var effects = this.getDropEffectForTabDrag(event);
var ind = this._tabDropIndicator;
if (effects == "" || effects == "none") {
ind.hidden = true;
return;
}
event.preventDefault();
event.stopPropagation();
var arrowScrollbox = this.arrowScrollbox;
if (effects == "link") {
let tab = this._getDragTargetTab(event, { ignoreTabSides: true });
if (tab) {
if (!this._dragTime) {
this._dragTime = Date.now();
}
if (Date.now() >= this._dragTime + this._dragOverDelay) {
this.selectedItem = tab;
}
ind.hidden = true;
return;
}
}
var rect = arrowScrollbox.getBoundingClientRect();
var newMarginX, newMarginY;
let newIndex = this._getDropIndex(event);
let children = this.allTabs;
if (newIndex == children.length) {
let tabRect = this._getVisibleTabs().at(-1).getBoundingClientRect();
newMarginX = tabRect.right - rect.left;
newMarginY = tabRect.top - rect.top + tabRect.height / 2 - rect.height / 2;
} else {
let tabRect = children[newIndex].getBoundingClientRect();
newMarginX = tabRect.left - rect.left;
newMarginY = tabRect.top - rect.top + tabRect.height / 2 - rect.height / 2;
}
ind.hidden = false;
newMarginX += ind.clientWidth / 2;
ind.style.transform = "translate(" + Math.round(newMarginX) + "px," + Math.round(newMarginY) + "px)";
}
gBrowser.tabContainer._on_drop = function(event) {
var dt = event.dataTransfer;
var dropEffect = dt.dropEffect;
var draggedTab;
let movingTabs;
if (dt.mozTypesAt(0)[0] == TAB_DROP_TYPE) {
// tab copy or move
draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
// not our drop then
if (!draggedTab) {
return;
}
movingTabs = draggedTab._dragData.movingTabs;
draggedTab.container._finishGroupSelectedTabs(draggedTab);
}
this._tabDropIndicator.hidden = true;
event.stopPropagation();
if (draggedTab && dropEffect == "copy") {
// copy the dropped tab (wherever it's from)
let newIndex = this._getDropIndex(event);
let draggedTabCopy;
for (let tab of movingTabs) {
let newTab = gBrowser.duplicateTab(tab);
gBrowser.moveTabTo(newTab, newIndex++);
if (tab == draggedTab) {
draggedTabCopy = newTab;
}
}
if (draggedTab.container != this || event.shiftKey) {
this.selectedItem = draggedTabCopy;
}
} else if (draggedTab && draggedTab.container == this) {
let oldTranslate = Math.round(draggedTab._dragData.translatePos);
let tabSize = Math.round(draggedTab._dragData.tabSize);
let translateOffset = oldTranslate % tabSize;
let newTranslate = oldTranslate - translateOffset;
if (oldTranslate > 0 && translateOffset > tabSize / 2) {
newTranslate += tabSize;
} else if (oldTranslate < 0 && -translateOffset > tabSize / 2) {
newTranslate -= tabSize;
}
let dropIndex;
if (draggedTab._dragData.fromTabList) {
dropIndex = this._getDropIndex(event);
} else {
dropIndex = this._getDropIndex(event);
// "animDropIndex" in draggedTab._dragData &&
// draggedTab._dragData.animDropIndex;
}
let incrementDropIndex = true;
if (dropIndex && dropIndex > movingTabs[0]._tPos) {
dropIndex--;
incrementDropIndex = false;
}
if (oldTranslate && oldTranslate != newTranslate && !gReduceMotion) {
for (let tab of movingTabs) {
tab.toggleAttribute("tabdrop-samewindow", true);
tab.style.transform = this.verticalMode
? "translateY(" + newTranslate + "px)"
: "translateX(" + newTranslate + "px)";
let postTransitionCleanup = () => {
tab.removeAttribute("tabdrop-samewindow");
this._finishAnimateTabMove();
if (dropIndex !== false) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
gBrowser.syncThrobberAnimations(tab);
};
if (gReduceMotion) {
postTransitionCleanup();
} else {
let onTransitionEnd = transitionendEvent => {
if (
transitionendEvent.propertyName != "transform" ||
transitionendEvent.originalTarget != tab
) {
return;
}
tab.removeEventListener("transitionend", onTransitionEnd);
postTransitionCleanup();
};
tab.addEventListener("transitionend", onTransitionEnd);
}
}
} else {
this._finishAnimateTabMove();
if (dropIndex !== false) {
for (let tab of movingTabs) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
}
}
} else if (draggedTab) {
// Move the tabs. To avoid multiple tab-switches in the original window,
// the selected tab should be adopted last.
const dropIndex = this._getDropIndex(event);
let newIndex = dropIndex;
let selectedTab;
let indexForSelectedTab;
for (let i = 0; i < movingTabs.length; ++i) {
const tab = movingTabs[i];
if (tab.selected) {
selectedTab = tab;
indexForSelectedTab = newIndex;
} else {
const newTab = gBrowser.adoptTab(tab, newIndex, tab == draggedTab);
if (newTab) {
++newIndex;
}
}
}
if (selectedTab) {
const newTab = gBrowser.adoptTab(
selectedTab,
indexForSelectedTab,
selectedTab == draggedTab
);
if (newTab) {
++newIndex;
}
}
// Restore tab selection
gBrowser.addRangeToMultiSelectedTabs(
gBrowser.tabs[dropIndex],
gBrowser.tabs[newIndex - 1]
);
} else {
// Pass true to disallow dropping javascript: or data: urls
let links;
try {
links = browserDragAndDrop.dropLinks(event, true);
} catch (ex) {}
if (!links || links.length === 0) {
return;
}
let inBackground = Services.prefs.getBoolPref(
"browser.tabs.loadInBackground"
);
if (event.shiftKey) {
inBackground = !inBackground;
}
let targetTab = this._getDragTargetTab(event, { ignoreTabSides: true });
let userContextId = this.selectedItem.getAttribute("usercontextid");
let replace = !!targetTab;
let newIndex = this._getDropIndex(event);
let urls = links.map(link => link.url);
let csp = browserDragAndDrop.getCsp(event);
let triggeringPrincipal =
browserDragAndDrop.getTriggeringPrincipal(event);
(async () => {
if (
urls.length >=
Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")
) {
// Sync dialog cannot be used inside drop event handler.
let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(
urls.length,
window
);
if (!answer) {
return;
}
}
gBrowser.loadTabs(urls, {
inBackground,
replace,
allowThirdPartyFixup: true,
targetTab,
newIndex,
userContextId,
triggeringPrincipal,
csp,
});
})();
}
if (draggedTab) {
delete draggedTab._dragData;
}
}
};
Alles anzeigen
Da ich dieses Script selber nicht verwende kann ich da nicht
viel dazu sagen.
Mfg.
Endor
.DeJaVu
Danke für die Info und Erklärung.
Mfg.
Endor
Das hat mit Yahoo nichts zu tun.
Da hat man nur wenn man aus Japan ist Zugriff.
VPN könnte da helfen.
Wer der Autor des obigen Scripts ist weiß ich ja nicht.
Er lädt es ja immer nur hier hoch:
https://u6.getuploader.com/script/.
Alice den ersten Autor kann man über Github leicht erreichen, wenn
man so wie ich dort angemeldet ist.
Mfg.
Endor
Hallo Herzmann !
Der Autor muss anscheinend hier mit gelesen haben.
Heute gab es eine einzige neue Version von ihm:
// ==UserScript==
// @name zzzz-MultiRowTab_LiteforFx48.uc.js
// @namespace http://space.geocities.yahoo.co.jp/gl/alice0775
// @description 多段タブもどき実験版 CSS入れ替えまくりLiteバージョン
// @include main
// @compatibility Firefox128esr Firefox131+
// @author Alice0775
// @version 2016/08/05 00:00 Firefox 48
// @version 2016/05/01 00:01 hide favicon if busy
// @version 2016/03/09 00:01 Bug 1222490 - Actually remove panorama for Fx45+
// @version 2016/02/09 00:01 workaround css for lwt
// @version 2016/02/09 00:00
// ==/UserScript==
"use strict";
MultiRowTabLiteforFx();
function MultiRowTabLiteforFx() {
// -- Config --
const // タブバーの段数を指定するか無制限にするか選択する。
TabBar_Rows = false ,// [false] = 無制限
// true = 段数指定
Maximum_Rows = 3 ,// 段数指定(デフォルト3段)
// ProtonUI タブの見た目を変更する。
ProtonUI = true ,// [true] = タブをProtonUIのままにする。
// タブバーの高さはUI密度に上下の空白を足した高さです。
// false = Firefox90以前には出来ていたbrowser.proton.enabledをfalseに設定した時の見た目にする。
// タブの周りにある空白を0にしてUI密度の高さに調整します。
// タブバーの位置を変更する。
TabBar_Position = 0 ,// [0] = 初期位置
// 1 = ツールバーの下
// 2 = ウインドウの下
// UI密度 タブの高さ
UI_Density_Compact = 29 ,// デフォルト 29px コンパクト
UI_Density_Normal = 36 ,// デフォルト 36px 通常
UI_Density_Touch = 41 ,// デフォルト 41px タッチ
// 同じ様なCSSを書いた場合userChrome.cssの方が反映されます。
// タブの横幅
// 指定する数値を両方同じにすると横幅が固定化されます。
Tab_Min_Width = 76 ,// 最小値 デフォルト 76px
Tab_Max_Width = 225 ,// 最大値 デフォルト 225px
// 同じ様なCSSを書いた場合userChrome.cssの方が反映されます。
// .tab-drop-indicator アイコン差し替え。
Tab_Drop_Indicator = false ,// [false] = ピン📍のようなアイコン
// true = 赤線(2px × 29px)アイコン
// タブの左右に境界線を表示する。
Tab_Separators = false ,// [false] = 表示しない
// true = 表示する
// Firefox90以前には出来ていたbrowser.proton.enabledをfalseに設定したら表示する様になっていた境界線のCSSを抽出して調整しています。
// タブバードラッグ領域
Left_Drag_Area = 0 ,// 左のドラッグ領域:デフォルト 40px
Right_Drag_Area = 0 ,// 右のドラッグ領域:デフォルト 40px
Window_Maximize_Left_Drag_Area = false ,// true = ウィンドウを最大化した時、非表示になる 左のドラッグ領域が表示出来ます。
Fullscreen_Drag_Area = false ,// true = フルスクリーンにした時、非表示になる 左右のドラッグ領域が表示出来ます。
// ピン留めタブの位置を変更する。
Separate_Tabs_and_PinnedTabs = false ,// [false] = 初期位置
// true = ピン留めタブをタブの行から分離して上に出来る行へ移動する。
// タブを一覧表示するボタン
All_Tabs_Button = false ,// [false] = 非表示
// true = 表示
// -- Config End --
css = `
#TabsToolbar {
/* UI密度 タブの高さ */
:root[uidensity="compact"] & { --tab-min-height: ${UI_Density_Compact}px; }
:root:not([uidensity]) & { --tab-min-height: ${UI_Density_Normal}px; }
:root[uidensity="touch"] & { --tab-min-height: ${UI_Density_Touch}px; }
${Tab_Drop_Indicator ? `
/* .tab-drop-indicator アイコン差し替え。 background: url() no-repeat center !important; に追記してるのはpngファイルをbase64に変換した赤線(2px × 29px)です。 */
#tabbrowser-tabs > .tab-drop-indicator {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAAdCAIAAAAPVCo9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAASSURBVBhXY3growJEQ5+SUQEAOb1EM8kwskcAAAAASUVORK5CYII=) no-repeat center !important;
}` : ``}
/* タブバー ドラッグ領域 */
.titlebar-spacer[type="pre-tabs"] {
width: ${Left_Drag_Area}px !important;
}
.titlebar-spacer[type="post-tabs"] {
width: ${Right_Drag_Area}px !important;
}
${Window_Maximize_Left_Drag_Area ? `
.titlebar-spacer {
@media (-moz-platform: windows) {
:root:not([sizemode="normal"], [inFullscreen]) &[type="pre-tabs"] {
display: block !important;
}}}` : ``}
${Fullscreen_Drag_Area ? `
.titlebar-spacer {
:root[inFullscreen] &, :root:not([tabsintitlebar]) & {
display: block !important;
}}` : ``}
/* タブ タブバー スクロールバー */
#tabbrowser-arrowscrollbox {
&::part(scrollbox) {
${TabBar_Rows ? `
max-height: calc((var(--tab-min-height) + ${ProtonUI ? 8 : 0}px) * ${Maximum_Rows});
overflow: hidden auto;
& scrollbar {
-moz-window-dragging: no-drag;
}
/* Maximum_Rows を 1 にするとスライダの無いスクロールバーが表示されて気になったので Maximum_Rows を 1 に設定した時だけ非表示にしました。
スクロールバーは非表示になりますが動作はするのでタブバーに2段目以降があると縦方向にスクロール出来ます。 */
${Maximum_Rows !== 1 ? `` : `scrollbar-width: none;`}
` : ``}}
&::part(overflow-start-indicator),
&::part(overflow-end-indicator),
&::part(scrollbutton-up),
&::part(scrollbutton-down) {
display: none;
}
.tabbrowser-tab[fadein]:not([pinned]) {
--tab-min-width: ${Tab_Min_Width}px;
--tab-max-width: ${Tab_Max_Width}px;
max-width: var(--tab-max-width);
}}
/* ピン留めタブとタブの間に出来る空白を0にする。 */
#tabbrowser-tabs[haspinnedtabs]:not([positionpinnedtabs]):not([orient="vertical"]) > #tabbrowser-arrowscrollbox > .tabbrowser-tab:nth-child(1 of :not([pinned], [hidden])) {
margin-inline-start: 0px !important; /* デフォルト 12px */
}
${ProtonUI ? `` : `
/* タブの周りにある空白を0にしてUI密度の高さに調整 */
.toolbarbutton-1 {
margin: 0 !important;
padding: 0 !important;
}
.tabbrowser-tab,
#tabs-newtab-button {
height: var(--tab-min-height);
padding: 0 !important;
}
.tab-background {
box-shadow: none !important;
margin-block: 0 !important;
}
/* コンテナータブ */
.tabbrowser-tab[usercontextid] > .tab-stack > .tab-background > .tab-context-line {
/* タブの周りにある空白を0にする調整で上のカラーバーが隠れるので見える様に調整 */
margin: 1px 2px 0; /* デフォルト margin: -3px 2px 0; */
}`}
${Tab_Separators ? `
.titlebar-spacer[type="pre-tabs"] {
border-inline-end: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}
.tabbrowser-tab::after,
.tabbrowser-tab::before {
border-left: 1px solid color-mix(in srgb, currentColor 50%, transparent);
height: calc(var(--tab-min-height) - 16.5%);
margin-block: auto;
}
.tabbrowser-tab:hover::after,.tabbrowser-tab[multiselected]::after,
#tabbrowser-tabs:not([movingtab]) .tabbrowser-tab:has(+ .tabbrowser-tab:hover)::after,
#tabbrowser-tabs:not([movingtab]) .tabbrowser-tab:has(+ [multiselected])::after {
height: 100%;
}
.tabbrowser-tab::after,
#tabbrowser-tabs[movingtab] .tabbrowser-tab[visuallyselected]::before {
content: "";
display: block;
}` : ``}
${All_Tabs_Button ? `` : `
/* タブを一覧表示するボタン */
#alltabs-button {
display: none;
}`}
}
/* 多段タブ */
scrollbox[part][orient="horizontal"] {
&:has(+ spacer) > slot,
.scrollbox-clip > & {
flex-wrap: wrap;
}}
${Separate_Tabs_and_PinnedTabs ? `
/* ピン留めタブをタブの行から分離して上に出来る行へ移動する。 */
scrollbox[part][orient="horizontal"] {
&:has(+ spacer) > slot::after,
.scrollbox-clip > &::after {
display: flow-root list-item;
content: "";
flex-basis: -moz-available;
height: 0;
overflow: hidden;
}}
#TabsToolbar {
#tabbrowser-tabs[haspinnedtabs] {
.tabbrowser-tab:not([pinned]) {
&, & + :not(#tabs-newtab-button) {
order: 1;
}}}}` : ``}
${TabBar_Position === 0 ? `
/* タイトルバーボタン[-□×] */
#TabsToolbar {
.titlebar-buttonbox-container {
height: calc(var(--tab-min-height) + ${ProtonUI ? 8 : 0}px);
margin-bottom: 0 !important;
}}` : `
#nav-bar {
:root:not([inFullscreen]) #toolbar-menubar:not([inactive]) + & > .titlebar-buttonbox-container {
display: none;
}
.titlebar-button {
padding-block: 0 !important;
}}`}
${TabBar_Position !== 2 ? `` : `
/* フルスクリーン時タブバーを隠して画面の一番上か一番下をマウスオーバーでツールバーと一緒に表示 */
body {
& > #fullscr-toggler[hidden] + tabbox,
:root[inFullscreen] & > tabbox:hover {
border-top: 0.5px solid var(--toolbar-bgcolor);
}
& > tabbox > #navigator-toolbox {
border-block: none !important;
}
:root[inFullscreen] & {
& > #navigator-toolbox {
transition: none;
&:has(~ tabbox:hover) {
margin-top: 0 !important;
}
&:hover ~ tabbox > #navigator-toolbox {
max-height: 100%;
}}
& > tabbox:not(:hover) {
border-top: .5px solid transparent;
& > #navigator-toolbox {
max-height: 0;
}}}}`}
`,
sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
uri = Services.io.newURI("data:text/css;charset=UTF=8," + encodeURIComponent(css));
if (TabBar_Rows == false) {
["0", "2"].find(type => {
if(sss.sheetRegistered(uri, type)) sss.unregisterSheet(uri, type); sss.loadAndRegisterSheet(uri, type);
});
} else {
["0", "2", "SSTabRestored", "TabMove", "TabOpen", "TabSelect"].find(type => {
if(sss.sheetRegistered(uri, type)) sss.unregisterSheet(uri, type); sss.loadAndRegisterSheet(uri, type);
gBrowser.tabContainer.addEventListener(type, (e) => { e.target.scrollIntoView({ block: "nearest" }); });
});
}
if (TabBar_Position !== 0) {
if (TabBar_Position === 1) {
document.getElementById("navigator-toolbox").prepend(
document.getElementById("toolbar-menubar"),
document.getElementById("nav-bar"),
document.getElementById("PersonalToolbar"),
document.getElementById("titlebar"),
);
} else {
document.getElementById("navigator-toolbox").prepend(
document.getElementById("toolbar-menubar"),
document.getElementById("nav-bar"),
document.getElementById("PersonalToolbar"),
);
}
document.getElementById("nav-bar").appendChild(
document.querySelector("#TabsToolbar > .titlebar-buttonbox-container")
);
}
if (TabBar_Position === 2) {
document.body.appendChild(
document.createXULElement("tabbox")
).appendChild(
document.importNode(document.getElementById("navigator-toolbox"))
).appendChild(
document.getElementById("titlebar")
);
}
gBrowser.tabContainer.addEventListener("dragover", function(event) { this._on_dragover(event); }, false)
gBrowser.tabContainer.addEventListener("drop", function(event) { this._on_drop(event); }, false)
gBrowser.tabContainer.on_dragover = function(event) { return false; }
gBrowser.tabContainer.on_drop = function(event) { return false; }
gBrowser.tabContainer._on_dragover = function(event) {
var effects = this.getDropEffectForTabDrag(event);
var ind = this._tabDropIndicator;
if (effects == "" || effects == "none") {
ind.hidden = true;
return;
}
event.preventDefault();
event.stopPropagation();
var arrowScrollbox = this.arrowScrollbox;
if (effects == "link") {
let tab = this._getDragTargetTab(event, { ignoreTabSides: true });
if (tab) {
if (!this._dragTime) {
this._dragTime = Date.now();
}
if (Date.now() >= this._dragTime + this._dragOverDelay) {
this.selectedItem = tab;
}
ind.hidden = true;
return;
}
}
var rect = arrowScrollbox.getBoundingClientRect();
var newMarginX, newMarginY;
let newIndex = this._getDropIndex(event);
let children = this.allTabs;
if (newIndex == children.length) {
let tabRect = this._getVisibleTabs().at(-1).getBoundingClientRect();
newMarginX = tabRect.right - rect.left;
newMarginY = tabRect.top - rect.top + tabRect.height / 2 - rect.height / 2;
} else {
let tabRect = children[newIndex].getBoundingClientRect();
newMarginX = tabRect.left - rect.left;
newMarginY = tabRect.top - rect.top + tabRect.height / 2 - rect.height / 2;
}
ind.hidden = false;
newMarginX += ind.clientWidth / 2;
ind.style.transform = "translate(" + Math.round(newMarginX) + "px," + Math.round(newMarginY) + "px)";
}
gBrowser.tabContainer._on_drop = function(event) {
var dt = event.dataTransfer;
var dropEffect = dt.dropEffect;
var draggedTab;
let movingTabs;
if (dt.mozTypesAt(0)[0] == TAB_DROP_TYPE) {
// tab copy or move
draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
// not our drop then
if (!draggedTab) {
return;
}
movingTabs = draggedTab._dragData.movingTabs;
draggedTab.container._finishGroupSelectedTabs(draggedTab);
}
this._tabDropIndicator.hidden = true;
event.stopPropagation();
if (draggedTab && dropEffect == "copy") {
// copy the dropped tab (wherever it's from)
let newIndex = this._getDropIndex(event);
let draggedTabCopy;
for (let tab of movingTabs) {
let newTab = gBrowser.duplicateTab(tab);
gBrowser.moveTabTo(newTab, newIndex++);
if (tab == draggedTab) {
draggedTabCopy = newTab;
}
}
if (draggedTab.container != this || event.shiftKey) {
this.selectedItem = draggedTabCopy;
}
} else if (draggedTab && draggedTab.container == this) {
let oldTranslate = Math.round(draggedTab._dragData.translatePos);
let tabSize = Math.round(draggedTab._dragData.tabSize);
let translateOffset = oldTranslate % tabSize;
let newTranslate = oldTranslate - translateOffset;
if (oldTranslate > 0 && translateOffset > tabSize / 2) {
newTranslate += tabSize;
} else if (oldTranslate < 0 && -translateOffset > tabSize / 2) {
newTranslate -= tabSize;
}
let dropIndex;
if (draggedTab._dragData.fromTabList) {
dropIndex = this._getDropIndex(event);
} else {
dropIndex = this._getDropIndex(event);
// "animDropIndex" in draggedTab._dragData &&
// draggedTab._dragData.animDropIndex;
}
let incrementDropIndex = true;
if (dropIndex && dropIndex > movingTabs[0]._tPos) {
dropIndex--;
incrementDropIndex = false;
}
if (oldTranslate && oldTranslate != newTranslate && !gReduceMotion) {
for (let tab of movingTabs) {
tab.toggleAttribute("tabdrop-samewindow", true);
tab.style.transform = this.verticalMode
? "translateY(" + newTranslate + "px)"
: "translateX(" + newTranslate + "px)";
let postTransitionCleanup = () => {
tab.removeAttribute("tabdrop-samewindow");
this._finishAnimateTabMove();
if (dropIndex !== false) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
gBrowser.syncThrobberAnimations(tab);
};
if (gReduceMotion) {
postTransitionCleanup();
} else {
let onTransitionEnd = transitionendEvent => {
if (
transitionendEvent.propertyName != "transform" ||
transitionendEvent.originalTarget != tab
) {
return;
}
tab.removeEventListener("transitionend", onTransitionEnd);
postTransitionCleanup();
};
tab.addEventListener("transitionend", onTransitionEnd);
}
}
} else {
this._finishAnimateTabMove();
if (dropIndex !== false) {
for (let tab of movingTabs) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
}
}
} else if (draggedTab) {
// Move the tabs. To avoid multiple tab-switches in the original window,
// the selected tab should be adopted last.
const dropIndex = this._getDropIndex(event);
let newIndex = dropIndex;
let selectedTab;
let indexForSelectedTab;
for (let i = 0; i < movingTabs.length; ++i) {
const tab = movingTabs[i];
if (tab.selected) {
selectedTab = tab;
indexForSelectedTab = newIndex;
} else {
const newTab = gBrowser.adoptTab(tab, newIndex, tab == draggedTab);
if (newTab) {
++newIndex;
}
}
}
if (selectedTab) {
const newTab = gBrowser.adoptTab(
selectedTab,
indexForSelectedTab,
selectedTab == draggedTab
);
if (newTab) {
++newIndex;
}
}
// Restore tab selection
gBrowser.addRangeToMultiSelectedTabs(
gBrowser.tabs[dropIndex],
gBrowser.tabs[newIndex - 1]
);
} else {
// Pass true to disallow dropping javascript: or data: urls
let links;
try {
links = browserDragAndDrop.dropLinks(event, true);
} catch (ex) {}
if (!links || links.length === 0) {
return;
}
let inBackground = Services.prefs.getBoolPref(
"browser.tabs.loadInBackground"
);
if (event.shiftKey) {
inBackground = !inBackground;
}
let targetTab = this._getDragTargetTab(event, { ignoreTabSides: true });
let userContextId = this.selectedItem.getAttribute("usercontextid");
let replace = !!targetTab;
let newIndex = this._getDropIndex(event);
let urls = links.map(link => link.url);
let csp = browserDragAndDrop.getCsp(event);
let triggeringPrincipal =
browserDragAndDrop.getTriggeringPrincipal(event);
(async () => {
if (
urls.length >=
Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")
) {
// Sync dialog cannot be used inside drop event handler.
let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(
urls.length,
window
);
if (!answer) {
return;
}
}
gBrowser.loadTabs(urls, {
inBackground,
replace,
allowThirdPartyFixup: true,
targetTab,
newIndex,
userContextId,
triggeringPrincipal,
csp,
});
})();
}
if (draggedTab) {
delete draggedTab._dragData;
}
}
};
Alles anzeigen
Die hat sehr große Ähnlichkeit mir Deiner.
Habe sie noch nicht übersetzt.
Mfg.
Endor
Hallo Sören Hentzschel
Vielen Dank.
Mfg.
Endor
#appcontent gibt es seit heute nicht mehr.
Womit müsste man das dann ersetzen?
Ich habe hier in einem Script folgendes:
if (this._FLOATING_SIDEBAR) {
let x = document.getElementById("appcontent").getBoundingClientRect().x;
this._sidebar_box.style.setProperty("left", x + "px", "");
this._sidebar.style.setProperty("left", x - 1 + "px", "");
}
if (ucjs_expand_sidebar._FLOATING_SIDEBAR) {
let x = document.getElementById("appcontent").getBoundingClientRect().x;
ucjs_expand_sidebar._sidebar_box.style.setProperty("left", x + "px", "");
}
Da müsste man das dann wohl auch ändern.
Mfg.
Endor
Hallo edvoldi!
Auch von mir alles alles Gute zum Geburtstag.
Vor allem viel Gesundheit, aber auch viel Glück und
Wohlergehen wünsche ich Dir von ganzen Herzen.
Mfg.
Endor
Hallo Mira_Belle!
Vielen Dank! Funktioniert bestens.
Mfg.
Endor
Hallo Mira_Belle !
Vielen Dank für Dein Script.
Habe mich mal so bedient.
Passt perfekt für mich.
Mfg.
Endor
Hallo Sören Hentzschel .
Zu Alice habe ich Kontakt bereits direkt über Github.
Der war wie oben geschrieben aber nicht gemeint.
Ich beziehe mich auf die Person die die Scripte im Paket
hier hoch lädt:
Trotzdem danke für Deine Mühe.
Mfg.
Endor
Hallo Herzmann.
Sieht ja toll aus. Vielen Dank!
Wenn ich eine Kontaktmöglichkeit zum Autor hätte würde ich ihn
auf Deine fantastische Arbeit aufmerksam machen. Mal sehen ob
ich was finde. Es geht da jetzt nicht um den ersten Autor Alice,
sondern den aktuellen der die Scripte am laufen hält.
Dürfte ich Ihm den Link auf Deine Version bei Gitlab weitergeben?
Wäre prima.
Mfg.
Endor
Hallo Herzmann.
Die Scripte sind nicht von mir, sondern von einem Japaner.
Ich lade die nur runter und übersetze den japanischen Text auf
Deutsch.
Quelle: https://u6.getuploader.com/script/
Sieht dort dann so aus: 多段タブ.zip
Ist ein Archiv mit eben 12 Versionen vom Script plus einiges an
Infodateien usw. in Japanischer Sprache.
Ich verstehe leider nicht genug von Java Script.
Mfg.
Endor