Der Autor hat was neues:
Ja, und damit funktioniert auch das Verschieben der Tabs wieder.
Der Autor hat was neues:
Ja, und damit funktioniert auch das Verschieben der Tabs wieder.
Seit der Version 137 ist die Tab leiste wieder oben. Bitte um hilfe
Wenn du die aktuelle Version von hier Mehrzeilige Tableiste für aktuelle Firefox-Versionen hast, dann funktioniert es bis Version 139.
Es geht auch etwas schneller
Du weisst nicht zufällig, wie ich in diesem (neuen) Skript diesen Pfeil rechts bei der Tableiste wegmache
Doch, eine Möglichkeit hat 2002Andreas dir im vorherigen Beitrag gezeigt.
Für mich habe ich das so gemacht, ein Rechtsklick auf eine freie Stelle in der Tabbar, und dann Symbolleiste anpassen auswählen.
In der Folge dann mit der linken Maus das Pfeil-Symbol anfassen und z.B. in das Fenster ziehen (kann auch in das große linke abgelegt werden),
Naja, manchmal hilft ein kleiner Input um festzustellen, dass irgendwas schief gelaufen ist
Da bist du nicht allein, glaube es mir.
Hat jemand eine Ahnung, wie man das beheben kann?
Kann ich nicht, aber diese Version 135+ habe ich zum Test in Nightly, da ist alles "normal". Darfst du probieren, eventuell hilft es weiter.
// ==UserScript==
// @name MultiRowTabLiteforFx.uc.js
// @namespace Based on Alice0775's zzzz-MultiRowTab_LiteforFx48.uc.js
// @description Mehrzeilige Tableiste - Experimentelle CSS Version
// @include main
// @compatibility Firefox 135+
// @version 2025/01/06 12:00
// ==/UserScript==
"use strict";
MultiRowTabLiteforFx();
function MultiRowTabLiteforFx() {
if (!window.gBrowser) { return; }
// -- Config --
// Vergleichbarer CSS Code in userChrome.css Datei wird vorrangig behandelt!
const // Mehrzeilige Tableiste Ein/Aus Anzahl der Tabzeilen
MultiRowTab_OnOff_and_TabBar_Rows = 2 ,// [-1] = Mehrzeilige Tableiste aktiv unbegrenzte Anzahl von Zeilen.
// 0 = Mehrzeilige Tableiste aus.
// 1 = Mehrzeilige Tableiste aktiv. Standard = 1 Zeile. Bei Berührung
// der Tableiste mit der der Maus, werden die zweite und die folgenden Zeilen
// bis zur angegebenen Anzahl von Zeilen angezeigt.
// 2 = Mehrzeilige Tableiste aktiv. Anzahl der Tabzeilen angeben.
TabBar_Rows_on_MouseOver = 3 ,// Standard = 1 Zeile. Anzahl der Zeilen angeben, die angezeigt werden sollen,
// wenn der Mauszeiger über die Tableiste bewegt wird. Voraussetzung:
// „MultiRowTab_OnOff_and_TabBar_Rows“ auf „1“ setzen.
TabBar_DisplayTime_on_MouseOver = 1 ,// Sie können die Anzeigezeit (Sekunden) festlegen, wann die zweite und die folgenden
// Zeilen beim Mouseover angezeigt werden. Das Display zeigt den eingestellten Wert
// (Sekunden) an und kehrt dann zur ersten Zeile zurück.
// Position der Tab-Leiste.
TabBar_Position = 0 ,// [0] = Standard
// 1 = unter der Symbolleiste
// 2 = unter dem Fenster
// Positionen der Tab-Leiste und der Lesezeichen-Symbolleiste tauschen.
// sofern die Position der Tab-Leiste unterhalb der Symbolleiste festgelegt ist.
// Voraussetzung: Setze "TabBar_Position" auf "1".
Bookmark_Toolbar_Position = true ,// [true] = Menüleiste, Navigationsleiste, Lesezeichenleiste, Tableiste
// false = Menüleiste, Navigationsleiste, Tableiste, Lesezeichensymbolleiste
// Tab-Höhe „UI-Dichte“
UI_Density_Compact = 26 ,// Standard = 29 Pixelbei Kompakt
UI_Density_Normal = 26 ,// Standard = 36 Pixel bei Normal
UI_Density_Touch = 26 ,// Standard = 41 Pixel bei Touch
// Tab-Breite
Tab_Min_Width = 270 ,// Standard - Mindestwert = 76px
Tab_Max_Width = 271 ,// Standard - Maxwert = 225px
// Bei gleichen Werten bei Min und Max, wird die Tabbreite fixiert!
// „Tab schließen“ Schaltfläche
Tab_Close_Button = 3 ,// [0] = Standard
// 1 = Ausgeblendet
// 2 = Auf allen Tabs anzeigen
// 3 = Nur bei Mausberührung anzeigen
// 4 = Aktive Tabs werden immer angezeigt, inaktive Tabs
// werden beim Mouseover angezeigt. *Standard für vertikalen Tab-Modus.
// ProtonUI Erscheinungsbild der Tabs ändern
Proton_Margins = false ,// [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.
// Wenn der Leerraum um die Tabs auf 0 und die Höhe auf die UI-Dichte eingestellt
// ist, ist sie 4 Pixel breiter und 8 Pixel niedriger als die Standardeinstellung.
// 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.
// Voraussetzung: „TabBar_Position“ auf „0“ setzen.
TitleBar_Button_Autohide = false ,// [false] = Aktiviert
// true = Deaktiviert
// Äußeren Rahmen der Titelleistenschaltfläche [-□×] reduzieren und transparent machen.
TitleBar_Button_DisplayTime = 0.6 ,// Dauer der Anzeige in Sekunden, nach der Rückkehr zur Originalgröße und dem Aufheben
// der Transparenz per Mouseover angeben.
// Tab-Leiste von Anfang an auf die angegebene Höhe einstellen.
// Voraussetzung: „MultiRowTab_OnOff_and_TabBar_Rows“ auf „2“ oder höher setzen.
Set_the_TabBar_to_the_Specified_Height = false ,// [false] = Die Tab-Leiste wird höher, wenn der nächsten Zeile weitere Tabs hinzugefügt werden.
// true = Verwendung: Die Tab-Leiste wird von Anfang an auf die angegebene Höhe eingestellt
// „.tabDropIndicator“, der beim Ziehen und Ablegen eines Tabs angezeigt wird, ersetzen.
// Voraussetzung: „MultiRowTab_OnOff_and_TabBar_Rows“ auf einen anderen Wert als „0“ setzen.
Tab_Drop_Indicator = false ,// [false] = Stecknadel Symbol 📍
// true = Rote Linie (2px × 29px) als Symbol
// Position der angepinnten Tabs
// Voraussetzung: „MultiRowTab_OnOff_and_TabBar_Rows“ auf einen Wert ungleich „0“ setzen.
Separate_Tabs_and_PinnedTabs = false ,// [false] = Standard
// true = Angeheftete Tabs von der Tab-Leiste lösen und in die darüber liegende
// Zeile verschieben. Breite der angehefteten Tabs für die Position der
// angehefteten Tabs „true“ anpassen.
PinnedTab_Width = false ,// [false] = Kein Standard
// true = Breite angehefteter Tabs anpassen, z. B. „Tab-Breite“.
PinnedTab_Min_Width = 76 ,// Standard Mindestbreite = 76 Pixel
PinnedTab_Max_Width = 225 ,// Standard Maximalbreite = 225 Pixel
// Bei gleichen Werten ist die Breite fixiert.
// Angeheftete Tab, Schließen Schaltfläche
// Voraussetzung: „Separate_Tabs_and_PinnedTabs“ auf „true“ setzen.
PinnedTab_Close_Button = 0 ,// [0] = Standard
// 1 = auf allen Tabs sichtbar
// 2 = auf Tab bei Mouseover anzeigen
// 3 = Aktiver Tab immer sichtbar, inaktiver Tab bei Mouseover sichtbar
// *Standard für vertikalen Tab-Modus.
// Tab-Leisten-Ziehbereich
Left_Drag_Area = 0 ,// Linker Ziehbereich Breite: Standard 40 Pixel
Right_Drag_Area = 0 ,// Rechter Ziehbereich Breite: Standard 40 Pixel
Maximize_Left_Drag_Area = false ,// true = Linken Ziehbereich bei maximiertem Fenster anzeigen. Standard ausgeblendet.
Fullscreen_Drag_Area = false ,// true = Linken und rechten Ziehbereich bei Vollbild anzeigen. Standard ausgeblendet.
// Wenn die Titelleiste angezeigt wird, funktioniert sie nicht als Drag-Bereich, selbst
// wenn „.titlebar-spacer“ angezeigt wird. Daher habe ich dafür gesorgt, dass sie nichts bewirkt.
// -- Config Ende --
css = `
#TabsToolbar:not([collapsed="true"]) {
: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;
}
#tabbrowser-tabs {
min-height: calc(var(--tab-min-height) + ${Proton_Margins ? 8 : 0}px);
${MultiRowTab_OnOff_and_TabBar_Rows != 0 ? `
&[overflow] {
padding-inline: 0 !important;
& > #tabbrowser-arrowscrollbox {
& > .tabbrowser-tab[pinned] {
display: flex;
margin-inline-start: 0 !important;
position: static !important;
}
&::part(scrollbox) {
padding-inline: 0;
}
}
& + #new-tab-button {
display: none;
}
}
${Tab_Drop_Indicator ? `
& > .tab-drop-indicator {
background: url(
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAAdCAIAAAAPVCo9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAASSURBVBhXY3growJEQ5+SUQEAOb1EM8kwskcAAAAASUVORK5CYII=
) no-repeat center;
}
` : ``}
#tabbrowser-arrowscrollbox {
&::part(scrollbox) {
& > slot {
flex-wrap: wrap;
}
${MultiRowTab_OnOff_and_TabBar_Rows != -1 ? `
${MultiRowTab_OnOff_and_TabBar_Rows == 1 ? `
${TabBar_Rows_on_MouseOver == 0 || TabBar_Rows_on_MouseOver == 1 ? `
max-height: calc((var(--tab-min-height) + ${Proton_Margins ? 8 : 0}px) * 2);
` : `
max-height: calc((var(--tab-min-height) + ${Proton_Margins ? 8 : 0}px) * ${TabBar_Rows_on_MouseOver});
`}
&:not(:hover) {
max-height: calc(var(--tab-min-height) + ${Proton_Margins ? 8 : 0}px) !important;
${Proton_Margins ? `scrollbar-width: none;` : ``}
transition: all 0s ease-in-out ${TabBar_DisplayTime_on_MouseOver}s;
}
` : `
${Set_the_TabBar_to_the_Specified_Height ? `
min-height: calc((var(--tab-min-height) + ${Proton_Margins ? 8 : 0}px) * ${MultiRowTab_OnOff_and_TabBar_Rows});
& > slot {
max-height: calc(var(--tab-min-height) + ${Proton_Margins ? 8 : 0}px);
}
` : `
max-height: calc((var(--tab-min-height) + ${Proton_Margins ? 8 : 0}px) * ${MultiRowTab_OnOff_and_TabBar_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 ? `
&:has(> .tabbrowser-tab[fadein][pinned]) {
&::part(scrollbox) {
& > slot::after {
display: flow-root list-item;
content: "";
flex-basis: -moz-available;
height: 0;
overflow: hidden;
}
}
}
.tabbrowser-tab[fadein] {
&:not([pinned]) {
#tabbrowser-tabs[haspinnedtabs] & {
&, & + :not(#tabs-newtab-button) {
order: 1;
}
}
}
&[pinned] {
.tab-background:after {
content: "📌";
font-size: 11px;
right: -2px;
position: absolute;
top: -2px;
}
${PinnedTab_Width ? `
flex: 100 100;
max-width: ${PinnedTab_Max_Width}px;
min-width: ${PinnedTab_Min_Width}px;
.tab-throbber, .tab-icon-pending, .tab-icon-image, .tab-sharing-icon-overlay, .tab-icon-overlay {
margin-inline-end: 5.5px !important;
}
${PinnedTab_Close_Button == 1 ? `
.tab-close-button {
display: flex;
}
` : PinnedTab_Close_Button == 2 ? `
.tab-close-button {
display: none;
}
&:hover .tab-close-button {
display: flex;
}
` : PinnedTab_Close_Button == 3 ? `
&:not([selected]):hover,
&[selected] {
.tab-close-button {
display: flex;
}
}
` : ``}
` : ``}
}
}
` : ``}
#tabbrowser-tabs[haspinnedtabs]:not([positionpinnedtabs]):not([orient="vertical"]) > & {
& > .tabbrowser-tab:nth-child(1 of :not([pinned], [hidden])) {
margin-inline-start: 0 !important;
}
}
}
` : ``}
}
.tabbrowser-tab[fadein]:not([pinned]) {
max-width: ${Tab_Max_Width}px;
min-width: ${Tab_Min_Width}px;
${Tab_Close_Button == 1 ? `
.tab-close-button {
display: none;
}
` : Tab_Close_Button == 2 ? `
.tab-close-button {
display: flex;
}
` : Tab_Close_Button == 3 ? `
.tab-close-button {
display: none;
background: none !important;
fill: white !important;
scale: 1.3 !important;
}
&:hover .tab-close-button {
display: flex;
}
.tab-close-button.close-icon:hover {
fill: red !important;
}
` : Tab_Close_Button == 4 ? `
&:not([selected]):hover {
.tab-close-button {
display: flex;
}
}
` : ``}
}
${Tab_Separators ? `
.titlebar-spacer[type="pre-tabs"] {
border-inline-end: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}
.tabbrowser-tab {
&::after,
&::before {
border-left: 1px solid color-mix(in srgb, currentColor 50%, transparent);
height: calc(var(--tab-min-height) - 15%);
margin-block: auto;
}
&:hover::after,
&[multiselected]::after,
#tabbrowser-tabs:not([movingtab]) &:has(+ .tabbrowser-tab:hover)::after,
#tabbrowser-tabs:not([movingtab]) &:has(+ [multiselected])::after {
height: 100%;
}
&::after,
#tabbrowser-tabs[movingtab] &[visuallyselected]::before {
display: flex;
content: "";
}
}
` : ``}
${Proton_Margins ? `` : `
.tabbrowser-tab,
.toolbarbutton-1 {
padding: 0;
}
.tabbrowser-tab,
#tabs-newtab-button {
height: var(--tab-min-height);
}
.tabbrowser-tab {
.tab-background {
box-shadow: none;
margin-block: 0;
}
.tab-label-container,
.tab-close-button {
height: var(--tab-min-height);
max-height: 24px;
}
.tab-close-button {
padding-block: 0;
}
&[usercontextid] > .tab-stack > .tab-background > .tab-context-line {
margin-block-start: 1px !important;
}
}
`}
${TabBar_Position == 0 ? `
.titlebar-buttonbox-container {
height: calc(var(--tab-min-height) + ${Proton_Margins ? 8 : 0}px);
}
${TitleBar_Button_Autohide ? `
& > .titlebar-buttonbox-container {
background-color: color-mix(in srgb, currentColor 20%, transparent);
position: fixed;
right: 0;
&:not(:hover) {
height: 6px;
.titlebar-button {
padding: 0;
}
&,& .titlebar-button {
opacity: 0;
transition: all 0s ease-in-out ${TitleBar_Button_DisplayTime}s;
}
}
}
` : ``}
}` : `
${TabBar_Position == 1 || TabBar_Position == 2 ? `
& > .titlebar-buttonbox-container {
display: none;
}}
#nav-bar {
&:not(.browser-titlebar) {
:root[customtitlebar] #toolbar-menubar[autohide="true"] ~ &,
:root[inFullscreen] #toolbar-menubar ~ & {
& > .titlebar-buttonbox-container {
display: flex;
}
}
}
.titlebar-button {
padding-block: 0;
}
}
` : ``}
body:has(> #navigator-toolbox:not([tabs-hidden])) {
${TabBar_Position == 1 ? `
script, toolbar:not(#TabsToolbar ${Bookmark_Toolbar_Position ? `` : `, #PersonalToolbar`}) {
order: -1;
}
` : TabBar_Position == 2 ? `
& > #fullscr-toggler[hidden] + tabbox,
:root[inFullscreen] & > tabbox:hover {
border-top: 0.01px solid var(--chrome-content-separator-color);
}
& > tabbox > #navigator-toolbox {
border-block: none !important;
}
:root[inFullscreen] & {
& > #navigator-toolbox {
transition: none;
&:has(~ tabbox:hover) {
margin-top: 0 !important;
}
&:hover ~ tabbox > #navigator-toolbox {
display: flex;
}
}
& > tabbox:not(:hover) {
border-top: 0.01px solid transparent;
& > #navigator-toolbox {
display: none;
}
}
}
` : ``}
}
`}
toolbar[id$="bar"].browser-titlebar {
.titlebar-spacer {
&[type="pre-tabs"] {
width: ${Left_Drag_Area}px;
}
&[type="post-tabs"] {
width: ${Right_Drag_Area}px;
}
${Maximize_Left_Drag_Area ? `
:root[customtitlebar]:not([sizemode="normal"], [inFullscreen]) &[type="pre-tabs"] {
display: flex;
}
` : ``}
${Fullscreen_Drag_Area ? `
:root[customtitlebar][inFullscreen] & {
display: flex;
}
` : ``}
}
#navigator-toolbox[tabs-hidden] & {
#new-tab-button {
display: none;
}
}
}
`,
sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
uri = Services.io.newURI("data:text/css;charset=UTF=8," + encodeURIComponent(css));
["0", "2", "dragend", "SSTabRestored", "TabAttrModified"].find(eventType => {
if(!sss.sheetRegistered(uri, eventType)) sss.loadAndRegisterSheet(uri, eventType);
if (MultiRowTab_OnOff_and_TabBar_Rows > 0) {
gBrowser.tabContainer.addEventListener(eventType, (e) => {
e.target.scrollIntoView({ behavior: "instant", block: "nearest" })
})
}
})
if (TabBar_Position == 2) {
document.body.appendChild(
document.createXULElement("tabbox")
).appendChild(
document.importNode(document.getElementById("navigator-toolbox"))
).appendChild(
document.adoptNode(document.getElementById("TabsToolbar"))
)
}
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 (this.verticalMode || MultiRowTab_OnOff_and_TabBar_Rows == 0) {
// autoscroll the tab strip if we drag over the scroll
// buttons, even if we aren't dragging a tab, but then
// return to avoid drawing the drop indicator
var pixelsToScroll = 0;
if (this.overflowing) {
switch (event.originalTarget) {
case arrowScrollbox._scrollButtonUp:
pixelsToScroll = arrowScrollbox.scrollIncrement * -1;
break;
case arrowScrollbox._scrollButtonDown:
pixelsToScroll = arrowScrollbox.scrollIncrement;
break;
}
if (pixelsToScroll) {
arrowScrollbox.scrollByPixels(
(RTL_UI ? -1 : 1) * pixelsToScroll,
true
);
}
}
let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
if (
(effects == "move" || effects == "copy") &&
this == draggedTab.container &&
!draggedTab._dragData.fromTabList
) {
ind.hidden = true;
// if (this.#isAnimatingMoveTogetherSelectedTabs()) {
// // Wait for moving selected tabs together animation to finish.
// return;
// }
this._finishMoveTogetherSelectedTabs(draggedTab);
if (effects == "move") {
// Pinned tabs in expanded vertical mode are on a grid format and require
// different logic to drag and drop.
// if (this.#isContainerVerticalPinnedExpanded(draggedTab)) {
// this.#animateExpandedPinnedTabMove(event);
// return;
// }
this._animateTabMove(event);
return;
}
}
this._finishAnimateTabMove();
}
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 newMargin, newMarginY;
if (pixelsToScroll) {
// if we are scrolling, put the drop indicator at the edge
// so that it doesn't jump while scrolling
let scrollRect = arrowScrollbox.scrollClientRect;
let minMargin = this.verticalMode
? scrollRect.top - rect.top
: scrollRect.left - rect.left;
let maxMargin = this.verticalMode
? Math.min(minMargin + scrollRect.height, scrollRect.bottom)
: Math.min(minMargin + scrollRect.width, scrollRect.right);
if (RTL_UI) {
[minMargin, maxMargin] = [
this.clientWidth - maxMargin,
this.clientWidth - minMargin,
];
}
newMargin = pixelsToScroll > 0 ? maxMargin : minMargin;
} else {
let newIndex = this._getDropIndex(event);
let children = this.allTabs;
if (newIndex === children.length) {
tabRect = this.visibleTabs.at(-1).getBoundingClientRect();
if (this.verticalMode) {
newMargin = tabRect.bottom - rect.top;
} else if (RTL_UI) {
newMargin = rect.right - tabRect.left;
} else {
newMargin = tabRect.right - rect.left;
}
} else {
tabRect = children[newIndex].getBoundingClientRect();
if (this.verticalMode) {
newMargin = rect.top - tabRect.bottom;
} else if (RTL_UI) {
newMargin = rect.right - tabRect.right;
} else {
newMargin = tabRect.left - rect.left;
}
}
newMarginY = tabRect.top - rect.top + tabRect.height / 2 - rect.height / 2;
}
ind.hidden = false;
newMargin += this.verticalMode ? ind.clientHeight : ind.clientWidth / 2;
if (RTL_UI) {
newMargin *= -1;
}
ind.style.transform = this.verticalMode
? "translateY(" + Math.round(newMargin) + "px)"
: MultiRowTab_OnOff_and_TabBar_Rows == 0
? "translateX(" + Math.round(newMargin) + "px)"
: "translate(" + Math.round(newMargin) + "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._finishMoveTogetherSelectedTabs(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 oldTranslateX = Math.round(draggedTab._dragData.translateX);
let oldTranslateY = Math.round(draggedTab._dragData.translateY);
let tabWidth = Math.round(draggedTab._dragData.tabWidth);
let tabHeight = Math.round(draggedTab._dragData.tabHeight);
let translateOffsetX = oldTranslateX % tabWidth;
let translateOffsetY = oldTranslateY % tabHeight;
let newTranslateX = oldTranslateX - translateOffsetX;
let newTranslateY = oldTranslateY - translateOffsetY;
// Update both translate axis for pinned vertical expanded tabs
if (oldTranslateX > 0 && translateOffsetX > tabWidth / 2) {
newTranslateX += tabWidth;
} else if (oldTranslateX < 0 && -translateOffsetX > tabWidth / 2) {
newTranslateX -= tabWidth;
}
if (oldTranslateY > 0 && translateOffsetY > tabHeight / 2) {
newTranslateY += tabHeight;
} else if (oldTranslateY < 0 && -translateOffsetY > tabHeight / 2) {
newTranslateY -= tabHeight;
}
let dropIndex;
if (draggedTab._dragData.fromTabList) {
dropIndex = this._getDropIndex(event);
} else {
dropIndex = this.verticalMode || MultiRowTab_OnOff_and_TabBar_Rows == 0
? "animDropIndex" in draggedTab._dragData && draggedTab._dragData.animDropIndex
: this._getDropIndex(event);
}
let incrementDropIndex = true;
if (dropIndex && dropIndex > movingTabs[0]._tPos) {
dropIndex--;
incrementDropIndex = false;
}
let shouldTranslate =
!gReduceMotion && !("groupDropIndex" in draggedTab._dragData);
// if (this.#isContainerVerticalPinnedExpanded(draggedTab)) {
// shouldTranslate &&=
// (oldTranslateX && oldTranslateX != newTranslateX) ||
// (oldTranslateY && oldTranslateY != newTranslateY);
// } else
if (this.verticalMode) {
shouldTranslate &&= oldTranslateY && oldTranslateY != newTranslateY;
} else {
shouldTranslate &&= oldTranslateX && oldTranslateX != newTranslateX;
}
if (shouldTranslate) {
for (let tab of movingTabs) {
tab.toggleAttribute("tabdrop-samewindow", true);
tab.style.transform = `translate(${newTranslateX}px, ${newTranslateY}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 {
let groupTab =
"groupDropIndex" in draggedTab._dragData
? this.allTabs[draggedTab._dragData.groupDropIndex]
: null;
this._finishAnimateTabMove();
if (dropIndex !== false) {
for (let tab of movingTabs) {
gBrowser.moveTabTo(tab, dropIndex);
if (incrementDropIndex) {
dropIndex++;
}
}
}
if (groupTab) {
gBrowser.addTabGroup([groupTab, ...movingTabs], {
insertBefore: draggedTab,
});
}
}
} 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
Das ist 1:1 das Script aus Beitrag #14.
Gern möglich, habe ich nicht kontrolliert. Es funktioniert aber, und das ist gut.
Und wie erwähnt, ich hatte es zum Test schon vor einer ganzen Weile installiert.
Sorry, jetzt fällt mir ein, ich hatte das Script aus #14 rüber kopiert, deshalb.
Das Script hatte ich zum Test in Nightly mal installiert, es funktioniert auch unter den "verschärften" Bedingungen, und auch ohne Fehler in der Konsole. Kannst du das bitte mal bei dir testen.
// ==UserScript==
// @name Toolbox Button
// @version 1.4.0
// @author aminomancer
// @homepageURL https://github.com/aminomancer/uc.css.js
// @long-description
// @description
/*
Adds a new toolbar button that 1) opens the content toolbox on left click; 2) opens the browser toolbox on right click; 3) toggles "Popup Auto-Hide" on middle click. Left click will open the toolbox for the active tab, or close it if it's already open. Right click will open the elevated browser toolbox if it's not already open. If it is already open, then instead of trying to start a new process and spawning an irritating dialog, it'll just show a brief notification saying the toolbox is already open. The button also shows a badge while a toolbox window is open. Middle click will toggle the preference for popup auto-hide: `ui.popup.disable_autohide`. This does the same thing as the "Disable Popup Auto-Hide" option in the menu at the top right of the browser toolbox, prevents popups from closing so you can debug them.
If you want to change which mouse buttons execute which functions, search for `userChrome.toolboxButton.mouseConfig` in <about:config>. Change the 0, 1, and 2 values. 0 = left click, 1 = middle, and 2 = right. By default, when you open a browser toolbox window, the script will disable popup auto-hide, and then re-enable it when you close the toolbox. I find that I usually want popup auto-hide disabled when I'm using the toolbox, and never want it disabled when I'm not using the toolbox, so I made it automatic, instead of having to right click and then immediately middle click every time. If you don't like this automatic feature, you can turn it off by setting `userChrome.toolboxButton.popupAutohide.toggle-on-toolbox-launch` to false in about:config.
You can force the browser toolbox to open in multiprocess mode by holding Shift and Accel (Ctrl/Cmd) when you right click (or whatever mouse button you set `browserToolbox` to for `userChrome.toolboxButton.mouseConfig`) the button.
When you middle click, the button will show a notification telling you the current status of popup auto-hide, e.g. "Holding popups open." This is just so that people who use the feature a lot won't lose track of whether it's on or off, and won't need to open a popup and try to close it to test it. The toolbar button also changes appearance while popup auto-hide is disabled. It becomes blue like the downloads button and the icon changes into a popup icon. This change is animated, as long as the user doesn't have reduced motion enabled. All of these notifications use the native confirmation hint custom element, since it looks nice. That's the one that appears when you save a bookmark, `#confirmation-hint`. So you can customize them with that selector.
*/
// @downloadURL https://cdn.jsdelivr.net/gh/aminomancer/uc.css.js@master/JS/atoolboxButton.uc.js
// @updateURL https://cdn.jsdelivr.net/gh/aminomancer/uc.css.js@master/JS/atoolboxButton.uc.js
// @license This Source Code Form is subject to the terms of the Creative Commons Attribution-NonCommercial-ShareAlike International License, v. 4.0. If a copy of the CC BY-NC-SA 4.0 was not distributed with this file, You can obtain one at http://creativecommons.org/licenses/by-nc-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
// ==/UserScript==
(() => {
// Modify these strings for easy localization. I tried to use built-in strings
// for this so it would automatically localize itself, but I found that every
// reference to the "Browser Toolbox" throughout the entire firefox UI is
// derived from a single message in a single localization file, which doesn't
// follow the standard format. It can only be parsed by the devtools' own
// special l10n module, which itself can only be imported by a CJS module.
// Requiring CJS just for a button seems ridiculous, plus there really aren't
// any localized strings that work for these confirmation messages anyway, or
// even the tooltip. So if your UI language isn't English you can modify all the
// strings created by this script in the following object:
const l10n = {
// Confirmation hint. You receive this message when you right click the
// toolbox button, but a toolbox process for the window is already open. You
// can only have one toolbox open per-window. So if I have 3 windows open, and
// I right-click the toolbox button in window 1, then it'll launch a browser
// toolbox for window 1. If I then right-click the toolbox button in window 2,
// it'll launch a browser toolbox for window 2. But if I go back to window 1
// and right-click the toolbox button a second time, it will do nothing except
// show a brief confirmation hint to explain the lack of action.
alreadyOpenMsg: "Browser Werkzeuge sind bereits geöffnet.",
// Confirmation hint. This appears when you first middle-click the toolbox
// button. It signifies that popups are being kept open. That is, "popup
// auto-hide" has been temporarily disabled.
holdingOpenMsg: "Popups werden offen gehalten.",
// Confirmation hint. This appears when you middle-click the toolbox button a
// second time, toggling "popup auto-hide" back on, thereby allowing popups to
// close on their own.
lettingCloseMsg: "Popups werden automatisch geschlossen.",
bundles: {},
strings: new Map(),
getString(name, where) {
let string = this.strings.get(name);
if (string) return string;
string = this.bundles[where].GetStringFromName(name);
this.strings.set(name, string);
return string;
},
getFluentValue(id, args) {
return this.fluentStrings.formatValueSync(id, args);
},
get defaultLabel() {
return this.getString("toolbox.label", "toolbox");
},
get defaultTooltip() {
return this.defaultLabel;
},
};
ChromeUtils.defineLazyGetter(l10n.bundles, "menu", () =>
Services.strings.createBundle("chrome://devtools/locale/menus.properties")
);
ChromeUtils.defineLazyGetter(l10n.bundles, "toolbox", () =>
Services.strings.createBundle("chrome://devtools/locale/toolbox.properties")
);
ChromeUtils.defineLazyGetter(
l10n,
"fluentStrings",
() => new Localization(["devtools/client/toolbox.ftl"], true)
);
if (
/^chrome:\/\/browser\/content\/browser.(xul||xhtml)$/i.test(location) &&
!CustomizableUI.getPlacementOfWidget("toolbox-button", true)
) {
const { loader } = ChromeUtils.importESModule(
"resource://devtools/shared/loader/Loader.sys.mjs"
);
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
BrowserToolboxLauncher:
"resource://devtools/client/framework/browser-toolbox/Launcher.sys.mjs",
});
for (const [key, val] of Object.entries({
gDevToolsBrowser:
"resource://devtools/client/framework/devtools-browser.js",
Actor: "resource://devtools/shared/protocol/Actor.js",
dumpn: "resource://devtools/shared/DevToolsUtils.js",
})) {
loader.lazyRequireGetter(lazy, key, val, true);
}
if (location.href !== 'chrome://browser/content/browser.xhtml') return;
CustomizableUI.createWidget({
id: "toolbox-button",
type: "custom",
defaultArea: CustomizableUI.AREA_NAVBAR,
label: l10n.defaultLabel,
removable: true,
overflows: true,
tooltiptext: l10n.defaultTooltip,
onBuild(aDoc) {
let CustomHint = {
...aDoc.ownerGlobal.ConfirmationHint,
/**
* Shows a transient, non-interactive confirmation hint anchored to an
* element, usually used in response to a user action to reaffirm that
* it was successful and potentially provide extra context.
*
* @param anchor (DOM node, required)
* The anchor for the panel. A value of null will anchor to the
* viewpoint (see options.x below)
* @param message (string, required)
* The message to be shown.
* @param options (object, optional)
* An object with any number of the following optional properties:
* - event (DOM event): The event that triggered the feedback.
* - hideArrow (boolean): Optionally hide the arrow.
* - hideCheck (boolean): Optionally hide the checkmark.
* - description (string): If provided, show a more detailed
* description/subtitle with the passed text.
* - duration (numeric): How long the hint should stick around, in
* milliseconds. Default is 1500 — 1.5 seconds.
* - position (string): One of a number of strings representing how the anchor point of the popup
* is aligned relative to the anchor point of the anchor node.
* Possible values for position are:
* before_start, before_end, after_start, after_end,
* start_before, start_after, end_before, end_after,
* overlap, after_pointer
* For example, after_start means the anchor node's bottom left corner will
* be aligned with the popup node's top left corner. overlap means their
* top left corners will be lined up exactly, so they will overlap.
* - x (number): Horizontal offset in pixels, relative to the anchor.
* If no anchor is provided, relative to the viewport.
* - y (number): Vertical offset in pixels, relative to the anchor. Negative
* values may also be used to move to the left and upwards respectively.
* Unanchored popups may be created by supplying null as the
* anchor node. An unanchored popup appears at the position
* specified by x and y, relative to the viewport of the document
* containing the popup node. (ignoring the anchor parameter)
*
*/
show(anchor, message, options = {}) {
this._reset();
this._message.removeAttribute("data-l10n-id");
this._message.textContent = message;
if (options.description) {
this._description.removeAttribute("data-l10n-id");
this._description.textContent = options.description;
this._description.hidden = false;
this._panel.classList.add("with-description");
} else {
this._description.hidden = true;
this._panel.classList.remove("with-description");
}
if (options.hideArrow) {
this._panel.setAttribute("hidearrow", "true");
}
if (options.hideCheck) {
this._animationBox.setAttribute("hidden", "true");
this._panel.setAttribute("data-message-id", "hideCheckHint");
} else {
this._animationBox.removeAttribute("hidden");
this._panel.setAttribute("data-message-id", "checkmarkHint");
}
const DURATION = options.duration || 1500;
this._panel.addEventListener(
"popupshown",
() => {
this._animationBox.setAttribute("animate", "true");
this._timerID = setTimeout(
() => this._panel.hidePopup(true),
DURATION + 120
);
},
{ once: true }
);
this._panel.addEventListener("popuphidden", () => this._reset(), {
once: true,
});
let { position, x, y } = options;
this._panel.openPopup(null, {
position,
triggerEvent: options.event,
});
this._panel.moveToAnchor(anchor, position, x, y);
},
_reset() {
if (this._timerID) {
clearTimeout(this._timerID);
this._timerID = null;
this._animationBox.removeAttribute("hidden");
}
if (this.__panel) {
this._panel.removeAttribute("hidearrow");
this._animationBox.removeAttribute("animate");
this._panel.removeAttribute("data-message-id");
this._panel.hidePopup();
}
},
_ensurePanel() {
if (!this.__panel) {
// hook into the built-in confirmation hint element
let wrapper = document.getElementById(
"confirmation-hint-wrapper"
);
wrapper?.replaceWith(wrapper.content);
this.__panel = ConfirmationHint.__panel =
document.getElementById("confirmation-hint");
}
},
};
let toolbarbutton = aDoc.createXULElement("toolbarbutton");
let badgeStack = aDoc.createXULElement("stack");
let icon = aDoc.createXULElement("image");
let label = aDoc.createXULElement("label");
let badgeLabel = aDoc.createElement("label");
for (const [key, val] of Object.entries({
class: "toolbarbutton-1 chromeclass-toolbar-additional",
badged: true,
label: l10n.defaultLabel,
id: "toolbox-button",
role: "button",
icon: "toolbox",
removable: true,
overflows: true,
tooltiptext: l10n.defaultTooltip,
})) {
toolbarbutton.setAttribute(key, val);
}
toolbarbutton.appendChild(badgeStack);
badgeStack.after(label);
badgeStack.appendChild(icon);
icon.after(badgeLabel);
badgeStack.setAttribute("class", "toolbarbutton-badge-stack");
icon.setAttribute("class", "toolbarbutton-icon");
badgeLabel.setAttribute("class", "toolbarbutton-badge");
for (const [key, val] of Object.entries({
class: "toolbarbutton-text",
crop: "right",
flex: "1",
value: l10n.defaultLabel,
})) {
label.setAttribute(key, val);
}
let prefSvc = Services.prefs;
let defaultPrefs = prefSvc.getDefaultBranch("");
let obSvc = Services.obs;
let toolboxBranch = "userChrome.toolboxButton";
let autoHide = "ui.popup.disable_autohide";
let autoTogglePopups =
"userChrome.toolboxButton.popupAutohide.toggle-on-toolbox-launch";
let mouseConfig = "userChrome.toolboxButton.mouseConfig";
let onClick = function (e) {
let { button } = e;
let accel = e.getModifierState("Accel");
let shift = e.getModifierState("Shift");
if (accel) {
if (button == 2 && !shift) {
return;
}
if (button == 0 && AppConstants.platform == "macosx") {
button = 2;
accel = false;
}
}
switch (button) {
case this.mouseConfig.contentToolbox:
// toggle the content toolbox
lazy.gDevToolsBrowser.toggleToolboxCommand(
aDoc.ownerGlobal.gBrowser
);
break;
case this.mouseConfig.browserToolbox:
if (lazy.BrowserToolboxLauncher.getBrowserToolboxSessionState()) {
// check if a browser toolbox window is already open. if so,
// just show a hint that it's already open.
CustomHint.show(toolbarbutton, l10n.alreadyOpenMsg, {
event: e,
hideCheck: true,
});
} else {
// if not, launch a new one.
lazy.BrowserToolboxLauncher.init({
forceMultiprocess: accel && shift,
});
}
break;
case this.mouseConfig.popupHide:
CustomHint.show(
toolbarbutton,
l10n[this.popupAutoHide ? "lettingCloseMsg" : "holdingOpenMsg"],
{ event: e, hideCheck: this.popupAutoHide }
);
// toggle the pref
prefSvc.setBoolPref(autoHide, !this.popupAutoHide);
// animate the icon transformation
this.triggerAnimation();
break;
default:
return;
}
e.preventDefault();
};
if (AppConstants.platform === "macosx") {
toolbarbutton.onmousedown = onClick;
toolbarbutton.onclick = e => {
if (e.getModifierState("Accel")) return;
e.preventDefault();
};
} else {
toolbarbutton.onclick = onClick;
}
toolbarbutton.triggerAnimation = function () {
this.addEventListener(
"animationend",
() => this.removeAttribute("animate"),
{ once: true }
);
this.setAttribute("animate", "true");
};
function getPref(root, pref) {
switch (root.getPrefType(pref)) {
case root.PREF_BOOL:
return root.getBoolPref(pref);
case root.PREF_INT:
return root.getIntPref(pref);
case root.PREF_STRING:
return root.getStringPref(pref);
default:
return null;
}
}
function prefObserver(sub, _top, pref) {
let value = getPref(sub, pref);
switch (pref) {
case autoHide:
if (value === null) value = false;
toolbarbutton.popupAutoHide = value;
if (value) {
// change icon src to popup icon
toolbarbutton.setAttribute("icon", "autohide");
// highlight color
icon.style.fill = "var(--toolbarbutton-icon-fill-attention)";
} else {
// change icon src to toolbox icon
toolbarbutton.setAttribute("icon", "toolbox");
// un-highlight color
icon.style.removeProperty("fill");
}
break;
case autoTogglePopups:
if (value === null) value = true;
toolbarbutton.autoTogglePopups = value;
break;
case mouseConfig:
if (value === null) {
value = {
contentToolbox: 0,
browserToolbox: 2,
popupHide: 1,
};
}
toolbarbutton.mouseConfig = JSON.parse(value);
toolbarbutton.setStrings();
break;
}
}
// listen for toolboxes opening and closing
function toolboxObserver(sub, top, _data) {
// whether a toolbox is open
let state =
lazy.BrowserToolboxLauncher.getBrowserToolboxSessionState();
// set toolbar button's badge content
badgeLabel.textContent = state ? 1 : "";
// if toolbox is open and autohide is not already enabled, enable it
switch (top) {
case "initial-load":
return;
// when a thread is created, set up its destroy method so it will
// call the observer when it's destroyed. this ensures that if a
// toolbox is closed while a content toolbox is inspecting the
// system principal (such as on about:preferences), we will still
// get notified that the toolbox has closed. otherwise, we wouldn't
// get notified until the content toolbox also closes.
case "devtools-thread-ready": {
let threadActor = sub?.wrappedJSObject;
if (threadActor) {
if (threadActor.destroy.name !== "destroyThreadActor") {
const STATES = {
DETACHED: "detached",
EXITED: "exited",
RUNNING: "running",
PAUSED: "paused",
};
threadActor.destroy = function destroyThreadActor() {
lazy.dumpn("in ThreadActor.prototype.destroy");
if (this._state == STATES.PAUSED) {
this.doResume();
}
this.removeAllWatchpoints();
this._xhrBreakpoints = [];
this._updateNetworkObserver();
this._activeEventBreakpoints = new Set();
this._debuggerNotificationObserver.removeListener(
this._eventBreakpointListener
);
for (const global of this.dbg.getDebuggees()) {
try {
this._debuggerNotificationObserver.disconnect(
global.unsafeDereference()
);
} catch (e) {
}
}
this.targetActor.off("window-ready", this._onWindowReady);
this.targetActor.off("will-navigate", this._onWillNavigate);
this.targetActor.off("navigate", this._onNavigate);
this.sourcesManager.off("newSource", this.onNewSourceEvent);
this.clearDebuggees();
this._threadLifetimePool.destroy();
this._threadLifetimePool = null;
this._dbg = null;
this._state = STATES.EXITED;
lazy.Actor.prototype.destroy.call(this);
// this leads back to toolboxObserver in 200ms
setTimeout(() => Services.obs.notifyObservers(null, "devtools-thread-destroyed"), 200);
}
}
}
break;
}
default:
break;
}
if (!toolbarbutton.autoTogglePopups) return;
if (state && !toolbarbutton.popupAutoHide) {
prefSvc.setBoolPref(autoHide, true);
}
// if toolbox just closed and autohide is not already disabled, disable it
else if (!state && toolbarbutton.popupAutoHide) {
prefSvc.setBoolPref(autoHide, false);
}
}
toolbarbutton.setStrings = function () {
let hotkey, labelString;
for (const [key, val] of Object.entries(toolbarbutton.mouseConfig)) {
if (val === 0) {
switch (key) {
case "contentToolbox":
labelString = l10n.getString("toolbox.label", "toolbox");
hotkey = aDoc.getElementById("key_toggleToolbox");
break;
case "browserToolbox":
labelString = l10n.getString(
"browserToolboxMenu.label",
"menu"
);
hotkey = aDoc.getElementById("key_browserToolbox");
break;
case "popupHide":
labelString = l10n.getFluentValue(
"toolbox-meatball-menu-noautohide-label"
);
break;
}
}
}
let shortcut = hotkey
? ` (${ShortcutUtils.prettifyShortcut(hotkey)})`
: "";
toolbarbutton.label = labelString;
label.value = labelString;
toolbarbutton.tooltipText = labelString + shortcut;
};
// remove this window's observers when the window closes, since observers are global
function uninit() {
prefSvc.removeObserver(autoHide, prefObserver);
prefSvc.removeObserver(toolboxBranch, prefObserver);
for (const topic of [
"devtools-thread-ready",
"devtools-thread-destroyed",
"devtools:loader:destroy",
]) {
obSvc.removeObserver(toolboxObserver, topic);
}
window.removeEventListener("unload", uninit);
}
function toolboxInit() {
prefObserver(prefSvc, null, autoHide);
prefObserver(prefSvc, null, autoTogglePopups);
prefObserver(prefSvc, null, mouseConfig);
toolboxObserver(null, "initial-load");
}
defaultPrefs.setBoolPref(autoTogglePopups, true);
defaultPrefs.setStringPref(
mouseConfig,
`{"contentToolbox": 0, "browserToolbox": 2, "popupHide": 1}`
);
window.addEventListener("unload", uninit);
prefSvc.addObserver(autoHide, prefObserver);
prefSvc.addObserver(toolboxBranch, prefObserver);
for (const topic of [
"devtools-thread-ready",
"devtools-thread-destroyed",
"devtools:loader:destroy",
]) {
obSvc.addObserver(toolboxObserver, topic);
}
if (gBrowserInit.delayedStartupFinished) {
toolboxInit();
} else {
let delayedListener2 = (subject, topic) => {
if (
topic == "browser-delayed-startup-finished" &&
subject == window
) {
obSvc.removeObserver(delayedListener2, topic);
toolboxInit();
}
};
obSvc.addObserver(
delayedListener2,
"browser-delayed-startup-finished"
);
}
return toolbarbutton;
},
});
}
let styleSvc = Cc["@mozilla.org/content/style-sheet-service;1"].getService(
Ci.nsIStyleSheetService
);
let toolboxCSS = /* css */ `
.toolbarbutton-1#toolbox-button {
--uc-toolbox-button: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAdUlEQVQokZVSwRHAIAgLPYfoXs7RCTpG53Avt7APrhaFU8gLMEEJAkEQgFbc7IxkVjt0r6Sp7VIVITumBpKt00FA2ThmjXzkfMMWO8EZFSj8LrUyjsG9b9DaJXq+qAIVxEUxtLHpaXE95dj1NcK2rmbwaGJ4Af0tIg00j/6iAAAAAElFTkSuQmCC');
--uc-autohide-button: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAATCAYAAABlcqYFAAABeUlEQVQ4ja3UMSiEcRjH8Z8jKWU8q03JYEAhZ7PcZDFYrMpOWaTEgsEom4RFBmEjcSaEU0onFN0Rd9dFzr3er+Ut7vV/eS/vU7/l3/s8n/f/PvVKrkKKIm0hJZEoIUmkTaQO90w3MFniYK8MewHRgACQLKRmE7IRIALSkglJBYzcmhDPhrtwGJ6fIZeDTOYrwF5ri2dfSchBZxumOpoY5+mXvpKQ7NzID+Dl4Z6TitCvn8w3kpbIJS5dxBv7TbV/7sU3chOuAssqIqzMOfGZUV5W1yAWIzE4+D9kp6vLGf0KWLjrIx9nO9L4T6SmhrWePs7GI2A/FgHvJ/PEqwNaPBLHPZEi4HB6ipugdoJEQeJqZRYAO59kt7+B1B+AF+L5101UCgppwOYwWmceWubk6+zChKx7IamVXk6XxzgtD/Hh4wZOFkxIO5LtfjgrsdVdRjzkPdAA55HqfyAONIRU8Pmm2ObzPNKAEfgGNSMtIl37xZxcIy2YbvAJBGtcN/WRF/UAAAAASUVORK5CYII');
list-style-image: var(--uc-toolbox-button);
align-items: center;
}
.toolbarbutton-1#toolbox-button[icon="autohide"] {
list-style-image: var(--uc-autohide-button);
}
.toolbarbutton-1#toolbox-button .toolbarbutton-badge-stack {
justify-items: center;
}
.toolbarbutton-1#toolbox-button .toolbarbutton-icon {
height: 16px;
width: 16px;
transition: fill 50ms ease-in-out 0s;
background-image: var(--uc-toolbox-button), var(--uc-autohide-button);
background-size: 0, 0;
}
@media (prefers-reduced-motion: no-preference) {
.toolbarbutton-1#toolbox-button[animate] .toolbarbutton-icon {
animation-name: toolboxButtonPulse;
animation-duration: 200ms;
animation-iteration-count: 1;
animation-timing-function: ease-in-out;
}
}
@keyframes toolboxButtonPulse {
from {
transform: scale(1);
}
40% {
transform: scale(0.7);
}
to {
transform: scale(1);
}
}
#confirmation-hint[data-message-id="hideCheckHint"] #confirmation-hint-message {
margin-inline: 0;
}`;
if (location.href !== 'chrome://browser/content/browser.xhtml') return;
let styleURI = makeURI(
`data:text/css;charset=UTF=8,${encodeURIComponent(toolboxCSS)}`
);
if (!styleSvc.sheetRegistered(styleURI, styleSvc.AUTHOR_SHEET)) {
styleSvc.loadAndRegisterSheet(styleURI, styleSvc.AUTHOR_SHEET);
}
let observer = new MutationObserver(() => {
if (document.getElementById("key_toggleToolbox")) {
CustomizableUI.getWidget("toolbox-button")
.forWindow(window)
.node.setStrings();
observer.disconnect();
observer = null;
}
});
observer.observe(document.body, { childList: true });
})();
Alles anzeigen
lieber wäre mir aber, jemand findet eine Lösung zur Anpassung vom Skript
Ja, das wäre natürlich das Beste. In der Konsole wird dieser Eintrag als Fehler ausgegeben, habe schon daran gebastelt, aber ohne Erfolg.
Die dritte wäre, dass ich noch erleuchtet werde und mir eine funktionierende Lösung "zufliegt".
Ich bin bei Dir.
Kannst Du bitte auch überprüfen, in Version 138 funktioniert das Verschieben von Tabs nicht mehr.
Gerade in Nightly Update eingespielt, nun ist es vorbei mit der doppelten Anzeige.
Edit: Irrtum!
Es ist wirklich so, es passiert nur über Rechtsklick einfügen. Mit STRG+V passiert es nicht.
wird der Code hier doppelt eingetragen.
Ist hier auch so.
Das heißt, selbst wenn man die Farbe entfernt, wird der Button doch immer noch bei Klick auf die falschen Stellen reagieren.
Stimmt, aber das konnte ich nur so erreichen, dass bei hover der Hintergrund ausgeblendet wird. Es wird bestimmt andere Möglichkeiten geben, aber i.M. konnte ich noch nichts finden.