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. Mira_Belle

Beiträge von Mira_Belle

  • Firefox und Online Apotheke Aliva

    • Mira_Belle
    • 31. August 2026 um 19:18
    Zitat von .DeJaVu

    Allerdings sehe ich Potenzial bei etlichen deiner Themen ;)

    :P

    Ne, im Ernst, auf dieser Sache mit dem AV, auch wenn der Themenstarter da etwas angepisst reagiert hat,
    war es geklärt und war eine Sache zwischen Andreas, Sören und Carbonbike.
    Da muss doch nicht das halbe Board auch noch seinen Senf dazu geben, oder?
    Sicher habt Ihr recht, aber das mit dem AV hatte doch mit dem Problem an sich nichts zu tun!
    Ich weiß, ist nicht immer so, aber hier war es so.

    Aber jetzt muss ich auch was los werden!

    Zitat

    Sicherheitslösungen von Drittanbietern lassen sich als Angriffsziel unter Windows missbrauchen. Nun hat Nightmare Eclipse einen weiteren 0-Day veröffentlicht, der Windows-Nutzer tangiert. In Kaspersky Antivirus For Endpoint gibt es eine 0-Day-Schwachstelle, die für normale Benutzer eine Erhöhung der Privilegien auf Systemrechte ermöglicht.

    Wo hab' ich's nur gelesen?

    Und ...

    Zitat

    es [gibt] eine Backdoor namens SLEEPWALKER, die den ESET Management Agenten in Windows-Systemen für Angriffe missbraucht.

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

    • Mira_Belle
    • 31. August 2026 um 19:06

    Bugfix!

    JavaScript
    // ==UserScript==
    // @name           Appmenu.uc.js
    // @namespace      Appmenu@gmail.com
    // @description    Basiert auf dem Script externalFuncButtonM.uc.js, Wiederherstellung der Orangenen FF-Menü Schaltfläche
    // @include        main
    // @author         defpt
    // @charset        UTF-8
    // @edit           2025.10.05 mit integriertem CSS-Loader-Menü und Konfiguration-Menü,
    // @edit           zum direkten bearbeiten verschiedener Dateien.
    // @edit           Sowie der Möglichkeit direkt verschiedene "about:"-Seiten aufrufen zu können.
    // @edit           2026.08.29 Aufruf von Verzeichnissen und "about:"-Seiten erweitert.
    // @edit           2026.08.30 integriert: Meine Scripte, Meine CSS-Dateien, Meine CSSWeb-Dateien,
    // @edit           Skriptliste in Zwischenablage (aus extras_config_menu.uc.js)
    // @edit           Funktionen aus dem JavaScriptLoader hinzugefügt.
    // @edit           2026.08.31 Bug im CSS-Loader gefixt! Mittelklick & Rechtsklick waren ohne Funktion.
    // Source          https://www.camp-firefox.de/forum/thema/139769/?postID=1293421#post1293421
    
    // ==/UserScript==
    
    /* ----------------------------------------------------------------------------------- */
    /*     Zu beachten ist, dass die Grafiken sich im richtigen Ordner befinden müssen     */
    /*            %appdata%\Mozilla\Firefox\Profiles\"Profilname"\chrome\icons             */
    /* ----------------------------------------------------------------------------------- */
    
    /* ----------------------------------------------------------------------------------- */
    /*  IMPORTANT!         This script was edited and modified using AI.                   */
    /* ----------------------------------------------------------------------------------- */
    
        // Definiere den Profilpfad für die Symbole
        let ProfilePath = PathUtils.toFileURI(
          PathUtils.join(PathUtils.profileDir, 'chrome', 'icons')
        );
        
        // Standard-Symbol-Dateiname
        ButtonIcon01 = 'restart_1.svg';           // Neustart
        ButtonIcon02 = 'quit.svg';                // Beenden
    
        Icon01 =       'profile.svg';             // Profil-Verzeichnis
        Icon02 =       'chrome.svg';              // Chrome-Ordner
        Icon03 =       'css4.svg';                // CSS-Ordner
        Icon04 =       'js.svg';                  // JS-Ordner
        Icon05 =       'folder-plus.svg';         // Icons-Ordner
        Icon06 =       'addons.svg';              // Addon-Verzeichnis
        Icon07 =       'folder.svg';              // Programm-Verzeichnis
        Icon08 =       'folder-1.svg';            // Startup-Cache
    
        Icon11 =       'Themes.svg';              // Anpassen
        Icon12 =       'debugging-workers.svg';   // Neustart im abgesicherten Modus
        Icon13 =       'command-console.svg';     // Browser-Konsole
        Icon14 =       'window-dev-tools.svg';    // Browser-Werkzeuge
        Icon15 =       'developer.svg';           // Web-Entwickler
        Icon16 =       'sync.svg';                // Firefox synchronisieren
        Icon17 =       'passwords.svg';           // Zugangsdaten und Passwörter
        Icon18 =       'performance.svg';         // Task Manager
        Icon19 =       'plug-disconnected.svg';   // Offline arbeiten
    
        Icon21 =       'firefox.svg';             // about:about
        Icon40 =       'extension.svg';           // about:addons
        Icon22 =       'info.svg';                // about:cache
        Icon23 =       'settings.svg';            // about:config
        Icon24 =       'warning.svg';             // about:crashes
        Icon25 =       'downloads.svg';           // about:downloads
        Icon26 =       'home.svg';                // about:home
        Icon27 =       'passwords.svg';           // about:logins
        Icon28 =       'debugging-workers.svg';   // about:support
        Icon29 =       'settings.svg';            // about:preferences
        Icon41 =       'performance.svg';         // about:processes
        Icon30 =       'profile.svg';             // about:profiles
    
        Icon31 =       'js.svg';                  // Meine Scripte
        Icon32 =       'css4.svg';                // Meine CSS-Dateien
        Icon33 =       'css4.svg';                // Meine CSSWeb-Dateien
        Icon34 =       'command-console.svg';     // Skriptliste in Zwischenablage
    
      var Appmenu = {
        // ■■ START UserConfiguration ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    
        // Editor mit angegebenem Pfad verwenden
        // editor: 'C:\\Program Files\\Notepad++\\notepad++.exe',
        editor: "C:\\Program Files\\Microsoft VS Code\\Code.exe",
        // oder
        // in 'view_source.editor.path' eingetragenen Editor verwenden
        //  editor: Services.prefs.getCharPref('view_source.editor.path'),
        // Dateimanager mit angegebenem Pfad verwenden oder leer ('') wenn System-Dateimanager verwenden
        //fileManager: 'C:\\Program files\\FreeCommander XE\\FreeCommander.exe',
        fileManager: "",
        // Parameter für Dateimanager oder leer ('')
        //FMParameter: '/T',
        FMParameter: "",
        // Submenüs ohne Inhalt im Hauptmenü automatisch ausblenden
        autohideEmptySubDirs: true,
        // Submenüs im Hauptmenü nach unten verschieben
        moveSubDirstoBottom: false,
        // Ort und Aussehen des Menü-Buttons einstellen
        //   isUrlbar: 1,  // 0: TabsToolbar; 1: navbar,
        isUrlbar: 2, // 0: TabsToolbar; 1: navbar; 2: toolbar-menubar
        isButton: 0, // 0: Hamburger,klein; 1: Firefox,groß,
        // Hotkey zum Öffnen des Appmenüs oder leer ('')
        hotkey: "f",
        hotkeyModifier: "alt",
    
        // ■■ Neu: Einstellungen für Script-/CSS-Listen (aus extras_config_menu.uc.js) ■■
        // Unterordner für uc.js-Skripte innerhalb des chrome-Verzeichnisses:
        jsSubfolder: 'scripts',
        // Zeigt die Datei userChromeShadow.uc.js in der Skriptliste an (1: ja, 0: nein):
        showuCS: 0,
        // Sortierung der Skript-/CSS-Dateien (1: ja, 0: nein):
        sortScripts: 0,
        // "Skriptliste in Zwischenablage" (1: ja, 2: mit Nummerierung, 0: deaktiviert):
        enableScriptsToClip: 2,
    
        // ■■ END UserConfiguration ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    
        // Submenüs im Hauptmenü nach unten verschieben
        subdirPopupHash: [],
        subdirMenuHash: [],
    
        // CSS-Loader-Funktionen (integriert)
        cssLoader: {
            AGENT_SHEET: Ci.nsIStyleSheetService.AGENT_SHEET,
            USER_SHEET: Ci.nsIStyleSheetService.USER_SHEET,
            AUTHOR_SHEET: Ci.nsIStyleSheetService.AUTHOR_SHEET,
            readCSS: {},
    
            get prefs() {
                delete this.prefs;
                return this.prefs = Services.prefs.getBranch("UserCSSLoader.");
            },
    
            get disabled_list() {
                try {
                    return JSON.parse(this.prefs.getCharPref("disabled_css_list")) || [];
                } catch (e) {
                    return [];
                }
            },
    
            set disabled_list(list) {
                this.prefs.setCharPref("disabled_css_list", JSON.stringify(list));
            },
    
            get FOLDER() {
                let aFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
                aFolder.appendRelativePath("CSS");
                if (!aFolder.exists() || !aFolder.isDirectory()) {
                    aFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0o664);
                }
                delete this.FOLDER;
                return this.FOLDER = aFolder;
            },
    
            initCSSLoader: function() {
                this.rebuildCSSMenu();
            },
    
            rebuildCSSMenu: function() {
                let ext = /\.css$/i;
                let not = /\.uc\.css/i;
                let files = this.FOLDER.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
                let popup = Appmenu.subdirPopupHash["CSS-Loader-Menü"];
    
                // Vorhandene Einträge löschen
                while (popup && popup.firstChild) {
                    popup.removeChild(popup.firstChild);
                }
    
                // Neue Einträge erstellen
                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);
                    let menuitem = document.createElementNS(
                        "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
                        "menuitem"
                    );
    
                    menuitem.setAttribute("label", file.leafName);
                    menuitem.setAttribute("id", "appmenu-css-" + file.leafName);
                    menuitem.setAttribute("class", "menuitem-iconic");
    
                    if (CSS.enabled) {
                        menuitem.setAttribute("image", `${ProfilePath}/menu-check_lime.svg`);
                    } else {
                        menuitem.setAttribute("image", `${ProfilePath}/stop_smal_red.svg`);
                    }
                    menuitem.setAttribute("tooltiptext", "Linksklick: an/aus, Mittelklick: an/aus (Menü bleibt offen), Rechtsklick: bearbeiten");
    
                    menuitem.addEventListener("command", () => this.toggleCSS(file.leafName));
                    menuitem.addEventListener("click", (event) => this.cssItemClick(event, file.leafName));
                    menuitem.addEventListener("mouseup", (event) => { if (event.button === 1) event.preventDefault(); });  // NEU
    
                    if (popup) {
                        popup.appendChild(menuitem);
                    }
                }
            },
    
            loadCSS: function(aFile) {
                let CSS = this.readCSS[aFile.leafName];
                if (!CSS) {
                    CSS = this.readCSS[aFile.leafName] = new CSSEntry(aFile);
                    CSS.enabled = !this.disabled_list.includes(aFile.leafName);
                }
                return CSS;
            },
    
            toggleCSS: function(aLeafName) {
                let CSS = this.readCSS[aLeafName];
                if (!CSS) return;
    
                CSS.enabled = !CSS.enabled;
    
                let currentDisabledList = this.disabled_list;
                if (CSS.enabled) {
                    currentDisabledList = currentDisabledList.filter(name => name !== aLeafName);
                } else {
                    if (!currentDisabledList.includes(aLeafName)) {
                        currentDisabledList.push(aLeafName);
                    }
                }
                this.disabled_list = currentDisabledList;
    
                let menuitem = document.getElementById("appmenu-css-" + aLeafName);
                if (menuitem) {
                    if (CSS.enabled) {
                        menuitem.setAttribute("image", `${ProfilePath}/menu-check_lime.svg`);
                    } else {
                        menuitem.setAttribute("image", `${ProfilePath}/stop_smal_red.svg`);
                    }
                }
            },
    
            cssItemClick: function(event, aLeafName) {
                event.preventDefault();
                event.stopPropagation();
                if (event.button === 0) {
                    return;
                } else if (event.button === 1) {
                    this.toggleCSS(aLeafName);
                } else if (event.button === 2) {
                    let file = this.getFileFromLeafName(aLeafName);
                    this.editCSS(file);
                }
            },
    
            getFileFromLeafName: function(aLeafName) {
                let f = this.FOLDER.clone();
                f.QueryInterface(Ci.nsIFile);
                f.appendRelativePath(aLeafName);
                return f;
            },
            editCSS: function(aFile) {
                let editor = Appmenu.editor || Services.prefs.getCharPref("view_source.editor.path");
                if (!editor) {
                    alert('Kein Editor konfiguriert! ...');
                    return;
                }
                // Rest bleibt gleich
            /*editCSS: function(aFile) {
                let editor = cssLoaderConfig.Editor || Services.prefs.getCharPref("view_source.editor.path");
                if (!editor) {
                    alert('Kein Editor konfiguriert! Bitte in about:config unter "view_source.editor.path" einen Editor eintragen.');
                    return;
                }
            */        
                try {
                    let UI = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
                    UI.charset = window.navigator.platform.toLowerCase().includes("win") ? "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) {
                    console.error("Fehler beim Öffnen des Editors:", e);
                }
            },
        },
    
        // ■■ JavaScript-Loader-Funktionen (aus rebuild_userChrome.uc.js integriert) ■■
        jsLoader: {
            init: function() {
                this.addPrefListener(this.readLaterPrefListener);
            },
    
            fillMenu: function(popup) {
                while (popup.hasChildNodes()) popup.removeChild(popup.firstChild);
    
                // --- Debug-Ausgabe ---
                let ucjs = window.userChrome_js;
                console.debug('[jsLoader] fillMenu aufgerufen. userChrome_js:', ucjs ? 'gefunden' : 'NICHT gefunden');
                if (ucjs) {
                    console.debug('[jsLoader] arrSubdir:', ucjs.arrSubdir);
                    console.debug('[jsLoader] scripts.length:', ucjs.scripts ? ucjs.scripts.length : 'undefined');
                    console.debug('[jsLoader] overlays.length:', ucjs.overlays ? ucjs.overlays.length : 'undefined');
                    console.debug('[jsLoader] dirDisable:', ucjs.dirDisable);
                    console.debug('[jsLoader] scriptDisable:', ucjs.scriptDisable);
                    if (ucjs.scripts && ucjs.scripts.length > 0) {
                        console.debug('[jsLoader] scripts[0].dir:', ucjs.scripts[0].dir, 'filename:', ucjs.scripts[0].filename);
                    }
                }
    
                if (!ucjs || !ucjs.scripts) {
                    let msg = document.createXULElement('menuitem');
                    msg.setAttribute('label', 'userChrome.js nicht gefunden oder nicht initialisiert');
                    msg.setAttribute('disabled', 'true');
                    popup.appendChild(msg);
                    return;
                }
    
                // Safety: dirDisable/scriptDisable können undefined sein
                if (!ucjs.dirDisable) ucjs.dirDisable = {};
                if (!ucjs.scriptDisable) ucjs.scriptDisable = {};
                if (!ucjs.overlays) ucjs.overlays = [];
    
                try {
    
                // --- Feste Menüeinträge ---
                let reuse = this.getPref("userChrome.enable.reuse", 'bool', true);
    
                let mSetting = document.createXULElement('menuitem');
                mSetting.setAttribute('label', 'Skript für jedes Fenster neuladen');
                mSetting.setAttribute('type', 'checkbox');
                mSetting.toggleAttribute('checked', !reuse);
                mSetting.addEventListener('command', () => this.setting());
                popup.appendChild(mSetting);
    
                popup.appendChild(document.createXULElement('menuseparator'));
    
                // --- Alle UserScripte aktivieren/deaktivieren ---
                let mAll = document.createXULElement('menuitem');
                mAll.setAttribute('label', 'Alle UserScripte aktivieren/deaktivieren');
                mAll.setAttribute('type', 'checkbox');
                mAll.toggleAttribute('checked', !userChrome_js.dirDisable['*']);
                mAll.dirName = '*';
                mAll.addEventListener('command', () => this.chgDirStat("*"));
                mAll.addEventListener('click', (event) => this.clickDirMenuitem(event, true));
                mAll.addEventListener('mouseup', (event) => { if (event.button == 1) event.preventDefault(); });
                popup.appendChild(mAll);
    
                // --- Pro Ordner: Script-Checkboxen direkt im Hauptpopup ---
                let foundAnyDir = false;
                let firstDir = true;
                for (let j = 0; j < ucjs.arrSubdir.length; j++) {
                    let dirName = ucjs.arrSubdir[j] === "" ? "root" : ucjs.arrSubdir[j];
                    let hasScripts = false;
    
                    for (let i = 0; i < ucjs.scripts.length; i++) {
                        if (ucjs.scripts[i].dir === dirName) { hasScripts = true; break; }
                    }
                    if (!hasScripts) {
                        for (let i = 0; i < ucjs.overlays.length; i++) {
                            if (ucjs.overlays[i].dir === dirName) { hasScripts = true; break; }
                        }
                    }
                    if (!hasScripts) continue;
    
                    if (firstDir) {
                        popup.appendChild(document.createXULElement('menuseparator'));
                        firstDir = false;
                    }
    
                    let displayDir = dirName === "root" ? "" : dirName;
    
                    let flg = false;
                    for (let i = 0; i < ucjs.scripts.length; i++) {
                        let script = ucjs.scripts[i];
                        if (script.dir !== dirName) continue;
                        flg = true;
                        let mScript = document.createXULElement('menuitem');
                        mScript.setAttribute('label', script.filename);
                        mScript.setAttribute('type', 'checkbox');
                        mScript.setAttribute('autocheck', 'false');
                        mScript.toggleAttribute('checked', !ucjs.scriptDisable[script.filename]);
                        if (script.description)
                            mScript.setAttribute('tooltiptext', script.description);
                        mScript.script = script;
                        mScript.addEventListener('command', () => this.chgScriptStat(script.filename));
                        mScript.addEventListener('click', (event) => this.clickScriptMenu(event, script));
                        mScript.addEventListener('mouseup', (event) => { if (event.button == 1) event.preventDefault(); });
                        popup.appendChild(mScript);
                    }
    
                    for (let i = 0; i < ucjs.overlays.length; i++) {
                        let script = ucjs.overlays[i];
                        if (script.dir !== dirName) continue;
                        if (flg) {
                            popup.appendChild(document.createXULElement('menuseparator'));
                        }
                        flg = false;
                        let mScript = document.createXULElement('menuitem');
                        mScript.setAttribute('label', script.filename);
                        mScript.setAttribute('type', 'checkbox');
                        mScript.setAttribute('autocheck', 'false');
                        mScript.toggleAttribute('checked', !ucjs.scriptDisable[script.filename]);
                        if (script.description)
                            mScript.setAttribute('tooltiptext', script.description);
                        mScript.script = script;
                        mScript.addEventListener('command', () => this.chgScriptStat(script.filename));
                        mScript.addEventListener('click', (event) => this.clickScriptMenu(event, script));
                        mScript.addEventListener('mouseup', (event) => { if (event.button == 1) event.preventDefault(); });
                        popup.appendChild(mScript);
                    }
    
                    foundAnyDir = true;
                }
    
                // Falls keine Scripts gefunden wurden, Hinweis anzeigen
                if (!foundAnyDir) {
                    let noScripts = document.createXULElement('menuitem');
                    noScripts.setAttribute('label', 'Keine UserScripte gefunden (Ordner: ' + ucjs.arrSubdir.join(', ') + ')');
                    noScripts.setAttribute('disabled', 'true');
                    popup.appendChild(noScripts);
                }
    
                } catch (e) {
                    console.error('[jsLoader] Fehler in fillMenu:', e);
                    let errMsg = document.createXULElement('menuitem');
                    errMsg.setAttribute('label', 'Fehler: ' + e.message);
                    errMsg.setAttribute('disabled', 'true');
                    popup.appendChild(errMsg);
                }
            },
    
            setting: function() {
                let flag = this.getPref("userChrome.enable.reuse", 'bool', true);
                this.setPref("userChrome.enable.reuse", 'bool', !flag);
            },
    
            clickDirMenu: function(event) {
                if (event.button == 1 || event.button == 2) {
                    event.stopPropagation();
                    event.preventDefault();
                    this.chgDirStat(event.target.dirName);
                    if (event.target.firstChild && event.target.firstChild.firstChild)
                        event.target.firstChild.firstChild.toggleAttribute('checked', !userChrome_js.dirDisable[event.target.dirName]);
                    if (!!userChrome_js.dirDisable[event.target.dirName])
                        event.target.setAttribute('style', 'font-style:italic;');
                    else
                        event.target.removeAttribute('style');
                }
            },
    
            clickDirMenuitem: function(event, stop) {
                if (event.button == 1 || event.button == 2) {
                    event.stopPropagation();
                    event.preventDefault();
                    this.chgDirStat(event.target.dirName);
                    event.target.toggleAttribute('checked', !userChrome_js.dirDisable[event.target.dirName]);
                    if (!stop && !!userChrome_js.dirDisable[event.target.dirName])
                        event.target.parentNode.parentNode.setAttribute('style', 'font-style:italic;');
                    else
                        event.target.parentNode.parentNode.removeAttribute('style');
                }
            },
    
            clickScriptMenu: function(event, script) {
                if (event.button == 1) {
                    event.stopPropagation();
                    event.preventDefault();
                    this.chgScriptStat(script.filename);
                    event.target.toggleAttribute('checked', !userChrome_js.scriptDisable[script.filename]);
                } else if (event.button == 2) {
                    event.stopPropagation();
                    event.preventDefault();
                    this.launchEditor(script);
                }
            },
    
            launchEditor: function(aScript) {
                let editor = Appmenu.editor;
                let path = Services.io.newURI(aScript.url).QueryInterface(Ci.nsIFileURL).file.path;
                let appfile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
                appfile.initWithPath(editor);
                let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
                process.init(appfile);
                process.runw(false, [path], 1, {});
            },
    
            chgDirStat: function(adirName) {
                let s = this.getPref("userChrome.disable.directory", "str", "");
                if (!userChrome_js.dirDisable[adirName]) {
                    s = (s + ',').replace(adirName + ',', '') + adirName + ',';
                } else {
                    s = (s + ',').replace(adirName + ',', '');
                }
                s = s.replace(/,,/g, ',').replace(/^,/, '');
                this.setPref("userChrome.disable.directory", "str", s);
                userChrome_js.dirDisable = this.restoreState(s.split(','));
            },
    
            chgScriptStat: function(afilename) {
                let s = this.getPref("userChrome.disable.script", "str", "");
                if (!userChrome_js.scriptDisable[afilename]) {
                    s = (s + ',').replace(afilename + ',', '') + afilename + ',';
                } else {
                    s = (s + ',').replace(afilename + ',', '');
                }
                s = s.replace(/,,/g, ',').replace(/^,/, '');
                this.setPref("userChrome.disable.script", "str", s);
                userChrome_js.scriptDisable = this.restoreState(s.split(','));
            },
    
            restoreState: function(arr) {
                let disable = [];
                for (let i = 0; i < arr.length; i++) disable[arr[i]] = true;
                return disable;
            },
    
            getPref: function(aPrefString, aPrefType, aDefault) {
                let xpPref = Services.prefs;
                try {
                    switch (aPrefType) {
                        case 'complex': return xpPref.getComplexValue(aPrefString, Ci.nsIFile);
                        case 'str': return unescape(xpPref.getCharPref(aPrefString).toString());
                        case 'int': return xpPref.getIntPref(aPrefString);
                        case 'bool': default: return xpPref.getBoolPref(aPrefString);
                    }
                } catch (e) {}
                return aDefault;
            },
    
            setPref: function(aPrefString, aPrefType, aValue) {
                let xpPref = Services.prefs;
                try {
                    switch (aPrefType) {
                        case 'complex': return xpPref.setComplexValue(aPrefString, Ci.nsIFile, aValue);
                        case 'str': return xpPref.setCharPref(aPrefString, escape(aValue));
                        case 'int': aValue = parseInt(aValue); return xpPref.setIntPref(aPrefString, aValue);
                        case 'bool': default: return xpPref.setBoolPref(aPrefString, aValue);
                    }
                } catch (e) {}
                return null;
            },
    
            addPrefListener: function(aObserver) {
                try { Services.prefs.addObserver(aObserver.domain, aObserver, false); }
                catch (e) {}
            },
    
            removePrefListener: function(aObserver) {
                try { Services.prefs.removeObserver(aObserver.domain, aObserver); }
                catch (e) {}
            },
    
            readLaterPrefListener: {
                domain: 'userChrome.disable',
                observe: function(aSubject, aTopic, aPrefstring) {
                    if (aTopic == 'nsPref:changed') {
                        setTimeout(function() {
                            let s = Appmenu.jsLoader.getPref("userChrome.disable.directory", "str", "");
                            userChrome_js.dirDisable = Appmenu.jsLoader.restoreState(s.split(','));
                            s = Appmenu.jsLoader.getPref("userChrome.disable.script", "str", "");
                            userChrome_js.scriptDisable = Appmenu.jsLoader.restoreState(s.split(','));
                        }, 0);
                    }
                }
            },
        },
    
        toolbar: {
          subdirs: [
            {
              name: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/folder_currentColor.svg`,
            },
            {
              name: 'Firefox Funktionen',
              image: `${ProfilePath}/settings_currentColor.svg`,
            },
            {
              name: 'separator',
            },
            {
              name: 'Meine Scripte',
              image: `${ProfilePath}/${Icon31}`,
            },
            {
              name: 'Meine CSS-Dateien',
              image: `${ProfilePath}/${Icon32}`,
            },
            {
              name: 'Meine CSSWeb-Dateien',
              image: `${ProfilePath}/${Icon33}`,
            },
            {
              name: 'Skriptliste in Zwischenablage',
              image: `${ProfilePath}/${Icon34}`,
              command: () => Appmenu.getScripts(1),
              tooltiptext: 'Kopiert eine Liste aller uc.js-Skripte in die Zwischenablage',
            },
            {
              name: 'separator',
            },
            {
              name: 'JavaScript-Loader-Menü',
              image: `${ProfilePath}/${Icon04}`,
            },
            {
              name: 'CSS-Loader-Menü',
              image: `${ProfilePath}/css4_currentColor.svg`,
            },
            {
              name: 'Konfiguration',
              image: `${ProfilePath}/Hammer-wrench_currentColor.svg`,
            },
            {
              name: '"about:"-Seiten',
              image: `${ProfilePath}/firefox_currentColor.svg`,
            },
          ],
    
          apps: [
            {
              name: 'Profil-Verzeichnis',
              id: 'AMProfil',
              root: 'ProfD',
              path: '\\',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon01}`,
            },
            {
              name: 'Chrome-Ordner',
              id: 'AMchrome',
              root: 'ProfD',
              path: '\\chrome',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon02}`,
            },
            {
              name: 'CSS-Ordner',
              id: 'AMCSS',
              root: 'ProfD',
              path: '\\chrome\\css',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon03}`,
            },
            {
              name: 'CSS-Web-Ordner',
              id: 'AMWEB',
              root: 'ProfD',
              path: '\\chrome\\cssWeb',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon03}`,
            },
            {
              name: 'JS-Ordner',
              id: 'AMJS',
              root: 'ProfD',
              path: '\\chrome\\scripts',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon04}`,
            },
            {
              name: 'Icons-Ordner',
              id: 'AMICO',
              root: 'ProfD',
              path: '\\chrome\\icons',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon05}`,
            },
            {
              name: 'Addon-Verzeichnis',
              id: 'AMAddons',
              root: 'ProfD',
              path: '\\extensions',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon06}`,
            },
            {
              name: 'Programm-Verzeichnis',
              id: 'AMProgramm',
              root: 'CurProcD',
              path: '\\',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon07}`,
            },
            {
              name: 'Startup-Cache',
              id: 'AMCache',
              root: 'ProfLD',
              path: '\\startupCache',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon08}`,
            },
          ],
    
          configs: [
            {
              name: 'Anpassen',
              id: 'AMAnpassen',
              command: 'gCustomizeMode.enter()',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon11}`,
            },
            {
              name: 'Neustart im abgesicherten Modus',
              id: 'AMModus',
              command: 'safeModeRestart();',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon12}`,
            },
            {
              name: 'Browser-Konsole',
              id: 'AMKonsole',
              command: 'goKonsole',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon13}`,
            },
            {
              name: 'Browser-Werkzeuge',
              id: 'AMWerkzeuge',
              command: 'goWerkzeuge',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon14}`,
            },
            {
              name: 'Web-Entwickler',
              id: 'AMEntwickler',
              command: 'goEntwickler',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon15}`,
            },
            {
              name: 'Firefox synchronisieren',
              id: 'AMsynchron',
              command: 'gSync',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon16}`,
            },
            {
              name: 'Zugangsdaten und Passwörter',
              id: 'AMdaten',
              command: 'LoginHelper.openPasswordManager(window, { entryPoint: "mainmenu" })',
              tooltiptext: 'about:logins',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon17}`,
            },
            {
              name: 'Task Manager',
              id: 'AMManager',
              command: 'switchToTabHavingURI("about:processes", true)',
              tooltiptext: 'about:processes',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon18}`,
            },
            {
              name: 'Offline arbeiten',
              id: 'AMOffline',
              command: 'BrowserOffline.toggleOfflineStatus();',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon19}`,
            },
            {
              name: 'Neustart (inkl. Script Cache leeren)',
              id: 'AMreboot',
              tooltiptext: 'userChrome.js-Cache wird geleert',
              command: 'goReeboot',
              image: `${ProfilePath}/${ButtonIcon01}`,
            },
            {
              name: 'Beenden',
              id: 'AMquit',
              command: 'goQuitApplication(event);',
              image: `${ProfilePath}/${ButtonIcon02}`,
            },
            // uProfMenu-Funktionen unter Menüeintrag "Konfiguration"
            {
              name: 'userChrome.css bearbeiten',
              id: 'AMuserChromeCss',
              command: () => Appmenu.edit(0, 'userChrome.css'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/css4.svg`,
            },
            {
              name: 'userChromeShadow.css bearbeiten',
              id: 'AMuserChromeShadowCss',
              command: () => Appmenu.edit(0, 'userChromeShadow.css'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/css4.svg`,
            },
            {
              name: 'userContent.css bearbeiten',
              id: 'AMuserContentCss',
              command: () => Appmenu.edit(0, 'userContent.css'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/css4.svg`,
            },
            {
              name: 'userChrome.js bearbeiten',
              id: 'AMuserChromeJs',
              command: () => Appmenu.edit(0, 'userChrome.js'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/js.svg`,
            },
            {
              name: 'prefs.js bearbeiten',
              id: 'AMprefsJs',
              command: () => Appmenu.edit(1, 'prefs.js'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/js.svg`,
            },
            {
              name: 'user.js bearbeiten',
              id: 'AMuserJs',
              command: () => Appmenu.edit(1, 'user.js'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/js.svg`,
            },
            // about:-Seiten
            {
              name: 'about:about',
              id: 'AMaboutAbout',
              command: () => openTrustedLinkIn("about:about", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon21}`,
            },
            {
              name: 'about:addons',
              id: 'AMaboutAddons',
              command: () => openTrustedLinkIn("about:addons", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon40}`,
            },
            {
              name: 'about:cache',
              id: 'AMaboutCache',
              command: () => openTrustedLinkIn("about:cache", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon22}`,
            },
            {
              name: 'about:config',
              id: 'AMaboutConfig',
              command: () => openTrustedLinkIn("about:config", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon23}`,
            },
            {
              name: 'about:crashes',
              id: 'AMaboutCrashes',
              command: () => openTrustedLinkIn("about:crashes", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon24}`,
            },
            {
              name: 'about:downloads',
              id: 'AMaboutDownloads',
              command: () => openTrustedLinkIn("about:downloads", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon25}`,
            },
            {
              name: 'about:home',
              id: 'AMaboutHome',
              command: () => openTrustedLinkIn("about:home", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon26}`,
            },
            {
              name: 'about:logins',
              id: 'AMaboutLogins',
              command: 'LoginHelper.openPasswordManager(window, { entryPoint: "mainmenu" })',
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon27}`,
            },
            {
              name: 'about:support',
              id: 'AMaboutSupport',
              command: () => openTrustedLinkIn("about:support", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon28}`,
            },
            {
              name: 'about:preferences',
              id: 'AMaboutPreferences',
              command: () => openTrustedLinkIn("about:preferences", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon29}`,
            },
            {
              name: 'about:processes',
              id: 'AMaboutProcesses',
              command: () => openTrustedLinkIn("about:processes", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon41}`,
            },
            {
              name: 'about:profiles',
              id: 'AMaboutProfiles',
              command: () => openTrustedLinkIn("about:profiles", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon30}`,
            },
          ]
        },
        _externalAppPopup: null,
        _isready: false,
    
        // uProfMenu-Funktionen (bereits integriert)
        getDirSep: function() {
          var osString = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULRuntime).OS;
          var dirsep = "/";
          switch(osString) {
            case "WINNT":
              dirsep = "\\";
              break;
            case "Darwin":
              dirsep = "/";
              break;
          }
          return dirsep;
        },
        getPrefDirectoryPath: function(str) {
          var file = Components.classes["@mozilla.org/file/directory_service;1"]
            .getService(Components.interfaces.nsIProperties)
            .get(str, Components.interfaces.nsIFile);
          if (str == 'CurProcD') {
            file = file.parent;
          }
          return file.path;
        },
        edit: function(OpenMode, Filename) {
          var Path = "";
          var dSep = this.getDirSep();
          // Wenn der Dateiname einen Pfad enthält (z. B. "chrome/scripts/test.uc.js"),
          // vom Profil-Verzeichnis aus auflösen:
          if (Filename.includes("/") || Filename.includes("\\")) {
            Path = this.getPrefDirectoryPath("ProfD") + dSep + Filename.replace(/\//g, dSep);
          } else {
            switch (OpenMode) {
              case 0:
                Path = this.getPrefDirectoryPath("UChrm") + dSep + Filename;
                break;
              case 1:
                Path = this.getPrefDirectoryPath("ProfD") + dSep + Filename;
                break;
              case 3:
                Path = this.getPrefDirectoryPath("UChrm") + dSep + "CSS" + dSep + Filename;
                break;
              case 4:
                Path = this.getPrefDirectoryPath("UChrm") + dSep + "CSSWeb" + dSep + Filename;
                break;
              case 5:
                Path = this.getPrefDirectoryPath("UChrm") + dSep + "CSSShadow" + dSep + Filename;
                break;
            }
          }
          this.launch(this.editor, Path);
        },
        launch: function(RanPath, OpenPath) {
          var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);
          var proc = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
          var args = [OpenPath];
          file.initWithPath(RanPath);
          if (!file.exists()) {
            var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
            RanPath = pref.getCharPref("view_source.editor.path");
            file.initWithPath(RanPath);
          }
          proc.init(file);
          proc.run(false, args, args.length);
        },
    
        // ■■ Neu: Script- und CSS-Listen (aus extras_config_menu.uc.js integriert) ■■
    
        getScripts: function(iType) {
          let ucJsScripts = [];
          let extjs = /\.uc\.js$/i;
    
          // 1. Standard-UChrm-Ordner durchsuchen
          let uchrmFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
          if (uchrmFolder.exists()) {
            let files = uchrmFolder.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
            while (files.hasMoreElements()) {
              let file = files.getNext().QueryInterface(Ci.nsIFile);
              if (extjs.test(file.leafName)) {
                if (file.leafName === "userChromeShadow.uc.js" && !this.showuCS) continue;
                ucJsScripts.push(file.leafName);
              }
            }
          }
    
          // 2. chrome/scripts-Unterverzeichnis durchsuchen
          if (this.jsSubfolder) {
            let scriptsFolder = Services.dirsvc.get("ProfD", Ci.nsIFile);
            scriptsFolder.append("chrome");
            scriptsFolder.append(this.jsSubfolder);
            if (scriptsFolder.exists()) {
              let files = scriptsFolder.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
              while (files.hasMoreElements()) {
                let file = files.getNext().QueryInterface(Ci.nsIFile);
                if (extjs.test(file.leafName)) {
                  ucJsScripts.push("chrome/" + this.jsSubfolder + "/" + file.leafName);
                }
              }
            }
          }
    
          if (this.sortScripts) ucJsScripts.sort(this.stringComparison.bind(this));
    
          if (iType === 0) {
            // Untermenü "Meine Scripte" befüllen
            this.fillFileMenu("Meine Scripte", "Meine Scripte", ucJsScripts, 0);
          } else {
            // Für Zwischenablage: Nur Dateinamen (ohne Pfad) verwenden
            let simpleNames = ucJsScripts.map(f => f.split(/[\\/]/).pop());
            let result = this.fillClipboardValue(simpleNames);
            Components.classes["@mozilla.org/widget/clipboardhelper;1"]
              .getService(Components.interfaces.nsIClipboardHelper).copyString(result);
          }
        },
    
        getCssFiles: function(iType) {
          let cssFiles = [];
          let extcss = /\.css$/i;
          let folderName = "";
          let subdirName = "";
          let menuLabel = "";
          let sType = 0;
    
          if (iType === 3) {
            folderName = "CSS";
            subdirName = "Meine CSS-Dateien";
            menuLabel = "Meine CSS-Dateien";
            sType = 3;
          } else if (iType === 4) {
            folderName = "CSSWeb";
            subdirName = "Meine CSSWeb-Dateien";
            menuLabel = "Meine CSSWeb-Dateien";
            sType = 4;
          } else if (iType === 5) {
            folderName = "CSSShadow";
            subdirName = "Meine CSSShadow-Dateien";
            menuLabel = "Meine CSSShadow-Dateien";
            sType = 5;
          } else {
            return;
          }
    
          let aFolder = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
          aFolder.initWithPath(Services.dirsvc.get("UChrm", Ci.nsIFile).path + this.getDirSep() + folderName);
    
          if (aFolder.exists() && aFolder.isDirectory()) {
            let files = aFolder.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
            while (files.hasMoreElements()) {
              let file = files.getNext().QueryInterface(Ci.nsIFile);
              if (extcss.test(file.leafName)) cssFiles.push(file.leafName);
            }
          }
    
          if (this.sortScripts) cssFiles.sort(this.stringComparison.bind(this));
          this.fillFileMenu(subdirName, menuLabel, cssFiles, sType);
        },
    
        fillFileMenu: function(subdirName, strlabel, fileArray, sType) {
          let submenuItem = Appmenu.subdirMenuHash[subdirName];
          if (submenuItem) {
            submenuItem.setAttribute('label', strlabel + ' (' + fileArray.length + ')');
          }
          let popup = Appmenu.subdirPopupHash[subdirName];
          if (!popup) return;
          // Vorhandene Einträge löschen
          while (popup.hasChildNodes()) popup.removeChild(popup.firstChild);
    
          // Symbol je nach Dateityp festlegen
          let iconPath = '';
          if (sType === 0) {
            iconPath = ProfilePath + '/' + Icon04;       // js.svg
          } else {
            iconPath = ProfilePath + '/' + Icon03;       // css4.svg
          }
    
          for (let i = 0; i < fileArray.length; i++) {
            let fileName = fileArray[i];
            let mitem = document.createXULElement('menuitem');
            mitem.setAttribute('class', 'menuitem-iconic');
            mitem.setAttribute('image', iconPath);
    
            if (sType === 0) {
              // Scripts: Linksklick = Bearbeiten, Mittelklick = GitHub, Rechtsklick = GitHub-Suche
              let displayName = fileName.split(/[\\/]/).pop();
              mitem.setAttribute('label', displayName);
              mitem.addEventListener('command', function() {
                Appmenu.edit(0, fileName);
              }, true);
              mitem.addEventListener('click', function(event) {
                Appmenu.openAtGithub(event, displayName);
              }, true);
              mitem.setAttribute('tooltiptext',
                'Linksklick: Bearbeiten,\nMittelklick: GitHub-Seite öffnen,\nRechtsklick: GitHub-Suche');
            } else if (sType === 3) {
              mitem.setAttribute('label', fileName);
              mitem.addEventListener('command', function() {
                Appmenu.edit(3, fileName);
              }, true);
            } else if (sType === 4) {
              mitem.setAttribute('label', fileName);
              mitem.addEventListener('command', function() {
                Appmenu.edit(4, fileName);
              }, true);
            } else if (sType === 5) {
              mitem.setAttribute('label', fileName);
              mitem.addEventListener('command', function() {
                Appmenu.edit(5, fileName);
              }, true);
            }
            popup.appendChild(mitem);
          }
        },
    
        fillClipboardValue: function(sArray) {
          var retValue = "Meine Skripte (" + sArray.length + "):\n------------------------";
          for (var i = 0; i < sArray.length; i++) {
            retValue += "\n" + (i + 1) + ". " + sArray[i];
          }
          return retValue;
        },
    
        openAtGithub: function(e, sScript) {
          if (e.button == 1) {
            var sUrl = "https://github.com/ardiman/userChrome.js/tree/master/" + this.cleanFileName(sScript);
            openWebLinkIn(sUrl, 'tab');
          }
          if (e.button == 2) {
            e.preventDefault();
            var sUrl = "https://github.com/search?langOverride=&language=&q=" + sScript + "&repo=&start_value=1&type=Code";
            openWebLinkIn(sUrl, 'tab');
          }
        },
    
        cleanFileName: function(sName) {
          sName = sName.toLowerCase();
          var regs = [/\.uc\.js$/, /\.uc\.xul$/, /^ucjs_/, /_\d.+/, /_fx\d+/, /[-+\.]/g, /_v\d+/];
          for (var i = 0; i < regs.length; i++) {
            sName = sName.replace(regs[i], "");
          }
          return sName;
        },
    
        stringComparison: function(a, b) {
          a = a.toLowerCase().replace(/ä/g,"a").replace(/ö/g,"o").replace(/ü/g,"u").replace(/ß/g,"s");
          b = b.toLowerCase().replace(/ä/g,"a").replace(/ö/g,"o").replace(/ü/g,"u").replace(/ß/g,"s");
          return (a == b) ? 0 : (a > b) ? 1 : -1;
        },
    
        init: function() {
          this.handleRelativePath(this.toolbar.apps);
          const XULNS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
          var ExternalAppBtn = document.createElementNS(XULNS, 'toolbarbutton');
          ExternalAppBtn.id = 'AppMenuButton';
          ExternalAppBtn.setAttribute('label', 'AppButton');
          ExternalAppBtn.addEventListener('click', event => {
            event.preventDefault();
            event.stopPropagation();
          });
          ExternalAppBtn.setAttribute('tooltiptext', 'Firefox Menü');
          ExternalAppBtn.setAttribute('type', 'menu');
          ExternalAppBtn.setAttribute('removable', 'true');
    
          let ProfilePath = PathUtils.toFileURI(
            PathUtils.join(PathUtils.profileDir, 'chrome', 'image')
          );
    
          let DefaultIcon = 'Button_groß.png';
          let AlternateIcon = 'Button_klein-5.png';
          if (Appmenu.isButton) {
            ExternalAppBtn.style.listStyleImage = `url('${ProfilePath}/${DefaultIcon}')`;
            ExternalAppBtn.style.width = '94px';
            ExternalAppBtn.style.height = '24px';
          } else {
            ExternalAppBtn.style.listStyleImage = `url('${ProfilePath}/${AlternateIcon}')`;
            ExternalAppBtn.style.width = '48px';
            ExternalAppBtn.style.height = '21px';
          }
    
          if (Appmenu.isUrlbar === 1) {
            var navBar = document.getElementById('nav-bar-customization-target');
            navBar.insertBefore(ExternalAppBtn, navBar.firstChild);
          } else if (Appmenu.isUrlbar === 2) {
            var menubar = document.getElementById('toolbar-menubar');
            menubar.insertBefore(ExternalAppBtn, menubar.firstChild);
          } else {
            var TabsToolbar = document.getElementById('TabsToolbar');
            TabsToolbar.insertBefore(ExternalAppBtn, TabsToolbar.firstChild);
          }
          var ExternalAppPopup = document.createElementNS(XULNS, 'menupopup');
          ExternalAppPopup.addEventListener('click', event => {
            event.stopPropagation();
          });
          ExternalAppPopup.setAttribute('id', 'AMpopup');
          this._externalAppPopup = ExternalAppPopup;
          ExternalAppBtn.appendChild(ExternalAppPopup);
          Appmenu.onpopupshowing();
    
          // CSS-Loader initialisieren
          this.cssLoader.initCSSLoader();
    
          // JS-Loader initialisieren (Pref-Listener registrieren)
          this.jsLoader.init();
    
          // Menü mit Tastaturkürzel öffnen
          if (Appmenu.hotkey) {
            let key = document.createXULElement('key');
            key.id = 'key_AppMenuPopup';
            key.setAttribute('key', Appmenu.hotkey);
            if (Appmenu.hotkeyModifier)
              key.setAttribute('modifiers', Appmenu.hotkeyModifier);
            key.addEventListener('command', function () {
              document.getElementById('AMpopup').openPopup();
            });
            document.getElementById('mainKeyset').appendChild(key);
          }
        },
    
        onpopupshowing: function() {
          if (this._isready) return;
          if (this._externalAppPopup === null) return;
          var ExternalAppPopup = this._externalAppPopup;
          for (let subdir of this.toolbar.subdirs) {
            if (subdir.name == 'separator') {
              ExternalAppPopup.appendChild(document.createXULElement('menuseparator'));
            } else if (subdir.command) {
              var actionItem = ExternalAppPopup.appendChild(document.createXULElement('menuitem'));
              actionItem.setAttribute('class', 'menuitem-iconic');
              actionItem.setAttribute('label', subdir.name);
              actionItem.setAttribute('image', subdir.image);
              if (subdir.tooltiptext) {
                actionItem.setAttribute('tooltiptext', subdir.tooltiptext);
              } else {
                actionItem.setAttribute('tooltiptext', subdir.name);
              }
              actionItem.addEventListener('command', subdir.command);
            } else {
              var subdirItem = ExternalAppPopup.appendChild(document.createXULElement('menu'));
              var subdirItemPopup = subdirItem.appendChild(document.createXULElement('menupopup'));
              subdirItem.setAttribute('class', 'menu-iconic');
              subdirItem.setAttribute('label', subdir.name);
              subdirItem.setAttribute('image', subdir.image);
              Appmenu.subdirPopupHash[subdir.name] = subdirItemPopup;
              Appmenu.subdirMenuHash[subdir.name] = subdirItem;
    
              // CSS-Loader-Menüeinträge für "CSS-Loader-Menü"
              if (subdir.name === "CSS-Loader-Menü") {
                Appmenu.cssLoader.rebuildCSSMenu();
              }
              // Neue dynamische Untermenüs befüllen
              if (subdir.name === "Meine Scripte") {
                Appmenu.getScripts(0);
              }
              if (subdir.name === "Meine CSS-Dateien") {
                Appmenu.getCssFiles(3);
              }
              if (subdir.name === "Meine CSSWeb-Dateien") {
                Appmenu.getCssFiles(4);
              }
              // JavaScript-Loader-Menü: popupshowing-Listener für dynamischen Aufbau
              // Wichtig: nur bei e.target === e.currentTarget ausführen,
              // sonst bubbelt popupshowing von Kind-Popups hoch und führt zu Endlosschleife
              if (subdir.name === "JavaScript-Loader-Menü") {
                subdirItemPopup.addEventListener('popupshowing', (e) => {
                  if (e.target === e.currentTarget) Appmenu.jsLoader.fillMenu(e.target);
                });
              }
            }
          }
          for (let app of this.toolbar.apps) {
            var appItem;
            if (app.name == 'separator') {
              appItem = document.createXULElement('menuseparator');
            } else {
              appItem = document.createXULElement('menuitem');
              appItem.setAttribute('class', 'menuitem-iconic');
              appItem.setAttribute('label', app.name);
              appItem.setAttribute('image', app.image);
              appItem.addEventListener('command', function () {
                Appmenu.exec(this.path, this.args);
              });
              appItem.setAttribute('tooltiptext', app.name);
              appItem.path = app.path;
              appItem.args = app.args;
            }
            if (app.subdir && Appmenu.subdirPopupHash[app.subdir])
              Appmenu.subdirPopupHash[app.subdir].appendChild(appItem);
            else ExternalAppPopup.appendChild(appItem);
          }
          for (let config of this.toolbar.configs) {
            var configItem;
            if (config.name == 'separator') {
              configItem = document.createXULElement('menuseparator');
            } else {
              configItem = ExternalAppPopup.appendChild(document.createXULElement('menuitem'));
              configItem.setAttribute('class', 'menuitem-iconic');
              configItem.setAttribute('label', config.name);
              configItem.setAttribute('image', config.image);
              configItem.addEventListener('command', () => {
                if (typeof config.command === 'function') {
                  config.command();
                } else {
                  Appmenu.executeCommand(config.command);
                }
              });
              if (config.tooltiptext) {
                configItem.setAttribute('tooltiptext', config.tooltiptext);
              } else {
                configItem.setAttribute('tooltiptext', config.name);
              }
              configItem.setAttribute('id', config.id);
            }
    
            if (config.subdir && Appmenu.subdirPopupHash[config.subdir]) {
              Appmenu.subdirPopupHash[config.subdir].appendChild(configItem);
            } else {
              ExternalAppPopup.appendChild(configItem);
            }
          }
          if (this.autohideEmptySubDirs) {
            // Lazy-gefüllte Untermenüs nicht verstecken (werben erst beim Aufklappen befüllt)
            let lazySubdirs = ['JavaScript-Loader-Menü'];
            for (let key of Object.keys(Appmenu.subdirPopupHash)) {
              if (lazySubdirs.includes(key)) continue;
              if (Appmenu.subdirPopupHash[key].hasChildNodes()) {
                continue;
              } else {
                Appmenu.subdirMenuHash[key].setAttribute('hidden', 'true');
              }
            }
          }
          if (this.moveSubDirstoBottom) {
            let i = ExternalAppPopup.childNodes.length;
            while (ExternalAppPopup.firstChild.getAttribute('class') != 'menuitem-iconic' && i-- != 0) {
              ExternalAppPopup.appendChild(ExternalAppPopup.firstChild);
            }
          }
          this._isready = true;
        },
    
        executeCommand: function(command) {
          const commandMap = {
            'gCustomizeMode.enter()': () => gCustomizeMode.enter(),
            'safeModeRestart();': () => safeModeRestart(),
            'goKonsole': () => {
                    var { require } = ChromeUtils.importESModule('resource://devtools/shared/loader/Loader.sys.mjs', {});
                    var { BrowserConsoleManager } = require('resource://devtools/client/webconsole/browser-console-manager');
                    BrowserConsoleManager.openBrowserConsoleOrFocus();
                  },
            'goWerkzeuge': () => {
                    var { require } = ChromeUtils.importESModule('resource://devtools/shared/loader/Loader.sys.mjs', {});
                    var { BrowserToolboxLauncher } = require('resource://devtools/client/framework/browser-toolbox/Launcher.sys.mjs');
                    BrowserToolboxLauncher.init();
                  },
            'goEntwickler': () => {
                    var { require } = ChromeUtils.importESModule('resource://devtools/shared/loader/Loader.sys.mjs', {});
                    var { gDevToolsBrowser } = require('resource://devtools/client/framework/devtools-browser');
                    gDevToolsBrowser.toggleToolboxCommand(window.gBrowser, performance.now());
                  },
            'gSync': () => gSync.openPrefs('menubar'),
            'LoginHelper.openPasswordManager(window, { entryPoint: "mainmenu" })': () => LoginHelper.openPasswordManager(window, { entryPoint: 'mainmenu' }),
            'switchToTabHavingURI("about:processes", true)': () => switchToTabHavingURI('about:processes', true),
            'BrowserOffline.toggleOfflineStatus();': () => BrowserOffline.toggleOfflineStatus(),
            'goReeboot': () => {
                      Services.appinfo.invalidateCachesOnRestart();
                      Services.startup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
                    },
            'goQuitApplication(event);': () => goQuitApplication(event),
          };
          if (commandMap[command]) {
            commandMap[command]();
          } else {
            console.warn('Unbekannter Befehl: ', command);
          }
        },
    
        handleRelativePath: function(apps) {
          for (let app of apps) {
            if (app.path) {
              app.path = app.path.replace(/\//g, '\\');
              var ffdir = Cc['@mozilla.org/file/directory_service;1'].getService(Ci.nsIProperties).get(app.root, Ci.nsIFile).path;
              if (/^(\\)/.test(app.path)) {
                app.path = ffdir + app.path;
              }
            }
          }
        },
    
        exec: function(path, args) {
          args = args || [];
          var args_t = args.slice(0);
          for (let arg of args_t) {
            arg = arg.replace(/%u/g, gBrowser.currentURI.spec);
          }
          var file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
          file.initWithPath(path);
          if (!file.exists()) {
            alert('Datei nicht gefunden: ' + path);
            return;
          }
          if (file.isExecutable() && !path.endsWith('.js')) {
            var process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
            process.init(file);
            process.run(false, args_t, args_t.length);
          } else if (file.isFile()) {
            if (this.editor) {
              let UI = Cc['@mozilla.org/intl/scriptableunicodeconverter'].createInstance(Ci.nsIScriptableUnicodeConverter);
              UI.charset = window.navigator.platform.toLowerCase().includes("win") ? "Shift_JIS" : "UTF-8";
              let path = UI.ConvertFromUnicode(file.path);
              let app = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
              app.initWithPath(this.editor);
              let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
              process.init(app);
              process.run(false, [path], 1);
            } else {
              file.launch();
            }
          } else if (file.isDirectory()) {
            if (this.fileManager) {
              let args=[this.FMParameter,path];
              let app = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
              app.initWithPath(this.fileManager);
              let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
              process.init(app);
              process.run(false, args, args.length);
            } else {
              file.launch();
            }
          }
        },
      };
    
    /* ***************************************************************************************************************************** */
    
      // CSSEntry-Klasse (aus UserCSSLoader)
      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();
            let lastModifiedTime = isExists ? aFile.lastModifiedTime : 0;
            let isForced = this.lastModifiedTime != lastModifiedTime;
            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)) {
                if (!isEnable || !isExists) {
                    this.sss.unregisterSheet(uri, this.SHEET);
                } else if (isForced) {
                    this.sss.unregisterSheet(uri, this.SHEET);
                    this.sss.loadAndRegisterSheet(uri, this.SHEET);
                }
            } else {
                if (isEnable && isExists) {
                    this.sss.loadAndRegisterSheet(uri, this.SHEET);
                }
            }
    
            this.lastModifiedTime = lastModifiedTime;
            return this._enabled = isEnable;
        },
      };
    
      (function () {
        let sss = Components.classes['@mozilla.org/content/style-sheet-service;1'].getService(Components.interfaces.nsIStyleSheetService);
        let uri = Services.io.newURI(
          'data:text/css;charset=utf-8,' +
            encodeURIComponent(`
              menuitem[label="Profil-Verzeichnis"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Chrome-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="CSS-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="CSS-Web-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="JS-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Icons-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Addon-Verzeichnis"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Programm-Verzeichnis"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Startup-Cache"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              #AMAnpassen     { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMModus        { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMKonsole      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMWerkzeuge    { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMEntwickler   { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMsynchron     { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMdaten        { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMManager      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMOffline      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              /* Neustart-Button */
              #AMreboot { -moz-context-properties: fill, fill-opacity !important; fill: #fbc96e !important; padding-left: 13px !important; }
              #AMreboot > img:nth-child(1) { width: 16px !important; height: 16px !important; }
              /* Beenden-Button */
              #AMquit { -moz-context-properties: fill, fill-opacity !important; fill: red !important; }
    
              /* Skriptliste in Zwischenablage */
              #AMscriptList    { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              /* about:-Seiten */
              #AMaboutAbout        { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutAddons       { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutCache        { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutConfig       { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutCrashes      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutDownloads    { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutHome         { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutLogins       { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutSupport      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutPreferences  { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutProcesses    { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutProfiles     { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              /* uProfMenu-Einträge */
              #AMuserChromeCss      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMuserChromeShadowCss { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMuserContentCss     { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMuserChromeJs      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMprefsJs            { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMuserJs             { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              /* 1 */
              menuitem[subdir="CSS-Loader-Menü"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menu[label="JavaScript-Loader-Menü"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #appmenu-css-CSS-Ordner-öffnen { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
            `),
          null,
          null
        );
        sss.loadAndRegisterSheet(uri, sss.AUTHOR_SHEET);
      })();
    
      if (window.gBrowser) Appmenu.init();
    Alles anzeigen
  • Firefox und Online Apotheke Aliva

    • Mira_Belle
    • 31. August 2026 um 18:35

    Oh Gott, jetzt lasst es doch gut sein:!:

    Das Problem mit der Webpage hat doch überhaupt nichts mit dem AV-Programm zu tun!

    Warum muss hier denn immer so abgedriftet werden?

    2002Andreas Bitte mach hier zu, bevor es noch weiter eskaliert. Danke.

  • extra_config_menu.uc.js > ohne security.allow_unsafe_dangerous_privileged_evil_eval auf false

    • Mira_Belle
    • 31. August 2026 um 18:32
    Zitat von seipe

    Button wieder da.

    Ja, manchmal ist auch der Firefox 'ne Zicke. ^^
    Freut mich, dass jetzt alles wieder funktioniert.

  • extra_config_menu.uc.js > ohne security.allow_unsafe_dangerous_privileged_evil_eval auf false

    • Mira_Belle
    • 31. August 2026 um 15:27
    Zitat von seipe

    Bei mir ist Notepad++ eingetragen. Habe jetzt den Pfad nochmals kopiert und neu eingegeben. Jetzt hat es geklappt. Alles gut. Danke

    Super. :thumbup:

    Zitat von seipe

    Nicht schimpfen. Der userCSSLoader-Button ist jetzt verschwunden.

    Das ist ....=O
    Mach dafür einen neuen Thread auf und poste da Dein komplettes Script.

  • extra_config_menu.uc.js > ohne security.allow_unsafe_dangerous_privileged_evil_eval auf false

    • Mira_Belle
    • 31. August 2026 um 14:41

    2002Andreas Du hast absolut recht!
    Die Leute lesen nichts mehr.

    Das ist auch in ganz anderen Bereichen so
    und so etwas regt mich tierisch auf.
    Wobei, ich versuche gelassener zu werden, aber DAS beeinflusst halt auch meine Zukunft!
    Siehe https://www.wahlrecht.de/umfragen/landt…hsen-anhalt.htm
    Nie und nimmer hat irgendwer auch nur EIN Wahlprogramm irgendEINER Partei gelesen!!
    Man glaubt lieber an das Stammtischgeschwätz und auf sein Bauchgefühl. Irre.

    Zurück zum Script!
    Wie 2002Andreas schon schrieb, muss natürlich auch der zu benutzende Editor ausgewählt werden!!
    Wenn Notepad++ oder Microsoft Visual Studio Code gar nicht installiert sind, ...
    Das klappt dann nicht und ergo wird natürlich auch kein Script zum Bearbeiten geöffnet.
    Wie denn dann auch?

  • extra_config_menu.uc.js > ohne security.allow_unsafe_dangerous_privileged_evil_eval auf false

    • Mira_Belle
    • 31. August 2026 um 12:04

    Endor Genau daran hatte ich auch gedacht.

    Ich hätte das Script heute Nachmittag fertig, gezipt noch mal hoch geladen.

  • extra_config_menu.uc.js > ohne security.allow_unsafe_dangerous_privileged_evil_eval auf false

    • Mira_Belle
    • 31. August 2026 um 11:35

    Ich bin mir ziemlich sicher, dass es nicht am Script selbst liegt.

    Erstelle Dir das Script doch noch mal neu.

    Eventuell ist beim erstenmal was schief gelaufen.


    Und eine Idee hätte ich dann doch noch!

    Aber erst heut Nachmittag.

    Bin auf Arbeit.

  • extra_config_menu.uc.js > ohne security.allow_unsafe_dangerous_privileged_evil_eval auf false

    • Mira_Belle
    • 31. August 2026 um 10:06

    Das ist wieder so eine "feine" Sache.
    Ok, laufen andere Skripte?
    Hast Du mal einen Test mit einem anderen Profil gemacht?
    Ist die Dateiendung im Explorer auch richtig, also => .uc.js
    Zum Testen auch mal ausprobieren, was passiert, wenn alle anderen Scripte temporär gelöscht sind!
    Erst alle z.B. mit 7-Zip packen und danach entfernen. Kannst sie aber auch ganz einfach in einen anderen Ordner verschieben.
    Dennoch das Profil besser vorher mal sichern!!
    Mehr Ideen habe ich gerade nicht.

  • extra_config_menu.uc.js > ohne security.allow_unsafe_dangerous_privileged_evil_eval auf false

    • Mira_Belle
    • 31. August 2026 um 09:11
    JavaScript
    /* ----------------------------------------------------------------------------------- */
    /*     Zu beachten ist, dass die Grafiken sich im richtigen Ordner befinden müssen     */
    /*            %appdata%\Mozilla\Firefox\Profiles\"Profilname"\chrome\icons             */
    /* ----------------------------------------------------------------------------------- */

    :!:

  • extra_config_menu.uc.js > ohne security.allow_unsafe_dangerous_privileged_evil_eval auf false

    • Mira_Belle
    • 31. August 2026 um 09:08

    seipe

    JavaScript
      // In der folgenden Zeile kann festgelegt werden, ob ein verschiebbarer Button erstellt wird:
      showAsButton: 1,  // 1: ja / Button wird erstellt, 0: nein / Menue unter "Extras"

    Mit dieser Einstellung wird ein Button generiert.

    JavaScript
      // Button-Aussehen (1: flexibles SVG-Icon aus Icon-Ordner, 0: festes Base64-PNG-Icon):
      buttonStyle: 0,  // Default => 0

    Mit dieser Einstellung sollte das Base64-PNG-Icon für den Button genutzt werden.

    Schaut so aus =>

  • extra_config_menu.uc.js > ohne security.allow_unsafe_dangerous_privileged_evil_eval auf false

    • Mira_Belle
    • 30. August 2026 um 22:23
    Zitat von 2002Andreas

    und du glaubst wirklich, dass sich das viele User durchlesen ;)

    Nö, aber selbst schuld.
    Wobei man diesem Fehler ja auch aus der Ferne recht schnell auf die Schliche kommen kann,
    bei den ::part() Selektoren, so denke ich, wird man nicht so schnell drauf kommen.


    Zitat von 2002Andreas

    beide Skripte(auch aus dem anderen Thread von dir) funktionieren hier auf die Schnelle, hast du gut gemacht :thumbup:

    Danke.


    Jetzt muss ich nur mal sehen, ob ich die "Liste" auch Mehrspaltig hinbekomme.
    Aber das wird wohl dauern.

  • extra_config_menu.uc.js > ohne security.allow_unsafe_dangerous_privileged_evil_eval auf false

    • Mira_Belle
    • 30. August 2026 um 22:18

    In der userChrome.uc.js sollte eigentlich auch diese Warnung stehen:

    JavaScript
    /*
     * userChrome.js
     *
     * The file userChrome.js can be used to customize the functioning of Mozilla's
     * user interface. Usage and syntax follow below; for useful code snippets see
     * http://mozilla.zeniko.ch/userchrome.js.html.
     *
     * Examples:
     * setTimeout(function() { document.title = "A new title for every window" }, 2000);
     *
     * if (location == "chrome://browser/content/browser.xul") {
     *   alert("Script loaded in main browser only");
     * }
     *
     * // DOMi window
     * if (location == "chrome://inspector/content/inspector.xul") {
     *    // Move Urlbar box to main toolbar
     *    var tb = document.getElementById('bxURLBar');
     *    var el = document.getElementById('mbrInspectorMain');
     *    if (tb && el) el.appendChild(tb, el.firstChild);
     * }
     *
     * NOTE:
     * userChromeJS includes an 'import' function to facilitate file management.
     * An absolute path or relative path with Directory name property token can be
     * used, as follows:
     *
     * // Single file (javascript .js or overlay .xul file)
     * userChrome.import("Full file path");
     * userChrome.import("Relative file path", "Token");
     * // All .js and .xul files in a folder will be loaded.
     * userChrome.import("Full file folder path");
     * userChrome.import("Relative file folder path/name", "Token");
     * userChrome.import("*", "Token");
     *
     * NOTE:
     * Absolute windows files and folders must be have backslash escaped:
     * "C:\\Program Files\\Mozilla\\scripts\\myscript.js"
     *
     * Examples:
     * // Import script in [ProfileDir]/chrome/scripts/myscript.js
     * userChrome.import("scripts/myscript.js", "UChrm");
     * // Import script in [Profiles]/scripts/myscript.js (share same script in
     * // multiple profiles
     * userChrome.import("scripts/myscript.js", "DefProfRt");
     * // All .js or .xul in profile chrome directory
     * userChrome.import("*", "UChrm");
     * // Import overlay
     * userChrome.import("C:\\Program Files\\Mozilla\\scripts\\myOverlay.xul");
     * // Import everything in Desktop folder /scripts
     * userChrome.import("scripts", "Desk");
     * // Perhaps the only thing you need in this file..
     * if (location == "chrome://browser/content/browser.xul") {
     *  userChrome.import("scripts", "DefProfRt");
     * }
     *
     * NOTE:
     * For a full listing of directory tokens see the two links found here:
     * https://developer.mozilla.org/en-US/Add-ons/Code_snippets/File_I_O#Getting_files_in_special_directories
     * // What's the path for a token? This will print it in the console.
     * userChrome.log(userChrome.getAbsoluteFile("Desk").path, "getAbsoluteFile:'Desk'");
     *
     * NOTE:
     * userChromeJS includes a log function, invoked as follows:
     * userChrome.log("string1"[, "string2"])
     * Example:
     * userChrome.log("hello world!", "myscript.js");
     * Results in a console message:
     * 2009-05-22 18:07:40 userChromeJS myscript.js: hello world!
     *
     * NOTE:
     * The date format for the userChrome.log console logger may be user defined:
     * Example:
     * userChrome.dateFormat = "%Y-%m-%d %H:%M:%S";
     *
     * NOTE:
     * The default charSet is "UTF-8"; for code using the 'import' or
     * 'importFolder' functions to manage files, the charSet for subscript loader
     * may be user defined, prior to calling the import or importFolder functions:
     * Example:
     * userChrome.charSet = "UTF-8";
     *
     * NOTE:
     * Scripts are stored in a startup cache and loaded from it.
     * After a change in userChrome.js you heve to restart Firefox with clearing
     * this cache to make sure the changed file is read.
     * By default this applies to imported .js files too. You can bypass the cache
     * for these scripts with this statement BEFORE any import statement:
     * userChrome.ignoreCache = true;
     *
     */
    Alles anzeigen
  • Meine Version des App-Menüs (JavaScript)

    • Mira_Belle
    • 30. August 2026 um 22:14
    Zitat von 2002Andreas

    was hast du gegen die Datei bzw. das Skript, warum blendest du das aus bzw. gibst eine Möglichkeit dazu :/

    Ich verweise mal auf meinen Kommentar im anderen Thread.

    Beitrag

    RE: extra_config_menu.uc.js > ohne security.allow_unsafe_dangerous_privileged_evil_eval auf false

    […]

    Die userChromeShadow.css wird doch angezeigt!!
    Und zwar immer!
    Es geht doch nur um das Anzeigen der userChromeShadow.uc.js.
    Diese dient doch nur der Einbindung eben der CSS-Datei,
    und ich bin der Meinung, dass da eigentlich niemand dran muss, um diese zu editieren.

    Hier mal deren Inhalt:

    (Quelltext, 15 Zeilen)

    Solange die funktioniert, sollte man da besser die Finger von lassen.

    Nachtrag!
    Das Menü dient ja nicht nur zum Anzeigen der eigenen Scripte,
    sondern per doppelklick zum direkten bearberiten…
    Mira_Belle
    30. August 2026 um 22:11
  • extra_config_menu.uc.js > ohne security.allow_unsafe_dangerous_privileged_evil_eval auf false

    • Mira_Belle
    • 30. August 2026 um 22:11
    Zitat von 2002Andreas

    Wenn dann müsste auch die userChromeShadow.css angezeigt werden.

    Die userChromeShadow.css wird doch angezeigt!!
    Und zwar immer!
    Es geht doch nur um das Anzeigen der userChromeShadow.uc.js.
    Diese dient doch nur der Einbindung eben der CSS-Datei,
    und ich bin der Meinung, dass da eigentlich niemand dran muss, um diese zu editieren.

    Hier mal deren Inhalt:

    JavaScript
    // userChromeShadow.uc.js by aborix
    // 28.07.2022 FF104+ Fix: using PathUtils.join (Sören Hentzschel)
    
    (async function() {
      if (location.href !== 'chrome://browser/content/browser.xhtml') return;   
      try {
        let path = PathUtils.join(PathUtils.profileDir, 'chrome', 'userChromeShadow.css');
        let cssIn = await IOUtils.readUTF8(path);
        let sss = Cc['@mozilla.org/content/style-sheet-service;1'].getService(Ci.nsIStyleSheetService);
        let uri = makeURI('data:text/css;charset=UTF=8,' + encodeURIComponent(cssIn));
          sss.loadAndRegisterSheet(uri, sss.AUTHOR_SHEET);
      } catch(e) { 
        console.log("UserChromeShadow-Error: " + e.name + ': ' + e.message );
      };        
    })();
    Alles anzeigen

    Solange die funktioniert, sollte man da besser die Finger von lassen.

    Nachtrag!
    Das Menü dient ja nicht nur zum Anzeigen der eigenen Scripte,
    sondern per doppelklick zum direkten bearberiten dieser.

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

    • Mira_Belle
    • 30. August 2026 um 21:44

    Ich habe mich getraut!
    Und,
    es hat geklappt:!:

    Aus meinem Appmenu.uc.js ist nun eine eierlegende Wollmilchsau geworden!
    Man kann direkt verschieden Verzeichnisse öffnen.
    Direkt verschieden Firefoxfunktionen aufrufen,
    bekommt nicht nur seine Skripte und CSS angezeigt, sondern kann sie auch nach einem Klick
    direkt im Editor seiner wahl bearbeiten.
    Funktionen des JavaScriptLoaders sowie des CSSLaoders wurden integriert,
    damit man diese direkt aktivieren/deaktivieren kann.
    Und so einiges mehr!!

    JavaScript
    // ==UserScript==
    // @name           Appmenu.uc.js
    // @namespace      Appmenu@gmail.com
    // @description    Basiert auf dem Script externalFuncButtonM.uc.js, Wiederherstellung der Orangenen FF-Menü Schaltfläche
    // @include        main
    // @author         defpt
    // @charset        UTF-8
    // @edit           2025.10.05 mit integriertem CSS-Loader-Menü und Konfiguration-Menü,
    // @edit           zum direkten bearbeiten verschiedener Dateien.
    // @edit           Sowie der Möglichkeit direkt verschiedene "about:"-Seiten aufrufen zu können.
    // @edit           2026.08.29 Aufruf von Verzeichnissen und "about:"-Seiten erweitert.
    // @edit           2026.08.30 integriert: Meine Scripte, Meine CSS-Dateien, Meine CSSWeb-Dateien,
    // @edit           Skriptliste in Zwischenablage (aus extras_config_menu.uc.js)
    // @edit           Funktionen aus dem JavaScriptLoader hinzugefügt
    // Source          https://www.camp-firefox.de/forum/thema/139769/?postID=1293355#post1293355
    
    // ==/UserScript==
    
    /* ----------------------------------------------------------------------------------- */
    /*     Zu beachten ist, dass die Grafiken sich im richtigen Ordner befinden müssen     */
    /*            %appdata%\Mozilla\Firefox\Profiles\"Profilname"\chrome\icons             */
    /* ----------------------------------------------------------------------------------- */
    
    /* ----------------------------------------------------------------------------------- */
    /*  IMPORTANT!         This script was edited and modified using AI.                   */
    /* ----------------------------------------------------------------------------------- */
    
        // Definiere den Profilpfad für die Symbole
        let ProfilePath = PathUtils.toFileURI(
          PathUtils.join(PathUtils.profileDir, 'chrome', 'icons')
        );
        
        // Standard-Symbol-Dateiname
        ButtonIcon01 = 'restart_1.svg';           // Neustart
        ButtonIcon02 = 'quit.svg';                // Beenden
    
        Icon01 =       'profile.svg';             // Profil-Verzeichnis
        Icon02 =       'chrome.svg';              // Chrome-Ordner
        Icon03 =       'css4.svg';                // CSS-Ordner
        Icon04 =       'js.svg';                  // JS-Ordner
        Icon05 =       'folder-plus.svg';         // Icons-Ordner
        Icon06 =       'addons.svg';              // Addon-Verzeichnis
        Icon07 =       'folder.svg';              // Programm-Verzeichnis
        Icon08 =       'folder-1.svg';            // Startup-Cache
    
        Icon11 =       'Themes.svg';              // Anpassen
        Icon12 =       'debugging-workers.svg';   // Neustart im abgesicherten Modus
        Icon13 =       'command-console.svg';     // Browser-Konsole
        Icon14 =       'window-dev-tools.svg';    // Browser-Werkzeuge
        Icon15 =       'developer.svg';           // Web-Entwickler
        Icon16 =       'sync.svg';                // Firefox synchronisieren
        Icon17 =       'passwords.svg';           // Zugangsdaten und Passwörter
        Icon18 =       'performance.svg';         // Task Manager
        Icon19 =       'plug-disconnected.svg';   // Offline arbeiten
    
        Icon21 =       'firefox.svg';             // about:about
        Icon40 =       'extension.svg';           // about:addons
        Icon22 =       'info.svg';                // about:cache
        Icon23 =       'settings.svg';            // about:config
        Icon24 =       'warning.svg';             // about:crashes
        Icon25 =       'downloads.svg';           // about:downloads
        Icon26 =       'home.svg';                // about:home
        Icon27 =       'passwords.svg';           // about:logins
        Icon28 =       'debugging-workers.svg';   // about:support
        Icon29 =       'settings.svg';            // about:preferences
        Icon41 =       'performance.svg';         // about:processes
        Icon30 =       'profile.svg';             // about:profiles
    
        Icon31 =       'js.svg';                  // Meine Scripte
        Icon32 =       'css4.svg';                // Meine CSS-Dateien
        Icon33 =       'css4.svg';                // Meine CSSWeb-Dateien
        Icon34 =       'command-console.svg';     // Skriptliste in Zwischenablage
    
      var Appmenu = {
        // ■■ START UserConfiguration ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    
        // Editor mit angegebenem Pfad verwenden
        // editor: 'C:\\Program Files\\Notepad++\\notepad++.exe',
        editor: "C:\\Program Files\\Microsoft VS Code\\Code.exe",
        // oder
        // in 'view_source.editor.path' eingetragenen Editor verwenden
        //  editor: Services.prefs.getCharPref('view_source.editor.path'),
        // Dateimanager mit angegebenem Pfad verwenden oder leer ('') wenn System-Dateimanager verwenden
        //fileManager: 'C:\\Program files\\FreeCommander XE\\FreeCommander.exe',
        fileManager: "",
        // Parameter für Dateimanager oder leer ('')
        //FMParameter: '/T',
        FMParameter: "",
        // Submenüs ohne Inhalt im Hauptmenü automatisch ausblenden
        autohideEmptySubDirs: true,
        // Submenüs im Hauptmenü nach unten verschieben
        moveSubDirstoBottom: false,
        // Ort und Aussehen des Menü-Buttons einstellen
        //   isUrlbar: 1,  // 0: TabsToolbar; 1: navbar,
        isUrlbar: 2, // 0: TabsToolbar; 1: navbar; 2: toolbar-menubar
        isButton: 0, // 0: Hamburger,klein; 1: Firefox,groß,
        // Hotkey zum Öffnen des Appmenüs oder leer ('')
        hotkey: "f",
        hotkeyModifier: "alt",
    
        // ■■ Neu: Einstellungen für Script-/CSS-Listen (aus extras_config_menu.uc.js) ■■
        // Unterordner für uc.js-Skripte innerhalb des chrome-Verzeichnisses:
        jsSubfolder: 'scripts',
        // Zeigt die Datei userChromeShadow.uc.js in der Skriptliste an (1: ja, 0: nein):
        showuCS: 0,
        // Sortierung der Skript-/CSS-Dateien (1: ja, 0: nein):
        sortScripts: 0,
        // "Skriptliste in Zwischenablage" (1: ja, 2: mit Nummerierung, 0: deaktiviert):
        enableScriptsToClip: 2,
    
        // ■■ END UserConfiguration ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    
        // Submenüs im Hauptmenü nach unten verschieben
        subdirPopupHash: [],
        subdirMenuHash: [],
    
        // CSS-Loader-Funktionen (integriert)
        cssLoader: {
            AGENT_SHEET: Ci.nsIStyleSheetService.AGENT_SHEET,
            USER_SHEET: Ci.nsIStyleSheetService.USER_SHEET,
            AUTHOR_SHEET: Ci.nsIStyleSheetService.AUTHOR_SHEET,
            readCSS: {},
    
            get prefs() {
                delete this.prefs;
                return this.prefs = Services.prefs.getBranch("UserCSSLoader.");
            },
    
            get disabled_list() {
                try {
                    return JSON.parse(this.prefs.getCharPref("disabled_css_list")) || [];
                } catch (e) {
                    return [];
                }
            },
    
            set disabled_list(list) {
                this.prefs.setCharPref("disabled_css_list", JSON.stringify(list));
            },
    
            get FOLDER() {
                let aFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
                aFolder.appendRelativePath("CSS");
                if (!aFolder.exists() || !aFolder.isDirectory()) {
                    aFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0o664);
                }
                delete this.FOLDER;
                return this.FOLDER = aFolder;
            },
    
            initCSSLoader: function() {
                this.rebuildCSSMenu();
            },
    
            rebuildCSSMenu: function() {
                let ext = /\.css$/i;
                let not = /\.uc\.css/i;
                let files = this.FOLDER.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
                let popup = Appmenu.subdirPopupHash["CSS-Loader-Menü"];
    
                // Vorhandene Einträge löschen
                while (popup && popup.firstChild) {
                    popup.removeChild(popup.firstChild);
                }
    
                // Neue Einträge erstellen
                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);
                    let menuitem = document.createElementNS(
                        "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
                        "menuitem"
                    );
    
                    menuitem.setAttribute("label", file.leafName);
                    menuitem.setAttribute("id", "appmenu-css-" + file.leafName);
                    menuitem.setAttribute("class", "menuitem-iconic");
    
                    if (CSS.enabled) {
                        menuitem.setAttribute("image", `${ProfilePath}/menu-check_lime.svg`);
                    } else {
                        menuitem.setAttribute("image", `${ProfilePath}/stop_smal_red.svg`);
                    }
                    menuitem.setAttribute("tooltiptext", "Linksklick: an/aus, Mittelklick: an/aus (Menü bleibt offen), Rechtsklick: bearbeiten");
    
                    menuitem.addEventListener("command", () => this.toggleCSS(file.leafName));
                    menuitem.addEventListener("click", (event) => this.cssItemClick(event, file.leafName));
    
                    if (popup) {
                        popup.appendChild(menuitem);
                    }
                }
            },
    
            loadCSS: function(aFile) {
                let CSS = this.readCSS[aFile.leafName];
                if (!CSS) {
                    CSS = this.readCSS[aFile.leafName] = new CSSEntry(aFile);
                    CSS.enabled = !this.disabled_list.includes(aFile.leafName);
                }
                return CSS;
            },
    
            toggleCSS: function(aLeafName) {
                let CSS = this.readCSS[aLeafName];
                if (!CSS) return;
    
                CSS.enabled = !CSS.enabled;
    
                let currentDisabledList = this.disabled_list;
                if (CSS.enabled) {
                    currentDisabledList = currentDisabledList.filter(name => name !== aLeafName);
                } else {
                    if (!currentDisabledList.includes(aLeafName)) {
                        currentDisabledList.push(aLeafName);
                    }
                }
                this.disabled_list = currentDisabledList;
    
                let menuitem = document.getElementById("appmenu-css-" + aLeafName);
                if (menuitem) {
                    if (CSS.enabled) {
                        menuitem.setAttribute("image", `${ProfilePath}/menu-check_lime.svg`);
                    } else {
                        menuitem.setAttribute("image", `${ProfilePath}/stop_smal_red.svg`);
                    }
                }
            },
    
            cssItemClick: function(event, aLeafName) {
                event.preventDefault();
                event.stopPropagation();
                if (event.button === 0) {
                    return;
                } else if (event.button === 1) {
                    this.toggleCSS(aLeafName);
                } else if (event.button === 2) {
                    let file = this.getFileFromLeafName(aLeafName);
                    this.editCSS(file);
                }
            },
    
            getFileFromLeafName: function(aLeafName) {
                let f = this.FOLDER.clone();
                f.QueryInterface(Ci.nsIFile);
                f.appendRelativePath(aLeafName);
                return f;
            },
    
            editCSS: function(aFile) {
                let editor = cssLoaderConfig.Editor || Services.prefs.getCharPref("view_source.editor.path");
                if (!editor) {
                    alert('Kein Editor konfiguriert! Bitte in about:config unter "view_source.editor.path" einen Editor eintragen.');
                    return;
                }
                try {
                    let UI = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
                    UI.charset = window.navigator.platform.toLowerCase().includes("win") ? "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) {
                    console.error("Fehler beim Öffnen des Editors:", e);
                }
            },
        },
    
        // ■■ JavaScript-Loader-Funktionen (aus rebuild_userChrome.uc.js integriert) ■■
        jsLoader: {
            init: function() {
                this.addPrefListener(this.readLaterPrefListener);
            },
    
            fillMenu: function(popup) {
                while (popup.hasChildNodes()) popup.removeChild(popup.firstChild);
    
                // --- Debug-Ausgabe ---
                let ucjs = window.userChrome_js;
                console.debug('[jsLoader] fillMenu aufgerufen. userChrome_js:', ucjs ? 'gefunden' : 'NICHT gefunden');
                if (ucjs) {
                    console.debug('[jsLoader] arrSubdir:', ucjs.arrSubdir);
                    console.debug('[jsLoader] scripts.length:', ucjs.scripts ? ucjs.scripts.length : 'undefined');
                    console.debug('[jsLoader] overlays.length:', ucjs.overlays ? ucjs.overlays.length : 'undefined');
                    console.debug('[jsLoader] dirDisable:', ucjs.dirDisable);
                    console.debug('[jsLoader] scriptDisable:', ucjs.scriptDisable);
                    if (ucjs.scripts && ucjs.scripts.length > 0) {
                        console.debug('[jsLoader] scripts[0].dir:', ucjs.scripts[0].dir, 'filename:', ucjs.scripts[0].filename);
                    }
                }
    
                if (!ucjs || !ucjs.scripts) {
                    let msg = document.createXULElement('menuitem');
                    msg.setAttribute('label', 'userChrome.js nicht gefunden oder nicht initialisiert');
                    msg.setAttribute('disabled', 'true');
                    popup.appendChild(msg);
                    return;
                }
    
                // Safety: dirDisable/scriptDisable können undefined sein
                if (!ucjs.dirDisable) ucjs.dirDisable = {};
                if (!ucjs.scriptDisable) ucjs.scriptDisable = {};
                if (!ucjs.overlays) ucjs.overlays = [];
    
                try {
    
                // --- Feste Menüeinträge ---
                let reuse = this.getPref("userChrome.enable.reuse", 'bool', true);
    
                let mSetting = document.createXULElement('menuitem');
                mSetting.setAttribute('label', 'Skript für jedes Fenster neuladen');
                mSetting.setAttribute('type', 'checkbox');
                mSetting.toggleAttribute('checked', !reuse);
                mSetting.addEventListener('command', () => this.setting());
                popup.appendChild(mSetting);
    
                popup.appendChild(document.createXULElement('menuseparator'));
    
                // --- Alle UserScripte aktivieren/deaktivieren ---
                let mAll = document.createXULElement('menuitem');
                mAll.setAttribute('label', 'Alle UserScripte aktivieren/deaktivieren');
                mAll.setAttribute('type', 'checkbox');
                mAll.toggleAttribute('checked', !userChrome_js.dirDisable['*']);
                mAll.dirName = '*';
                mAll.addEventListener('command', () => this.chgDirStat("*"));
                mAll.addEventListener('click', (event) => this.clickDirMenuitem(event, true));
                mAll.addEventListener('mouseup', (event) => { if (event.button == 1) event.preventDefault(); });
                popup.appendChild(mAll);
    
                // --- Pro Ordner: Script-Checkboxen direkt im Hauptpopup ---
                let foundAnyDir = false;
                let firstDir = true;
                for (let j = 0; j < ucjs.arrSubdir.length; j++) {
                    let dirName = ucjs.arrSubdir[j] === "" ? "root" : ucjs.arrSubdir[j];
                    let hasScripts = false;
    
                    for (let i = 0; i < ucjs.scripts.length; i++) {
                        if (ucjs.scripts[i].dir === dirName) { hasScripts = true; break; }
                    }
                    if (!hasScripts) {
                        for (let i = 0; i < ucjs.overlays.length; i++) {
                            if (ucjs.overlays[i].dir === dirName) { hasScripts = true; break; }
                        }
                    }
                    if (!hasScripts) continue;
    
                    if (firstDir) {
                        popup.appendChild(document.createXULElement('menuseparator'));
                        firstDir = false;
                    }
    
                    let displayDir = dirName === "root" ? "" : dirName;
    
                    let flg = false;
                    for (let i = 0; i < ucjs.scripts.length; i++) {
                        let script = ucjs.scripts[i];
                        if (script.dir !== dirName) continue;
                        flg = true;
                        let mScript = document.createXULElement('menuitem');
                        mScript.setAttribute('label', script.filename);
                        mScript.setAttribute('type', 'checkbox');
                        mScript.setAttribute('autocheck', 'false');
                        mScript.toggleAttribute('checked', !ucjs.scriptDisable[script.filename]);
                        if (script.description)
                            mScript.setAttribute('tooltiptext', script.description);
                        mScript.script = script;
                        mScript.addEventListener('command', () => this.chgScriptStat(script.filename));
                        mScript.addEventListener('click', (event) => this.clickScriptMenu(event, script));
                        mScript.addEventListener('mouseup', (event) => { if (event.button == 1) event.preventDefault(); });
                        popup.appendChild(mScript);
                    }
    
                    for (let i = 0; i < ucjs.overlays.length; i++) {
                        let script = ucjs.overlays[i];
                        if (script.dir !== dirName) continue;
                        if (flg) {
                            popup.appendChild(document.createXULElement('menuseparator'));
                        }
                        flg = false;
                        let mScript = document.createXULElement('menuitem');
                        mScript.setAttribute('label', script.filename);
                        mScript.setAttribute('type', 'checkbox');
                        mScript.setAttribute('autocheck', 'false');
                        mScript.toggleAttribute('checked', !ucjs.scriptDisable[script.filename]);
                        if (script.description)
                            mScript.setAttribute('tooltiptext', script.description);
                        mScript.script = script;
                        mScript.addEventListener('command', () => this.chgScriptStat(script.filename));
                        mScript.addEventListener('click', (event) => this.clickScriptMenu(event, script));
                        mScript.addEventListener('mouseup', (event) => { if (event.button == 1) event.preventDefault(); });
                        popup.appendChild(mScript);
                    }
    
                    foundAnyDir = true;
                }
    
                // Falls keine Scripts gefunden wurden, Hinweis anzeigen
                if (!foundAnyDir) {
                    let noScripts = document.createXULElement('menuitem');
                    noScripts.setAttribute('label', 'Keine UserScripte gefunden (Ordner: ' + ucjs.arrSubdir.join(', ') + ')');
                    noScripts.setAttribute('disabled', 'true');
                    popup.appendChild(noScripts);
                }
    
                } catch (e) {
                    console.error('[jsLoader] Fehler in fillMenu:', e);
                    let errMsg = document.createXULElement('menuitem');
                    errMsg.setAttribute('label', 'Fehler: ' + e.message);
                    errMsg.setAttribute('disabled', 'true');
                    popup.appendChild(errMsg);
                }
            },
    
            setting: function() {
                let flag = this.getPref("userChrome.enable.reuse", 'bool', true);
                this.setPref("userChrome.enable.reuse", 'bool', !flag);
            },
    
            clickDirMenu: function(event) {
                if (event.button == 1 || event.button == 2) {
                    event.stopPropagation();
                    event.preventDefault();
                    this.chgDirStat(event.target.dirName);
                    if (event.target.firstChild && event.target.firstChild.firstChild)
                        event.target.firstChild.firstChild.toggleAttribute('checked', !userChrome_js.dirDisable[event.target.dirName]);
                    if (!!userChrome_js.dirDisable[event.target.dirName])
                        event.target.setAttribute('style', 'font-style:italic;');
                    else
                        event.target.removeAttribute('style');
                }
            },
    
            clickDirMenuitem: function(event, stop) {
                if (event.button == 1 || event.button == 2) {
                    event.stopPropagation();
                    event.preventDefault();
                    this.chgDirStat(event.target.dirName);
                    event.target.toggleAttribute('checked', !userChrome_js.dirDisable[event.target.dirName]);
                    if (!stop && !!userChrome_js.dirDisable[event.target.dirName])
                        event.target.parentNode.parentNode.setAttribute('style', 'font-style:italic;');
                    else
                        event.target.parentNode.parentNode.removeAttribute('style');
                }
            },
    
            clickScriptMenu: function(event, script) {
                if (event.button == 1) {
                    event.stopPropagation();
                    event.preventDefault();
                    this.chgScriptStat(script.filename);
                    event.target.toggleAttribute('checked', !userChrome_js.scriptDisable[script.filename]);
                } else if (event.button == 2) {
                    event.stopPropagation();
                    event.preventDefault();
                    this.launchEditor(script);
                }
            },
    
            launchEditor: function(aScript) {
                let editor = Appmenu.editor;
                let path = Services.io.newURI(aScript.url).QueryInterface(Ci.nsIFileURL).file.path;
                let appfile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
                appfile.initWithPath(editor);
                let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
                process.init(appfile);
                process.runw(false, [path], 1, {});
            },
    
            chgDirStat: function(adirName) {
                let s = this.getPref("userChrome.disable.directory", "str", "");
                if (!userChrome_js.dirDisable[adirName]) {
                    s = (s + ',').replace(adirName + ',', '') + adirName + ',';
                } else {
                    s = (s + ',').replace(adirName + ',', '');
                }
                s = s.replace(/,,/g, ',').replace(/^,/, '');
                this.setPref("userChrome.disable.directory", "str", s);
                userChrome_js.dirDisable = this.restoreState(s.split(','));
            },
    
            chgScriptStat: function(afilename) {
                let s = this.getPref("userChrome.disable.script", "str", "");
                if (!userChrome_js.scriptDisable[afilename]) {
                    s = (s + ',').replace(afilename + ',', '') + afilename + ',';
                } else {
                    s = (s + ',').replace(afilename + ',', '');
                }
                s = s.replace(/,,/g, ',').replace(/^,/, '');
                this.setPref("userChrome.disable.script", "str", s);
                userChrome_js.scriptDisable = this.restoreState(s.split(','));
            },
    
            restoreState: function(arr) {
                let disable = [];
                for (let i = 0; i < arr.length; i++) disable[arr[i]] = true;
                return disable;
            },
    
            getPref: function(aPrefString, aPrefType, aDefault) {
                let xpPref = Services.prefs;
                try {
                    switch (aPrefType) {
                        case 'complex': return xpPref.getComplexValue(aPrefString, Ci.nsIFile);
                        case 'str': return unescape(xpPref.getCharPref(aPrefString).toString());
                        case 'int': return xpPref.getIntPref(aPrefString);
                        case 'bool': default: return xpPref.getBoolPref(aPrefString);
                    }
                } catch (e) {}
                return aDefault;
            },
    
            setPref: function(aPrefString, aPrefType, aValue) {
                let xpPref = Services.prefs;
                try {
                    switch (aPrefType) {
                        case 'complex': return xpPref.setComplexValue(aPrefString, Ci.nsIFile, aValue);
                        case 'str': return xpPref.setCharPref(aPrefString, escape(aValue));
                        case 'int': aValue = parseInt(aValue); return xpPref.setIntPref(aPrefString, aValue);
                        case 'bool': default: return xpPref.setBoolPref(aPrefString, aValue);
                    }
                } catch (e) {}
                return null;
            },
    
            addPrefListener: function(aObserver) {
                try { Services.prefs.addObserver(aObserver.domain, aObserver, false); }
                catch (e) {}
            },
    
            removePrefListener: function(aObserver) {
                try { Services.prefs.removeObserver(aObserver.domain, aObserver); }
                catch (e) {}
            },
    
            readLaterPrefListener: {
                domain: 'userChrome.disable',
                observe: function(aSubject, aTopic, aPrefstring) {
                    if (aTopic == 'nsPref:changed') {
                        setTimeout(function() {
                            let s = Appmenu.jsLoader.getPref("userChrome.disable.directory", "str", "");
                            userChrome_js.dirDisable = Appmenu.jsLoader.restoreState(s.split(','));
                            s = Appmenu.jsLoader.getPref("userChrome.disable.script", "str", "");
                            userChrome_js.scriptDisable = Appmenu.jsLoader.restoreState(s.split(','));
                        }, 0);
                    }
                }
            },
        },
    
        toolbar: {
          subdirs: [
            {
              name: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/folder_currentColor.svg`,
            },
            {
              name: 'Firefox Funktionen',
              image: `${ProfilePath}/settings_currentColor.svg`,
            },
            {
              name: 'separator',
            },
            {
              name: 'Meine Scripte',
              image: `${ProfilePath}/${Icon31}`,
            },
            {
              name: 'Meine CSS-Dateien',
              image: `${ProfilePath}/${Icon32}`,
            },
            {
              name: 'Meine CSSWeb-Dateien',
              image: `${ProfilePath}/${Icon33}`,
            },
            {
              name: 'Skriptliste in Zwischenablage',
              image: `${ProfilePath}/${Icon34}`,
              command: () => Appmenu.getScripts(1),
              tooltiptext: 'Kopiert eine Liste aller uc.js-Skripte in die Zwischenablage',
            },
            {
              name: 'separator',
            },
            {
              name: 'JavaScript-Loader-Menü',
              image: `${ProfilePath}/${Icon04}`,
            },
            {
              name: 'CSS-Loader-Menü',
              image: `${ProfilePath}/css4_currentColor.svg`,
            },
            {
              name: 'Konfiguration',
              image: `${ProfilePath}/Hammer-wrench_currentColor.svg`,
            },
            {
              name: '"about:"-Seiten',
              image: `${ProfilePath}/firefox_currentColor.svg`,
            },
          ],
    
          apps: [
            {
              name: 'Profil-Verzeichnis',
              id: 'AMProfil',
              root: 'ProfD',
              path: '\\',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon01}`,
            },
            {
              name: 'Chrome-Ordner',
              id: 'AMchrome',
              root: 'ProfD',
              path: '\\chrome',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon02}`,
            },
            {
              name: 'CSS-Ordner',
              id: 'AMCSS',
              root: 'ProfD',
              path: '\\chrome\\css',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon03}`,
            },
            {
              name: 'CSS-Web-Ordner',
              id: 'AMWEB',
              root: 'ProfD',
              path: '\\chrome\\cssWeb',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon03}`,
            },
            {
              name: 'JS-Ordner',
              id: 'AMJS',
              root: 'ProfD',
              path: '\\chrome\\scripts',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon04}`,
            },
            {
              name: 'Icons-Ordner',
              id: 'AMICO',
              root: 'ProfD',
              path: '\\chrome\\icons',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon05}`,
            },
            {
              name: 'Addon-Verzeichnis',
              id: 'AMAddons',
              root: 'ProfD',
              path: '\\extensions',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon06}`,
            },
            {
              name: 'Programm-Verzeichnis',
              id: 'AMProgramm',
              root: 'CurProcD',
              path: '\\',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon07}`,
            },
            {
              name: 'Startup-Cache',
              id: 'AMCache',
              root: 'ProfLD',
              path: '\\startupCache',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon08}`,
            },
          ],
    
          configs: [
            {
              name: 'Anpassen',
              id: 'AMAnpassen',
              command: 'gCustomizeMode.enter()',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon11}`,
            },
            {
              name: 'Neustart im abgesicherten Modus',
              id: 'AMModus',
              command: 'safeModeRestart();',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon12}`,
            },
            {
              name: 'Browser-Konsole',
              id: 'AMKonsole',
              command: 'goKonsole',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon13}`,
            },
            {
              name: 'Browser-Werkzeuge',
              id: 'AMWerkzeuge',
              command: 'goWerkzeuge',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon14}`,
            },
            {
              name: 'Web-Entwickler',
              id: 'AMEntwickler',
              command: 'goEntwickler',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon15}`,
            },
            {
              name: 'Firefox synchronisieren',
              id: 'AMsynchron',
              command: 'gSync',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon16}`,
            },
            {
              name: 'Zugangsdaten und Passwörter',
              id: 'AMdaten',
              command: 'LoginHelper.openPasswordManager(window, { entryPoint: "mainmenu" })',
              tooltiptext: 'about:logins',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon17}`,
            },
            {
              name: 'Task Manager',
              id: 'AMManager',
              command: 'switchToTabHavingURI("about:processes", true)',
              tooltiptext: 'about:processes',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon18}`,
            },
            {
              name: 'Offline arbeiten',
              id: 'AMOffline',
              command: 'BrowserOffline.toggleOfflineStatus();',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon19}`,
            },
            {
              name: 'Neustart (inkl. Script Cache leeren)',
              id: 'AMreboot',
              tooltiptext: 'userChrome.js-Cache wird geleert',
              command: 'goReeboot',
              image: `${ProfilePath}/${ButtonIcon01}`,
            },
            {
              name: 'Beenden',
              id: 'AMquit',
              command: 'goQuitApplication(event);',
              image: `${ProfilePath}/${ButtonIcon02}`,
            },
            // uProfMenu-Funktionen unter Menüeintrag "Konfiguration"
            {
              name: 'userChrome.css bearbeiten',
              id: 'AMuserChromeCss',
              command: () => Appmenu.edit(0, 'userChrome.css'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/css4.svg`,
            },
            {
              name: 'userChromeShadow.css bearbeiten',
              id: 'AMuserChromeShadowCss',
              command: () => Appmenu.edit(0, 'userChromeShadow.css'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/css4.svg`,
            },
            {
              name: 'userContent.css bearbeiten',
              id: 'AMuserContentCss',
              command: () => Appmenu.edit(0, 'userContent.css'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/css4.svg`,
            },
            {
              name: 'userChrome.js bearbeiten',
              id: 'AMuserChromeJs',
              command: () => Appmenu.edit(0, 'userChrome.js'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/js.svg`,
            },
            {
              name: 'prefs.js bearbeiten',
              id: 'AMprefsJs',
              command: () => Appmenu.edit(1, 'prefs.js'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/js.svg`,
            },
            {
              name: 'user.js bearbeiten',
              id: 'AMuserJs',
              command: () => Appmenu.edit(1, 'user.js'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/js.svg`,
            },
            // about:-Seiten
            {
              name: 'about:about',
              id: 'AMaboutAbout',
              command: () => openTrustedLinkIn("about:about", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon21}`,
            },
            {
              name: 'about:addons',
              id: 'AMaboutAddons',
              command: () => openTrustedLinkIn("about:addons", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon40}`,
            },
            {
              name: 'about:cache',
              id: 'AMaboutCache',
              command: () => openTrustedLinkIn("about:cache", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon22}`,
            },
            {
              name: 'about:config',
              id: 'AMaboutConfig',
              command: () => openTrustedLinkIn("about:config", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon23}`,
            },
            {
              name: 'about:crashes',
              id: 'AMaboutCrashes',
              command: () => openTrustedLinkIn("about:crashes", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon24}`,
            },
            {
              name: 'about:downloads',
              id: 'AMaboutDownloads',
              command: () => openTrustedLinkIn("about:downloads", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon25}`,
            },
            {
              name: 'about:home',
              id: 'AMaboutHome',
              command: () => openTrustedLinkIn("about:home", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon26}`,
            },
            {
              name: 'about:logins',
              id: 'AMaboutLogins',
              command: 'LoginHelper.openPasswordManager(window, { entryPoint: "mainmenu" })',
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon27}`,
            },
            {
              name: 'about:support',
              id: 'AMaboutSupport',
              command: () => openTrustedLinkIn("about:support", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon28}`,
            },
            {
              name: 'about:preferences',
              id: 'AMaboutPreferences',
              command: () => openTrustedLinkIn("about:preferences", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon29}`,
            },
            {
              name: 'about:processes',
              id: 'AMaboutProcesses',
              command: () => openTrustedLinkIn("about:processes", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon41}`,
            },
            {
              name: 'about:profiles',
              id: 'AMaboutProfiles',
              command: () => openTrustedLinkIn("about:profiles", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon30}`,
            },
          ]
        },
        _externalAppPopup: null,
        _isready: false,
    
        // uProfMenu-Funktionen (bereits integriert)
        getDirSep: function() {
          var osString = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULRuntime).OS;
          var dirsep = "/";
          switch(osString) {
            case "WINNT":
              dirsep = "\\";
              break;
            case "Darwin":
              dirsep = "/";
              break;
          }
          return dirsep;
        },
        getPrefDirectoryPath: function(str) {
          var file = Components.classes["@mozilla.org/file/directory_service;1"]
            .getService(Components.interfaces.nsIProperties)
            .get(str, Components.interfaces.nsIFile);
          if (str == 'CurProcD') {
            file = file.parent;
          }
          return file.path;
        },
        edit: function(OpenMode, Filename) {
          var Path = "";
          var dSep = this.getDirSep();
          // Wenn der Dateiname einen Pfad enthält (z. B. "chrome/scripts/test.uc.js"),
          // vom Profil-Verzeichnis aus auflösen:
          if (Filename.includes("/") || Filename.includes("\\")) {
            Path = this.getPrefDirectoryPath("ProfD") + dSep + Filename.replace(/\//g, dSep);
          } else {
            switch (OpenMode) {
              case 0:
                Path = this.getPrefDirectoryPath("UChrm") + dSep + Filename;
                break;
              case 1:
                Path = this.getPrefDirectoryPath("ProfD") + dSep + Filename;
                break;
              case 3:
                Path = this.getPrefDirectoryPath("UChrm") + dSep + "CSS" + dSep + Filename;
                break;
              case 4:
                Path = this.getPrefDirectoryPath("UChrm") + dSep + "CSSWeb" + dSep + Filename;
                break;
              case 5:
                Path = this.getPrefDirectoryPath("UChrm") + dSep + "CSSShadow" + dSep + Filename;
                break;
            }
          }
          this.launch(this.editor, Path);
        },
        launch: function(RanPath, OpenPath) {
          var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);
          var proc = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
          var args = [OpenPath];
          file.initWithPath(RanPath);
          if (!file.exists()) {
            var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
            RanPath = pref.getCharPref("view_source.editor.path");
            file.initWithPath(RanPath);
          }
          proc.init(file);
          proc.run(false, args, args.length);
        },
    
        // ■■ Neu: Script- und CSS-Listen (aus extras_config_menu.uc.js integriert) ■■
    
        getScripts: function(iType) {
          let ucJsScripts = [];
          let extjs = /\.uc\.js$/i;
    
          // 1. Standard-UChrm-Ordner durchsuchen
          let uchrmFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
          if (uchrmFolder.exists()) {
            let files = uchrmFolder.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
            while (files.hasMoreElements()) {
              let file = files.getNext().QueryInterface(Ci.nsIFile);
              if (extjs.test(file.leafName)) {
                if (file.leafName === "userChromeShadow.uc.js" && !this.showuCS) continue;
                ucJsScripts.push(file.leafName);
              }
            }
          }
    
          // 2. chrome/scripts-Unterverzeichnis durchsuchen
          if (this.jsSubfolder) {
            let scriptsFolder = Services.dirsvc.get("ProfD", Ci.nsIFile);
            scriptsFolder.append("chrome");
            scriptsFolder.append(this.jsSubfolder);
            if (scriptsFolder.exists()) {
              let files = scriptsFolder.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
              while (files.hasMoreElements()) {
                let file = files.getNext().QueryInterface(Ci.nsIFile);
                if (extjs.test(file.leafName)) {
                  ucJsScripts.push("chrome/" + this.jsSubfolder + "/" + file.leafName);
                }
              }
            }
          }
    
          if (this.sortScripts) ucJsScripts.sort(this.stringComparison.bind(this));
    
          if (iType === 0) {
            // Untermenü "Meine Scripte" befüllen
            this.fillFileMenu("Meine Scripte", "Meine Scripte", ucJsScripts, 0);
          } else {
            // Für Zwischenablage: Nur Dateinamen (ohne Pfad) verwenden
            let simpleNames = ucJsScripts.map(f => f.split(/[\\/]/).pop());
            let result = this.fillClipboardValue(simpleNames);
            Components.classes["@mozilla.org/widget/clipboardhelper;1"]
              .getService(Components.interfaces.nsIClipboardHelper).copyString(result);
          }
        },
    
        getCssFiles: function(iType) {
          let cssFiles = [];
          let extcss = /\.css$/i;
          let folderName = "";
          let subdirName = "";
          let menuLabel = "";
          let sType = 0;
    
          if (iType === 3) {
            folderName = "CSS";
            subdirName = "Meine CSS-Dateien";
            menuLabel = "Meine CSS-Dateien";
            sType = 3;
          } else if (iType === 4) {
            folderName = "CSSWeb";
            subdirName = "Meine CSSWeb-Dateien";
            menuLabel = "Meine CSSWeb-Dateien";
            sType = 4;
          } else if (iType === 5) {
            folderName = "CSSShadow";
            subdirName = "Meine CSSShadow-Dateien";
            menuLabel = "Meine CSSShadow-Dateien";
            sType = 5;
          } else {
            return;
          }
    
          let aFolder = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
          aFolder.initWithPath(Services.dirsvc.get("UChrm", Ci.nsIFile).path + this.getDirSep() + folderName);
    
          if (aFolder.exists() && aFolder.isDirectory()) {
            let files = aFolder.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
            while (files.hasMoreElements()) {
              let file = files.getNext().QueryInterface(Ci.nsIFile);
              if (extcss.test(file.leafName)) cssFiles.push(file.leafName);
            }
          }
    
          if (this.sortScripts) cssFiles.sort(this.stringComparison.bind(this));
          this.fillFileMenu(subdirName, menuLabel, cssFiles, sType);
        },
    
        fillFileMenu: function(subdirName, strlabel, fileArray, sType) {
          let submenuItem = Appmenu.subdirMenuHash[subdirName];
          if (submenuItem) {
            submenuItem.setAttribute('label', strlabel + ' (' + fileArray.length + ')');
          }
          let popup = Appmenu.subdirPopupHash[subdirName];
          if (!popup) return;
          // Vorhandene Einträge löschen
          while (popup.hasChildNodes()) popup.removeChild(popup.firstChild);
    
          // Symbol je nach Dateityp festlegen
          let iconPath = '';
          if (sType === 0) {
            iconPath = ProfilePath + '/' + Icon04;       // js.svg
          } else {
            iconPath = ProfilePath + '/' + Icon03;       // css4.svg
          }
    
          for (let i = 0; i < fileArray.length; i++) {
            let fileName = fileArray[i];
            let mitem = document.createXULElement('menuitem');
            mitem.setAttribute('class', 'menuitem-iconic');
            mitem.setAttribute('image', iconPath);
    
            if (sType === 0) {
              // Scripts: Linksklick = Bearbeiten, Mittelklick = GitHub, Rechtsklick = GitHub-Suche
              let displayName = fileName.split(/[\\/]/).pop();
              mitem.setAttribute('label', displayName);
              mitem.addEventListener('command', function() {
                Appmenu.edit(0, fileName);
              }, true);
              mitem.addEventListener('click', function(event) {
                Appmenu.openAtGithub(event, displayName);
              }, true);
              mitem.setAttribute('tooltiptext',
                'Linksklick: Bearbeiten,\nMittelklick: GitHub-Seite öffnen,\nRechtsklick: GitHub-Suche');
            } else if (sType === 3) {
              mitem.setAttribute('label', fileName);
              mitem.addEventListener('command', function() {
                Appmenu.edit(3, fileName);
              }, true);
            } else if (sType === 4) {
              mitem.setAttribute('label', fileName);
              mitem.addEventListener('command', function() {
                Appmenu.edit(4, fileName);
              }, true);
            } else if (sType === 5) {
              mitem.setAttribute('label', fileName);
              mitem.addEventListener('command', function() {
                Appmenu.edit(5, fileName);
              }, true);
            }
            popup.appendChild(mitem);
          }
        },
    
        fillClipboardValue: function(sArray) {
          var retValue = "Meine Skripte (" + sArray.length + "):\n------------------------";
          for (var i = 0; i < sArray.length; i++) {
            retValue += "\n" + (i + 1) + ". " + sArray[i];
          }
          return retValue;
        },
    
        openAtGithub: function(e, sScript) {
          if (e.button == 1) {
            var sUrl = "https://github.com/ardiman/userChrome.js/tree/master/" + this.cleanFileName(sScript);
            openWebLinkIn(sUrl, 'tab');
          }
          if (e.button == 2) {
            e.preventDefault();
            var sUrl = "https://github.com/search?langOverride=&language=&q=" + sScript + "&repo=&start_value=1&type=Code";
            openWebLinkIn(sUrl, 'tab');
          }
        },
    
        cleanFileName: function(sName) {
          sName = sName.toLowerCase();
          var regs = [/\.uc\.js$/, /\.uc\.xul$/, /^ucjs_/, /_\d.+/, /_fx\d+/, /[-+\.]/g, /_v\d+/];
          for (var i = 0; i < regs.length; i++) {
            sName = sName.replace(regs[i], "");
          }
          return sName;
        },
    
        stringComparison: function(a, b) {
          a = a.toLowerCase().replace(/ä/g,"a").replace(/ö/g,"o").replace(/ü/g,"u").replace(/ß/g,"s");
          b = b.toLowerCase().replace(/ä/g,"a").replace(/ö/g,"o").replace(/ü/g,"u").replace(/ß/g,"s");
          return (a == b) ? 0 : (a > b) ? 1 : -1;
        },
    
        init: function() {
          this.handleRelativePath(this.toolbar.apps);
          const XULNS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
          var ExternalAppBtn = document.createElementNS(XULNS, 'toolbarbutton');
          ExternalAppBtn.id = 'AppMenuButton';
          ExternalAppBtn.setAttribute('label', 'AppButton');
          ExternalAppBtn.addEventListener('click', event => {
            event.preventDefault();
            event.stopPropagation();
          });
          ExternalAppBtn.setAttribute('tooltiptext', 'Firefox Menü');
          ExternalAppBtn.setAttribute('type', 'menu');
          ExternalAppBtn.setAttribute('removable', 'true');
    
          let ProfilePath = PathUtils.toFileURI(
            PathUtils.join(PathUtils.profileDir, 'chrome', 'image')
          );
    
          let DefaultIcon = 'Button_groß.png';
          let AlternateIcon = 'Button_klein-5.png';
          if (Appmenu.isButton) {
            ExternalAppBtn.style.listStyleImage = `url('${ProfilePath}/${DefaultIcon}')`;
            ExternalAppBtn.style.width = '94px';
            ExternalAppBtn.style.height = '24px';
          } else {
            ExternalAppBtn.style.listStyleImage = `url('${ProfilePath}/${AlternateIcon}')`;
            ExternalAppBtn.style.width = '48px';
            ExternalAppBtn.style.height = '21px';
          }
    
          if (Appmenu.isUrlbar === 1) {
            var navBar = document.getElementById('nav-bar-customization-target');
            navBar.insertBefore(ExternalAppBtn, navBar.firstChild);
          } else if (Appmenu.isUrlbar === 2) {
            var menubar = document.getElementById('toolbar-menubar');
            menubar.insertBefore(ExternalAppBtn, menubar.firstChild);
          } else {
            var TabsToolbar = document.getElementById('TabsToolbar');
            TabsToolbar.insertBefore(ExternalAppBtn, TabsToolbar.firstChild);
          }
          var ExternalAppPopup = document.createElementNS(XULNS, 'menupopup');
          ExternalAppPopup.addEventListener('click', event => {
            event.stopPropagation();
          });
          ExternalAppPopup.setAttribute('id', 'AMpopup');
          this._externalAppPopup = ExternalAppPopup;
          ExternalAppBtn.appendChild(ExternalAppPopup);
          Appmenu.onpopupshowing();
    
          // CSS-Loader initialisieren
          this.cssLoader.initCSSLoader();
    
          // JS-Loader initialisieren (Pref-Listener registrieren)
          this.jsLoader.init();
    
          // Menü mit Tastaturkürzel öffnen
          if (Appmenu.hotkey) {
            let key = document.createXULElement('key');
            key.id = 'key_AppMenuPopup';
            key.setAttribute('key', Appmenu.hotkey);
            if (Appmenu.hotkeyModifier)
              key.setAttribute('modifiers', Appmenu.hotkeyModifier);
            key.addEventListener('command', function () {
              document.getElementById('AMpopup').openPopup();
            });
            document.getElementById('mainKeyset').appendChild(key);
          }
        },
    
        onpopupshowing: function() {
          if (this._isready) return;
          if (this._externalAppPopup === null) return;
          var ExternalAppPopup = this._externalAppPopup;
          for (let subdir of this.toolbar.subdirs) {
            if (subdir.name == 'separator') {
              ExternalAppPopup.appendChild(document.createXULElement('menuseparator'));
            } else if (subdir.command) {
              var actionItem = ExternalAppPopup.appendChild(document.createXULElement('menuitem'));
              actionItem.setAttribute('class', 'menuitem-iconic');
              actionItem.setAttribute('label', subdir.name);
              actionItem.setAttribute('image', subdir.image);
              if (subdir.tooltiptext) {
                actionItem.setAttribute('tooltiptext', subdir.tooltiptext);
              } else {
                actionItem.setAttribute('tooltiptext', subdir.name);
              }
              actionItem.addEventListener('command', subdir.command);
            } else {
              var subdirItem = ExternalAppPopup.appendChild(document.createXULElement('menu'));
              var subdirItemPopup = subdirItem.appendChild(document.createXULElement('menupopup'));
              subdirItem.setAttribute('class', 'menu-iconic');
              subdirItem.setAttribute('label', subdir.name);
              subdirItem.setAttribute('image', subdir.image);
              Appmenu.subdirPopupHash[subdir.name] = subdirItemPopup;
              Appmenu.subdirMenuHash[subdir.name] = subdirItem;
    
              // CSS-Loader-Menüeinträge für "CSS-Loader-Menü"
              if (subdir.name === "CSS-Loader-Menü") {
                Appmenu.cssLoader.rebuildCSSMenu();
              }
              // Neue dynamische Untermenüs befüllen
              if (subdir.name === "Meine Scripte") {
                Appmenu.getScripts(0);
              }
              if (subdir.name === "Meine CSS-Dateien") {
                Appmenu.getCssFiles(3);
              }
              if (subdir.name === "Meine CSSWeb-Dateien") {
                Appmenu.getCssFiles(4);
              }
              // JavaScript-Loader-Menü: popupshowing-Listener für dynamischen Aufbau
              // Wichtig: nur bei e.target === e.currentTarget ausführen,
              // sonst bubbelt popupshowing von Kind-Popups hoch und führt zu Endlosschleife
              if (subdir.name === "JavaScript-Loader-Menü") {
                subdirItemPopup.addEventListener('popupshowing', (e) => {
                  if (e.target === e.currentTarget) Appmenu.jsLoader.fillMenu(e.target);
                });
              }
            }
          }
          for (let app of this.toolbar.apps) {
            var appItem;
            if (app.name == 'separator') {
              appItem = document.createXULElement('menuseparator');
            } else {
              appItem = document.createXULElement('menuitem');
              appItem.setAttribute('class', 'menuitem-iconic');
              appItem.setAttribute('label', app.name);
              appItem.setAttribute('image', app.image);
              appItem.addEventListener('command', function () {
                Appmenu.exec(this.path, this.args);
              });
              appItem.setAttribute('tooltiptext', app.name);
              appItem.path = app.path;
              appItem.args = app.args;
            }
            if (app.subdir && Appmenu.subdirPopupHash[app.subdir])
              Appmenu.subdirPopupHash[app.subdir].appendChild(appItem);
            else ExternalAppPopup.appendChild(appItem);
          }
          for (let config of this.toolbar.configs) {
            var configItem;
            if (config.name == 'separator') {
              configItem = document.createXULElement('menuseparator');
            } else {
              configItem = ExternalAppPopup.appendChild(document.createXULElement('menuitem'));
              configItem.setAttribute('class', 'menuitem-iconic');
              configItem.setAttribute('label', config.name);
              configItem.setAttribute('image', config.image);
              configItem.addEventListener('command', () => {
                if (typeof config.command === 'function') {
                  config.command();
                } else {
                  Appmenu.executeCommand(config.command);
                }
              });
              if (config.tooltiptext) {
                configItem.setAttribute('tooltiptext', config.tooltiptext);
              } else {
                configItem.setAttribute('tooltiptext', config.name);
              }
              configItem.setAttribute('id', config.id);
            }
    
            if (config.subdir && Appmenu.subdirPopupHash[config.subdir]) {
              Appmenu.subdirPopupHash[config.subdir].appendChild(configItem);
            } else {
              ExternalAppPopup.appendChild(configItem);
            }
          }
          if (this.autohideEmptySubDirs) {
            // Lazy-gefüllte Untermenüs nicht verstecken (werben erst beim Aufklappen befüllt)
            let lazySubdirs = ['JavaScript-Loader-Menü'];
            for (let key of Object.keys(Appmenu.subdirPopupHash)) {
              if (lazySubdirs.includes(key)) continue;
              if (Appmenu.subdirPopupHash[key].hasChildNodes()) {
                continue;
              } else {
                Appmenu.subdirMenuHash[key].setAttribute('hidden', 'true');
              }
            }
          }
          if (this.moveSubDirstoBottom) {
            let i = ExternalAppPopup.childNodes.length;
            while (ExternalAppPopup.firstChild.getAttribute('class') != 'menuitem-iconic' && i-- != 0) {
              ExternalAppPopup.appendChild(ExternalAppPopup.firstChild);
            }
          }
          this._isready = true;
        },
    
        executeCommand: function(command) {
          const commandMap = {
            'gCustomizeMode.enter()': () => gCustomizeMode.enter(),
            'safeModeRestart();': () => safeModeRestart(),
            'goKonsole': () => {
                    var { require } = ChromeUtils.importESModule('resource://devtools/shared/loader/Loader.sys.mjs', {});
                    var { BrowserConsoleManager } = require('resource://devtools/client/webconsole/browser-console-manager');
                    BrowserConsoleManager.openBrowserConsoleOrFocus();
                  },
            'goWerkzeuge': () => {
                    var { require } = ChromeUtils.importESModule('resource://devtools/shared/loader/Loader.sys.mjs', {});
                    var { BrowserToolboxLauncher } = require('resource://devtools/client/framework/browser-toolbox/Launcher.sys.mjs');
                    BrowserToolboxLauncher.init();
                  },
            'goEntwickler': () => {
                    var { require } = ChromeUtils.importESModule('resource://devtools/shared/loader/Loader.sys.mjs', {});
                    var { gDevToolsBrowser } = require('resource://devtools/client/framework/devtools-browser');
                    gDevToolsBrowser.toggleToolboxCommand(window.gBrowser, performance.now());
                  },
            'gSync': () => gSync.openPrefs('menubar'),
            'LoginHelper.openPasswordManager(window, { entryPoint: "mainmenu" })': () => LoginHelper.openPasswordManager(window, { entryPoint: 'mainmenu' }),
            'switchToTabHavingURI("about:processes", true)': () => switchToTabHavingURI('about:processes', true),
            'BrowserOffline.toggleOfflineStatus();': () => BrowserOffline.toggleOfflineStatus(),
            'goReeboot': () => {
                      Services.appinfo.invalidateCachesOnRestart();
                      Services.startup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
                    },
            'goQuitApplication(event);': () => goQuitApplication(event),
          };
          if (commandMap[command]) {
            commandMap[command]();
          } else {
            console.warn('Unbekannter Befehl: ', command);
          }
        },
    
        handleRelativePath: function(apps) {
          for (let app of apps) {
            if (app.path) {
              app.path = app.path.replace(/\//g, '\\');
              var ffdir = Cc['@mozilla.org/file/directory_service;1'].getService(Ci.nsIProperties).get(app.root, Ci.nsIFile).path;
              if (/^(\\)/.test(app.path)) {
                app.path = ffdir + app.path;
              }
            }
          }
        },
    
        exec: function(path, args) {
          args = args || [];
          var args_t = args.slice(0);
          for (let arg of args_t) {
            arg = arg.replace(/%u/g, gBrowser.currentURI.spec);
          }
          var file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
          file.initWithPath(path);
          if (!file.exists()) {
            alert('Datei nicht gefunden: ' + path);
            return;
          }
          if (file.isExecutable() && !path.endsWith('.js')) {
            var process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
            process.init(file);
            process.run(false, args_t, args_t.length);
          } else if (file.isFile()) {
            if (this.editor) {
              let UI = Cc['@mozilla.org/intl/scriptableunicodeconverter'].createInstance(Ci.nsIScriptableUnicodeConverter);
              UI.charset = window.navigator.platform.toLowerCase().includes("win") ? "Shift_JIS" : "UTF-8";
              let path = UI.ConvertFromUnicode(file.path);
              let app = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
              app.initWithPath(this.editor);
              let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
              process.init(app);
              process.run(false, [path], 1);
            } else {
              file.launch();
            }
          } else if (file.isDirectory()) {
            if (this.fileManager) {
              let args=[this.FMParameter,path];
              let app = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
              app.initWithPath(this.fileManager);
              let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
              process.init(app);
              process.run(false, args, args.length);
            } else {
              file.launch();
            }
          }
        },
      };
    
    /* ***************************************************************************************************************************** */
    
      // CSSEntry-Klasse (aus UserCSSLoader)
      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();
            let lastModifiedTime = isExists ? aFile.lastModifiedTime : 0;
            let isForced = this.lastModifiedTime != lastModifiedTime;
            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)) {
                if (!isEnable || !isExists) {
                    this.sss.unregisterSheet(uri, this.SHEET);
                } else if (isForced) {
                    this.sss.unregisterSheet(uri, this.SHEET);
                    this.sss.loadAndRegisterSheet(uri, this.SHEET);
                }
            } else {
                if (isEnable && isExists) {
                    this.sss.loadAndRegisterSheet(uri, this.SHEET);
                }
            }
    
            this.lastModifiedTime = lastModifiedTime;
            return this._enabled = isEnable;
        },
      };
    
      (function () {
        let sss = Components.classes['@mozilla.org/content/style-sheet-service;1'].getService(Components.interfaces.nsIStyleSheetService);
        let uri = Services.io.newURI(
          'data:text/css;charset=utf-8,' +
            encodeURIComponent(`
              menuitem[label="Profil-Verzeichnis"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Chrome-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="CSS-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="CSS-Web-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="JS-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Icons-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Addon-Verzeichnis"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Programm-Verzeichnis"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Startup-Cache"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              #AMAnpassen     { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMModus        { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMKonsole      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMWerkzeuge    { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMEntwickler   { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMsynchron     { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMdaten        { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMManager      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMOffline      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              /* Neustart-Button */
              #AMreboot { -moz-context-properties: fill, fill-opacity !important; fill: #fbc96e !important; padding-left: 13px !important; }
              #AMreboot > img:nth-child(1) { width: 16px !important; height: 16px !important; }
              /* Beenden-Button */
              #AMquit { -moz-context-properties: fill, fill-opacity !important; fill: red !important; }
    
              /* Skriptliste in Zwischenablage */
              #AMscriptList    { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              /* about:-Seiten */
              #AMaboutAbout        { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutAddons       { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutCache        { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutConfig       { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutCrashes      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutDownloads    { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutHome         { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutLogins       { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutSupport      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutPreferences  { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutProcesses    { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutProfiles     { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              /* uProfMenu-Einträge */
              #AMuserChromeCss      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMuserChromeShadowCss { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMuserContentCss     { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMuserChromeJs      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMprefsJs            { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMuserJs             { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              /* 1 */
              menuitem[subdir="CSS-Loader-Menü"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menu[label="JavaScript-Loader-Menü"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #appmenu-css-CSS-Ordner-öffnen { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
            `),
          null,
          null
        );
        sss.loadAndRegisterSheet(uri, sss.AUTHOR_SHEET);
      })();
    
      if (window.gBrowser) Appmenu.init();
    Alles anzeigen
  • Meine Version des App-Menüs (JavaScript)

    • Mira_Belle
    • 30. August 2026 um 11:04

    Eine neue Version dieses Scripts!
    Langsam aber sicher entwickelt es sich zu einer eierlegenden Wollmilchsau. :D

    JavaScript
    // ==UserScript==
    // @name           Appmenu.uc.js
    // @namespace      Appmenu@gmail.com
    // @description    Basiert auf dem Script externalFuncButtonM.uc.js, Wiederherstellung der Orangenen FF-Menü Schaltfläche
    // @include        main
    // @author         defpt
    // @charset        UTF-8
    // @edit           2025.10.05 mit integriertem CSS-Loader-Menü und Konfiguration-Menü,
    // @edit           zum direkten bearbeiten verschiedener Dateien.
    // @edit           Sowie der Möglichkeit direkt verschiedene "about:"-Seiten aufrufen zu können.
    // @edit           2026.08.29 Aufruf von Verzeichnissen und "about:"-Seiten erweitert.
    // @edit           2026.08.30 integriert: Meine Scripte, Meine CSS-Dateien, Meine CSSWeb-Dateien,
    // @edit           Skriptliste in Zwischenablage (aus extras_config_menu.uc.js)
    // Source          https://www.camp-firefox.de/forum/thema/139769/?postID=1293342#post1293342
    // ==/UserScript==
    
        // Definiere den Profilpfad für die Symbole
        let ProfilePath = PathUtils.toFileURI(
          PathUtils.join(PathUtils.profileDir, 'chrome', 'icons')
        );
        // Standard-Symbol-Dateiname
        let ButtonIcon01 = 'restart_1.svg';       // Neustart
        let ButtonIcon02 = 'quit.svg';            // Beenden
    
        let Icon01 = 'profile.svg';             // Profil-Verzeichnis
        let Icon02 = 'chrome.svg';              // Chrome-Ordner
        let Icon03 = 'css4.svg';                // CSS-Ordner
        let Icon04 = 'js.svg';                  // JS-Ordner
        let Icon05 = 'folder-plus.svg';         // Icons-Ordner
        let Icon06 = 'addons.svg';              // Addon-Verzeichnis
        let Icon07 = 'folder.svg';              // Programm-Verzeichnis
        let Icon08 = 'folder-1.svg';            // Startup-Cache
    
        let Icon11 = 'Themes.svg';              // Anpassen
        let Icon12 = 'debugging-workers.svg';   // Neustart im abgesicherten Modus
        let Icon13 = 'command-console.svg';     // Browser-Konsole
        let Icon14 = 'window-dev-tools.svg';    // Browser-Werkzeuge
        let Icon15 = 'developer.svg';           // Web-Entwickler
        let Icon16 = 'sync.svg';                // Firefox synchronisieren
        let Icon17 = 'passwords.svg';           // Zugangsdaten und Passwörter
        let Icon18 = 'performance.svg';         // Task Manager
        let Icon19 = 'plug-disconnected.svg';   // Offline arbeiten
    
        let Icon21 = 'firefox.svg';             // about:about
        let Icon40 = 'extension.svg';           // about:addons
        let Icon22 = 'info.svg';                // about:cache
        let Icon23 = 'settings.svg';            // about:config
        let Icon24 = 'warning.svg';             // about:crashes
        let Icon25 = 'downloads.svg';           // about:downloads
        let Icon26 = 'home.svg';                // about:home
        let Icon27 = 'passwords.svg';           // about:logins
        let Icon28 = 'debugging-workers.svg';   // about:support
        let Icon29 = 'settings.svg';            // about:preferences
        let Icon41 = 'performance.svg';         // about:processes
        let Icon30 = 'profile.svg';             // about:profiles
    
        let Icon31 = 'js.svg';                  // Meine Scripte
        let Icon32 = 'css4.svg';                // Meine CSS-Dateien
        let Icon33 = 'css4.svg';                // Meine CSSWeb-Dateien
        let Icon34 = 'command-console.svg';     // Skriptliste in Zwischenablage
    
      var Appmenu = {
        // ■■ START UserConfiguration ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    
        // Editor mit angegebenem Pfad verwenden
        // editor: 'C:\\Program Files\\Notepad++\\notepad++.exe',
        editor: "C:\\Program Files\\Microsoft VS Code\\Code.exe",
        // oder
        // in 'view_source.editor.path' eingetragenen Editor verwenden
        //  editor: Services.prefs.getCharPref('view_source.editor.path'),
        // Dateimanager mit angegebenem Pfad verwenden oder leer ('') wenn System-Dateimanager verwenden
        //fileManager: 'C:\\Program files\\FreeCommander XE\\FreeCommander.exe',
        fileManager: "",
        // Parameter für Dateimanager oder leer ('')
        //FMParameter: '/T',
        FMParameter: "",
        // Submenüs ohne Inhalt im Hauptmenü automatisch ausblenden
        autohideEmptySubDirs: true,
        // Submenüs im Hauptmenü nach unten verschieben
        moveSubDirstoBottom: false,
        // Ort und Aussehen des Menü-Buttons einstellen
        //   isUrlbar: 1,  // 0: TabsToolbar; 1: navbar,
        isUrlbar: 2, // 0: TabsToolbar; 1: navbar; 2: toolbar-menubar
        isButton: 0, // 0: Hamburger,klein; 1: Firefox,groß,
        // Hotkey zum Öffnen des Appmenüs oder leer ('')
        hotkey: "f",
        hotkeyModifier: "alt",
    
        // ■■ Neu: Einstellungen für Script-/CSS-Listen (aus extras_config_menu.uc.js) ■■
        // Unterordner für uc.js-Skripte innerhalb des chrome-Verzeichnisses:
        jsSubfolder: 'scripts',
        // Zeigt die Datei userChromeShadow.uc.js in der Skriptliste an (1: ja, 0: nein):
        showuCS: 0,
        // Sortierung der Skript-/CSS-Dateien (1: ja, 0: nein):
        sortScripts: 0,
        // "Skriptliste in Zwischenablage" (1: ja, 2: mit Nummerierung, 0: deaktiviert):
        enableScriptsToClip: 2,
    
        // ■■ END UserConfiguration ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    
        // Submenüs im Hauptmenü nach unten verschieben
        subdirPopupHash: [],
        subdirMenuHash: [],
    
        // CSS-Loader-Funktionen (integriert)
        cssLoader: {
            AGENT_SHEET: Ci.nsIStyleSheetService.AGENT_SHEET,
            USER_SHEET: Ci.nsIStyleSheetService.USER_SHEET,
            AUTHOR_SHEET: Ci.nsIStyleSheetService.AUTHOR_SHEET,
            readCSS: {},
    
            get prefs() {
                delete this.prefs;
                return this.prefs = Services.prefs.getBranch("UserCSSLoader.");
            },
    
            get disabled_list() {
                try {
                    return JSON.parse(this.prefs.getCharPref("disabled_css_list")) || [];
                } catch (e) {
                    return [];
                }
            },
    
            set disabled_list(list) {
                this.prefs.setCharPref("disabled_css_list", JSON.stringify(list));
            },
    
            get FOLDER() {
                let aFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
                aFolder.appendRelativePath("CSS");
                if (!aFolder.exists() || !aFolder.isDirectory()) {
                    aFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0o664);
                }
                delete this.FOLDER;
                return this.FOLDER = aFolder;
            },
    
            initCSSLoader: function() {
                this.rebuildCSSMenu();
            },
    
            rebuildCSSMenu: function() {
                let ext = /\.css$/i;
                let not = /\.uc\.css/i;
                let files = this.FOLDER.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
                let popup = Appmenu.subdirPopupHash["CSS-Loader-Menü"];
    
                // Vorhandene Einträge löschen
                while (popup && popup.firstChild) {
                    popup.removeChild(popup.firstChild);
                }
    
                // Neue Einträge erstellen
                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);
                    let menuitem = document.createElementNS(
                        "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
                        "menuitem"
                    );
    
                    menuitem.setAttribute("label", file.leafName);
                    menuitem.setAttribute("id", "appmenu-css-" + file.leafName);
                    menuitem.setAttribute("class", "menuitem-iconic");
    
                    if (CSS.enabled) {
                        menuitem.setAttribute("image", `${ProfilePath}/menu-check_lime.svg`);
                    } else {
                        menuitem.setAttribute("image", `${ProfilePath}/stop_smal_red.svg`);
                    }
                    menuitem.setAttribute("tooltiptext", "Linksklick: an/aus, Mittelklick: an/aus (Menü bleibt offen), Rechtsklick: bearbeiten");
    
                    menuitem.addEventListener("command", () => this.toggleCSS(file.leafName));
                    menuitem.addEventListener("click", (event) => this.cssItemClick(event, file.leafName));
    
                    if (popup) {
                        popup.appendChild(menuitem);
                    }
                }
            },
    
            loadCSS: function(aFile) {
                let CSS = this.readCSS[aFile.leafName];
                if (!CSS) {
                    CSS = this.readCSS[aFile.leafName] = new CSSEntry(aFile);
                    CSS.enabled = !this.disabled_list.includes(aFile.leafName);
                }
                return CSS;
            },
    
            toggleCSS: function(aLeafName) {
                let CSS = this.readCSS[aLeafName];
                if (!CSS) return;
    
                CSS.enabled = !CSS.enabled;
    
                let currentDisabledList = this.disabled_list;
                if (CSS.enabled) {
                    currentDisabledList = currentDisabledList.filter(name => name !== aLeafName);
                } else {
                    if (!currentDisabledList.includes(aLeafName)) {
                        currentDisabledList.push(aLeafName);
                    }
                }
                this.disabled_list = currentDisabledList;
    
                let menuitem = document.getElementById("appmenu-css-" + aLeafName);
                if (menuitem) {
                    if (CSS.enabled) {
                        menuitem.setAttribute("image", `${ProfilePath}/menu-check_lime.svg`);
                    } else {
                        menuitem.setAttribute("image", `${ProfilePath}/stop_smal_red.svg`);
                    }
                }
            },
    
            cssItemClick: function(event, aLeafName) {
                event.preventDefault();
                event.stopPropagation();
                if (event.button === 0) {
                    return;
                } else if (event.button === 1) {
                    this.toggleCSS(aLeafName);
                } else if (event.button === 2) {
                    let file = this.getFileFromLeafName(aLeafName);
                    this.editCSS(file);
                }
            },
    
            getFileFromLeafName: function(aLeafName) {
                let f = this.FOLDER.clone();
                f.QueryInterface(Ci.nsIFile);
                f.appendRelativePath(aLeafName);
                return f;
            },
    
            editCSS: function(aFile) {
                let editor = cssLoaderConfig.Editor || Services.prefs.getCharPref("view_source.editor.path");
                if (!editor) {
                    alert('Kein Editor konfiguriert! Bitte in about:config unter "view_source.editor.path" einen Editor eintragen.');
                    return;
                }
                try {
                    let UI = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
                    UI.charset = window.navigator.platform.toLowerCase().includes("win") ? "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) {
                    console.error("Fehler beim Öffnen des Editors:", e);
                }
            },
        },
    
        toolbar: {
          subdirs: [
            {
              name: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/folder_currentColor.svg`,
            },
            {
              name: 'Firefox Funktionen',
              image: `${ProfilePath}/settings_currentColor.svg`,
            },
            {
              name: 'separator',
            },
            {
              name: 'Meine Scripte',
              image: `${ProfilePath}/${Icon31}`,
            },
            {
              name: 'Meine CSS-Dateien',
              image: `${ProfilePath}/${Icon32}`,
            },
            {
              name: 'Meine CSSWeb-Dateien',
              image: `${ProfilePath}/${Icon33}`,
            },
            {
              name: 'Skriptliste in Zwischenablage',
              image: `${ProfilePath}/${Icon34}`,
              command: () => Appmenu.getScripts(1),
              tooltiptext: 'Kopiert eine Liste aller uc.js-Skripte in die Zwischenablage',
            },
            {
              name: 'separator',
            },
            {
              name: 'CSS-Loader-Menü',
              image: `${ProfilePath}/css4_currentColor.svg`,
            },
            {
              name: 'Konfiguration',
              image: `${ProfilePath}/Hammer-wrench_currentColor.svg`,
            },
            {
              name: '"about:"-Seiten',
              image: `${ProfilePath}/firefox_currentColor.svg`,
            },
          ],
    
          apps: [
            {
              name: 'Profil-Verzeichnis',
              id: 'AMProfil',
              root: 'ProfD',
              path: '\\',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon01}`,
            },
            {
              name: 'Chrome-Ordner',
              id: 'AMchrome',
              root: 'ProfD',
              path: '\\chrome',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon02}`,
            },
            {
              name: 'CSS-Ordner',
              id: 'AMCSS',
              root: 'ProfD',
              path: '\\chrome\\css',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon03}`,
            },
            {
              name: 'CSS-Web-Ordner',
              id: 'AMWEB',
              root: 'ProfD',
              path: '\\chrome\\cssWeb',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon03}`,
            },
            {
              name: 'JS-Ordner',
              id: 'AMJS',
              root: 'ProfD',
              path: '\\chrome\\scripts',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon04}`,
            },
            {
              name: 'Icons-Ordner',
              id: 'AMICO',
              root: 'ProfD',
              path: '\\chrome\\icons',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon05}`,
            },
            {
              name: 'Addon-Verzeichnis',
              id: 'AMAddons',
              root: 'ProfD',
              path: '\\extensions',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon06}`,
            },
            {
              name: 'Programm-Verzeichnis',
              id: 'AMProgramm',
              root: 'CurProcD',
              path: '\\',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon07}`,
            },
            {
              name: 'Startup-Cache',
              id: 'AMCache',
              root: 'ProfLD',
              path: '\\startupCache',
              subdir: 'Firefox Verzeichnisse',
              image: `${ProfilePath}/${Icon08}`,
            },
          ],
    
          configs: [
            {
              name: 'Anpassen',
              id: 'AMAnpassen',
              command: 'gCustomizeMode.enter()',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon11}`,
            },
            {
              name: 'Neustart im abgesicherten Modus',
              id: 'AMModus',
              command: 'safeModeRestart();',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon12}`,
            },
            {
              name: 'Browser-Konsole',
              id: 'AMKonsole',
              command: 'goKonsole',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon13}`,
            },
            {
              name: 'Browser-Werkzeuge',
              id: 'AMWerkzeuge',
              command: 'goWerkzeuge',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon14}`,
            },
            {
              name: 'Web-Entwickler',
              id: 'AMEntwickler',
              command: 'goEntwickler',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon15}`,
            },
            {
              name: 'Firefox synchronisieren',
              id: 'AMsynchron',
              command: 'gSync',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon16}`,
            },
            {
              name: 'Zugangsdaten und Passwörter',
              id: 'AMdaten',
              command: 'LoginHelper.openPasswordManager(window, { entryPoint: "mainmenu" })',
              tooltiptext: 'about:logins',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon17}`,
            },
            {
              name: 'Task Manager',
              id: 'AMManager',
              command: 'switchToTabHavingURI("about:processes", true)',
              tooltiptext: 'about:processes',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon18}`,
            },
            {
              name: 'Offline arbeiten',
              id: 'AMOffline',
              command: 'BrowserOffline.toggleOfflineStatus();',
              subdir: 'Firefox Funktionen',
              image: `${ProfilePath}/${Icon19}`,
            },
            {
              name: 'Neustart',
              id: 'AMreboot',
              tooltiptext: 'userChrome.js-Cache wird geleert',
              command: 'goReeboot',
              image: `${ProfilePath}/${ButtonIcon01}`,
            },
            {
              name: 'Beenden',
              id: 'AMquit',
              command: 'goQuitApplication(event);',
              image: `${ProfilePath}/${ButtonIcon02}`,
            },
            // uProfMenu-Funktionen unter Menüeintrag "Konfiguration"
            {
              name: 'userChrome.css bearbeiten',
              id: 'AMuserChromeCss',
              command: () => Appmenu.edit(0, 'userChrome.css'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/css4.svg`,
            },
            {
              name: 'userChromeShadow.css bearbeiten',
              id: 'AMuserChromeShadowCss',
              command: () => Appmenu.edit(0, 'userChromeShadow.css'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/css4.svg`,
            },
            {
              name: 'userContent.css bearbeiten',
              id: 'AMuserContentCss',
              command: () => Appmenu.edit(0, 'userContent.css'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/css4.svg`,
            },
            {
              name: 'userChrome.js bearbeiten',
              id: 'AMuserChromeJs',
              command: () => Appmenu.edit(0, 'userChrome.js'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/js.svg`,
            },
            {
              name: 'prefs.js bearbeiten',
              id: 'AMprefsJs',
              command: () => Appmenu.edit(1, 'prefs.js'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/js.svg`,
            },
            {
              name: 'user.js bearbeiten',
              id: 'AMuserJs',
              command: () => Appmenu.edit(1, 'user.js'),
              subdir: 'Konfiguration',
              image: `${ProfilePath}/js.svg`,
            },
            // about:-Seiten
            {
              name: 'about:about',
              id: 'AMaboutAbout',
              command: () => openTrustedLinkIn("about:about", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon21}`,
            },
            {
              name: 'about:addons',
              id: 'AMaboutAddons',
              command: () => openTrustedLinkIn("about:addons", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon40}`,
            },
            {
              name: 'about:cache',
              id: 'AMaboutCache',
              command: () => openTrustedLinkIn("about:cache", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon22}`,
            },
            {
              name: 'about:config',
              id: 'AMaboutConfig',
              command: () => openTrustedLinkIn("about:config", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon23}`,
            },
            {
              name: 'about:crashes',
              id: 'AMaboutCrashes',
              command: () => openTrustedLinkIn("about:crashes", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon24}`,
            },
            {
              name: 'about:downloads',
              id: 'AMaboutDownloads',
              command: () => openTrustedLinkIn("about:downloads", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon25}`,
            },
            {
              name: 'about:home',
              id: 'AMaboutHome',
              command: () => openTrustedLinkIn("about:home", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon26}`,
            },
            {
              name: 'about:logins',
              id: 'AMaboutLogins',
              command: 'LoginHelper.openPasswordManager(window, { entryPoint: "mainmenu" })',
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon27}`,
            },
            {
              name: 'about:support',
              id: 'AMaboutSupport',
              command: () => openTrustedLinkIn("about:support", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon28}`,
            },
            {
              name: 'about:preferences',
              id: 'AMaboutPreferences',
              command: () => openTrustedLinkIn("about:preferences", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon29}`,
            },
            {
              name: 'about:processes',
              id: 'AMaboutProcesses',
              command: () => openTrustedLinkIn("about:processes", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon41}`,
            },
            {
              name: 'about:profiles',
              id: 'AMaboutProfiles',
              command: () => openTrustedLinkIn("about:profiles", "tab"),
              subdir: '"about:"-Seiten',
              image: `${ProfilePath}/${Icon30}`,
            },
          ]
        },
        _externalAppPopup: null,
        _isready: false,
    
        // uProfMenu-Funktionen (bereits integriert)
        getDirSep: function() {
          var osString = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULRuntime).OS;
          var dirsep = "/";
          switch(osString) {
            case "WINNT":
              dirsep = "\\";
              break;
            case "Darwin":
              dirsep = "/";
              break;
          }
          return dirsep;
        },
        getPrefDirectoryPath: function(str) {
          var file = Components.classes["@mozilla.org/file/directory_service;1"]
            .getService(Components.interfaces.nsIProperties)
            .get(str, Components.interfaces.nsIFile);
          if (str == 'CurProcD') {
            file = file.parent;
          }
          return file.path;
        },
        edit: function(OpenMode, Filename) {
          var Path = "";
          var dSep = this.getDirSep();
          // Wenn der Dateiname einen Pfad enthält (z. B. "chrome/scripts/test.uc.js"),
          // vom Profil-Verzeichnis aus auflösen:
          if (Filename.includes("/") || Filename.includes("\\")) {
            Path = this.getPrefDirectoryPath("ProfD") + dSep + Filename.replace(/\//g, dSep);
          } else {
            switch (OpenMode) {
              case 0:
                Path = this.getPrefDirectoryPath("UChrm") + dSep + Filename;
                break;
              case 1:
                Path = this.getPrefDirectoryPath("ProfD") + dSep + Filename;
                break;
              case 3:
                Path = this.getPrefDirectoryPath("UChrm") + dSep + "CSS" + dSep + Filename;
                break;
              case 4:
                Path = this.getPrefDirectoryPath("UChrm") + dSep + "CSSWeb" + dSep + Filename;
                break;
              case 5:
                Path = this.getPrefDirectoryPath("UChrm") + dSep + "CSSShadow" + dSep + Filename;
                break;
            }
          }
          this.launch(this.editor, Path);
        },
        launch: function(RanPath, OpenPath) {
          var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);
          var proc = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
          var args = [OpenPath];
          file.initWithPath(RanPath);
          if (!file.exists()) {
            var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
            RanPath = pref.getCharPref("view_source.editor.path");
            file.initWithPath(RanPath);
          }
          proc.init(file);
          proc.run(false, args, args.length);
        },
    
        // ■■ Neu: Script- und CSS-Listen (aus extras_config_menu.uc.js integriert) ■■
    
        getScripts: function(iType) {
          let ucJsScripts = [];
          let extjs = /\.uc\.js$/i;
    
          // 1. Standard-UChrm-Ordner durchsuchen
          let uchrmFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
          if (uchrmFolder.exists()) {
            let files = uchrmFolder.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
            while (files.hasMoreElements()) {
              let file = files.getNext().QueryInterface(Ci.nsIFile);
              if (extjs.test(file.leafName)) {
                if (file.leafName === "userChromeShadow.uc.js" && !this.showuCS) continue;
                ucJsScripts.push(file.leafName);
              }
            }
          }
    
          // 2. chrome/scripts-Unterverzeichnis durchsuchen
          if (this.jsSubfolder) {
            let scriptsFolder = Services.dirsvc.get("ProfD", Ci.nsIFile);
            scriptsFolder.append("chrome");
            scriptsFolder.append(this.jsSubfolder);
            if (scriptsFolder.exists()) {
              let files = scriptsFolder.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
              while (files.hasMoreElements()) {
                let file = files.getNext().QueryInterface(Ci.nsIFile);
                if (extjs.test(file.leafName)) {
                  ucJsScripts.push("chrome/" + this.jsSubfolder + "/" + file.leafName);
                }
              }
            }
          }
    
          if (this.sortScripts) ucJsScripts.sort(this.stringComparison.bind(this));
    
          if (iType === 0) {
            // Untermenü "Meine Scripte" befüllen
            this.fillFileMenu("Meine Scripte", "Meine Scripte", ucJsScripts, 0);
          } else {
            // Für Zwischenablage: Nur Dateinamen (ohne Pfad) verwenden
            let simpleNames = ucJsScripts.map(f => f.split(/[\\/]/).pop());
            let result = this.fillClipboardValue(simpleNames);
            Components.classes["@mozilla.org/widget/clipboardhelper;1"]
              .getService(Components.interfaces.nsIClipboardHelper).copyString(result);
          }
        },
    
        getCssFiles: function(iType) {
          let cssFiles = [];
          let extcss = /\.css$/i;
          let folderName = "";
          let subdirName = "";
          let menuLabel = "";
          let sType = 0;
    
          if (iType === 3) {
            folderName = "CSS";
            subdirName = "Meine CSS-Dateien";
            menuLabel = "Meine CSS-Dateien";
            sType = 3;
          } else if (iType === 4) {
            folderName = "CSSWeb";
            subdirName = "Meine CSSWeb-Dateien";
            menuLabel = "Meine CSSWeb-Dateien";
            sType = 4;
          } else if (iType === 5) {
            folderName = "CSSShadow";
            subdirName = "Meine CSSShadow-Dateien";
            menuLabel = "Meine CSSShadow-Dateien";
            sType = 5;
          } else {
            return;
          }
    
          let aFolder = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
          aFolder.initWithPath(Services.dirsvc.get("UChrm", Ci.nsIFile).path + this.getDirSep() + folderName);
    
          if (aFolder.exists() && aFolder.isDirectory()) {
            let files = aFolder.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
            while (files.hasMoreElements()) {
              let file = files.getNext().QueryInterface(Ci.nsIFile);
              if (extcss.test(file.leafName)) cssFiles.push(file.leafName);
            }
          }
    
          if (this.sortScripts) cssFiles.sort(this.stringComparison.bind(this));
          this.fillFileMenu(subdirName, menuLabel, cssFiles, sType);
        },
    
        fillFileMenu: function(subdirName, strlabel, fileArray, sType) {
          let submenuItem = Appmenu.subdirMenuHash[subdirName];
          if (submenuItem) {
            submenuItem.setAttribute('label', strlabel + ' (' + fileArray.length + ')');
          }
          let popup = Appmenu.subdirPopupHash[subdirName];
          if (!popup) return;
          // Vorhandene Einträge löschen
          while (popup.hasChildNodes()) popup.removeChild(popup.firstChild);
    
          // Symbol je nach Dateityp festlegen
          let iconPath = '';
          if (sType === 0) {
            iconPath = ProfilePath + '/' + Icon04;       // js.svg
          } else {
            iconPath = ProfilePath + '/' + Icon03;       // css4.svg
          }
    
          for (let i = 0; i < fileArray.length; i++) {
            let fileName = fileArray[i];
            let mitem = document.createXULElement('menuitem');
            mitem.setAttribute('class', 'menuitem-iconic');
            mitem.setAttribute('image', iconPath);
    
            if (sType === 0) {
              // Scripts: Linksklick = Bearbeiten, Mittelklick = GitHub, Rechtsklick = GitHub-Suche
              let displayName = fileName.split(/[\\/]/).pop();
              mitem.setAttribute('label', displayName);
              mitem.addEventListener('command', function() {
                Appmenu.edit(0, fileName);
              }, true);
              mitem.addEventListener('click', function(event) {
                Appmenu.openAtGithub(event, displayName);
              }, true);
              mitem.setAttribute('tooltiptext',
                'Linksklick: Bearbeiten,\nMittelklick: GitHub-Seite öffnen,\nRechtsklick: GitHub-Suche');
            } else if (sType === 3) {
              mitem.setAttribute('label', fileName);
              mitem.addEventListener('command', function() {
                Appmenu.edit(3, fileName);
              }, true);
            } else if (sType === 4) {
              mitem.setAttribute('label', fileName);
              mitem.addEventListener('command', function() {
                Appmenu.edit(4, fileName);
              }, true);
            } else if (sType === 5) {
              mitem.setAttribute('label', fileName);
              mitem.addEventListener('command', function() {
                Appmenu.edit(5, fileName);
              }, true);
            }
            popup.appendChild(mitem);
          }
        },
    
        fillClipboardValue: function(sArray) {
          var retValue = "Meine Skripte (" + sArray.length + "):\n------------------------";
          for (var i = 0; i < sArray.length; i++) {
            retValue += "\n" + (i + 1) + ". " + sArray[i];
          }
          return retValue;
        },
    
        openAtGithub: function(e, sScript) {
          if (e.button == 1) {
            var sUrl = "https://github.com/ardiman/userChrome.js/tree/master/" + this.cleanFileName(sScript);
            openWebLinkIn(sUrl, 'tab');
          }
          if (e.button == 2) {
            e.preventDefault();
            var sUrl = "https://github.com/search?langOverride=&language=&q=" + sScript + "&repo=&start_value=1&type=Code";
            openWebLinkIn(sUrl, 'tab');
          }
        },
    
        cleanFileName: function(sName) {
          sName = sName.toLowerCase();
          var regs = [/\.uc\.js$/, /\.uc\.xul$/, /^ucjs_/, /_\d.+/, /_fx\d+/, /[-+\.]/g, /_v\d+/];
          for (var i = 0; i < regs.length; i++) {
            sName = sName.replace(regs[i], "");
          }
          return sName;
        },
    
        stringComparison: function(a, b) {
          a = a.toLowerCase().replace(/ä/g,"a").replace(/ö/g,"o").replace(/ü/g,"u").replace(/ß/g,"s");
          b = b.toLowerCase().replace(/ä/g,"a").replace(/ö/g,"o").replace(/ü/g,"u").replace(/ß/g,"s");
          return (a == b) ? 0 : (a > b) ? 1 : -1;
        },
    
        init: function() {
          this.handleRelativePath(this.toolbar.apps);
          const XULNS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
          var ExternalAppBtn = document.createElementNS(XULNS, 'toolbarbutton');
          ExternalAppBtn.id = 'AppMenuButton';
          ExternalAppBtn.setAttribute('label', 'AppButton');
          ExternalAppBtn.addEventListener('click', event => {
            event.preventDefault();
            event.stopPropagation();
          });
          ExternalAppBtn.setAttribute('tooltiptext', 'Firefox Menü');
          ExternalAppBtn.setAttribute('type', 'menu');
          ExternalAppBtn.setAttribute('removable', 'true');
    
          let ProfilePath = PathUtils.toFileURI(
            PathUtils.join(PathUtils.profileDir, 'chrome', 'image')
          );
    
          let DefaultIcon = 'Button_groß.png';
          let AlternateIcon = 'Button_klein-5.png';
          if (Appmenu.isButton) {
            ExternalAppBtn.style.listStyleImage = `url('${ProfilePath}/${DefaultIcon}')`;
            ExternalAppBtn.style.width = '94px';
            ExternalAppBtn.style.height = '24px';
          } else {
            ExternalAppBtn.style.listStyleImage = `url('${ProfilePath}/${AlternateIcon}')`;
            ExternalAppBtn.style.width = '48px';
            ExternalAppBtn.style.height = '21px';
          }
    
          if (Appmenu.isUrlbar === 1) {
            var navBar = document.getElementById('nav-bar-customization-target');
            navBar.insertBefore(ExternalAppBtn, navBar.firstChild);
          } else if (Appmenu.isUrlbar === 2) {
            var menubar = document.getElementById('toolbar-menubar');
            menubar.insertBefore(ExternalAppBtn, menubar.firstChild);
          } else {
            var TabsToolbar = document.getElementById('TabsToolbar');
            TabsToolbar.insertBefore(ExternalAppBtn, TabsToolbar.firstChild);
          }
          var ExternalAppPopup = document.createElementNS(XULNS, 'menupopup');
          ExternalAppPopup.addEventListener('click', event => {
            event.stopPropagation();
          });
          ExternalAppPopup.setAttribute('id', 'AMpopup');
          this._externalAppPopup = ExternalAppPopup;
          ExternalAppBtn.appendChild(ExternalAppPopup);
          Appmenu.onpopupshowing();
    
          // CSS-Loader initialisieren
          this.cssLoader.initCSSLoader();
    
          // Menü mit Tastaturkürzel öffnen
          if (Appmenu.hotkey) {
            let key = document.createXULElement('key');
            key.id = 'key_AppMenuPopup';
            key.setAttribute('key', Appmenu.hotkey);
            if (Appmenu.hotkeyModifier)
              key.setAttribute('modifiers', Appmenu.hotkeyModifier);
            key.addEventListener('command', function () {
              document.getElementById('AMpopup').openPopup();
            });
            document.getElementById('mainKeyset').appendChild(key);
          }
        },
    
        onpopupshowing: function() {
          if (this._isready) return;
          if (this._externalAppPopup === null) return;
          var ExternalAppPopup = this._externalAppPopup;
          for (let subdir of this.toolbar.subdirs) {
            if (subdir.name == 'separator') {
              ExternalAppPopup.appendChild(document.createXULElement('menuseparator'));
            } else if (subdir.command) {
              var actionItem = ExternalAppPopup.appendChild(document.createXULElement('menuitem'));
              actionItem.setAttribute('class', 'menuitem-iconic');
              actionItem.setAttribute('label', subdir.name);
              actionItem.setAttribute('image', subdir.image);
              if (subdir.tooltiptext) {
                actionItem.setAttribute('tooltiptext', subdir.tooltiptext);
              } else {
                actionItem.setAttribute('tooltiptext', subdir.name);
              }
              actionItem.addEventListener('command', subdir.command);
            } else {
              var subdirItem = ExternalAppPopup.appendChild(document.createXULElement('menu'));
              var subdirItemPopup = subdirItem.appendChild(document.createXULElement('menupopup'));
              subdirItem.setAttribute('class', 'menu-iconic');
              subdirItem.setAttribute('label', subdir.name);
              subdirItem.setAttribute('image', subdir.image);
              Appmenu.subdirPopupHash[subdir.name] = subdirItemPopup;
              Appmenu.subdirMenuHash[subdir.name] = subdirItem;
    
              // CSS-Loader-Menüeinträge für "CSS-Loader-Menü"
              if (subdir.name === "CSS-Loader-Menü") {
                Appmenu.cssLoader.rebuildCSSMenu();
              }
              // Neue dynamische Untermenüs befüllen
              if (subdir.name === "Meine Scripte") {
                Appmenu.getScripts(0);
              }
              if (subdir.name === "Meine CSS-Dateien") {
                Appmenu.getCssFiles(3);
              }
              if (subdir.name === "Meine CSSWeb-Dateien") {
                Appmenu.getCssFiles(4);
              }
            }
          }
          for (let app of this.toolbar.apps) {
            var appItem;
            if (app.name == 'separator') {
              appItem = document.createXULElement('menuseparator');
            } else {
              appItem = document.createXULElement('menuitem');
              appItem.setAttribute('class', 'menuitem-iconic');
              appItem.setAttribute('label', app.name);
              appItem.setAttribute('image', app.image);
              appItem.addEventListener('command', function () {
                Appmenu.exec(this.path, this.args);
              });
              appItem.setAttribute('tooltiptext', app.name);
              appItem.path = app.path;
              appItem.args = app.args;
            }
            if (app.subdir && Appmenu.subdirPopupHash[app.subdir])
              Appmenu.subdirPopupHash[app.subdir].appendChild(appItem);
            else ExternalAppPopup.appendChild(appItem);
          }
          for (let config of this.toolbar.configs) {
            var configItem;
            if (config.name == 'separator') {
              configItem = document.createXULElement('menuseparator');
            } else {
              configItem = ExternalAppPopup.appendChild(document.createXULElement('menuitem'));
              configItem.setAttribute('class', 'menuitem-iconic');
              configItem.setAttribute('label', config.name);
              configItem.setAttribute('image', config.image);
              configItem.addEventListener('command', () => {
                if (typeof config.command === 'function') {
                  config.command();
                } else {
                  Appmenu.executeCommand(config.command);
                }
              });
              if (config.tooltiptext) {
                configItem.setAttribute('tooltiptext', config.tooltiptext);
              } else {
                configItem.setAttribute('tooltiptext', config.name);
              }
              configItem.setAttribute('id', config.id);
            }
    
            if (config.subdir && Appmenu.subdirPopupHash[config.subdir]) {
              Appmenu.subdirPopupHash[config.subdir].appendChild(configItem);
            } else {
              ExternalAppPopup.appendChild(configItem);
            }
          }
          if (this.autohideEmptySubDirs) {
            for (let key of Object.keys(Appmenu.subdirPopupHash)) {
              if (Appmenu.subdirPopupHash[key].hasChildNodes()) {
                continue;
              } else {
                Appmenu.subdirMenuHash[key].setAttribute('hidden', 'true');
              }
            }
          }
          if (this.moveSubDirstoBottom) {
            let i = ExternalAppPopup.childNodes.length;
            while (ExternalAppPopup.firstChild.getAttribute('class') != 'menuitem-iconic' && i-- != 0) {
              ExternalAppPopup.appendChild(ExternalAppPopup.firstChild);
            }
          }
          this._isready = true;
        },
    
        executeCommand: function(command) {
          const commandMap = {
            'gCustomizeMode.enter()': () => gCustomizeMode.enter(),
            'safeModeRestart();': () => safeModeRestart(),
            'goKonsole': () => {
                    var { require } = ChromeUtils.importESModule('resource://devtools/shared/loader/Loader.sys.mjs', {});
                    var { BrowserConsoleManager } = require('resource://devtools/client/webconsole/browser-console-manager');
                    BrowserConsoleManager.openBrowserConsoleOrFocus();
                  },
            'goWerkzeuge': () => {
                    var { require } = ChromeUtils.importESModule('resource://devtools/shared/loader/Loader.sys.mjs', {});
                    var { BrowserToolboxLauncher } = require('resource://devtools/client/framework/browser-toolbox/Launcher.sys.mjs');
                    BrowserToolboxLauncher.init();
                  },
            'goEntwickler': () => {
                    var { require } = ChromeUtils.importESModule('resource://devtools/shared/loader/Loader.sys.mjs', {});
                    var { gDevToolsBrowser } = require('resource://devtools/client/framework/devtools-browser');
                    gDevToolsBrowser.toggleToolboxCommand(window.gBrowser, performance.now());
                  },
            'gSync': () => gSync.openPrefs('menubar'),
            'LoginHelper.openPasswordManager(window, { entryPoint: "mainmenu" })': () => LoginHelper.openPasswordManager(window, { entryPoint: 'mainmenu' }),
            'switchToTabHavingURI("about:processes", true)': () => switchToTabHavingURI('about:processes', true),
            'BrowserOffline.toggleOfflineStatus();': () => BrowserOffline.toggleOfflineStatus(),
            'goReeboot': () => {
                      Services.appinfo.invalidateCachesOnRestart();
                      Services.startup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
                    },
            'goQuitApplication(event);': () => goQuitApplication(event),
          };
          if (commandMap[command]) {
            commandMap[command]();
          } else {
            console.warn('Unbekannter Befehl: ', command);
          }
        },
    
        handleRelativePath: function(apps) {
          for (let app of apps) {
            if (app.path) {
              app.path = app.path.replace(/\//g, '\\');
              var ffdir = Cc['@mozilla.org/file/directory_service;1'].getService(Ci.nsIProperties).get(app.root, Ci.nsIFile).path;
              if (/^(\\)/.test(app.path)) {
                app.path = ffdir + app.path;
              }
            }
          }
        },
    
        exec: function(path, args) {
          args = args || [];
          var args_t = args.slice(0);
          for (let arg of args_t) {
            arg = arg.replace(/%u/g, gBrowser.currentURI.spec);
          }
          var file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
          file.initWithPath(path);
          if (!file.exists()) {
            alert('Datei nicht gefunden: ' + path);
            return;
          }
          if (file.isExecutable() && !path.endsWith('.js')) {
            var process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
            process.init(file);
            process.run(false, args_t, args_t.length);
          } else if (file.isFile()) {
            if (this.editor) {
              let UI = Cc['@mozilla.org/intl/scriptableunicodeconverter'].createInstance(Ci.nsIScriptableUnicodeConverter);
              UI.charset = window.navigator.platform.toLowerCase().includes("win") ? "Shift_JIS" : "UTF-8";
              let path = UI.ConvertFromUnicode(file.path);
              let app = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
              app.initWithPath(this.editor);
              let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
              process.init(app);
              process.run(false, [path], 1);
            } else {
              file.launch();
            }
          } else if (file.isDirectory()) {
            if (this.fileManager) {
              let args=[this.FMParameter,path];
              let app = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
              app.initWithPath(this.fileManager);
              let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
              process.init(app);
              process.run(false, args, args.length);
            } else {
              file.launch();
            }
          }
        },
      };
    
    /* ***************************************************************************************************************************** */
    
      // CSSEntry-Klasse (aus UserCSSLoader)
      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();
            let lastModifiedTime = isExists ? aFile.lastModifiedTime : 0;
            let isForced = this.lastModifiedTime != lastModifiedTime;
            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)) {
                if (!isEnable || !isExists) {
                    this.sss.unregisterSheet(uri, this.SHEET);
                } else if (isForced) {
                    this.sss.unregisterSheet(uri, this.SHEET);
                    this.sss.loadAndRegisterSheet(uri, this.SHEET);
                }
            } else {
                if (isEnable && isExists) {
                    this.sss.loadAndRegisterSheet(uri, this.SHEET);
                }
            }
    
            this.lastModifiedTime = lastModifiedTime;
            return this._enabled = isEnable;
        },
      };
    
      (function () {
        let sss = Components.classes['@mozilla.org/content/style-sheet-service;1'].getService(Components.interfaces.nsIStyleSheetService);
        let uri = Services.io.newURI(
          'data:text/css;charset=utf-8,' +
            encodeURIComponent(`
              menuitem[label="Profil-Verzeichnis"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Chrome-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="CSS-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="CSS-Web-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="JS-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Icons-Ordner"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Addon-Verzeichnis"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Programm-Verzeichnis"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              menuitem[label="Startup-Cache"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              #AMAnpassen     { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMModus        { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMKonsole      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMWerkzeuge    { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMEntwickler   { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMsynchron     { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMdaten        { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMManager      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMOffline      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              /* Neustart-Button */
              #AMreboot { -moz-context-properties: fill, fill-opacity !important; fill: #fbc96e !important; padding-left: 13px !important; }
              #AMreboot > img:nth-child(1) { width: 16px !important; height: 16px !important; }
              /* Beenden-Button */
              #AMquit { -moz-context-properties: fill, fill-opacity !important; fill: red !important; }
    
              /* Skriptliste in Zwischenablage */
              #AMscriptList    { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              /* about:-Seiten */
              #AMaboutAbout        { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutAddons       { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutCache        { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutConfig       { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutCrashes      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutDownloads    { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutHome         { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutLogins       { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutSupport      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutPreferences  { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutProcesses    { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMaboutProfiles     { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              /* uProfMenu-Einträge */
              #AMuserChromeCss      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMuserChromeShadowCss { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMuserContentCss     { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMuserChromeJs      { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMprefsJs            { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #AMuserJs             { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
    
              /* 1 */
              menuitem[subdir="CSS-Loader-Menü"] { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
              #appmenu-css-CSS-Ordner-öffnen { -moz-context-properties: fill, fill-opacity; fill: currentColor; }
            `),
          null,
          null
        );
        sss.loadAndRegisterSheet(uri, sss.AUTHOR_SHEET);
      })();
    
      if (window.gBrowser) Appmenu.init();
    Alles anzeigen

    Und ich spiele schon eine ganze Weile mit dem Gedanken auch den JavaScriptLoader zu integrieren.
    Na, mal schauen.

  • Firefox und Online Apotheke Aliva

    • Mira_Belle
    • 29. August 2026 um 16:07

    Na toll, englisch!
    Da bin ich raus.
    Das sollte jemand machen, der mit dieser Sprach nicht auf Kriegsfuß steht!
    Also mit Version 152.0 funktionierte es noch, ab Version 153.0 nicht mehr!
    Hoffe, das hilft.

  • Firefox und Online Apotheke Aliva

    • Mira_Belle
    • 29. August 2026 um 15:52

    :/
    Habe es gerade mit 151.0.1 getestet, da klappt es mit dem Warenkorb!
    Mit der aktuellen Version 154.0.1 nicht!
    Und mit der 152.0 geht es auch noch.

  • Andere Tabs schließen?

    • Mira_Belle
    • 28. August 2026 um 17:11
    Zitat von Mitleser

    Aber es soll ja in erster Linie auch 'Spass machen'. Der Weg ist das Ziel.

    So sei es! :S

Unterstütze uns!

Jährlich (2026)

71,6 %

71,6% (554,79 von 775 EUR)

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