1. Nachrichten
  2. Forum
    1. Unerledigte Themen
    2. Forenregeln
  3. Spenden
  • Anmelden
  • Registrieren
  • Suche
Alles
  • Alles
  • Artikel
  • Seiten
  • Forum
  • Erweiterte Suche
  1. camp-firefox.de
  2. Speravir

Beiträge von Speravir

  • UserCSSLoader (2025)

    • Speravir
    • 7. September 2025 um 01:34

    Zunächst: Allgemein danke für die Rückmeldung, Bege!

    Zitat von bege

    Bei mir funktioniert der FreeCommander mit der bisherigen Version seit Jahren.

    Hmm, interessant: Ich hab mir eine portable Version heruntergeladen und mit der funktioniert es nicht (ich rufe dann die PortableExe auf, die die Parameter weiterreicht). Aber vor allem ist in der Online-Hilfe für Kommandozeilenparameter des Freecommander eindeutig zu erkennen, dass der Parameter /T nachgestellt wird.

    Zitat von bege

    Das funktioniert in deiner vorherigen Version, nicht aber in der neuesten in Beitrag #63. Schaust du bitte mal, was geändert werden muss, damit es wieder geht?

    Anschauen ja, versprechen nein.

    Zitat von bege

    und in openCSSFolder:function() könnte if {} else {} raus, weil dann immer ein Dateimanager eingetragen ist. Auch die Abfrage für menutooltip wäre dann überflüssig.

    Nein, das entferne ich nicht. Das ist sozusagen die Backup-Funktion. Du solltest nicht vergessen, dass es noch Linux und MacOS gibt oder allgemein neben Windows noch die unixoiden Systeme.

    Zitat von bege

    Wenn ich das in openFile: wiederherstelle, funktioniert es wieder. Sieht so aus, als ob der Windows-Explorer die systemspezifischen Separatoren braucht.

    Code
    const PathSep = AppConstants.platform === "win" ? "\\" : "/";
    				let target= this.FOLDER.path + PathSep + fname;

    Oh, vielleicht lag es wirklich genau daran, dass es meine Versuche mit dem Explorer nicht erfolgreich waren, habe ich gar nicht mehr dran gedacht.

    Dann müsste ich aber auch

    ChromeUtils.importESModule("resource://gre/modules/AppConstants.sys.mjs");

    wieder einführen und genau darauf wollte ich verzichten, denn das erzeugt eine Inkompatibilität: Der Aufruf verändert sich vermutlich von Fx 142 zu 143 und jemand, der eine Nightly-Version nutzt ( 2002Andreas, milupo?), müsste mir den neuen Pfad mitteilen.

    Zitat von bege

    Wobei die Änderung von openFolder zu openFile nicht ganz passt. Die CSS-Dateien werden nicht geöffnet, sondern nur im Dateimanager im Order angezeigt.

    Stimmt, das ist missverständlich.

    Zitat von bege

    Hm, ist noch nicht "produktionsreif". /select, führt dazu, dass der Explorer alles nur auswählt. Damit werden auch die Ordner nicht geöffnet, sondern nur ausgewählt.

    Auch merkwürdig. Wenn ich direkt von der Kommandozeile C:\Windows\explorer.exe /select, C:\Beispielpfad\Beispiel.txt aufrufe, dann geht das bei mir.

  • UserCSSLoader (2025)

    • Speravir
    • 4. September 2025 um 01:23

    Und nochmal eine Ergänzung nur in der Anleitung, dieses Mal nur im CSS-Code (Hover-Regel). Ich poste den Teil einmal im herkömmlichen Stil (nicht verschachtelt, also ohne "&"), vielleicht für Boersenfeger interessant:

    CSS
    #usercssloader-menu-item {
    	background-image: url("Relativer/Pfad/zum/CSS_Symbol.png");
    	background-position: center;
    	background-repeat: no-repeat;
    	background-size: 16px;
    }
    
    #usercssloader-menu-item:hover {
    	background-color: var(--toolbarbutton-hover-background);
    }
    
    #usercssloader-menu-item #usercssloader-menu > .menu-text[value="CSS"] {
    	opacity: 0;
    	width: calc(2 * var(--toolbarbutton-inner-padding) + 16px);
    	height: calc(2 * var(--toolbarbutton-inner-padding) + 16px);
    }
    Alles anzeigen

    Die Hover-Regel und die Deklarationen zu Breite und Höhe entsprechen dem Standard für Toolbar-Buttons mit den jeweiligen Vorgaben der Variablen (angepasste Eigenschaften).

  • UserCSSLoader (2025)

    • Speravir
    • 31. August 2025 um 00:08

    Erneute kleine Codeänderung in der Anleitung wegen des Symbols und im Code wegen userChrome/userContent bearbeiten, siehe weiterhin am Ende von Beitrag #63.

    seipe, sieh dir bitte die Anleitung ab Zeile 53 an. Ist das verständlich genug für dich?

  • UserCSSLoader (2025)

    • Speravir
    • 30. August 2025 um 01:21

    Hinweis: Kleine Änderung am Code: Statt hideUserChromeCSS/hideUserContentCSS heißt es jetzt showUserChromeCSS/showUserContentCSS mit entsprechender Umkehrung der Logik. Ich habe das Skript in #63 angepasst.

  • UserCSSLoader (2025)

    • Speravir
    • 29. August 2025 um 02:29

    Endor, BarbaraZ-, bege, Boersenfeger, lenny2, Mira_Belle, seipe (noch jemand ohne Fahrschein vergessen?):

    Bitte die am Ende dieses Postings angehängte Version testen. Mehr kann ich daran nicht mehr ändern, denke ich, außer es fallen Tippfehler auf.

    Vorher noch ein paar Anmerkungen:

    • Manche Editoren benötigen nach dem Pfad angehängte Parameter, beispielsweise der FreeCommander, Dafür gibt es jetzt die Variable fileManagerParamPost.
    • fileManagerParam verträgt anscheinend nur einen einzigen Parameter ohne Leerzeichen. Ich weiß nicht, ob beispielsweise BrokenHeart das ändern kann. Als Ausweg bleibe weiterhin, die Variable im Skript leer zu lassen und als Dateimanager eine Link- beziehungsweise Shell-Datei einzutragen, in der dann die Parameter eingetragen werden.
    • Ich habe einige Tastenzuordnungen geändert, bitte Bescheid geben, wenn das nicht gefällt. Bege wollte „Chrome-Ordner öffnen“ zu M ändern, ich habe es auf X gelassen (vergleiche Diskussion auf der vorigen Threadseite). Jeder kann das aber für sich ändern (wie auch die anderen Tasten, man muss nur auf Kollisionen mit bestehenden Verwendungen achten).
    Zitat von Mira_Belle

    Jetzt muss ich nur noch sehen, wie ich das Skript, bzw, die Funktionen in das App-Menü bekomme.

    Verlinke bitte mal zum Thread, wo Du das Skript gepostet hast.

    Zitat von Mira_Belle

    Kann man den "überflüssigen" Code dann nicht entfernen?

    Hab ich getan. Das heißt für die Zukunft, dass Vergleiche mit der externen Vorlage aufwendiger werden.

    Zitat von Boersenfeger

    Meine CSS-Datei dafür

    CSS
    /* UserStyles Loader Button */
    /* weitere Kommentare von Speravir eingefügt */    
    	#usercssloader-menu { /* besser #usercssloader-menu-item */
    	/* … */
    	content: '' !important; /* kann entfernt werden */
    	/* … */
    	}
        
    	#usercssloader-menu > .menu-text,
    	#usercssloader-menu > .menu-right { /* .menu-right gibt es nicht mehr */
        display: none !important;
    	}
        
    	#usercssloader-menu:hover { /* besser #usercssloader-menu:hover-item */
    	/* … */
    	content: '' !important; /* kann entfernt werden */
    	/* … */
    	}
        
        /* doppelt: */
    	#usercssloader-menu > .menu-text,
    	#usercssloader-menu > .menu-right { /* .menu-right gibt es nicht mehr */
        display: none !important;
    	}
    	
    	/*… */
    Alles anzeigen

    Die Eigenschaft content kann jeweils entfernt werden. Ich hielte es auch für besser, das Symbol der ID #usercssloader-menu-item zuzuorden, damit es keine Konflikte mit dem Menü gibt. Die Deklaration zum Ausblenden hast du doppelt eingetragen – einmal reicht, davon kann der Teil mit .menu-right entfernt werden (der erste Teil kann so bleiben, nur Komma entfernen). Beachte meine Kommentare im Stil.

    Zitat von bege

    Ich bekam die Windows-Fehlermeldung, dass das System den Pfad "...\CSS\undefined" nicht finden kann.

    Das hätte mir sofort zu denken geben müssen. Die Ursache dessen habe ich irgendwann mal eingebaut. Es war wohl von Anfang fehlerhaft, wurde aber stillschweigend ignoriert, jedenfalls funktionierte das, was ich einbaute, so, wie gedacht, wie Du selbst bestätigst. Genau dazu gab es aber in einer der letzten Versionen eine Verhaltensänderung des Fuxes. Ich bin jetzt im Prinzip bei Deiner Lösung gelandet, nachdem ich vergeblich mehrere andere Varianten ausprobiert habe.

    Zitat von bege

    Kann man "openFolder" so ergänzen, dass auch im Windows-Explorer die Datei und nicht nur der Ordner angezeigt werden?

    Ich wollte erst schreiben, indem man ihn explizit als Dateimanager einträgt, aber ein Test zeigte, dass es mit ihm nicht funktioniert, und zwar überhaupt nicht. Ich bin damit ebenso wie Du überfragt.

    JavaScript: UserCSSLoader_2025-08-29
    // ==UserScript==
    // @name           UserCSSLoader
    // @description    CSS-Codes - Styles laden und verwalten
    // @namespace      http://d.hatena.ne.jp/Griever/
    // @author         Griever
    // @include        main
    // @license        MIT License
    // @compatibility  Firefox 141+
    // @charset        UTF-8
    // @version        0.0.4r4++
    // @note           erneute Änderungen von Speravir mit Hilfe von bege, Entfernung von Codeteilen
    // @note           0.0.4r4 prevent close menu when middleclick
    // @note           Aktualisierungen von BrokenHeart (mit 0.0.4r4 obsolet) und Speravir - www.camp-firefox.de
    // @note           0.0.4r3 Fx92: getURLSpecFromFile() -> getURLSpecFromActualFile()
    // @note           0.0.4r2 AUTHOR_SHEET-Unterstützung hinzugefügt, wichtig: Dateiendung muss .author.css sein!
    // @note           Version 0.0.4.g ermöglicht "Styles importieren" per Mittelklick und Verwendung
    // @note           eines anderen Dateimanagers (siehe in Konfiguration), ergänzt um einen
    // @note           Parameter für den Dateimanager, von aborix
    // @note           Frei verschiebbare Schaltfläche eingebaut von aborix
    // @note           0.0.4 Remove E4X
    // @note           CSS-Entry-Klasse erstellt
    // @note           Style-Test-Funktion überarbeitet
    // @note           Wenn die Datei gelöscht wurde, CSS beim Neu-Erstellen und Löschen des Menüs abbrechen
    // @note           uc einlesen .uc.css temporäre Korrespondenz zum erneuten Lesen
    // ==/UserScript==
    
    /*
      Endor in https://www.camp-firefox.de/forum/thema/138814/?postID=1277236#post1277236
      Speravir in https://www.camp-firefox.de/forum/thema/138814/?postID=1278065#post1278065
    */
    
    /****** Bedienungsanleitung ******
    
    CSS-Ordner im Chrome-Ordner erstellen, CSS-Dateien dort ablegen - speichern.
    Diejenigen, deren Dateiname mit "xul-" beginnen, diejenigen, die mit ".as.css" enden, sind AGENT_SHEET, 
    alle anderen außer USER_SHEET werden gelesen. Da der Inhalt der Datei nicht überprüft wird,
    darauf achten, die Angabe von @namespace nicht zu vergessen!
    
    Schaltfläche wird in Navigationsleiste eingefügt (konfigurierbar, siehe Variable "position").
    
    Linksklick auf Stil, zum Aktivieren/Deaktivieren
    Mittelklick auf Stil zum Aktivieren/Deaktivieren, ohne Menü zu schließen
    Rechtsklick auf Stil zum Öffnen im Editor
    Strg+Linksklick zum Anzeigen im Dateimanager
    
    Die Tastenkombinationen können im Menü eingeblendet werden, dazu nach
    "acceltext" suchen und den Zeilenkommentar "//" entfernen.
    
    Verwenden des in "view_source.editor.path" angegebenen Editors.
    
    Dateiordner, Dateimanager und Texteditor können in Konfiguration geändert werden.
    
    Ein Symbol für die Schaltfläche muss in der "userChrome.css" festgelegt werden,
    Pfad zum Bild (PNG nur als Beispiel):
    * relativ zur userChrome.css
    	background-image: url("Relativer/Pfad/zum/CSS_Symbol.png") !important;
    * eine absolute Pfadangabe zum Symbol muss mit File-Protokoll-Präfix erfolgen:
    	background-image: url("file:///Absoluter/Pfad/zum/CSS_Symbol.png") !important;
    
    #usercssloader-menu-item {
    	background-image: url("Relativer/Pfad/zum/CSS_Symbol.png");
    	background-position: center;
    	background-repeat: no-repeat;
    	background-size: 16px;
    
    	&:hover {
    		background-color: var(--toolbarbutton-hover-background);
    	}
    
    	& #usercssloader-menu > .menu-text[value="CSS"] {
    		opacity: 0;
    		width: calc(2 * var(--toolbarbutton-inner-padding) + 16px);
    		height: calc(2 * var(--toolbarbutton-inner-padding) + 16px);
    	}
    }
    
    **** Anleitung Ende ****/
    
    (function(){
    
    /***** Konfiguration *****/
    // Position: als frei verschiebbare-Schaltfläche = 0, als Menü anzeigen = 1
    let position = 0;//1
    /* alternativer Dateimanager, Beispiele:
         let fileManager = "C:\\Programme\\FreeCommanderXE\\FreeCommander.exe";
         let fileManager = "C:\\Programme\\totalcmd\\TOTALCMD.EXE"
    */
    let fileManager = "";
    /* eventuelle Parameter für den alternativen Dateimanager;
       manche Editoren benötigen Parameter nach der Pfadangabe,
       dann "fileManagerParamPost" auf true setzen */
    //let fileManagerParam = "/T";//FreeCommander oder Totalcommander
    let fileManagerParam = "";
    let fileManagerParamPost = false;// beispielsweise FreeCommander benötigt true
    /* eigener Texteditor mit Pfad - Standard leer, dann wird Wert aus Einstellung
       "view_source.editor.path" verwendet mit Warnmeldung, wenn auch dieser leer ist */
    //let customEditor = "C:\\Windows\\System32\\notepad.exe";
    let customEditor = "";
    // Unterordner für die CSS-Dateien:
    let cssFolder = "CSS";
    // Menüeintrag zum Bearbeiten der userChrome.css anzeigen (true) oder verstecken (false)
    let showUserChromeCSS = true;
    // Menüeintrag zum Bearbeiten der userContent.css anzeigen (true) oder verstecken (false)
    let showUserContentCSS = true;
    // zusätzlich Chrome-Ordner im Untermenü anzeigen: 1 = ja, 0 = nein
    let showChrome = 1;
    /***** Ende Konfiguration *****/
    
    // Wenn beim Start ein weiteres Fenster (zweites Fenster) vorhanden ist, beenden
    let list = Services.wm.getEnumerator("navigator:browser");
    while(list.hasMoreElements()){ if(list.getNext() != window) return; }
    
    if (window.UCL) {
    	window.UCL.destroy();
    	delete window.UCL;
    }
    
    let menutooltip = "Linksklick: an/aus, Menü schließt\nMittelklick: an/aus, Menü bleibt offen\nRechtsklick: bearbeiten";
    if (fileManager !== "") {
    		menutooltip = menutooltip + "\nStrg+Rechtsklick: im Dateimanager anzeigen";
    }
    
    window.UCL = {
    	AGENT_SHEET : Ci.nsIStyleSheetService.AGENT_SHEET,
    	USER_SHEET  : Ci.nsIStyleSheetService.USER_SHEET,
    	AUTHOR_SHEET: Ci.nsIStyleSheetService.AUTHOR_SHEET,
    	readCSS: {},
    	get disabled_list() {
    		let obj = [];
    		try {
    			obj = decodeURIComponent(this.prefs.getCharPref("disabled_list")).split("|");
    		} catch(e) {}
    		delete this.disabled_list;
    		return this.disabled_list = obj;
    	},
    	get prefs() {
    		delete this.prefs;
    		return this.prefs = Services.prefs.getBranch("UserCSSLoader.");
    	},
    	get styleSheetServices() {
    		delete this.styleSheetServices;
    		return this.styleSheetServices = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
    	},
    	get FOLDER() {
    		let aFolder;
    		try {
    			// UserCSSLoader.FOLDER verwenden
    			let folderPath = this.prefs.getCharPref("FOLDER");
    			aFolder = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
    			aFolder.initWithPath(folderPath);
    		} catch (e) {
    			aFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
    			aFolder.appendRelativePath(cssFolder);
    		}
    		if (!aFolder.exists() || !aFolder.isDirectory()) {
    			aFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0o664);
    		}
    		delete this.FOLDER;
    		return this.FOLDER = aFolder;
    	},
    	get CHRMFOLDER() {
    			let cFolder;
    			try {
    					// UserCSSLoader.CHRMFOLDER verwenden
    					let CHRMfolderPath = this.prefs.getCharPref("CHRMFOLDER");
    					cFolder = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
    					cFolder.initWithPath(CHRMfolderPath);
    			} catch (e) {
    					cFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
    			}
    			if (!cFolder.exists() || !cFolder.isDirectory()) {
    					cFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0o664);
    			}
    			delete this.CHRMFOLDER;
    			return this.CHRMFOLDER = cFolder;
    	},
    
    	init: function() {
    		const cssmenu = $C("menu", {
    			id: "usercssloader-menu",
    			label: "CSS",
    			tooltiptext: "UserCSSLoader\n\nLinksklick: Stylesheets anzeigen\nMittelklick: Styles importieren",
    			accesskey: "Y"
    		});
    		cssmenu.addEventListener("click", (event) => { if (event.button === 1) UCL.rebuild(); });
    		const menupopup = $C("menupopup", {
    			id: "usercssloader-menupopup"
    		});
    		cssmenu.appendChild(menupopup);
    
    		let menu = $C("menu", {
    			label: "Style-Loader-Menü",
    			id: "style-loader-menu",
    			accesskey: "S",
    			//acceltext: "S"
    		});
    		menupopup.appendChild(menu);
    		menupopup.appendChild($C("menuseparator"));
    
    		let mp = $C("menupopup", { id: "usercssloader-submenupopup" });
    		menu.appendChild(mp);
    		let rebuildItem = $C("menuitem", {
    			label: "Styles importieren",
    			accesskey: "I",
    			//acceltext: "I"
    		});
    		rebuildItem.addEventListener("command", () => UCL.rebuild());
    		mp.appendChild(rebuildItem);
    		mp.appendChild($C("menuseparator"));
    		//
    		let createCSS = $C("menuitem", {
    			label: "CSS-Datei erstellen",
    			accesskey: "D",
    			//acceltext: "D"
    		});
    		createCSS.addEventListener("command", () => UCL.create());
    		mp.appendChild(createCSS);
    		let openFolder = $C("menuitem", {
    			label: "CSS-Ordner öffnen",
    			accesskey: "O",
    			//acceltext: "O"
    		});
    		openFolder.addEventListener("command", () => UCL.openCSSFolder());
    		mp.appendChild(openFolder);
    		if (showChrome === 1) {
    				let openChromeFolder = $C("menuitem", {
    					label: "Chrome-Ordner öffnen",
    					accesskey: "X",
    					//acceltext: "X"
    				});
    				openChromeFolder.addEventListener("command", () => UCL.openCHRMFolder());
    				mp.appendChild(openChromeFolder);
    		}
    		if (showUserChromeCSS || showUserContentCSS)// wenigstens eine der beiden Variablen muss …
    				mp.appendChild($C('menuseparator'));// … true sein, damit Trennlinie angezeigt wird
    		if (showUserChromeCSS) {
    				let editChromeItem = $C("menuitem", {
    					label: "userChrome.css bearbeiten"
    				});
    				editChromeItem.addEventListener("command", () => UCL.editUserCSS("userChrome.css"));
    				mp.appendChild(editChromeItem);
    		}
    		if (showUserContentCSS) {
    				let editContentItem = $C("menuitem", {
    					label: "userContent.css bearbeiten"
    				});
    				editContentItem.addEventListener("command", () => UCL.editUserCSS("userContent.css"));
    				mp.appendChild(editContentItem);
    		}
    
    		CustomizableUI.createWidget({
    			id: 'usercssloader-menu-item',
    			type: 'custom',
    			defaultArea: CustomizableUI.AREA_NAVBAR,
    			onBuild: function(aDocument) {
    				let toolbaritem = aDocument.createXULElement('toolbaritem');
    				toolbaritem.id = 'usercssloader-menu-item';
    				toolbaritem.className = 'chromeclass-toolbar-additional';
    				return toolbaritem;
    			}
    		});
    		$('usercssloader-menu-item').appendChild(cssmenu);
    
    		if (position === 1) {
    				let refNode = $('helpMenu');
    				refNode.parentNode.insertBefore(cssmenu, refNode.nextSibling);
    		}
    
    		// Stile neu laden, ohne Menü zu öffnen
    		let key = $C("key", {
    			id: "usercssloader-rebuild-key",
    			key: "R",
    			modifiers: "alt",
    		});
    		key.addEventListener("command", () => UCL.rebuild());
    		$("mainKeyset").appendChild(key);
    
    		this.rebuild();
    		this.initialized = true;
    		window.addEventListener("unload", this, false);
    	},
    	uninit: function() {
    		const dis = [];
    		for (let x of Object.keys(this.readCSS)) {
    			if (!this.readCSS[x].enabled)
    				dis.push(x);
    		}
    		this.prefs.setCharPref("disabled_list", encodeURIComponent(dis.join("|")));
    		window.removeEventListener("unload", this, false);
    	},
    	destroy: function() {
    		var i = document.getElementById("usercssloader-menu");
    		if (i) i.parentNode.removeChild(i);
    		var i = document.getElementById("usercssloader-rebuild-key");
    		if (i) i.parentNode.removeChild(i);
    		this.uninit();
    	},
    	handleEvent: function(event) {
    		switch(event.type){
    			case "unload": this.uninit(); break;
    		}
    	},
    	rebuild: function() {
    		let ext = /\.css$/i;
    		let not = /\.uc\.css/i;
    		let files = this.FOLDER.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
    
    		while (files.hasMoreElements()) {
    			let file = files.getNext().QueryInterface(Ci.nsIFile);
    			if (!ext.test(file.leafName) || not.test(file.leafName)) continue;
    			let CSS = this.loadCSS(file);
    			CSS.flag = true;
    		}
    		for (let leafName of Object.keys(this.readCSS)) {
    			const CSS = this.readCSS[leafName];
    			if (!CSS.flag) {
    				CSS.enabled = false;
    				delete this.readCSS[leafName];
    			}
    			delete CSS.flag;
    			this.rebuildMenu(leafName);
    		}
    		if (this.initialized) {
    			if (typeof(StatusPanel) !== "undefined")
    				StatusPanel._label = "Styles importiert";
    			else
    				XULBrowserWindow.statusTextField.label = "Styles importiert";
    		}
    	},
    	loadCSS: function(aFile) {
    		let CSS = this.readCSS[aFile.leafName];
    		if (!CSS) {
    			CSS = this.readCSS[aFile.leafName] = new CSSEntry(aFile);
    			if (this.disabled_list.indexOf(CSS.leafName) === -1) {
    				CSS.enabled = true;
    			}
    		} else if (CSS.enabled) {
    			CSS.enabled = true;
    		}
    		return CSS;
    	},
    	rebuildMenu: function(aLeafName) {
    		let CSS = this.readCSS[aLeafName];
    		let menuitem = document.getElementById("usercssloader-" + aLeafName);
    		if (!CSS) {
    			if (menuitem)
    				menuitem.parentNode.removeChild(menuitem);
    			return;
    		}
    
    		if (!menuitem) {
    			menuitem = $C("menuitem", {
    				label: aLeafName,
    				id: "usercssloader-" + aLeafName,
    				class: "usercssloader-item " + (CSS.SHEET == this.AGENT_SHEET? "AGENT_SHEET" : CSS.SHEET == this.AUTHOR_SHEET? "AUTHOR_SHEET": "USER_SHEET"),
    				type: "checkbox",
    				autocheck: "false",
    				tooltiptext: menutooltip
    			});
    			menuitem.addEventListener("command", () => UCL.toggle(aLeafName));
    			menuitem.addEventListener("click", (event) => UCL.itemClick(event));
    			menuitem.addEventListener("mouseup", (event) => { if (event.button === 1) event.preventDefault(); });
    			document.getElementById("usercssloader-menupopup").appendChild(menuitem);
    		}
    		menuitem.setAttribute("checked", CSS.enabled);
    	},
    	toggle: function(aLeafName) {
    		let CSS = this.readCSS[aLeafName];
    		if (!CSS || event.ctrlKey) return;
    		CSS.enabled = !CSS.enabled;
    		this.rebuildMenu(aLeafName);
    	},
    	itemClick: function(event) {
    		let label = event.currentTarget.getAttribute("label");
    		event.preventDefault();
    		event.stopPropagation();
    		if (event.button === 0) {
    				return;
    		} else if (event.button === 1) {
    				this.toggle(label);
    		} else if (event.button === 2) {
    				if (event.ctrlKey) {
    						UCL.openFile(label);
    				} else {
    				closeMenus(event.target);
    				this.edit(this.getFileFromLeafName(label));
    				}
    		}
    	},
    	getFileFromLeafName: function(aLeafName) {
    		let f = this.FOLDER.clone();
    		f.QueryInterface(Ci.nsIFile); // use appendRelativePath
    		f.appendRelativePath(aLeafName);
    		return f;
    	},
    	openFile: function(fname) {
    		if (fileManager.length !== 0) {
    				let target= this.FOLDER.path + "/" + fname;
    				let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
    				let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
    				let args = (!fileManagerParamPost) ? [fileManagerParam,target,] :
    				           [target,fileManagerParam];
    				file.initWithPath(fileManager);
    				process.init(file);
    				// Verzeichnis mit anderem Dateimanager öffnen
    				process.run(false, args, args.length);
    		} else {
    				// Verzeichnis mit Dateimanager des Systems öffnen
    				this.FOLDER.launch();
    		}
    	},
    	openCSSFolder:function(){
    		if (fileManager.length !== 0) {
    				let target = this.FOLDER.path;
    				let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
    				let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
    				let args = (!fileManagerParamPost) ? [fileManagerParam,target,] :
    				           [target,fileManagerParam];
    				file.initWithPath(fileManager);
    				process.init(file);
    				// Verzeichnis mit anderem Dateimanager öffnen
    				process.run(false, args, args.length);
    		} else {
    				// Verzeichnis mit Dateimanager des Systems öffnen
    				this.FOLDER.launch();
    		}
    	},
    	openCHRMFolder:function(){
    		if (fileManager.length !== 0) {
    				let target = this.CHRMFOLDER.path;
    				let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
    				let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
    				let args = (!fileManagerParamPost) ? [fileManagerParam,target,] :
    				           [target,fileManagerParam];
    				file.initWithPath(fileManager);
    				process.init(file);
    				// Verzeichnis mit anderem Dateimanager öffnen
    				process.run(false, args, args.length);
    		} else {
    				// Verzeichnis mit Dateimanager des Systems öffnen
    				this.CHRMFOLDER.launch();
    		}
    	},
    	editUserCSS: function(aLeafName) {
    		let file = Services.dirsvc.get("UChrm", Ci.nsIFile);
    		file.appendRelativePath(aLeafName);
    		this.edit(file);
    	},
    	edit: function(aFile) {
    		let editor = (customEditor !== "") ? customEditor : Services.prefs.getCharPref("view_source.editor.path");
    		if (!editor) return alert('In der Konfiguration einen Texteditor festlegen ("customEditor") oder\n unter about:config im vorhandenen Schalter "view_source.editor.path"\n den vollständigen Editorpfad eintragen.');
    		try {
    			let UI = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
    			UI.charset = window.navigator.platform.toLowerCase().indexOf("win") >= 0? "Shift_JIS": "UTF-8";
    			let path = UI.ConvertFromUnicode(aFile.path);
    			let app = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
    			app.initWithPath(editor);
    			let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
    			process.init(app);
    			process.run(false, [path], 1);
    		} catch (e) {}
    	},
    	create: function(aLeafName) {
    		if (!aLeafName) aLeafName = prompt("Name des Styles", dateFormat(new Date(), "%Y_%m%d_%H%M%S"));
    		if (aLeafName) aLeafName = aLeafName.replace(/\s+/g, " ").replace(/[\\/:*?\"<>|]/g, "");
    		if (!aLeafName || !/\S/.test(aLeafName)) return;
    		if (!/\.css$/.test(aLeafName)) aLeafName += ".css";
    		let file = this.getFileFromLeafName(aLeafName);
    		this.edit(file);
    	},
    	UCrebuild: function() {
    		let re = /^file:.*\.uc\.css(?:\?\d+)?$/i;
    		let query = "?" + new Date().getTime();
    		Array.slice(document.styleSheets).forEach(function(css){
    			if (!re.test(css.href)) return;
    			if (css.ownerNode) {
    				css.ownerNode.parentNode.removeChild(css.ownerNode);
    			}
    			let pi = document.createProcessingInstruction('xml-stylesheet','type="text/css" href="'+ css.href.replace(/\?.*/, '') + query +'"');
    			document.insertBefore(pi, document.documentElement);
    		});
    		UCL.UCcreateMenuitem();
    	},
    	UCcreateMenuitem: function() {
    		let sep = $("usercssloader-ucseparator");
    		let popup = sep.parentNode;
    		if (sep.nextSibling) {
    			let range = document.createRange();
    			range.setStartAfter(sep);
    			range.setEndAfter(popup.lastChild);
    			range.deleteContents();
    			range.detach();
    		}
    
    		let re = /^file:.*\.uc\.css(?:\?\d+)?$/i;
    		Array.slice(document.styleSheets).forEach(function(css) {
    			if (!re.test(css.href)) return;
    			let fileURL = decodeURIComponent(css.href).split("?")[0];
    			let aLeafName = fileURL.split("/").pop();
    			let m = $C("menuitem", {
    				label: aLeafName,
    				tooltiptext: fileURL,
    				id: "usercssloader-" + aLeafName,
    				type: "checkbox",
    				autocheck: "false",
    				checked: "true",
    			});
    			m.css = css;
    			m.addEventListener("command", function() {
    				if (!event.ctrlKey) {this.setAttribute("checked", !(this.css.disabled = !this.css.disabled));}
    			});
    			m.addEventListener("mouseup", function(event) {
    				if (event.button === 1) event.preventDefault();
    			});
    			m.addEventListener("click", function(event) {
    				UCL.UCItemClick(event);
    			});
    			popup.appendChild(m);
    		});
    	},
    	UCItemClick: function(event) {
    		if (event.button === 0) return;
    		event.preventDefault();
    		event.stopPropagation();
    
    		if (event.button === 1) {
    			event.target.doCommand();
    		}
    		else if (event.button === 2) {
    			closeMenus(event.target);
    			let fileURL = event.currentTarget.getAttribute("tooltiptext");
    			let file = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler).getFileFromURLSpec(fileURL);
    			this.edit(file);
    		}
    	},
    };
    
    function CSSEntry(aFile) {
    	this.path = aFile.path;
    	this.leafName = aFile.leafName;
    	this.lastModifiedTime = 1;
    	this.SHEET = /^xul-|\.as\.css$/i.test(this.leafName) ?
    		Ci.nsIStyleSheetService.AGENT_SHEET:
    		/\.author\.css$/i.test(this.leafName)?
    			Ci.nsIStyleSheetService.AUTHOR_SHEET:
    			Ci.nsIStyleSheetService.USER_SHEET;
    }
    CSSEntry.prototype = {
    	sss: Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
    	_enabled: false,
    	get enabled() {
    		return this._enabled;
    	},
    	set enabled(isEnable) {
    		let aFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile)
    		aFile.initWithPath(this.path);
    
    		let isExists = aFile.exists(); // true, wenn die Datei bereits existiert
    		let lastModifiedTime = isExists ? aFile.lastModifiedTime : 0;
    		let isForced = this.lastModifiedTime != lastModifiedTime; //true, wenn es eine Änderung in der Datei gibt
    
    		let fileURL = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler).getURLSpecFromActualFile(aFile);
    		let uri = Services.io.newURI(fileURL, null, null);
    
    		if (this.sss.sheetRegistered(uri, this.SHEET)) {
    			// Wenn diese Datei bereits gelesen wurde
    			if (!isEnable || !isExists) {
    				this.sss.unregisterSheet(uri, this.SHEET);
    			}
    			else if (isForced) {
    				// Nach Stornierung erneut einlesen
    				this.sss.unregisterSheet(uri, this.SHEET);
    				this.sss.loadAndRegisterSheet(uri, this.SHEET);
    			}
    		} else {
    			// Datei wurde nicht gelesen
    			if (isEnable && isExists) {
    				this.sss.loadAndRegisterSheet(uri, this.SHEET);
    			}
    		}
    		if (this.lastModifiedTime !== 1 && isEnable && isForced) {
    			log(this.leafName + " wurde aktualisiert");
    		}
    		this.lastModifiedTime = lastModifiedTime;
    		return this._enabled = isEnable;
    	},
    };
    
    UCL.init();
    
    function $(id) { return document.getElementById(id); }
    function $A(arr) { return Array.slice(arr); }
    function $C(name, attr) {
    	const el = document.createXULElement(name);
    	if (attr) Object.keys(attr).forEach(function(n) { el.setAttribute(n, attr[n]) });
    	return el;
    }
    function dateFormat(date, format) {
    	format = format.replace("%Y", ("000" + date.getFullYear()).substr(-4));
    	format = format.replace("%m", ("0" + (date.getMonth()+1)).substr(-2));
    	format = format.replace("%d", ("0" + date.getDate()).substr(-2));
    	format = format.replace("%H", ("0" + date.getHours()).substr(-2));
    	format = format.replace("%M", ("0" + date.getMinutes()).substr(-2));
    	format = format.replace("%S", ("0" + date.getSeconds()).substr(-2));
    	return format;
    }
    
    function log(mes) { console.log(mes); }
    })();
    Alles anzeigen
  • UserCSSLoader (2025)

    • Speravir
    • 26. August 2025 um 01:30

    Mir ist heute nicht nach Grübeln, deshalb kurz:

    Zitat von Mira_Belle

    Der Code ist für die UserCSSLoader.css um dem Menü eine Grafik zu verpassen!

    Ja, aber nur, wenn er als Schaltfläche eingefügt ist.

    Zitat von seipe

    Welchen Wert muss ich in der CSS Datei für User Styles Button aus #28 ändern, damit er mittig in der Leiste angezeigt wird.

    Teste mal meinen viel kürzeren Stil aus #53.

    Zitat von Mira_Belle

    Kann man den "überflüssigen" Code dann nicht entfernen?
    Denn ich habe es nachgestellt, und es tut sich auch bei mir nichts!

    Ich denke, das werde ich tun. Und danke für die Bestätigung.

    Zitat von bege

    Ich meinte C für die Schaltfläche bzw. das Menü in der Menüleiste. Also "CSS" statt "CSS (Y)".

    Alt+C ist in einem deutschsprachigen Firefox schon für die Chronik vergeben und Alt+S geht auch nicht, was mir erst kürzlich auffiel (oder erst seit jüngeren Versionen so ist).

  • UserCSSLoader (2025)

    • Speravir
    • 25. August 2025 um 02:52
    Zitat von Speravir

    (#addonbar #usercssloader-menu), so dass dort kein Konflikt entsteht (ich sehe gerade, dass Teile des Stil nicht mehr wirken, aber .menu-text[value="CSS"] gibt’s noch). Ich habe es selber noch nicht ausprobiert, aber man könnte vermutlich das Symbol auch dem übergeordneten Toolbaritem mit der ID #usercssloader-menu-item zuordnen.

    Ich hab das nun so geändert:

    CSS
    #usercssloader-menu-item {
        background-image: url("./images/CSS.png") !important;
        background-position: center !important;
        background-repeat: no-repeat !important;
        background-size: 16px !important;
        & #usercssloader-menu > .menu-text[value="CSS"] { opacity: 0 !important }
    }

    (Das & könnte hier auch weggelassen werden, hilft mir aber zu erkennen, dass dort quasi noch etwas davor steht.)

    Frei festlegbarer Texteditor:

    Zitat von Mira_Belle

    Funktioniert!

    let editor = 'C:\\Windows\\System32\\notepad.exe'; und z.B. userChrome.css wird in Notepad geöffnet.

    Zitat von bege

    Bitte nicht umbauen. Ich finde das genial und nutze es seit Jahr und Tag. Das wird bei mir in zwei weiteren Skripten verwendet (extras_config_menu und AppMenu) und so muss ich das nicht in jedem Skript, wo der Editor gebraucht wird, einbauen.

    Zitat von Mira_Belle

    Ist dann wohl eine "Geschmacksfrage"! Denn ich würde es viel lieber in einem Skript definieren, als Hand an Firefoxinterna anzulegen.

    Mir kam gestern bereits während des Schreibens eine Idee, die ich auch umgesetzt habe. Man findet jetzt Folgendes in der Konfiguration (und entsprechend angepassten Code):

    JavaScript
    /* eigener Texteditor mit Pfad - Standard leer, dann wird Wert aus Einstellung
      "view_source.editor.path" verwendet mit Warnmeldung, wenn auch dieser leer ist */
    //let customEditor = "C:\\Windows\\System32\\notepad.exe";
    let customEditor = "";

    Damit sollten beide Positionen zufrieden gestellt sein.

    Zitat von Mira_Belle

    :/ Mal blöd gefragt.
    Am welcher Stelle soll den DAS im Menü auftauchen?

    Nee, nicht blöd. Das ist ein Punkt, der mir selbst nicht klar ist. Das Menü wird angezeigt, wenn sich effektiv hidden: false ergibt – an der Stelle muss also UCL.USE_UC true sein und heißt, wenn "UC" in window true ist. Du kannst ja mal explizit auf false setzen, dann erscheint das Menü, aber das tut bei mir nichts. Dann dachte ich, ich ändere eine CSS zu .uc.css und habe in dieser Testcode eingebaut, aber er wurde nicht aktiviert.

    Zitat von Endor

    Tastaturkürzel zum Importieren von Stilen funktioniert nur mit Alt+R.
    Bei Alt+I tut sich nichts.

    Alt+R in jedem beliebigen Fenster (ist übrigens risikoreich, die Kombi könnte anderweitig benutzt werden), wenn der Loader als Symbol eingefügt wird. Aber I (ohne Alt) ist doch nur für den Untermenüpunkt festgelegt und das funktioniert auch.

    Zitat von bege

    Alt+R wird andernorts als key definiert. Dafür braucht es keinen Eventlistener. Wenn ich den in deiner neuen Version auskommentiere, funktioniert es trotzdem.

    Oh, tatsächlich!

    Zitat von bege

    Warum dann nicht "C" als accelkey für Schaltfläche/Menü und z.B. "M" bei "Chrome-Ordner öffnen"?

    Zweimal C fand ich nicht eindeutig (CSS/Chrome), aber zugegebenermaßen gibt’s Ordner auch zweimal. X halte ich für mnemotechnisch besser als M, das mitten in Chrome steht, zumal es direkt vorher dazu gedrückt werden muss, um das Untermenü aufzuklappen; das birgt die Gefahr des doppelten Tastendrucks. Das könnte man aber zu S ändern, war schon mal so, wenn ich mich nicht irre. Es können sich ja gern mal andere Nutzer dazu melden (für mich selber deaktiviere ich die Kurztasten).

    Den Rest muss ich mir nochmal genauer zu Gemüte führen, da steht mir gerade irgendjemand auf dem Schlauch oder so ähnlich, nur eines:

    Zitat von bege

    Mich wundert eher, warum es mit dem Windows-Explorer nicht auch eine Fehlermeldung gibt,

    Der Windows-Explorer wird ja aufgerufen, wenn kein anderer Dateimanager festgelegt wurde und das ist dann der Else-Zweig, der nur aus this.FOLDER.launch(); besteht.

    JavaScript: UserCSSLoader_2025-08-25
    // ==UserScript==
    // @name           UserCSSLoader
    // @description    CSS-Codes - Styles laden und verwalten
    // @namespace      http://d.hatena.ne.jp/Griever/
    // @author         Griever
    // @include        main
    // @license        MIT License
    // @compatibility  Firefox 141+
    // @charset        UTF-8
    // @version        0.0.4r4
    // @note           0.0.4r4 prevent close menu when middleclick
    // @note           Aktualisierungen von BrokenHeart (mit 0.0.4r4 obsolet) und Speravir - www.camp-firefox.de
    // @note           0.0.4r3 Fx92: getURLSpecFromFile() -> getURLSpecFromActualFile()
    // @note           0.0.4r2 AUTHOR_SHEET-Unterstützung hinzugefügt, wichtig: Dateiendung muss .author.css sein!
    // @note           Version 0.0.4.g ermöglicht "Styles importieren" per Mittelklick und Verwendung
    // @note           eines anderen Dateimanagers (siehe in Konfiguration), ergänzt um einen
    // @note           Parameter für den Dateimanager (vFMParameter in der Konfiguration) von aborix
    // @note           Frei verschiebbare Schaltfläche eingebaut von aborix
    // @note           0.0.4 Remove E4X
    // @note           CSS-Entry-Klasse erstellt
    // @note           Style-Test-Funktion überarbeitet
    // @note           Wenn die Datei gelöscht wurde, CSS beim Neu-Erstellen und Löschen des Menüs abbrechen
    // @note           uc einlesen .uc.css temporäre Korrespondenz zum erneuten Lesen
    // ==/UserScript==
    /* Endor in https://www.camp-firefox.de/forum/thema/112673/?postID=1277236#post1277236 */
    /****** Bedienungsanleitung ******
    CSS-Ordner im Chrome-Ordner erstellen, CSS-Dateien dort ablegen - speichern.
    Diejenigen, deren Dateiname mit "xul-" beginnen, diejenigen, die mit ".as.css" enden, sind AGENT_SHEET, 
    alle anderen außer USER_SHEET werden gelesen. Da der Inhalt der Datei nicht überprüft wird,
    darauf achten, die Angabe von @namespace nicht zu vergessen!
    Schaltfläche wird in Navigationsleiste eingefügt (konfigurierbar, siehe Variable "position").
    Linksklick auf Stil, zum Aktivieren/Deaktivieren
    Mittelklick auf Stil zum Aktivieren/Deaktivieren, ohne Menü zu schließen
    Rechtsklick auf Stil zum Öffnen im Editor
    Strg+Linksklick zum Anzeigen im Dateimanager
    Die Tastenkombinationen können im Menü eingeblendet werden, dazu nach
    "acceltext" suchen und den Zeilenkommentar "//" entfernen bzw. einfügen.
    Verwenden des in "view_source.editor.path" angegebenen Editors.
    Dateiordner, Dateimanager und Texteditor können in Konfiguration geändert werden.
    Ein Symbol für die Schaltfläche muss in der "userChrome.css" festgelegt werden:
    #usercssloader-menu-item {
        background-image: url("Pfad/zu/Symbol_CSS.png") !important;
        background-position: center !important;
        background-repeat: no-repeat !important;
        background-size: 16px !important;
        & #usercssloader-menu > .menu-text[value="CSS"] { opacity: 0 !important }
    }
    **** Anleitung Ende ****/
    (function(){
    /***** Konfiguration *****/
    // Position: als frei verschiebbare-Schaltfläche = 0, als Menü anzeigen = 1
    let position = 0;//1
    // alternativer Dateimanager, Bsp.:
    //let filemanager = "C:\\Programme\\totalcmd\\TOTALCMD.EXE";
    let filemanager = "";
    // eventuelle Parameter für den alternativen Dateimanager, sonst filemanagerParam = "";
    //let filemanagerParam = "/O /T";//Totalcommander
    let filemanagerParam = "";
    /* eigener Texteditor mit Pfad - Standard leer, dann wird Wert aus Einstellung
      "view_source.editor.path" verwendet mit Warnmeldung, wenn auch dieser leer ist */
    //let customEditor = "C:\\Windows\\System32\\notepad.exe";
    let customEditor = "";
    // Unterordner für die CSS-Dateien:
    let cssFolder = "CSS";
    // Menüeintrag zum Bearbeiten der userChrome.css verstecken (true) oder anzeigen (false)
    let hideUserChromeCSS = false;
    // Menüeintrag zum Bearbeiten der userContent.css verstecken (true) oder anzeigen (false)
    let hideUserContentCSS = false;
    // zusätzlich Chrome-Ordner im Untermenü anzeigen: 1 = ja, 0 = nein
    let showChrome = 1;
    /***** Ende Konfiguration *****/
    ChromeUtils.importESModule("resource://gre/modules/AppConstants.sys.mjs");
    // Wenn beim Start ein weiteres Fenster (zweites Fenster) vorhanden ist, beenden
    let list = Services.wm.getEnumerator("navigator:browser");
    while(list.hasMoreElements()){ if(list.getNext() != window) return; }
    if (window.UCL) {
        window.UCL.destroy();
        delete window.UCL;
    }
    window.UCL = {
            vFileManager: filemanager,
            vFMParameter: filemanagerParam,
            USE_UC: "UC" in window,
            AGENT_SHEET : Ci.nsIStyleSheetService.AGENT_SHEET,
            USER_SHEET  : Ci.nsIStyleSheetService.USER_SHEET,
            AUTHOR_SHEET: Ci.nsIStyleSheetService.AUTHOR_SHEET,
            readCSS: {},
            get disabled_list() {
            let obj = [];
            try {
                obj = decodeURIComponent(this.prefs.getCharPref("disabled_list")).split("|");
            } catch(e) {}
            delete this.disabled_list;
            return this.disabled_list = obj;
        },
        get prefs() {
            delete this.prefs;
            return this.prefs = Services.prefs.getBranch("UserCSSLoader.");
        },
        get styleSheetServices(){
            delete this.styleSheetServices;
            return this.styleSheetServices = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
        },
        get FOLDER() {
            let aFolder;
            try {
                // UserCSSLoader.FOLDER verwenden
                let folderPath = this.prefs.getCharPref("FOLDER");
                aFolder = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
                aFolder.initWithPath(folderPath);
            } catch (e) {
                aFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
                aFolder.appendRelativePath(cssFolder);
            }
            if (!aFolder.exists() || !aFolder.isDirectory()) {
                aFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0o664);
            }
            delete this.FOLDER;
            return this.FOLDER = aFolder;
        },
        get CHRMFOLDER() {
                let bFolder;
                try {
                        // UserCSSLoader.CHRMFOLDER verwenden
                        let CHRMfolderPath = this.prefs.getCharPref("CHRMFOLDER");
                        bFolder = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
                        bFolder.initWithPath(CHRMfolderPath);
                } catch (e) {
                        bFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
                }
                if (!bFolder.exists() || !bFolder.isDirectory()) {
                        bFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0o664);
                }
                delete this.CHRMFOLDER;
                return this.CHRMFOLDER = bFolder;
        },
        getFocusedWindow: function() {
            let win = document.commandDispatcher.focusedWindow;
            if (!win || win == window) win = content;
            return win;
        },
        init: function() {
            const cssmenu = $C("menu", {
                id: "usercssloader-menu",
                label: "CSS",
                tooltiptext: "UserCSSLoader\n\nLinksklick: Stylesheets anzeigen\nMittelklick: Styles importieren",
                accesskey: "Y"
            });
            // cssmenu.addEventListener("command", () => UCL.rebuild());
            cssmenu.addEventListener("click", (event) => { if (event.button === 1) UCL.rebuild(); });
            const menupopup = $C("menupopup", {
                id: "usercssloader-menupopup"
            });
            cssmenu.appendChild(menupopup);
            let menu = $C("menu", {
                label: "Style-Loader-Menü",
                id: "style-loader-menu",
                accesskey: "M",
                //acceltext: "M"
            });
            menupopup.appendChild(menu);
            menupopup.appendChild($C("menuseparator"));
            let mp = $C("menupopup", { id: "usercssloader-submenupopup" });
            menu.appendChild(mp);
            let rebuildItem = $C("menuitem", {
                label: "Styles importieren",
                accesskey: "I",
                //acceltext: "I"
            });
            rebuildItem.addEventListener("command", () => UCL.rebuild());
            mp.appendChild(rebuildItem);
            mp.appendChild($C("menuseparator"));
            let createCSS = $C("menuitem", {
                label: "CSS-Datei erstellen",
                accesskey: "E",
                //acceltext: "E"
            });
            createCSS.addEventListener("command", () => UCL.create());
            mp.appendChild(createCSS);
            let openFolder = $C("menuitem", {
                label: "CSS-Ordner öffnen",
                accesskey: "O",
                //acceltext: "O"
            });
            openFolder.addEventListener("command", () => UCL.openFolder());
            mp.appendChild(openFolder);
            if (showChrome === 1) {
                    let openChromeFolder = $C("menuitem", {
                        label: "Chrome-Ordner öffnen",
                        accesskey: "X",
                        //acceltext: "X"
                    });
                    openChromeFolder.addEventListener("command", () => UCL.openCHRMFolder());
                    mp.appendChild(openChromeFolder);
            }
            mp.appendChild($C('menuseparator'));
            let editChromeItem = $C("menuitem", {
                label: "userChrome.css bearbeiten",
                hidden: hideUserChromeCSS,
            });
            editChromeItem.addEventListener("command", () => UCL.editUserCSS("userChrome.css"));
            mp.appendChild(editChromeItem);
            let editContentItem = $C("menuitem", {
                label: "userContent.css bearbeiten",
                hidden: hideUserContentCSS,
            });
            editContentItem.addEventListener("command", () => UCL.editUserCSS("userContent.css"));
            mp.appendChild(editContentItem);
            menu = $C("menu", {
                label: ".uc.css",
                accesskey: "U",
                //acceltext: "U",
                hidden: !UCL.USE_UC
            });
            menupopup.appendChild(menu);
            mp = $C("menupopup", { id: "usercssloader-ucmenupopup" });
            menu.appendChild(mp);
            let UCrebuild = $C("menuitem", {
                label: "Importieren (.uc.css)",
            });
            UCrebuild.addEventListener("command", () => UCL.UCrebuild());
            mp.appendChild(UCrebuild);
            mp.appendChild($C("menuseparator", { id: "usercssloader-ucseparator" }));
            CustomizableUI.createWidget({
                id: 'usercssloader-menu-item',
                type: 'custom',
                defaultArea: CustomizableUI.AREA_NAVBAR,
                onBuild: function(aDocument) {
                    let toolbaritem = aDocument.createXULElement('toolbaritem');
                    toolbaritem.id = 'usercssloader-menu-item';
                    toolbaritem.className = 'chromeclass-toolbar-additional';
                    return toolbaritem;
                }
            });
            $('usercssloader-menu-item').appendChild(cssmenu);
            if (position === 1) {
                    let refNode = $('helpMenu');
                    refNode.parentNode.insertBefore(cssmenu, refNode.nextSibling);
            }
            let key = $C("key", {
                id: "usercssloader-rebuild-key",
                key: "R",
                modifiers: "alt",
            });
            key.addEventListener("command", () => UCL.rebuild());
            $("mainKeyset").appendChild(key);
            this.rebuild();
            this.initialized = true;
            if (UCL.USE_UC) {
                setTimeout(function() {
                    UCL.UCcreateMenuitem();
                }, 1000);
            }
            window.addEventListener("unload", this, false);
        },
        uninit: function() {
            const dis = [];
            for (let x of Object.keys(this.readCSS)) {
                if (!this.readCSS[x].enabled)
                    dis.push(x);
            }
            this.prefs.setCharPref("disabled_list", encodeURIComponent(dis.join("|")));
            window.removeEventListener("unload", this, false);
        },
        destroy: function() {
            var i = document.getElementById("usercssloader-menu");
            if (i) i.parentNode.removeChild(i);
            var i = document.getElementById("usercssloader-rebuild-key");
            if (i) i.parentNode.removeChild(i);
            this.uninit();
        },
        handleEvent: function(event) {
            switch(event.type){
                case "unload": this.uninit(); break;
            }
        },
        rebuild: function() {
            let ext = /\.css$/i;
            let not = /\.uc\.css/i;
            let files = this.FOLDER.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
            while (files.hasMoreElements()) {
                let file = files.getNext().QueryInterface(Ci.nsIFile);
                if (!ext.test(file.leafName) || not.test(file.leafName)) continue;
                let CSS = this.loadCSS(file);
                CSS.flag = true;
            }
            for (let leafName of Object.keys(this.readCSS)) {
                const CSS = this.readCSS[leafName];
                if (!CSS.flag) {
                    CSS.enabled = false;
                    delete this.readCSS[leafName];
                }
                delete CSS.flag;
                this.rebuildMenu(leafName);
            }
            if (this.initialized) {
                if (typeof(StatusPanel) !== "undefined")
                    StatusPanel._label = "Styles importiert";
                else
                    XULBrowserWindow.statusTextField.label = "Styles importiert";
            }
        },
        loadCSS: function(aFile) {
            let CSS = this.readCSS[aFile.leafName];
            if (!CSS) {
                CSS = this.readCSS[aFile.leafName] = new CSSEntry(aFile);
                if (this.disabled_list.indexOf(CSS.leafName) === -1) {
                    CSS.enabled = true;
                }
            } else if (CSS.enabled) {
                CSS.enabled = true;
            }
            return CSS;
        },
        rebuildMenu: function(aLeafName) {
            let CSS = this.readCSS[aLeafName];
            let menuitem = document.getElementById("usercssloader-" + aLeafName);
            if (!CSS) {
                if (menuitem)
                    menuitem.parentNode.removeChild(menuitem);
                return;
            }
            if (!menuitem) {
                menuitem = $C("menuitem", {
                    label: aLeafName,
                    id: "usercssloader-" + aLeafName,
                    class: "usercssloader-item " + (CSS.SHEET == this.AGENT_SHEET? "AGENT_SHEET" : CSS.SHEET == this.AUTHOR_SHEET? "AUTHOR_SHEET": "USER_SHEET"),
                    type: "checkbox",
                    autocheck: "false",
                    tooltiptext: "Linksklick: an/aus, Menü schließt\nMittelklick: an/aus, Menü bleibt offen\nRechtsklick: bearbeiten\nStrg+Rechtsklick: im Dateimanager anzeigen"
                });
                menuitem.addEventListener("command", () => UCL.toggle(aLeafName));
                menuitem.addEventListener("click", (event) => UCL.itemClick(event));
                menuitem.addEventListener("mouseup", (event) => { if (event.button === 1) event.preventDefault(); });
                document.getElementById("usercssloader-menupopup").appendChild(menuitem);
            }
            menuitem.setAttribute("checked", CSS.enabled);
        },
        toggle: function(aLeafName) {
            let CSS = this.readCSS[aLeafName];
            if (!CSS || event.ctrlKey) return;
            CSS.enabled = !CSS.enabled;
            this.rebuildMenu(aLeafName);
        },
        itemClick: function(event) {
            let label = event.currentTarget.getAttribute("label");
            event.preventDefault();
            event.stopPropagation();
            if (event.button === 0) {
                    return;
            } else if (event.button === 1) {
                    this.toggle(label);
            } else if (event.button === 2) {
                    if (event.ctrlKey) {
                            UCL.openFolder(label);
                    } else {
                    closeMenus(event.target);
                    this.edit(this.getFileFromLeafName(label));
                    }
            }
        },
        getFileFromLeafName: function(aLeafName) {
            let f = this.FOLDER.clone();
            f.QueryInterface(Ci.nsIFile); // use appendRelativePath
            f.appendRelativePath(aLeafName);
            return f;
        },
        openFolder: function(label) {
            const PathSep = AppConstants.platform === "win" ? "\\" : "/";
            let target= this.FOLDER.path + PathSep + label;
            if (this.vFileManager.length !== 0) {
                    let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
                    let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
                    let args = [this.vFMParameter,target];
                    file.initWithPath(this.vFileManager);
                    process.init(file);
                    // Verzeichnis mit anderem Dateimanager öffnen
                    process.run(false, args, args.length);
            } else {
                    // Verzeichnis mit Dateimanager des Systems öffnen
                    this.FOLDER.launch();
            }
        },
        openCHRMFolder:function(){
                if (this.vFileManager.length !== 0) {
                        let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
                        let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
                        let args = [this.vFMParameter,this.CHRMFOLDER.path];
                        file.initWithPath(this.vFileManager);
                        process.init(file);
                        // Verzeichnis mit anderem Dateimanager öffnen
                        process.run(false, args, args.length);
                } else {
                        // Verzeichnis mit Dateimanager des Systems öffnen
                        this.CHRMFOLDER.launch();
                }
        },
        editUserCSS: function(aLeafName) {
            let file = Services.dirsvc.get("UChrm", Ci.nsIFile);
            file.appendRelativePath(aLeafName);
            this.edit(file);
        },
        edit: function(aFile) {
            let editor = (customEditor !== "") ? customEditor : Services.prefs.getCharPref("view_source.editor.path");
            if (!editor) return alert('In der Konfiguration einen Texteditor festlegen ("customEditor") oder\n unter about:config im vorhandenen Schalter "view_source.editor.path"\n den vollständigen Editorpfad eintragen.');
            try {
                let UI = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
                UI.charset = window.navigator.platform.toLowerCase().indexOf("win") >= 0? "Shift_JIS": "UTF-8";
                let path = UI.ConvertFromUnicode(aFile.path);
                let app = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
                app.initWithPath(editor);
                let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
                process.init(app);
                process.run(false, [path], 1);
            } catch (e) {}
        },
        create: function(aLeafName) {
            if (!aLeafName) aLeafName = prompt("Name des Styles", dateFormat(new Date(), "%Y_%m%d_%H%M%S"));
            if (aLeafName) aLeafName = aLeafName.replace(/\s+/g, " ").replace(/[\\/:*?\"<>|]/g, "");
            if (!aLeafName || !/\S/.test(aLeafName)) return;
            if (!/\.css$/.test(aLeafName)) aLeafName += ".css";
            let file = this.getFileFromLeafName(aLeafName);
            this.edit(file);
        },
        UCrebuild: function() {
            let re = /^file:.*\.uc\.css(?:\?\d+)?$/i;
            let query = "?" + new Date().getTime();
            Array.slice(document.styleSheets).forEach(function(css){
                if (!re.test(css.href)) return;
                if (css.ownerNode) {
                    css.ownerNode.parentNode.removeChild(css.ownerNode);
                }
                let pi = document.createProcessingInstruction('xml-stylesheet','type="text/css" href="'+ css.href.replace(/\?.*/, '') + query +'"');
                document.insertBefore(pi, document.documentElement);
            });
            UCL.UCcreateMenuitem();
        },
        UCcreateMenuitem: function() {
            let sep = $("usercssloader-ucseparator");
            let popup = sep.parentNode;
            if (sep.nextSibling) {
                let range = document.createRange();
                range.setStartAfter(sep);
                range.setEndAfter(popup.lastChild);
                range.deleteContents();
                range.detach();
            }
            let re = /^file:.*\.uc\.css(?:\?\d+)?$/i;
            Array.slice(document.styleSheets).forEach(function(css) {
                if (!re.test(css.href)) return;
                let fileURL = decodeURIComponent(css.href).split("?")[0];
                let aLeafName = fileURL.split("/").pop();
                let m = $C("menuitem", {
                    label: aLeafName,
                    tooltiptext: fileURL,
                    id: "usercssloader-" + aLeafName,
                    type: "checkbox",
                    autocheck: "false",
                    checked: "true",
                });
                m.css = css;
                m.addEventListener("command", function() {
                    if (!event.ctrlKey) {this.setAttribute("checked", !(this.css.disabled = !this.css.disabled));}
                });
                m.addEventListener("mouseup", function(event) {
                    if (event.button === 1) event.preventDefault();
                });
                m.addEventListener("click", function(event) {
                    UCL.UCItemClick(event);
                });
                popup.appendChild(m);
            });
        },
        UCItemClick: function(event) {
            if (event.button === 0) return;
            event.preventDefault();
            event.stopPropagation();
            if (event.button === 1) {
                event.target.doCommand();
            }
            else if (event.button === 2) {
                closeMenus(event.target);
                let fileURL = event.currentTarget.getAttribute("tooltiptext");
                let file = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler).getFileFromURLSpec(fileURL);
                this.edit(file);
            }
        },
    };
    function CSSEntry(aFile) {
        this.path = aFile.path;
        this.leafName = aFile.leafName;
        this.lastModifiedTime = 1;
        this.SHEET = /^xul-|\.as\.css$/i.test(this.leafName) ?
            Ci.nsIStyleSheetService.AGENT_SHEET:
            /\.author\.css$/i.test(this.leafName)?
                Ci.nsIStyleSheetService.AUTHOR_SHEET:
                Ci.nsIStyleSheetService.USER_SHEET;
    }
    CSSEntry.prototype = {
        sss: Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
        _enabled: false,
        get enabled() {
            return this._enabled;
        },
        set enabled(isEnable) {
            let aFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile)
            aFile.initWithPath(this.path);
            let isExists = aFile.exists(); // true, wenn die Datei bereits existiert
            let lastModifiedTime = isExists ? aFile.lastModifiedTime : 0;
            let isForced = this.lastModifiedTime != lastModifiedTime; //true, wenn es eine Änderung in der Datei gibt
            let fileURL = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler).getURLSpecFromActualFile(aFile);
            let uri = Services.io.newURI(fileURL, null, null);
            if (this.sss.sheetRegistered(uri, this.SHEET)) {
                // Wenn diese Datei bereits gelesen wurde
                if (!isEnable || !isExists) {
                    this.sss.unregisterSheet(uri, this.SHEET);
                }
                else if (isForced) {
                    // Nach Stornierung erneut einlesen
                    this.sss.unregisterSheet(uri, this.SHEET);
                    this.sss.loadAndRegisterSheet(uri, this.SHEET);
                }
            } else {
                // Datei wurde nicht gelesen
                if (isEnable && isExists) {
                    this.sss.loadAndRegisterSheet(uri, this.SHEET);
                }
            }
            if (this.lastModifiedTime !== 1 && isEnable && isForced) {
                log(this.leafName + " wurde aktualisiert");
            }
            this.lastModifiedTime = lastModifiedTime;
            return this._enabled = isEnable;
        },
    };
    UCL.init();
    function $(id) { return document.getElementById(id); }
    function $A(arr) { return Array.slice(arr); }
    function $C(name, attr) {
        const el = document.createXULElement(name);
        if (attr) Object.keys(attr).forEach(function(n) { el.setAttribute(n, attr[n]) });
        return el;
    }
    function dateFormat(date, format) {
        format = format.replace("%Y", ("000" + date.getFullYear()).substr(-4));
        format = format.replace("%m", ("0" + (date.getMonth()+1)).substr(-2));
        format = format.replace("%d", ("0" + date.getDate()).substr(-2));
        format = format.replace("%H", ("0" + date.getHours()).substr(-2));
        format = format.replace("%M", ("0" + date.getMinutes()).substr(-2));
        format = format.replace("%S", ("0" + date.getSeconds()).substr(-2));
        return format;
    }
    function log(mes) { console.log(mes); }
    })();
    Alles anzeigen
  • UserCSSLoader (2025)

    • Speravir
    • 24. August 2025 um 03:48
    Zitat von Endor

    in unserem Original konnte man auch mit
    Mittelklick auf die Schaltfläche die Stile importieren. Das geht weder
    bei der von mir noch bei Deiner Version.

    Zitat von bege

    Bei der Version RE: UserCSSLoader (2025) von Speravir (danke für die "Runderneuerung"!) habe ich die Zeile 155 entsprechend der letzten Version im Github von Endor angepasst. Damit funktioniert das Laden der Styles mit Mittelklick wieder.

    Ein ärgerlicher Unaufmerksamkeitsfehler war das von mir.

    bege: Ich hab deine Version nicht ausprobiert, aber mit einem Click-Event dürfte die vergebene Tastenkombi Alt+R nicht mehr funktionieren. Ich hab deshalb einen Click- und einen Command-Eventlistener eingefügt.

    Zitat von Mira_Belle
    Zitat von Speravir

    In der Konfiguration position = 0 zu 1 ändern. Ich hatte das bei mir getestet und da hat es funktioniert.

    Das hatte ich gar nicht gemeint!
    Sondern =>

    […]

    Das wäre das Menü "CSS", bzw. der Menüeintrag, der in der Menüleiste erzeugt werden sollte!
    Wird er aber nicht und ich weiß nicht, was an dem entsprechenden Code, der diesen erzeugen soll,
    kaputt ist, denn offensichtlich wird dieses Menü, bzw. der Eintrag "CSS", gar nicht erzeugt.

    Wie gesagt, bei mir funktioniert das genau so.

    Zitat von Endor

    Verwendest Du den CSS Code für die Symbolleistenschaltfläche?
    Den muss du deaktivieren dann steht CSS an der Stelle.

    Nöö, ich muss den Stilcode (siehe erstes Posting) nicht deaktivieren – aber das könnte daran liegen, dass das Symbol bei mir in einer separaten Addonbar liegt und ich das im Stil berücksichtige (#addonbar #usercssloader-menu), so dass dort kein Konflikt entsteht (ich sehe gerade, dass Teile des Stil nicht mehr wirken, aber .menu-text[value="CSS"] gibt’s noch). Ich habe es selber noch nicht ausprobiert, aber man könnte vermutlich das Symbol auch dem übergeordneten Toolbaritem mit der ID #usercssloader-menu-item zuordnen. Wäre nett, wenn ihr das mal testet.

    Zitat von Mira_Belle

    Was ich am Skript aber generell doof finde, dass der Editor im Firefox hinterlegt werden muss!

    Wäre es nicht besser es gäbe da eine Variabel im Skript dafür,
    so wie der Dateimanager da definiert wird?

    Such mal nach let editor = Services.prefs.getCharPref("view_source.editor.path"); und ersetze alles nach dem Gleichheitszeichen mit dem Pfad zu einem Editor (Anführungszeichen und Semikolon nicht vergessen), Wenn es funktioniert, sollte man das tatsächlich umbauen können (sollte eigentlich gehen).

    Zitat von Mira_Belle

    Und auch mit const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; komme ich nicht so wirklich zurecht,

    Das ist übrigens einfach nur eine Konstante. Sie hätte auch Namensraum_Definition heißen können oder Just_Another_Constant_with_XUL_in_its_name_to_confuse_Mira_Belle. Die wurde an nur einer einzige Stelle verwendet, an einer zweiten, wo die Adresse ebenso vorkam, nicht. Hab ich aber alles vereinheitlicht und die Konstante entfernt.

    Zitat von bege

    Bei den acceltext muss jeweils das "Alt + " weg. Der Shortcut ist nur der Buchstabe ohne Alt-Taste.
    Weiß jemand, warum der Shortcut (X) für das Öffnen des Chrome-Ordners auch dann angezeigt wird, wenn acceltext auskommentiert ist, bei den anderen Einträgen aber nicht?

    Upps, danke für den Hinweis zur überflüssigen Alt-Taste. Das X wird angezeigt, weil es im als Label definierten Text nicht vorkommt, dasselbe jetzt, wenn Du dir den Loader als Menü anzeigen lässt (sowohl Alt+C als auch Alt+S sind schon vergeben, an der Stelle benötigt man die Alt-Taste).

    Zitat von bege

    Schon mit Endors Version hat seit kurzem komischer Weise das Öffnen des CSS-Ordners mit meinem alternativen Dateimanager nicht mehr funktioniert. Ich kann nicht sagen, wann das begonnen hat, mit Fx 135 ging es auf jeden Fall noch. Ich bekam die Windows-Fehlermeldung, dass das System den Pfad "...\CSS\undefined" nicht finden kann.

    Das ist, denke ich, was ich oben mit „Wenn ich mich aber recht erinnere, ging schon beim letzten Mal die Sache mit den Dateimanagerparametern nicht“ meinte. Mir fällt gerade ein, dass ich vergessen habe, was zu testen. In Deiner Version macht STRG+Rechtsklick nicht mehr nicht mehr das, was es tun soll. Und wenn Du bei dir in Zeile 369 noch openFolder durch openCSSFolder ersetztest, könntest Du das gesamte openFolder-Objekt entfernen, weil es dann gar nicht mehr aufgerufen würde.

    Zitat von Endor

    Sobald du das OK gibst lade ich die dann bei mir hoch.

    Wie erkennbar, sehe ich schon noch Verbesserungspotential. Man sollte anscheinend auch mindestens einen Hinweis zum Symbol in das Skript einfügen, oder? Wie mir beim Schreiben auffiel, sollte ich selbst noch einiges testen, ich hänge aber mal meine aktuelle Skriptversion an:

    JavaScript: UserCSSÖoader_2025-08-23
    // ==UserScript==
    // @name           UserCSSLoader
    // @description    CSS-Codes - Styles laden und verwalten
    // @namespace      http://d.hatena.ne.jp/Griever/
    // @author         Griever
    // @include        main
    // @license        MIT License
    // @compatibility  Firefox 141+
    // @charset        UTF-8
    // @version        0.0.4r4
    // @note           0.0.4r4 prevent close menu when middleclick
    // @note           Aktualisierungen von BrokenHeart (mit 0.0.4r4 obsolet) und Speravir - www.camp-firefox.de
    // @note           0.0.4r3 Fx92: getURLSpecFromFile() -> getURLSpecFromActualFile()
    // @note           0.0.4r2 AUTHOR_SHEET-Unterstützung hinzugefügt, wichtig: Dateiendung muss .author.css sein!
    // @note           Version 0.0.4.g ermöglicht "Styles importieren" per Mittelklick und Verwendung
    // @note           eines anderen Dateimanagers (siehe in Konfiguration), ergänzt um einen
    // @note           Parameter für den Dateimanager (vFMParameter in der Konfiguration) von aborix
    // @note           Frei verschiebbare Schaltfläche eingebaut von aborix
    // @note           0.0.4 Remove E4X
    // @note           CSS-Entry-Klasse erstellt
    // @note           Style-Test-Funktion überarbeitet
    // @note           Wenn die Datei gelöscht wurde, CSS beim Neu-Erstellen und Löschen des Menüs abbrechen
    // @note           uc einlesen .uc.css temporäre Korrespondenz zum erneuten Lesen
    // ==/UserScript==
    
    /* Endor in https://www.camp-firefox.de/forum/thema/112673/?postID=1277236#post1277236 */
    
    /****** Bedienungsanleitung ******
    
    CSS-Ordner im Chrome-Ordner erstellen, CSS-Dateien dort ablegen - speichern.
    Diejenigen, deren Dateiname mit "xul-" beginnen, diejenigen, die mit ".as.css" enden, sind AGENT_SHEET, 
    alle anderen außer USER_SHEET werden gelesen. Da der Inhalt der Datei nicht überprüft wird,
    darauf achten, die Angabe von @namespace nicht zu vergessen!
    
    Schaltfläche wird in Navigationsleiste eingefügt (konfigurierbar, siehe Variable "position")
    
    Linksklick auf Stil, zum Aktivieren/Deaktivieren
    Mittelklick auf Stil zum Aktivieren/Deaktivieren, ohne Menü zu schließen
    Rechtsklick auf Stil zum Öffnen im Editor
    Strg+Linksklick zum Anzeigen im Dateimanager
    
    Die Tastenkombinationen können im Menü eingeblendet werden, dazu nach
    "acceltext" suchen und den Zeilenkommentar "//" entfernen bzw. einfügen.
    
    Verwenden des in "view_source.editor.path" angegebenen Editors.
    
    Dateiordner kann in Konfiguration geändert werden.
    
    **** Anleitung Ende ****/
    
    (function(){
    
    /***** Konfiguration *****/
    // Position: als frei verschiebbare-Schaltfläche = 0, als Menü anzeigen = 1
    let position = 0;//1
    // alternativer Dateimanager, Bsp.:
    // let filemanager = "C:\\Programme\\totalcmd\\TOTALCMD.EXE";
    let filemanager = "";
    // eventuelle Parameter für den alternativen Dateimanager, sonst filemanagerParam = "";
    //let filemanagerParam = "/O /T";//Totalcommander
    let filemanagerParam = "";
    // Unterordner für die CSS-Dateien:
    let cssFolder = "CSS";
    // Menüeintrag zum Bearbeiten der userChrome.css verstecken (true) oder anzeigen (false)
    let hideUserChromeCSS = false;
    // Menüeintrag zum Bearbeiten der userContent.css verstecken (true) oder anzeigen (false)
    let hideUserContentCSS = false;
    // zusätzlich Chrome-Ordner im Untermenü anzeigen: 1 = ja, 0 = nein
    let showChrome = 1;
    /***** Ende Konfiguration *****/
    
    ChromeUtils.importESModule("resource://gre/modules/AppConstants.sys.mjs");
    
    // Wenn beim Start ein weiteres Fenster (zweites Fenster) vorhanden ist, beenden
    let list = Services.wm.getEnumerator("navigator:browser");
    while(list.hasMoreElements()){ if(list.getNext() != window) return; }
    
    if (window.UCL) {
    	window.UCL.destroy();
    	delete window.UCL;
    }
    
    window.UCL = {
    		vFileManager: filemanager,
    		vFMParameter: filemanagerParam,
    		USE_UC: "UC" in window,
    		AGENT_SHEET : Ci.nsIStyleSheetService.AGENT_SHEET,
    		USER_SHEET  : Ci.nsIStyleSheetService.USER_SHEET,
    		AUTHOR_SHEET: Ci.nsIStyleSheetService.AUTHOR_SHEET,
    		readCSS: {},
    		get disabled_list() {
    		let obj = [];
    		try {
    			obj = decodeURIComponent(this.prefs.getCharPref("disabled_list")).split("|");
    		} catch(e) {}
    		delete this.disabled_list;
    		return this.disabled_list = obj;
    	},
    	get prefs() {
    		delete this.prefs;
    		return this.prefs = Services.prefs.getBranch("UserCSSLoader.");
    	},
    	get styleSheetServices(){
    		delete this.styleSheetServices;
    		return this.styleSheetServices = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
    	},
    	get FOLDER() {
    		let aFolder;
    		try {
    			// UserCSSLoader.FOLDER verwenden
    			let folderPath = this.prefs.getCharPref("FOLDER");
    			aFolder = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
    			aFolder.initWithPath(folderPath);
    		} catch (e) {
    			aFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
    			aFolder.appendRelativePath(cssFolder);
    		}
    		if (!aFolder.exists() || !aFolder.isDirectory()) {
    			aFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0o664);
    		}
    		delete this.FOLDER;
    		return this.FOLDER = aFolder;
    	},
    	get CHRMFOLDER() {
    			let bFolder;
    			try {
    					// UserCSSLoader.CHRMFOLDER verwenden
    					let CHRMfolderPath = this.prefs.getCharPref("CHRMFOLDER");
    					bFolder = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
    					bFolder.initWithPath(CHRMfolderPath);
    			} catch (e) {
    					bFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
    			}
    			if (!bFolder.exists() || !bFolder.isDirectory()) {
    					bFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0o664);
    			}
    			delete this.CHRMFOLDER;
    			return this.CHRMFOLDER = bFolder;
    	},
    
    	getFocusedWindow: function() {
    		let win = document.commandDispatcher.focusedWindow;
    		if (!win || win == window) win = content;
    		return win;
    	},
    
    	init: function() {
    		const cssmenu = $C("menu", {
    			id: "usercssloader-menu",
    			label: "CSS",
    			tooltiptext: "UserCSSLoader\n\nLinksklick: Stylesheets anzeigen\nMittelklick: Styles importieren",
    			accesskey: "Y"
    		});
    		cssmenu.addEventListener("command", () => UCL.rebuild());
    		cssmenu.addEventListener("click", (event) => { if (event.button === 1) UCL.rebuild(); });
    		const menupopup = $C("menupopup", {
    			id: "usercssloader-menupopup"
    		});
    		cssmenu.appendChild(menupopup);
    
    		let menu = $C("menu", {
    			label: "Style-Loader-Menü",
    			id: "style-loader-menu",
    			accesskey: "M",
    			//acceltext: "M"
    		});
    		menupopup.appendChild(menu);
    		menupopup.appendChild($C("menuseparator"));
    
    		let mp = $C("menupopup", { id: "usercssloader-submenupopup" });
    		menu.appendChild(mp);
    		let rebuildItem = $C("menuitem", {
    			label: "Styles importieren",
    			accesskey: "I",
    			//acceltext: "I"
    		});
    		rebuildItem.addEventListener("command", () => UCL.rebuild());
    		mp.appendChild(rebuildItem);
    		mp.appendChild($C("menuseparator"));
    		let createCSS = $C("menuitem", {
    			label: "CSS-Datei erstellen",
    			accesskey: "E",
    			//acceltext: "E"
    		});
    		createCSS.addEventListener("command", () => UCL.create());
    		mp.appendChild(createCSS);
    		let openFolder = $C("menuitem", {
    			label: "CSS-Ordner öffnen",
    			accesskey: "O",
    			//acceltext: "O"
    		});
    		openFolder.addEventListener("command", () => UCL.openFolder());
    		mp.appendChild(openFolder);
    		if (showChrome === 1) {
    				let openChromeFolder = $C("menuitem", {
    					label: "Chrome-Ordner öffnen",
    					accesskey: "X",
    					//acceltext: "X"
    				});
    				openChromeFolder.addEventListener("command", () => UCL.openCHRMFolder());
    				mp.appendChild(openChromeFolder);
    		}
    		mp.appendChild($C('menuseparator'));
    		let editChromeItem = $C("menuitem", {
    			label: "userChrome.css bearbeiten",
    			hidden: hideUserChromeCSS,
    		});
    		editChromeItem.addEventListener("command", () => UCL.editUserCSS("userChrome.css"));
    		mp.appendChild(editChromeItem);
    		let editContentItem = $C("menuitem", {
    			label: "userContent.css bearbeiten",
    			hidden: hideUserContentCSS,
    		});
    		editContentItem.addEventListener("command", () => UCL.editUserCSS("userContent.css"));
    		mp.appendChild(editContentItem);
    
    		menu = $C("menu", {
    			label: ".uc.css",
    			accesskey: "U",
    			//acceltext: "U",
    			hidden: !UCL.USE_UC
    		});
    		menupopup.appendChild(menu);
    		mp = $C("menupopup", { id: "usercssloader-ucmenupopup" });
    		menu.appendChild(mp);
    		let UCrebuild = $C("menuitem", {
    			label: "Importieren(.uc.js)",
    		});
    		UCrebuild.addEventListener("command", () => UCL.UCrebuild());
    		mp.appendChild(UCrebuild);
    		mp.appendChild($C("menuseparator", { id: "usercssloader-ucseparator" }));
    
    		CustomizableUI.createWidget({
    			id: 'usercssloader-menu-item',
    			type: 'custom',
    			defaultArea: CustomizableUI.AREA_NAVBAR,
    			onBuild: function(aDocument) {
    				let toolbaritem = aDocument.createXULElement('toolbaritem');
    				toolbaritem.id = 'usercssloader-menu-item';
    				toolbaritem.className = 'chromeclass-toolbar-additional';
    				return toolbaritem;
    			}
    		});
    		$('usercssloader-menu-item').appendChild(cssmenu);
    
    		if (position === 1) {
    				let refNode = $('helpMenu');
    				refNode.parentNode.insertBefore(cssmenu, refNode.nextSibling);
    		}
    
    		let key = $C("key", {
    			id: "usercssloader-rebuild-key",
    			key: "R",
    			modifiers: "alt",
    		});
    		key.addEventListener("command", () => UCL.rebuild());
    		$("mainKeyset").appendChild(key);
    
    		this.rebuild();
    		this.initialized = true;
    		if (UCL.USE_UC) {
    			setTimeout(function() {
    				UCL.UCcreateMenuitem();
    			}, 1000);
    		}
    		window.addEventListener("unload", this, false);
    	},
    	uninit: function() {
    		const dis = [];
    		for (let x of Object.keys(this.readCSS)) {
    			if (!this.readCSS[x].enabled)
    				dis.push(x);
    		}
    		this.prefs.setCharPref("disabled_list", encodeURIComponent(dis.join("|")));
    		window.removeEventListener("unload", this, false);
    	},
    	destroy: function() {
    		var i = document.getElementById("usercssloader-menu");
    		if (i) i.parentNode.removeChild(i);
    		var i = document.getElementById("usercssloader-rebuild-key");
    		if (i) i.parentNode.removeChild(i);
    		this.uninit();
    	},
    	handleEvent: function(event) {
    		switch(event.type){
    			case "unload": this.uninit(); break;
    		}
    	},
    	rebuild: function() {
    		let ext = /\.css$/i;
    		let not = /\.uc\.css/i;
    		let files = this.FOLDER.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
    
    		while (files.hasMoreElements()) {
    			let file = files.getNext().QueryInterface(Ci.nsIFile);
    			if (!ext.test(file.leafName) || not.test(file.leafName)) continue;
    			let CSS = this.loadCSS(file);
    			CSS.flag = true;
    		}
    		for (let leafName of Object.keys(this.readCSS)) {
    			const CSS = this.readCSS[leafName];
    			if (!CSS.flag) {
    				CSS.enabled = false;
    				delete this.readCSS[leafName];
    			}
    			delete CSS.flag;
    			this.rebuildMenu(leafName);
    		}
    		if (this.initialized) {
    			if (typeof(StatusPanel) !== "undefined")
    				StatusPanel._label = "Styles importiert";
    			else
    				XULBrowserWindow.statusTextField.label = "Styles importiert";
    		}
    	},
    	loadCSS: function(aFile) {
    		let CSS = this.readCSS[aFile.leafName];
    		if (!CSS) {
    			CSS = this.readCSS[aFile.leafName] = new CSSEntry(aFile);
    			if (this.disabled_list.indexOf(CSS.leafName) === -1) {
    				CSS.enabled = true;
    			}
    		} else if (CSS.enabled) {
    			CSS.enabled = true;
    		}
    		return CSS;
    	},
    	rebuildMenu: function(aLeafName) {
    		let CSS = this.readCSS[aLeafName];
    		let menuitem = document.getElementById("usercssloader-" + aLeafName);
    		if (!CSS) {
    			if (menuitem)
    				menuitem.parentNode.removeChild(menuitem);
    			return;
    		}
    
    		if (!menuitem) {
    			menuitem = $C("menuitem", {
    				label		: aLeafName,
    				id			: "usercssloader-" + aLeafName,
    				class		: "usercssloader-item " + (CSS.SHEET == this.AGENT_SHEET? "AGENT_SHEET" : CSS.SHEET == this.AUTHOR_SHEET? "AUTHOR_SHEET": "USER_SHEET"),
    				type		: "checkbox",
    				autocheck	: "false",
    				tooltiptext : "Linksklick: an/aus, Menü schließt\nMittelklick: an/aus, Menü bleibt offen\nRechtsklick: bearbeiten\nStrg+Rechtsklick: im Dateimanager anzeigen"
    			});
    			menuitem.addEventListener("command", () => UCL.toggle(aLeafName));
    			menuitem.addEventListener("click", (event) => UCL.itemClick(event));
    			menuitem.addEventListener("mouseup", (event) => { if (event.button === 1) event.preventDefault(); });
    			document.getElementById("usercssloader-menupopup").appendChild(menuitem);
    		}
    		menuitem.setAttribute("checked", CSS.enabled);
    	},
    	toggle: function(aLeafName) {
    		let CSS = this.readCSS[aLeafName];
    		if (!CSS || event.ctrlKey) return;
    		CSS.enabled = !CSS.enabled;
    		this.rebuildMenu(aLeafName);
    	},
    	itemClick: function(event) {
    		let label = event.currentTarget.getAttribute("label");
    		event.preventDefault();
    		event.stopPropagation();
    		if (event.button === 0) {
    				return;
    		} else if (event.button === 1) {
    				this.toggle(label);
    		} else if (event.button === 2) {
    				if (event.ctrlKey) {
    						UCL.openFolder(label);
    				} else {
    				closeMenus(event.target);
    				this.edit(this.getFileFromLeafName(label));
    				}
    		}
    	},
    	getFileFromLeafName: function(aLeafName) {
    		let f = this.FOLDER.clone();
    		f.QueryInterface(Ci.nsIFile); // use appendRelativePath
    		f.appendRelativePath(aLeafName);
    		return f;
    	},
    	openFolder: function(label) {
    		const PathSep = AppConstants.platform === "win" ? "\\" : "/";
    		let target= this.FOLDER.path + PathSep + label;
    		if (this.vFileManager.length !== 0) {
    				let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
    				let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
    				let args = [this.vFMParameter,target];
    				file.initWithPath(this.vFileManager);
    				process.init(file);
    				// Verzeichnis mit anderem Dateimanager öffnen
    				process.run(false, args, args.length);
    		} else {
    				// Verzeichnis mit Dateimanager des Systems öffnen
    				this.FOLDER.launch();
    		}
    	},
    	openCHRMFolder:function(){
    			if (this.vFileManager.length !== 0) {
    					let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
    					let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
    					let args = [this.vFMParameter,this.CHRMFOLDER.path];
    					file.initWithPath(this.vFileManager);
    					process.init(file);
    					// Verzeichnis mit anderem Dateimanager öffnen
    					process.run(false, args, args.length);
    			} else {
    					// Verzeichnis mit Dateimanager des Systems öffnen
    					this.CHRMFOLDER.launch();
    			}
    	},
    	editUserCSS: function(aLeafName) {
    		let file = Services.dirsvc.get("UChrm", Ci.nsIFile);
    		file.appendRelativePath(aLeafName);
    		this.edit(file);
    	},
    	edit: function(aFile) {
    		let editor = Services.prefs.getCharPref("view_source.editor.path");
    		if (!editor) return alert('Unter about:config den vorhandenen Schalter\n "view_source.editor.path" mit dem Editorpfad ergänzen');
    		try {
    			let UI = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
    			UI.charset = window.navigator.platform.toLowerCase().indexOf("win") >= 0? "Shift_JIS": "UTF-8";
    			let path = UI.ConvertFromUnicode(aFile.path);
    			let app = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
    			app.initWithPath(editor);
    			let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
    			process.init(app);
    			process.run(false, [path], 1);
    		} catch (e) {}
    	},
    	create: function(aLeafName) {
    		if (!aLeafName) aLeafName = prompt("Name des Styles", dateFormat(new Date(), "%Y_%m%d_%H%M%S"));
    		if (aLeafName) aLeafName = aLeafName.replace(/\s+/g, " ").replace(/[\\/:*?\"<>|]/g, "");
    		if (!aLeafName || !/\S/.test(aLeafName)) return;
    		if (!/\.css$/.test(aLeafName)) aLeafName += ".css";
    		let file = this.getFileFromLeafName(aLeafName);
    		this.edit(file);
    	},
    	UCrebuild: function() {
    		let re = /^file:.*\.uc\.css(?:\?\d+)?$/i;
    		let query = "?" + new Date().getTime();
    		Array.slice(document.styleSheets).forEach(function(css){
    			if (!re.test(css.href)) return;
    			if (css.ownerNode) {
    				css.ownerNode.parentNode.removeChild(css.ownerNode);
    			}
    			let pi = document.createProcessingInstruction('xml-stylesheet','type="text/css" href="'+ css.href.replace(/\?.*/, '') + query +'"');
    			document.insertBefore(pi, document.documentElement);
    		});
    		UCL.UCcreateMenuitem();
    	},
    	UCcreateMenuitem: function() {
    		let sep = $("usercssloader-ucseparator");
    		let popup = sep.parentNode;
    		if (sep.nextSibling) {
    			let range = document.createRange();
    			range.setStartAfter(sep);
    			range.setEndAfter(popup.lastChild);
    			range.deleteContents();
    			range.detach();
    		}
    
    		let re = /^file:.*\.uc\.css(?:\?\d+)?$/i;
    		Array.slice(document.styleSheets).forEach(function(css) {
    			if (!re.test(css.href)) return;
    			let fileURL = decodeURIComponent(css.href).split("?")[0];
    			let aLeafName = fileURL.split("/").pop();
    			let m = $C("menuitem", {
    				label		: aLeafName,
    				tooltiptext	: fileURL,
    				id			: "usercssloader-" + aLeafName,
    				type		: "checkbox",
    				autocheck	: "false",
    				checked		: "true",
    			});
    			m.css = css;
    			m.addEventListener("command", function() {
    				if (!event.ctrlKey) {this.setAttribute("checked", !(this.css.disabled = !this.css.disabled));}
    			});
    			m.addEventListener("mouseup", function(event) {
    				if (event.button === 1) event.preventDefault();
    			});
    			m.addEventListener("click", function(event) {
    				UCL.UCItemClick(event);
    			});
    			popup.appendChild(m);
    		});
    	},
    	UCItemClick: function(event) {
    		if (event.button === 0) return;
    		event.preventDefault();
    		event.stopPropagation();
    
    		if (event.button === 1) {
    			event.target.doCommand();
    		}
    		else if (event.button === 2) {
    			closeMenus(event.target);
    			let fileURL = event.currentTarget.getAttribute("tooltiptext");
    			let file = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler).getFileFromURLSpec(fileURL);
    			this.edit(file);
    		}
    	},
    };
    
    function CSSEntry(aFile) {
    	this.path = aFile.path;
    	this.leafName = aFile.leafName;
    	this.lastModifiedTime = 1;
    	this.SHEET = /^xul-|\.as\.css$/i.test(this.leafName) ?
    		Ci.nsIStyleSheetService.AGENT_SHEET:
    		/\.author\.css$/i.test(this.leafName)?
    			Ci.nsIStyleSheetService.AUTHOR_SHEET:
    			Ci.nsIStyleSheetService.USER_SHEET;
    }
    CSSEntry.prototype = {
    	sss: Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
    	_enabled: false,
    	get enabled() {
    		return this._enabled;
    	},
    	set enabled(isEnable) {
    		let aFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile)
    		aFile.initWithPath(this.path);
    
    		let isExists = aFile.exists(); // true, wenn die Datei bereits existiert
    		let lastModifiedTime = isExists ? aFile.lastModifiedTime : 0;
    		let isForced = this.lastModifiedTime != lastModifiedTime; //true, wenn es eine Änderung in der Datei gibt
    
    		let fileURL = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler).getURLSpecFromActualFile(aFile);
    		let uri = Services.io.newURI(fileURL, null, null);
    
    		if (this.sss.sheetRegistered(uri, this.SHEET)) {
    			// Wenn diese Datei bereits gelesen wurde
    			if (!isEnable || !isExists) {
    				this.sss.unregisterSheet(uri, this.SHEET);
    			}
    			else if (isForced) {
    				// Nach Stornierung erneut einlesen
    				this.sss.unregisterSheet(uri, this.SHEET);
    				this.sss.loadAndRegisterSheet(uri, this.SHEET);
    			}
    		} else {
    			// Datei wurde nicht gelesen
    			if (isEnable && isExists) {
    				this.sss.loadAndRegisterSheet(uri, this.SHEET);
    			}
    		}
    		if (this.lastModifiedTime !== 1 && isEnable && isForced) {
    			log(this.leafName + " wurde aktualisiert");
    		}
    		this.lastModifiedTime = lastModifiedTime;
    		return this._enabled = isEnable;
    	},
    };
    
    UCL.init();
    
    function $(id) { return document.getElementById(id); }
    function $A(arr) { return Array.slice(arr); }
    function $C(name, attr) {
    	const el = document.createXULElement(name);
    	if (attr) Object.keys(attr).forEach(function(n) { el.setAttribute(n, attr[n]) });
    	return el;
    }
    function dateFormat(date, format) {
    	format = format.replace("%Y", ("000" + date.getFullYear()).substr(-4));
    	format = format.replace("%m", ("0" + (date.getMonth()+1)).substr(-2));
    	format = format.replace("%d", ("0" + date.getDate()).substr(-2));
    	format = format.replace("%H", ("0" + date.getHours()).substr(-2));
    	format = format.replace("%M", ("0" + date.getMinutes()).substr(-2));
    	format = format.replace("%S", ("0" + date.getSeconds()).substr(-2));
    	return format;
    }
    
    function log(mes) { console.log(mes); }
    })();
    Alles anzeigen
  • [ab 143.0] Update meiner Menuscripts + Goodie

    • Speravir
    • 24. August 2025 um 01:57

    Bezogen auf meine Frage: Alles klar.

  • [ab 143.0] Update meiner Menuscripts + Goodie

    • Speravir
    • 23. August 2025 um 00:00
    Zitat von Mitleser

    Ich habe gerade festgestellt, dass sich in meinen hier publizierten 'Menuscripts' ab Firefox 143 die Iconeinbindung obsolet ist.

    Was genau musste geändert werden?

  • UserCSSLoader (2025)

    • Speravir
    • 22. August 2025 um 23:50
    Zitat von Endor

    Dieser Tippfehler ist schon in der ersten Version dieses Scripts,
    also vor 14 Jahren enthalten. Hatte sogar Aborix diesbezüglich
    mal gefragt ob man das ändern müsste er sagte da spezifiziert nicht nötig.

    Aha, das erstaunt mich, aber danke für die Info. Ich halte es trotzdem für besser, das Semikolon zu ergänzen.

    Zitat von Endor

    Eine Frage dazu noch, in unserem Original konnte man auch mit
    Mittelklick auf die Schaltfläche die Stile importieren. Das geht weder
    bei der von mir noch bei Deiner Version. Ließe sich das eventuell
    noch einbauen. Das hatte Aborix seinerzeit auch eingefügt.

    Oh, das muss ich mir ansehen, kann wie immer aber nichts versprechen. Die Vorgängerversion hat diesbezüglich funktioniert.

    Zitat von Mira_Belle

    Und dann wäre da noch die Zahl 0664.

    Upps, das hattest Du weiter oben schon moniert und ich hab total vergessen, das zu ändern.

    Zitat von Mira_Belle

    Was ich auch nicht in den Griff bekommen habe, bzw, wo ich nicht weiter weiß, es sollte eigentlich ein neues Menü "CSS"
    in der Menüleiste erzeugt werden. Tut es aber nicht!!

    In der Konfiguration position = 0 zu 1 ändern. Ich hatte das bei mir getestet und da hat es funktioniert.

    Zitat von Sören Hentzschel
    Zitat von Mira_Belle

    So werden die Variablen "Cu" und "Cr" niemals aufgerufen, sind aber definiert.

    Das ist richtig. Man kann sogar die komplette Zeile weglassen, weil Cc, was im Script genutzt wird, standardmäßig von Firefox exportiert wird.

    Na, dann machen wir das doch! (Ich hatte mich schon gewundert, warum das überhaupt drin steht.)

    Zitat von Sören Hentzschel
    Zitat von Mira_Belle

    Und auch mit const XULNS = "http://www.mozilla.org/keymaster/gate…ere.is.only.xul"; komme ich nicht so wirklich zurecht,
    XUL mag eventuell noch gehen, wird aber so nach und nach ersetzt.
    XML User Interface Language – Wikipedia

    Nicht für alls gibt es eine Entsprechung in HTML. Wenn XUL-Elemente erzeugt werden sollen - und das Script erzeugt eindeutig XUL-Elemente, menupopup und menuseparator gibt es in HTML nicht -, muss auch der entsprechende Namespace genutzt werden.

    (etc.) Das Skript ist da nicht einheitlich: An anderer Stelle wird document.createElementNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul') genutzt. Und in der Vorgängerversion wurde tatsächlich an genau der Stelle, wo jetzt die Konstante eingesetzt wird, document.createXULElement() verwendet. Ich wollte das alles nicht auch noch ändern, aber im Sinne der Einheitlichkeit wäre es vielleicht gar nicht so schlecht.

    Danke auch für die restlichen Anmerkungen, Sören! Ach so:

    Zitat von Sören Hentzschel

    Die Rechte sind nach dem Anlegen des Ordners nicht 664, sondern 644. Ob das in der Praxis für diesen konkreten Anwendungsfall überhaupt notwendig ist, die Rechte auf 664 zu setzen, weiß ich nicht. In jedem Fall ist der Aufruf falsch.

    In Windows wird das ja völlig ignoriert, so dass man das überhaupt nicht überprüfen kann, insofern speziell danke für den Test. Ob die Rechteänderung überhaupt notwendig ist, weiß ich natürlich noch weniger.


    Zitat von bege

    habe ich die Zeile 155 entsprechend der letzten Version im Github von Endor angepasst. Damit funktioniert das Laden der Styles mit Mittelklick wieder.

    Oh, das hat sich überschnitten. Danke, sehe ich mir natürlich auch an!

  • Kompatibilität Mehrzeilenskript/Addon Bar

    • Speravir
    • 22. August 2025 um 01:17

    Zum Verständnis: Wäre es sinnvoll, Aris zu informieren und wenn ja, auf welches Posting genau sollte er hingewiesen werden? Allerdings funktioniert bei mir mit Aris’ Skript die Einbindung des Themes.

  • UserCSSLoader (2025)

    • Speravir
    • 22. August 2025 um 01:00
    Zitat von Endor

    Habe eine funktionierende Version vom usercssloader.uc.js auf Basis einer
    Version aus den asiatischen Tiefen gemacht.

    Oh … :whistling:

    Ich hab die Änderungen aus der vorigen Version (UserCSSLoader.uc.js bei Endor) wieder eingebaut inklusive des Konfigurationsteils und einigen Fehlerkorrekturen (an einer Stelle fehlte sicher eine Semikolon, in einer anderen kann man es weglassen, glaube ich, es ist aber besser, es zu setzen; plus Rechtschreib-/Tippfehler, zum Teil von mir selber aus der Vorgängerversion).

    Zitat von Endor

    Im Moment fehlt noch der Eintrag zum öffnen des Chromeordners
    und die Möglichkeit zur Verwendung eines alternativen Dateimanagers.
    Also anstelle vom Explorer zbs. den Totalcomander.

    Bei mir funktioniert es. (Bis auf das:) Wenn ich mich aber recht erinnere, ging schon beim letzten Mal die Sache mit den Dateimanagerparametern nicht, vielleicht will sich BrokenHeart das mal ansehen? Ich nutze daher eine Windows-Verknüpfung (.LNK-Datei), in Linux und MacOS würde man wohl eine Shell-Datei einsetzen. Eine Tastenkombi musste auch wieder eingefügt, dabei aber geändert werden, bei einer anderen war mir nicht aufgefallen, dass meine Änderung schon vergeben war, Details bei Anfrage und vielleicht fällt anderen eine weitere Kollision auf.

    Den CSS-Tester und alle dazugehörigen Codeteile habe ich wieder herausgeworfen: Erstens ist das in der Skript-Vorlage sowieso standardmäßig deaktiviert und zweitens erhielt ich nach Aktivierung nur leere Fenster ohne Inhalt, was aber, sofern ich die Fehlerkonsole nicht missverstehe, an meinen Schutzeinstellungen im Firefox liegen könnte.

    JavaScript: UserCSSLoader_2025-08
    // ==UserScript==
    // @name           UserCSSLoader
    // @description    CSS-Codes - Styles laden und verwalten
    // @namespace      http://d.hatena.ne.jp/Griever/
    // @author         Griever
    // @include        main
    // @license        MIT License
    // @compatibility  Firefox 141+
    // @charset        UTF-8
    // @version        0.0.4r4
    // @note           0.0.4r4 prevent close menu when middleclick
    // @note           Aktualisierungen von BrokenHeart (mit 0.0.4r4 obsolet) und Speravir - www.camp-firefox.de
    // @note           0.0.4r3 Fx92: getURLSpecFromFile() -> getURLSpecFromActualFile()
    // @note           0.0.4r2 AUTHOR_SHEET-Unterstützung hinzugefügt, wichtig: Dateiendung muss .author.css sein!
    // @note           Version 0.0.4.g ermöglicht "Styles importieren" per Mittelklick und Verwendung
    // @note           eines anderen Dateimanagers (siehe in Konfiguration), ergänzt um einen
    // @note           Parameter für den Dateimanager (vFMParameter in der Konfiguration) von aborix
    // @note           Frei verschiebbare Schaltfläche eingebaut von aborix
    // @note           0.0.4 Remove E4X
    // @note           CSS-Entry-Klasse erstellt
    // @note           Style-Test-Funktion überarbeitet
    // @note           Wenn die Datei gelöscht wurde, CSS beim Neu-Erstellen und Löschen des Menüs abbrechen
    // @note           uc einlesen .uc.css temporäre Korrespondenz zum erneuten Lesen
    // ==/UserScript==
    
    /****** Bedienungsanleitung ******
    
    CSS-Ordner im Chrome-Ordner erstellen, CSS-Dateien dort ablegen - speichern.
    Diejenigen, deren Dateiname mit "xul-" beginnen, diejenigen, die mit ".as.css" enden, sind AGENT_SHEET, 
    alle anderen außer USER_SHEET werden gelesen. Da der Inhalt der Datei nicht überprüft wird,
    darauf achten, die Angabe von @namespace nicht zu vergessen!
    
    Schaltfläche wird in Navigationsleiste eingefügt (konfigurierbar, siehe Variable "position")
    
    Linksklick auf Stil, zum Aktivieren/Deaktivieren
    Mittelklick auf Stil zum Aktivieren/Deaktivieren, ohne Menü zu schließen
    Rechtsklick auf Stil zum Öffnen im Editor
    Strg+Linksklick zum Anzeigen im Dateimanager
    
    Die Tastenkombinationen können im Menü eingeblendet werden, dazu nach
    "acceltext" suchen und den Zeilenkommentar "//" entfernen bzw. einfügen.
    
    Verwenden des in "view_source.editor.path" angegebenen Editors.
    
    Dateiordner kann in Konfiguration geändert werden.
    
    **** Anleitung Ende ****/
    
    (function(){
    
    /***** Konfiguration *****/
    // Position: als frei verschiebbare-Schaltfläche = 0, als Menü anzeigen = 1
    let position = 0;//1
    // alternativer Dateimanager, Bsp.:
    // let filemanager = "C:\\Programme\\totalcmd\\TOTALCMD.EXE";
    let filemanager = "";
    // eventuelle Parameter für den alternativen Dateimanager, sonst filemanagerParam = "";
    //let filemanagerParam = "/O /T";//Totalcommander
    let filemanagerParam = "";
    // Unterordner für die CSS-Dateien:
    let cssFolder = "CSS";
    // Menüeintrag zum Bearbeiten der userChrome.css verstecken (true) oder anzeigen (false)
    let hideUserChromeCSS = false;
    // Menüeintrag zum Bearbeiten der userContent.css verstecken (true) oder anzeigen (false)
    let hideUserContentCSS = false;
    // zusätzlich Chrome-Ordner im Untermenü anzeigen: 1 = ja, 0 = nein
    let showChrome = 1;
    /***** Ende Konfiguration *****/
    
    ChromeUtils.importESModule("resource://gre/modules/AppConstants.sys.mjs");
    
    let { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
    const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
    
    // Wenn beim Start ein weiteres Fenster (zweites Fenster) vorhanden ist, beenden
    let list = Services.wm.getEnumerator("navigator:browser");
    while(list.hasMoreElements()){ if(list.getNext() != window) return; }
    
    if (window.UCL) {
    	window.UCL.destroy();
    	delete window.UCL;
    }
    
    window.UCL = {
    		vFileManager: filemanager,
    		vFMParameter: filemanagerParam,
    		USE_UC: "UC" in window,
    		AGENT_SHEET : Ci.nsIStyleSheetService.AGENT_SHEET,
    		USER_SHEET  : Ci.nsIStyleSheetService.USER_SHEET,
    		AUTHOR_SHEET: Ci.nsIStyleSheetService.AUTHOR_SHEET,
    		readCSS: {},
    		get disabled_list() {
    		let obj = [];
    		try {
    			obj = decodeURIComponent(this.prefs.getCharPref("disabled_list")).split("|");
    		} catch(e) {}
    		delete this.disabled_list;
    		return this.disabled_list = obj;
    	},
    	get prefs() {
    		delete this.prefs;
    		return this.prefs = Services.prefs.getBranch("UserCSSLoader.");
    	},
    	get styleSheetServices(){
    		delete this.styleSheetServices;
    		return this.styleSheetServices = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
    	},
    	get FOLDER() {
    		let aFolder;
    		try {
    			// UserCSSLoader.FOLDER verwenden
    			let folderPath = this.prefs.getCharPref("FOLDER");
    			aFolder = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
    			aFolder.initWithPath(folderPath);
    		} catch (e) {
    			aFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
    			aFolder.appendRelativePath(cssFolder);
    		}
    		if (!aFolder.exists() || !aFolder.isDirectory()) {
    			aFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0664);
    		}
    		delete this.FOLDER;
    		return this.FOLDER = aFolder;
    	},
    	get CHRMFOLDER() {
    			let bFolder;
    			try {
    					// UserCSSLoader.CHRMFOLDER verwenden
    					let CHRMfolderPath = this.prefs.getCharPref("CHRMFOLDER");
    					bFolder = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
    					bFolder.initWithPath(CHRMfolderPath);
    			} catch (e) {
    					bFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
    			}
    			if (!bFolder.exists() || !bFolder.isDirectory()) {
    					bFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0664);
    			}
    			delete this.CHRMFOLDER;
    			return this.CHRMFOLDER = bFolder;
    	},
    
    	getFocusedWindow: function() {
    		let win = document.commandDispatcher.focusedWindow;
    		if (!win || win == window) win = content;
    		return win;
    	},
    
    	init: function() {
    		const cssmenu = $C("menu", {
    			id: "usercssloader-menu",
    			label: "CSS",
    			tooltiptext: "UserCSSLoader\n\nLinksklick: Stylesheets anzeigen\nMittelklick: Styles importieren",
    			accesskey: "Y"
    		});
    		cssmenu.addEventListener("mouseup", (event) => { if (event.button === 1) event.preventDefault(); });
    		cssmenu.addEventListener("command", () => UCL.rebuild());
    		const menupopup = $C("menupopup", {
    			id: "usercssloader-menupopup"
    		});
    		cssmenu.appendChild(menupopup);
    
    		let menu = $C("menu", {
    			label: "Style-Loader-Menü",
    			id: "style-loader-menu",
    			accesskey: "M",
    			//acceltext: "Alt + M"
    		});
    		menupopup.appendChild(menu);
    		menupopup.appendChild($C("menuseparator"));
    
    		let mp = $C("menupopup", { id: "usercssloader-submenupopup" });
    		menu.appendChild(mp);
    		let rebuildItem = $C("menuitem", {
    			label: "Styles importieren",
    			accesskey: "I",
    			//acceltext: "Alt + I"
    		});
    		rebuildItem.addEventListener("command", () => UCL.rebuild());
    		mp.appendChild(rebuildItem);
    		mp.appendChild($C("menuseparator"));
    		let createCSS = $C("menuitem", {
    			label: "CSS-Datei erstellen",
    			accesskey: "E",
    			//acceltext: "Alt + E"
    		});
    		createCSS.addEventListener("command", () => UCL.create());
    		mp.appendChild(createCSS);
    		let openFolder = $C("menuitem", {
    			label: "CSS-Ordner öffnen",
    			accesskey: "O",
    			//acceltext: "Alt + O"
    		});
    		openFolder.addEventListener("command", () => UCL.openFolder());
    		mp.appendChild(openFolder);
    		if (showChrome === 1) {
    				let openChromeFolder = $C("menuitem", {
    					label: "Chrome-Ordner öffnen",
    					accesskey: "X",
    					//acceltext: "Alt + X"
    				});
    				openChromeFolder.addEventListener("command", () => UCL.openCHRMFolder());
    				mp.appendChild(openChromeFolder);
    		}
    		mp.appendChild($C('menuseparator'));
    		let editChromeItem = $C("menuitem", {
    			label: "userChrome.css bearbeiten",
    			hidden: hideUserChromeCSS,
    		});
    		editChromeItem.addEventListener("command", () => UCL.editUserCSS("userChrome.css"));
    		mp.appendChild(editChromeItem);
    		let editContentItem = $C("menuitem", {
    			label: "userContent.css bearbeiten",
    			hidden: hideUserContentCSS,
    		});
    		editContentItem.addEventListener("command", () => UCL.editUserCSS("userContent.css"));
    		mp.appendChild(editContentItem);
    
    		menu = $C("menu", {
    			label: ".uc.css",
    			accesskey: "U",
    			//acceltext: "Alt + U",
    			hidden: !UCL.USE_UC
    		});
    		menupopup.appendChild(menu);
    		mp = $C("menupopup", { id: "usercssloader-ucmenupopup" });
    		menu.appendChild(mp);
    		let UCrebuild = $C("menuitem", {
    			label: "Importieren(.uc.js)",
    		});
    		UCrebuild.addEventListener("command", () => UCL.UCrebuild());
    		mp.appendChild(UCrebuild);
    		mp.appendChild($C("menuseparator", { id: "usercssloader-ucseparator" }));
    
    		CustomizableUI.createWidget({
    			id: 'usercssloader-menu-item',
    			type: 'custom',
    			defaultArea: CustomizableUI.AREA_NAVBAR,
    			onBuild: function(aDocument) {
    				let toolbaritem = aDocument.createElementNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul', 'toolbaritem');
    				toolbaritem.id = 'usercssloader-menu-item';
    				toolbaritem.className = 'chromeclass-toolbar-additional';
    				return toolbaritem;
    			}
    		});
    		$('usercssloader-menu-item').appendChild(cssmenu);
    
    		if (position === 1) {
    				let refNode = $('helpMenu');
    				refNode.parentNode.insertBefore(cssmenu, refNode.nextSibling);
    		}
    
    		let key = $C("key", {
    			id: "usercssloader-rebuild-key",
    			key: "R",
    			modifiers: "alt",
    		});
    		key.addEventListener("command", () => UCL.rebuild());
    		$("mainKeyset").appendChild(key);
    
    		this.rebuild();
    		this.initialized = true;
    		if (UCL.USE_UC) {
    			setTimeout(function() {
    				UCL.UCcreateMenuitem();
    			}, 1000);
    		}
    		window.addEventListener("unload", this, false);
    	},
    	uninit: function() {
    		const dis = [];
    		for (let x of Object.keys(this.readCSS)) {
    			if (!this.readCSS[x].enabled)
    				dis.push(x);
    		}
    		this.prefs.setCharPref("disabled_list", encodeURIComponent(dis.join("|")));
    		window.removeEventListener("unload", this, false);
    	},
    	destroy: function() {
    		var i = document.getElementById("usercssloader-menu");
    		if (i) i.parentNode.removeChild(i);
    		var i = document.getElementById("usercssloader-rebuild-key");
    		if (i) i.parentNode.removeChild(i);
    		this.uninit();
    	},
    	handleEvent: function(event) {
    		switch(event.type){
    			case "unload": this.uninit(); break;
    		}
    	},
    	rebuild: function() {
    		let ext = /\.css$/i;
    		let not = /\.uc\.css/i;
    		let files = this.FOLDER.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
    
    		while (files.hasMoreElements()) {
    			let file = files.getNext().QueryInterface(Ci.nsIFile);
    			if (!ext.test(file.leafName) || not.test(file.leafName)) continue;
    			let CSS = this.loadCSS(file);
    			CSS.flag = true;
    		}
    		for (let leafName of Object.keys(this.readCSS)) {
    			const CSS = this.readCSS[leafName];
    			if (!CSS.flag) {
    				CSS.enabled = false;
    				delete this.readCSS[leafName];
    			}
    			delete CSS.flag;
    			this.rebuildMenu(leafName);
    		}
    		if (this.initialized) {
    			if (typeof(StatusPanel) !== "undefined")
    				StatusPanel._label = "Styles importiert";
    			else
    				XULBrowserWindow.statusTextField.label = "Styles importiert";
    		}
    	},
    	loadCSS: function(aFile) {
    		let CSS = this.readCSS[aFile.leafName];
    		if (!CSS) {
    			CSS = this.readCSS[aFile.leafName] = new CSSEntry(aFile);
    			if (this.disabled_list.indexOf(CSS.leafName) === -1) {
    				CSS.enabled = true;
    			}
    		} else if (CSS.enabled) {
    			CSS.enabled = true;
    		}
    		return CSS;
    	},
    	rebuildMenu: function(aLeafName) {
    		let CSS = this.readCSS[aLeafName];
    		let menuitem = document.getElementById("usercssloader-" + aLeafName);
    		if (!CSS) {
    			if (menuitem)
    				menuitem.parentNode.removeChild(menuitem);
    			return;
    		}
    
    		if (!menuitem) {
    			menuitem = $C("menuitem", {
    				label		: aLeafName,
    				id			: "usercssloader-" + aLeafName,
    				class		: "usercssloader-item " + (CSS.SHEET == this.AGENT_SHEET? "AGENT_SHEET" : CSS.SHEET == this.AUTHOR_SHEET? "AUTHOR_SHEET": "USER_SHEET"),
    				type		: "checkbox",
    				autocheck	: "false",
    				tooltiptext : "Linksklick: an/aus, Menü schließt\nMittelklick: an/aus, Menü bleibt offen\nRechtsklick: bearbeiten\nStrg+Rechtsklick: im Dateimanager anzeigen"
    			});
    			menuitem.addEventListener("command", () => UCL.toggle(aLeafName));
    			menuitem.addEventListener("click", (event) => UCL.itemClick(event));
    			menuitem.addEventListener("mouseup", (event) => { if (event.button === 1) event.preventDefault(); });
    			document.getElementById("usercssloader-menupopup").appendChild(menuitem);
    		}
    		menuitem.setAttribute("checked", CSS.enabled);
    	},
    	toggle: function(aLeafName) {
    		let CSS = this.readCSS[aLeafName];
    		if (!CSS || event.ctrlKey) return;
    		CSS.enabled = !CSS.enabled;
    		this.rebuildMenu(aLeafName);
    	},
    	itemClick: function(event) {
    		let label = event.currentTarget.getAttribute("label");
    		event.preventDefault();
    		event.stopPropagation();
    		if (event.button === 0) {
    				return;
    		} else if (event.button === 1) {
    				this.toggle(label);
    		} else if (event.button === 2) {
    				if (event.ctrlKey) {
    						UCL.openFolder(label);
    				} else {
    				closeMenus(event.target);
    				this.edit(this.getFileFromLeafName(label));
    				}
    		}
    	},
    	getFileFromLeafName: function(aLeafName) {
    		let f = this.FOLDER.clone();
    		f.QueryInterface(Ci.nsIFile); // use appendRelativePath
    		f.appendRelativePath(aLeafName);
    		return f;
    	},
    	openFolder: function(label) {
    		const PathSep = AppConstants.platform === "win" ? "\\" : "/";
    		let target= this.FOLDER.path + PathSep + label;
    		if (this.vFileManager.length !== 0) {
    				let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
    				let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
    				let args = [this.vFMParameter,target];
    				file.initWithPath(this.vFileManager);
    				process.init(file);
    				// Verzeichnis mit anderem Dateimanager öffnen
    				process.run(false, args, args.length);
    		} else {
    				// Verzeichnis mit Dateimanager des Systems öffnen
    				this.FOLDER.launch();
    		}
    	},
    	openCHRMFolder:function(){
    			if (this.vFileManager.length !== 0) {
    					let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
    					let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
    					let args = [this.vFMParameter,this.CHRMFOLDER.path];
    					file.initWithPath(this.vFileManager);
    					process.init(file);
    					// Verzeichnis mit anderem Dateimanager öffnen
    					process.run(false, args, args.length);
    			} else {
    					// Verzeichnis mit Dateimanager des Systems öffnen
    					this.CHRMFOLDER.launch();
    			}
    	},
    	editUserCSS: function(aLeafName) {
    		let file = Services.dirsvc.get("UChrm", Ci.nsIFile);
    		file.appendRelativePath(aLeafName);
    		this.edit(file);
    	},
    	edit: function(aFile) {
    		let editor = Services.prefs.getCharPref("view_source.editor.path");
    		if (!editor) return alert('Unter about:config den vorhandenen Schalter\n "view_source.editor.path" mit dem Editorpfad ergänzen');
    		try {
    			let UI = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
    			UI.charset = window.navigator.platform.toLowerCase().indexOf("win") >= 0? "Shift_JIS": "UTF-8";
    			let path = UI.ConvertFromUnicode(aFile.path);
    			let app = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
    			app.initWithPath(editor);
    			let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
    			process.init(app);
    			process.run(false, [path], 1);
    		} catch (e) {}
    	},
    	create: function(aLeafName) {
    		if (!aLeafName) aLeafName = prompt("Name des Styles", dateFormat(new Date(), "%Y_%m%d_%H%M%S"));
    		if (aLeafName) aLeafName = aLeafName.replace(/\s+/g, " ").replace(/[\\/:*?\"<>|]/g, "");
    		if (!aLeafName || !/\S/.test(aLeafName)) return;
    		if (!/\.css$/.test(aLeafName)) aLeafName += ".css";
    		let file = this.getFileFromLeafName(aLeafName);
    		this.edit(file);
    	},
    	UCrebuild: function() {
    		let re = /^file:.*\.uc\.css(?:\?\d+)?$/i;
    		let query = "?" + new Date().getTime();
    		Array.slice(document.styleSheets).forEach(function(css){
    			if (!re.test(css.href)) return;
    			if (css.ownerNode) {
    				css.ownerNode.parentNode.removeChild(css.ownerNode);
    			}
    			let pi = document.createProcessingInstruction('xml-stylesheet','type="text/css" href="'+ css.href.replace(/\?.*/, '') + query +'"');
    			document.insertBefore(pi, document.documentElement);
    		});
    		UCL.UCcreateMenuitem();
    	},
    	UCcreateMenuitem: function() {
    		let sep = $("usercssloader-ucseparator");
    		let popup = sep.parentNode;
    		if (sep.nextSibling) {
    			let range = document.createRange();
    			range.setStartAfter(sep);
    			range.setEndAfter(popup.lastChild);
    			range.deleteContents();
    			range.detach();
    		}
    
    		let re = /^file:.*\.uc\.css(?:\?\d+)?$/i;
    		Array.slice(document.styleSheets).forEach(function(css) {
    			if (!re.test(css.href)) return;
    			let fileURL = decodeURIComponent(css.href).split("?")[0];
    			let aLeafName = fileURL.split("/").pop();
    			let m = $C("menuitem", {
    				label		: aLeafName,
    				tooltiptext	: fileURL,
    				id			: "usercssloader-" + aLeafName,
    				type		: "checkbox",
    				autocheck	: "false",
    				checked		: "true",
    			});
    			m.css = css;
    			m.addEventListener("command", function() {
    				if (!event.ctrlKey) {this.setAttribute("checked", !(this.css.disabled = !this.css.disabled));}
    			});
    			m.addEventListener("mouseup", function(event) {
    				if (event.button === 1) event.preventDefault();
    			});
    			m.addEventListener("click", function(event) {
    				UCL.UCItemClick(event);
    			});
    			popup.appendChild(m);
    		});
    	},
    	UCItemClick: function(event) {
    		if (event.button === 0) return;
    		event.preventDefault();
    		event.stopPropagation();
    
    		if (event.button === 1) {
    			event.target.doCommand();
    		}
    		else if (event.button === 2) {
    			closeMenus(event.target);
    			let fileURL = event.currentTarget.getAttribute("tooltiptext");
    			let file = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler).getFileFromURLSpec(fileURL);
    			this.edit(file);
    		}
    	},
    };
    
    function CSSEntry(aFile) {
    	this.path = aFile.path;
    	this.leafName = aFile.leafName;
    	this.lastModifiedTime = 1;
    	this.SHEET = /^xul-|\.as\.css$/i.test(this.leafName) ?
    		Ci.nsIStyleSheetService.AGENT_SHEET:
    		/\.author\.css$/i.test(this.leafName)?
    			Ci.nsIStyleSheetService.AUTHOR_SHEET:
    			Ci.nsIStyleSheetService.USER_SHEET;
    }
    CSSEntry.prototype = {
    	sss: Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
    	_enabled: false,
    	get enabled() {
    		return this._enabled;
    	},
    	set enabled(isEnable) {
    		let aFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile)
    		aFile.initWithPath(this.path);
    
    		let isExists = aFile.exists(); // true, wenn die Datei bereits existiert
    		let lastModifiedTime = isExists ? aFile.lastModifiedTime : 0;
    		let isForced = this.lastModifiedTime != lastModifiedTime; //true, wenn es eine Änderung in der Datei gibt
    
    		let fileURL = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler).getURLSpecFromActualFile(aFile);
    		let uri = Services.io.newURI(fileURL, null, null);
    
    		if (this.sss.sheetRegistered(uri, this.SHEET)) {
    			// Wenn diese Datei bereits gelesen wurde
    			if (!isEnable || !isExists) {
    				this.sss.unregisterSheet(uri, this.SHEET);
    			}
    			else if (isForced) {
    				// Nach Stornierung erneut einlesen
    				this.sss.unregisterSheet(uri, this.SHEET);
    				this.sss.loadAndRegisterSheet(uri, this.SHEET);
    			}
    		} else {
    			// Datei wurde nicht gelesen
    			if (isEnable && isExists) {
    				this.sss.loadAndRegisterSheet(uri, this.SHEET);
    			}
    		}
    		if (this.lastModifiedTime !== 1 && isEnable && isForced) {
    			log(this.leafName + " wurde aktualisiert");
    		}
    		this.lastModifiedTime = lastModifiedTime;
    		return this._enabled = isEnable;
    	},
    };
    
    UCL.init();
    
    function $(id) { return document.getElementById(id); }
    function $A(arr) { return Array.slice(arr); }
    function $C(name, attr) {
    	const el = document.createElementNS(XULNS, name);
    	if (attr) Object.keys(attr).forEach(function(n) { el.setAttribute(n, attr[n]) });
    	return el;
    }
    function dateFormat(date, format) {
    	format = format.replace("%Y", ("000" + date.getFullYear()).substr(-4));
    	format = format.replace("%m", ("0" + (date.getMonth()+1)).substr(-2));
    	format = format.replace("%d", ("0" + date.getDate()).substr(-2));
    	format = format.replace("%H", ("0" + date.getHours()).substr(-2));
    	format = format.replace("%M", ("0" + date.getMinutes()).substr(-2));
    	format = format.replace("%S", ("0" + date.getSeconds()).substr(-2));
    	return format;
    }
    
    function log(mes) { console.log(mes); }
    })();
    Alles anzeigen

    BrokenHeart , die Bemerkung, dass Deine Änderung obsolet sei, bezieht sich auf diese von Januar dieses Jahres, wo Du die benötigten Eventlistener über eine Funktion eingebaut hast. Das ist in der aktuellen Version nicht mehr notwendig.

    Zitat von Boersenfeger

    In Zeile 376 steht let sep = $("usercssloader-ucsepalator");

    Ist das korrekt oder muss es ucseparator heißen?

    Ja, das ist ein Tippfehler, der mir ebenso auffiel und den ich auch geändert habe. Es betrifft hier aber eine ID und die könnte irgendeinen auch völlig kryptischen Namen erhalten, solange sie eindeutig ist, was hier der Fall ist (diese ID mit Tippfehler wird bereits weiter vorn erzeugt/zugeordnet, in Z. 179).

  • ScrollTopAndBottom.uc.js und Open with.uc.js zeigen keine Icons mehr an im Nightly

    • Speravir
    • 7. August 2025 um 01:35

    Probiert doch die hier oben von milupo (#41) und Endor in einer aktualisierten Version (siehe am 5.2.2025, 14:32) gepostete Variante ( Endor, ich glaube, Du hast die nicht bei GitHub hochgeladen). Ich vermute, dass ich diese früher benutzt habe, weil sie bei Endor oder schon Mithrandir/Ardiman verfügbar war.

    Ich nutze aber seit Jahren das entsprechende Addon Open With (dessen Entwicklung leider eingestellt wurde, wie man im GitHub-Repository lesen kann/muss). Dort kann man die Parameter einfach zusätzlich einfügen, es benötigt allerdings zusätzlich eine Python-Installation und einmalig etwas Mehraufwand.

  • Allgemeine Diskussion über Firefox

    • Speravir
    • 7. August 2025 um 00:54
    Zitat von Sören Hentzschel

    Wenn Firefox auf Windows keinen dedizierten Shortcut dafür hat, gibt es immer noch die Möglichkeit, die Menüleiste über die Tastatur zu bedienen, was auch bei standardmäßig ausgeblendeter Menüleiste funktioniert.

    Ja, stimmt natürlich.

    Zitat von Sören Hentzschel

    Bei nur gelegentlicher Nutzung bietet sich die Einblendung über die Alt-Taste ein

    Ja, genau das tue ich. Das wollte ich mit „Ich benötige die Menüleiste auch nicht ständig“ andeuten.

    Zitat von Sören Hentzschel

    Welche Funktion, die du tatsächlich nutzt, findest du denn nur in der Menüleiste?

    Selten, aber gelegentlich dann doch: Im Menü Ansicht die Punkte Webseiten-Stil und Textkodierung reparieren.

  • Allgemeine Diskussion über Firefox

    • Speravir
    • 6. August 2025 um 01:38

    Und zusätzlich:

    Zitat von Sören Hentzschel

    Einstellungen und neues privates Fenster […]. Beides öffne ich aber ohnehin ausschließlich mit der Tastatur.

    Für die Einstellungen gibt es in Windows keine Tastenkombination. Jedenfalls wird keine im Menü angezeigt und auch auf der SUMO-Seite Tastenkombinationen in Firefox zur schnellen Durchführung häufiger Befehle finde ich nichts (dort ist natürlich Windows11 ausgewählt). Zu SUMO bin ich jetzt übrigens über das Hilfemenü gelangt. :)

    Ich benötige die Menüleiste auch nicht ständig, aber manche Sachen finde ich dort einfacher oder anscheinend nur dort. Für einiges gibt es noch Buttons, beispielsweise die Einstellungen.

  • ScrollTopAndBottom.uc.js und Open with.uc.js zeigen keine Icons mehr an im Nightly

    • Speravir
    • 6. August 2025 um 01:16
    Zitat von lenny2

    Weil das Skript nicht auf .lnk reagiert.

    Schade. Ich hab so geantwortet, weil eine von mir früher benutzte Variante des Skriptes so funktionierte.

  • ScrollTopAndBottom.uc.js und Open with.uc.js zeigen keine Icons mehr an im Nightly

    • Speravir
    • 5. August 2025 um 01:57
    Zitat von lenny2

    Wie kann ich in OpenWith den Pfad zum Browser mit Befehlszeilentasten angeben?

    In Windows: Erzeuge eine Verknüpfung (.lnk-Datei), in der der du die Befehlszeilenoptionen im Ziel zusätzlich einträgst, und verlinke im Skript diese Verknüpfung. In Linux und MacOS müsste es dann mit Shell-Dateien funktioneren.

  • Code für min, max, close funktioniert nach Update nicht mehr richtig

    • Speravir
    • 27. Juli 2025 um 01:16
    Zitat von Horstmann

    Es gibt auch noch […] light-dark

    Stimmt, daran habe ich nicht gedacht. Ist ja auch noch relativ neu. Hilft mir selbst allerdings nicht.

  • Code für min, max, close funktioniert nach Update nicht mehr richtig

    • Speravir
    • 26. Juli 2025 um 01:04

    OK, Andreas.

    Zum Thema: Alles, was Horstmann schreibt, kann ich unterschreiben.

    Zu meinem obigen Nachtrag: Es ist so, dass ich den geposteten Code so ähnlich für mich schon gebastelt hatte (ich hab nur :root[lwtheme-image] statt #main-window), dann wegen der Frage verschiedene Themes aktiviert habe und der Code dann plötzlich nicht funktionierte, und zwar wie erwartet bei den System-Themes (wegen des lwtheme-image), aber auch bei diesem: Dark Cyan Blur. obwohl dort das entsprechende Attribut auf true gesetzt ist. Ich hab den Stilcode jetzt auf das aktuelle Theme eingeschränkt, das geht zum Glück, weil es im Style-Attribut eingetragen ist. Bei manchen sehr hellen Themes sind weiße Schalter sowieso schlecht bis gar nicht zu erkennen. Dann muss ich den Teil in Testprofilen eben anpassen, wenn nötig (Nachtrag: durch die Beschränkung muss ich das aber gar nicht, wie ich inzwischen sehe; das von mir benutzte standardmäig Theme ist offensichtlich eher eine Ausnahme).

Unterstütze uns!

Jährlich (2025)

101,9 %

101,9% (662,48 von 650 EUR)

Jetzt spenden
  1. Kontakt
  2. Datenschutz
  3. Impressum
Community-Software: WoltLab Suite™
Mastodon