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

  • Firefox 143.0.1 behebt durch Trend Micro verursachten Absturz

    • Speravir
    • 20. September 2025 um 23:57

    Statt an jede einzelne Antwort ein „Gefällt-mir“-Bapperl anzuhängen einfach mal danke für die gesamte Konversation hier!

  • UserCSSLoader (2025)

    • Speravir
    • 17. September 2025 um 00:13
    Zitat von bege

    Leider funktioniert das Skript mit diesen Konfigurationen nicht:
    Windows Explorer ist mit Parameter angegeben: Chrome- und CSS-Ordner werden nicht geöffnet, sondern nur im Elternordner ausgewählt, weil diese Abfrage aus meiner Version fehlt: if (fileManagerParam !== "/select,")
    Windows Explorer ist ohne Parameter angegeben: Weder die Ordner lassen sich öffnen noch die Dateien im Explorer anzeigen. Aus der Konfigurationserklärung wird nicht deutlich, dass in deiner Version beim Explorer der Parameter angegeben werden muss.

    Hmpf. Ich hatte das natürlich explizit getestet vor der letzten Veröffentlichung. Nachdem ich deinen Text gelesen habe, ging es aber bei mir auch nicht mehr – was nicht gut ist, weil das vermuten lässt, dass eine Race Condition vorhanden ist (bei Mira_Belle scheint beispielsweise alles zu funktionieren). Ich hatte die Sonderbehandlung des Windows-Explorer vermeiden wollen, habe nun aber die Bedingung eingebaut. Der Punkt „Chrome- und CSS-Ordner werden nicht geöffnet, sondern nur im Elternordner ausgewählt“ ist jedoch weiterhin gültig. Das erfordert einen einzigen weiteren Klick, damit sollte man leben können. Es kann sein, dass das schon vorher so war und mir nur nie aufgefallen ist.

    Zitat von bege

    Kleinigkeiten:
    in den Zeilen 408 und 424 kann das Komma nach target weg, glaube ich.
    Ich vermisse im Header @version und @compatibility, damit man bei zukünftigen Änderungen gleich sieht, welche Version man hat.

    Kommata: Upps. So etwas Unscheinbares kann schon die Ursache für Probleme sein. Man sollte zwar denken, dass ein leerer (eigentlich: undefinierter) angehängter Parameter keine Rolle spielt, aber vielleicht wqr genau das die Ursache für die oben genannte Merkwürdigkeit.

    Ich hatte den langen Header absichtlich entfernt, die Versionierung stimmte sowieso nicht richtig, ich wäre da eher für eine (ISO-)Datumsangabe. Zur Kompatibilität kann ich überhaupt nichts sagen und deshalb nichts derartiges im Skript eintragen.

    Zitat von 2002Andreas

    Ich hoffe das hilft dir weiter.

    Danke, Andreas. Ich hab die entsprechenden Eigenschaften samt Werten eingefügt und diesen Text ergänzt:

    Zitat

    Absolute Zahlenwerte müssen eventuell etwas an die eigenen Gegebenheiten
    angepasst werden (größeres Symbol, anderer Rand); der Zahlenwert für Höhe
    und Breite des Menütextes ("CSS") sollte nicht größer sein als für das
    Symbol (hier 16px).

    Man könnte jetzt noch eine eigene angepasste Eigenschaft einführen, damit man nicht dreimal denselben Zahlenwert ändern muss, Es fragt sich nur, inwiefern man damit andere überfordert.

    JavaScript
    /* UserCSSLoader 2025-09-16
     *
     * original author: Griever -
     * https://github.com/Griever/userChromeJS/tree/master/UserCSSLoader
     *
     * Enhancements and several other changes including German translation
     * and configuration section by users aborix, Endor, bege, Speravir of
     * Camp Firefox forum - https://www.camp-firefox.de/forum/ - latest version:
     * https://www.camp-firefox.de/forum/thema/138814/?postID=1279211#post1279211
     */
    
    /****** 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 oder Menü wird in Navigationsleiste eingefügt (einstellbar, siehe
    Variable "position" in unten anschließender Konfiguration).
    
    Dateiordner, Dateimanager und Texteditor können in der unten anschließenden
    Konfiguration geändert werden. Die Verwendung des in "view_source.editor.path"
    angegebenen Editors ist möglich.
    
    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.
    
    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");
    * eine absolute Pfadangabe zum Symbol muss mit File-Protokoll-Präfix erfolgen:
        background-image: url("file:///Absoluter/Pfad/zum/CSS_Symbol.png");
    
    Absolute Zahlenwerte müssen eventuell etwas an die eigenen Gegebenheiten
    angepasst werden (größeres Symbol, anderer Rand); der Zahlenwert für Höhe
    und Breite des Menütextes ("CSS") sollte nicht größer sein als für das
    Symbol (hier 16px).
    
    #usercssloader-menu-item {
    	background-image: url("Relativer/Pfad/zum/CSS_Symbol.png");
    	background-position: center;
    	background-repeat: no-repeat;
    	background-size: 16px;
    	border-radius: var(--toolbarbutton-border-radius);
    	margin-block: 3px;
    
    	&: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);
    	}
    }
    
    **** Ende der Anleitung ****/
    
    (function(){
    
    /***** Konfiguration *****/
    /* Position: als frei verschiebbare-Schaltfläche = 0, als Menü anzeigen = 1 */
    let position = 0;//1
    /* Dateimanager festlegen, Beispiele:
     *    let fileManager = "C:\\Programme\\FreeCommanderXE\\FreeCommander.exe";
     *    let fileManager = "C:\\Programme\\totalcmd\\TOTALCMD.EXE";
     * auch möglich:
     *    let fileManager = "C:\\Windows\\explorer.exe";
     * Bleibt Parameter leer, wird Standardmanager des Systems ohne Parameter
     * verwendet mit leicht eingeschränkter Funktionalität. */
    let fileManager = "";
    /* eventuelle Parameter für den Dateimanager, Beispiele:
     *    let fileManagerParam = "/T";//FreeCommander oder Totalcommander
     *    let fileManagerParam = "/select,";//Windows Explorer, mit Komma korrekt!
     */
    let fileManagerParam = "";
    /* manche Manager benötigen den Parameter nach der Pfadangabe,
       dann "fileManagerParamPost" auf true setzen */
    let fileManagerParamPost = false;
    /* eigener Texteditor mit Pfad - Standard leer, dann wird Wert aus
     * Einstellung "view_source.editor.path" verwendet mit Warnmeldung,
     * wenn auch dieser leer ist, Beispiel:
     *    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 (true)
       oder verstecken (false) */
    let showChrome = true;
    /***** Ende der 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) {
    				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 && fileManager  !== "") {
    						UCL.showFile(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;
    	},
    	showFile: function(fname) {
    				const PathSep = AppConstants.platform === "win" ? "\\" : "/";
    				let target= this.FOLDER.path + PathSep + 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);
    	},
    	openCSSFolder:function(){
    		if (fileManager !== "" && fileManager !== "/select,") {
    				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 !== "" && fileManager !== "/select,") {
    				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
    • 14. September 2025 um 01:02
    Zitat von Boersenfeger

    Allerdings ist da der Abstand zum linken und rechten Icon größer als bei den anderen in meiner Statuszeile. Vielleicht kann man ja noch da etwas ändern!?

    Ausgehend von Deinem zuvor geposteten Stil würde ich als Erstes das hier versuchen:

    Code
    #usercssloader-menu-item #usercssloader-menu > .menu-text[value="CSS"] {
    	opacity: 0;
    	width: calc(2 * var(--toolbarbutton-inner-padding) + 20px);
    	height: calc(2 * var(--toolbarbutton-inner-padding) + 20px);
    }

    Dort ist jeweils der Wert von 24px zu 20px geändert.

    Zitat von 2002Andreas

    Was mir aber gar nicht gefällt, bei hover passt der Hintergrund nicht:

    […]

    CSS
    margin-top: 5px !important;
    margin-bottom: 5px !important;

    die beiden unteren Werte sind neu eingefügt.

    Bei der Höhe meiner Leiste ist mir das überhaupt nicht aufgefallen.

    Kannst du bitte das mal austesten:

    CSS
    #usercssloader-menu-item {
    	height: var(--button-min-height);
    }

    Und, wenn das zu groß ist, als nächstes var(--button-min-height-small)? Ich hab noch nicht herausgefunden, wo die Unterscheidung stattfindet, wann welche Variable aktiviert wird.

    Zitat von 2002Andreas

    Und hier der Radius-Wert

    Hmm, stiimmt. Ist mir auch nicht aufgefallen. Aber warum nur bei Hover? Und es gibt eine Variable dafür, also gleich mal mittesten:

    CSS
    #usercssloader-menu-item {
    	border-radius: var(--toolbarbutton-border-radius);
    }

    Dann würde ich das alles noch in die Anleitung einfügen.

  • UserCSSLoader (2025)

    • Speravir
    • 13. September 2025 um 01:02
    Zitat von Boersenfeger

    in Zeile 404 if (fileManager !== "") {

    […]

    So sieht diese Zeile bei mir in der vorherigen Version aus if (fileManager.length !== 0) {

    Ist dies eine bewusste Änderung oder ein Kopierfehler oder ähnliches?

    Sören hat das Entscheidende schon gesagt. Der Hintergrund ist, dass ich dachte, den Code dahingehend zu vereinheitlichen und die gewählte Variante etwas kürzer und für mich auch etwas besser verständlich ist (und als ich diese eingeführt habe, war mir gar nicht bewusst, dass die andere bereits verwendet wurde).

    Zur Nachfrage, Börsi, hattest Du meine Hinweise zur Kürzung Deines CSS-Stils in Beitrag #63 bemerkt und waren diese nachvollziehbar? Oder bist du sogar auf die kürzere Version, wie jetzt im Skript beschrieben, umgestiegen?

  • UserCSSLoader (2025)

    • Speravir
    • 12. September 2025 um 01:44

    Leute, Leute, kaum ist man mal ein paar Tage nicht anwesend, kommt man hier nicht mehr mit.

    Unten folgt das hoffentlich letzte Update, bevor Endor es bei sich hochladen kann.

    Ich habe erstens

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

    wieder eingefügt. Meine Aussage

    Zitat von Speravir

    Dann müsste ich aber auch

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

    wieder einführen

    stimmt übrigens nicht, wie Bege uns mit seiner letzten Skriptversion zeigte und ich dann in der Konsole ausprobierte. Ich meine, es war einmal anders, aber egal.

    Zweitens habe ich das hier geändert:

    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. Geöffnet wird also tatsächlich nur der Ordner.

    Heißt jetzt showFile.

    Sonst habe ich am Code nichts geändert und damit auch das nicht entfernt, was ich als Backup-Funktion bezeichnet habe. In dem Zusammenhang: Wenn ich explizit den Windows-Explorer (beziehungsweise File-Explorer, wie es in Win11 heißt) samt Parameter auswähle, funktioniert es hier mit der jüngsten Version.

    Alles andere sind Änderungen am kommentierten Teil zu Beginn des Skripts:

    Ich hab den alten Header entfernt, dafür eine kürzere Angabe zur Urheberschaft eingefügt (bewusst in Englisch). Und dann gibt es Änderungen an Bedienungsanleitung und Konfigurationserläuterungen. Ob der erste Absatz der Bedienungsanleitung noch auf dem aktuellen Stand ist, dessen bin ich mir unsicher.

    JavaScript
    /* UserCSSLoader
     * original author: Griever -
     * https://github.com/Griever/userChromeJS/tree/master/UserCSSLoader
     *
     * Enhancements and several other changes including German translation
     * and configuration section by users aborix, Endor, bege, Speravir of
     * Camp Firefox forum - https://www.camp-firefox.de/forum/ - latest version:
     * https://www.camp-firefox.de/forum/thema/138814/?postID=1278991#post1278991
     */
    
    /****** 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 oder Menü wird in Navigationsleiste eingefügt (einstellbar, siehe
    Variable "position" in unten anschließender Konfiguration).
    
    Dateiordner, Dateimanager und Texteditor können in der unten anschließenden
    Konfiguration geändert werden. Die Verwendung des in "view_source.editor.path"
    angegebenen Editors ist möglich.
    
    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.
    
    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");
    * eine absolute Pfadangabe zum Symbol muss mit File-Protokoll-Präfix erfolgen:
        background-image: url("file:///Absoluter/Pfad/zum/CSS_Symbol.png");
    
    #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);
    	}
    }
    
    **** Ende der Anleitung ****/
    
    (function(){
    
    /***** Konfiguration *****/
    /* Position: als frei verschiebbare-Schaltfläche = 0, als Menü anzeigen = 1 */
    let position = 0;//1
    /* Dateimanager festlegen, Beispiele:
     *    let fileManager = "C:\\Programme\\FreeCommanderXE\\FreeCommander.exe";
     *    let fileManager = "C:\\Programme\\totalcmd\\TOTALCMD.EXE";
     * auch möglich:
     *    let fileManager = "C:\\Windows\\explorer.exe";
     * Bleibt Parameter leer, wird Standardmanager des Systems ohne Parameter
     * verwendet mit leicht eingeschränkter Funktionalität. */
    let fileManager = "";
    /* eventuelle Parameter für den Dateimanager, Beispiele:
     *    let fileManagerParam = "/T";//FreeCommander oder Totalcommander
     *    let fileManagerParam = "/select,";//Windows Explorer, mit Komma korrekt!
     */
    let fileManagerParam = "";
    /* manche Manager benötigen den Parameter nach der Pfadangabe,
       dann "fileManagerParamPost" auf true setzen */
    let fileManagerParamPost = false;
    /* eigener Texteditor mit Pfad - Standard leer, dann wird Wert aus
     * Einstellung "view_source.editor.path" verwendet mit Warnmeldung,
     * wenn auch dieser leer ist, Beispiel:
     *    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 (true)
       oder verstecken (false) */
    let showChrome = true;
    /***** Ende der 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) {
    				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.showFile(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;
    	},
    	showFile: function(fname) {
    		if (fileManager !== "") {
    				const PathSep = AppConstants.platform === "win" ? "\\" : "/";
    				let target= this.FOLDER.path + PathSep + 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 !== "") {
    				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 !== "") {
    				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
  • Schaltfläche um Lesezeichen Leiste ein/auszublenden ?

    • Speravir
    • 12. September 2025 um 01:01
    Zitat von grisu2099

    Geh mal oben im Menü Einstellungen auf Optionen. Dort dann auf den Punkt Neues Dokument. Da kannst du rechts die Codierung einstellen auf UTF-8. Danach sollte sich nichts mehr verstellen... :/

    Genau den Punkt meinte ich, Enterhaken.

    Zitat von Enterhaken

    Genau so ist es bei mir auch eingestellt:

    Bei mir auch mit einer Ausnahme: Ich hab „UTF-8 auch beim Öffnen von ANSI-Dokumenten“ deaktiviert und muss dann eben mit den Konsequenzen leben. Zuletzt ist das Problem hier aber nicht mehr vorgekommen.

  • Schaltfläche um Lesezeichen Leiste ein/auszublenden ?

    • Speravir
    • 7. September 2025 um 02:15
    Zitat von Enterhaken

    Wenn ich die Skripte mit Notepad++ erstelle, springt die Kodierung nur dann automatisch von UTF-8 um wenn in den Code-Schnipseln Umlaute verbaut sind.

    Das ist mir auch schon diverse Male passiert, weshalb ich bei dir sofort daran dachte, nur waren andere schneller mit der Lösung. Was hast du eigentlich für eine Einstellung für neue Dokumente in den Optionen von N++?

  • Custom toolbars buttons have no icons

    • Speravir
    • 7. September 2025 um 02:07

    lenny2, Mira_Belle: Es muss sich um about_button.uc.js oder about_button_generic.uc.js handeln, aber über Anpassungen muss uns tatsächlich der OP Bescheid geben.

    juzzlukin, please, post your actual script, so we can see your (necessary) edits. Do other scripts work?

  • Meine Version des App-Menüs (JavaScript)

    • Speravir
    • 7. September 2025 um 01:53
    Zitat von Mira_Belle

    Hast Du Dir das schon mal angeschaut?

    Ja, aber ich bin auch kein Experte. Das läuft eher wie bei den meisten hier: Blindes Huhn und hochprozentiger Schnaps. ;)

    Sehe ich das richtig, dass Deine Version eine Abwandlung von einem Skript ist, dass 2002Andreas hier irgendwo mal gepostet hat, als er Probleme damit hatte?

  • UserCSSLoader (2025)

    • Speravir
    • 7. September 2025 um 01:49
    Zitat von bege

    Dazu muss jetzt immer ein Dateimanager angegeben werden, z.B. eben auch der Windows Explorer.

    Jetzt scheinen sich unsere Postings überschnitten zu haben. Ernaut danke und ich schau mir das natürlich an, aber ich bleibe dabei: Diesen letzten Ausweg würde ich nicht entfernen, eher darauf hinweisen, dass man auch den Windows Explorer explizit angeben kann.

  • 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?

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