Eine neue Version dieses Scripts!
Langsam aber sicher entwickelt es sich zu einer eierlegenden Wollmilchsau. ![]()
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.