Полезная информация

Список ответов на каверзные вопросы можно получить в FAQ-разделе форума.

№15101-05-2024 14:17:01

6e73epo
Участник
 
Группа: Members
Зарегистрирован: 06-05-2022
Сообщений: 207
UA: Firefox 124.0

Re: userChrome.js

Dumby
Вернул по старому и ошибок нет, а раньше была AboutNewTab is not defined. Теперь уже не знаю почему. Может Cu.import проходил с задержкой. Долго экспериментировал в стилях для установки фонового локального изображения для blanktab.html и about:blank. В итоге оставил только для blanktab.html.

Отсутствует

 

№15219-08-2024 10:40:37

fuchsfan
Участник
 
Группа: Members
Зарегистрирован: 07-08-2023
Сообщений: 124
UA: Firefox 115.0

Re: userChrome.js

@Dumby
Большая просьба восстановить работоспособность скрипта. Скрипт от aborix создает кнопку для обновления закладки, перестал работать в v129 (в v115.14.0esr работает). В чем его удобство и преимущество, так в том, что с ним, в отличие от скрипта в контекстное меню, невозможно ошибочно обновить (заменить), например, закладку на эту тему на закладку погодного сайта, вкладка которого сейчас активна.
По умолчанию скрипт имеет большую цветную демо-кнопку, но это не проблема, я могу заменить ее на свою.

Выделить код

Код:

(function() {

  if (window.__SSi != 'window0')
    return;

  CustomizableUI.createWidget({
    id: 'bookmark-update-button',
    label: 'Update Bookmark',
    tooltiptext: 'Update this Bookmark',
    defaultArea: CustomizableUI.AREA_NAVBAR,

    onCreated: button => {
  button.style.backgroundColor = 'hotpink';				// icon like a pink square
    },

    onCommand: async (event) => {
      let window = event.target.ownerGlobal;
      let document = window.document;
      window.FillHistoryMenu(document.getElementById('backForwardMenu'));
      let bookmarkUrl = document.querySelector('#backForwardMenu > menuitem[historyindex="-1"]')
                        ?.getAttribute('uri');
      let bookmark = await window.PlacesUtils.bookmarks.fetch({url: bookmarkUrl});
      if (bookmark) {
        window.PlacesUtils.bookmarks.update({
          guid: bookmark.guid,
          url: window.gBrowser.currentURI
        });
      }
    }
  });

})();

Отсутствует

 

№15319-08-2024 15:01:51

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2229
UA: Firefox 78.0

Re: userChrome.js

fuchsfan пишет

перестал работать в v129

FillHistoryMenu() теперь хочет event

скрытый текст

Выделить код

Код:

/*
      window.FillHistoryMenu(document.getElementById('backForwardMenu'));
*/
      window.FillHistoryMenu({
        preventDefault() {},
        target: document.getElementById('backForwardMenu')
      });

Отсутствует

 

№15419-08-2024 17:14:48

fuchsfan
Участник
 
Группа: Members
Зарегистрирован: 07-08-2023
Сообщений: 124
UA: Firefox 129.0

Re: userChrome.js

Dumby пишет

FillHistoryMenu() теперь хочет event

Большое спасибо, чудесно!

Отсутствует

 

№15531-08-2024 00:01:54

Farby
Участник
 
Группа: Members
Зарегистрирован: 21-11-2012
Сообщений: 290
UA: Google 2.1

Re: userChrome.js

Как-то копаясь по сампу, я там тестирую [firefox] переводчик. Нарвался на пост Mira-Belle. Оказывается они пытаются создать что-то на подобии рыжего [firefox] меню, правда я про меню совсем не помню, ибо [seamonkey]. Да ещё тут на форуме полетел шумок про main-menubar, Dumby его конечно же поправил. При всем уважении кому-то должно было стать стыдно, зачем нужно использовать три скрипта, да ещё перегруженных png,base64. В общем покопался и пересобрал рыжее меню для рыжего лиса, взял Endor8, прибавил Aris-t2 и конечно коды Dumby не прошел стороной.

Appmenu.uc.js

Выделить код

Код:

// ==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
// @version        update für Firefox 129+ by bege
// @author         defpt
// @charset        UTF-8
// @version        2019.08.04
// @version        2020.05.27
// @version        2020.07.13 Weitere Menüs und Funktionen ergänzt by bege
// @version        2024.08.10 alle Einstellungen im Abschnitt Konfiguration vornehmen
// ==/UserScript==

var Appmenu = {
    // Beginn der Konfiguration ------------------
    // Editor mit angegebenem Pfad verwenden
    // editor: 'C:\\Program Files\\Notepad++\\notepad++.exe',
    // oder
    // in 'view_source.editor.path' eingetragenen Editor verwenden
    editor: Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch).getCharPref('view_source.editor.path'),
    // Dateimanager mit angegebenem Pfad verwenden oder leer ('') wenn System-Dateimanager verwenden
    fileManager: '',
    // fileManager: 'C:\\Program files\\FreeCommander XE\\FreeCommander.exe',
    // Parameter für Dateimanager oder leer ('')
    FMParameter: '/T',
    // 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: 0,  // 0: TabsToolbar, 1: navbar, 2: toolbar-menubar;
    isButton: 1,  // 0: Hamburger, klein; 1: Firefox, groß
    isEditMenu: 1, // Move Main-Menubar
    // Hotkey zum Öffnen des Appmenüs oder leer ('')
    hotkey: 'x',
    hotkeyModifier: 'alt',
    // Ende der Konfiguration --------------------

    isDElang: Cc["@mozilla.org/intl/localeservice;1"].getService(Ci.mozILocaleService).requestedLocale.includes("de"), // German Language
    style: `
/* appbutton */
  #main-window[tabsintitlebar] #AppMenuButton {
    padding-inline-start: 1.6em !important;
    padding-inline-end: 2em !important;
    border-radius: 0 0 4px 4px !important;
    border-top: none !important;
    border-right: 1px solid !important;
    border-left: 1px solid !important;
    border-bottom: 1px solid !important;
  }
  #main-window[tabsintitlebar] #AppMenuButton .toolbarbutton-icon {
    display: none !important;
  }
  /* 'Firefox' title */
  #main-window[tabsintitlebar] #AppMenuButton[label="Firefox"]::after,
  #main-window[tabsintitlebar] #AppMenuButton:not([label="Nightly"],[label="Firefox Nightly"],[label="Firefox Developer Edition"],[label="Firefox"],[label="Tor Browser"],[label="Tor-Browser"])::after {
    content: "Firefox" !important;
  }
  /* 'DevFox' title */
  #main-window[tabsintitlebar] #AppMenuButton[label="Firefox Developer Edition"]::after {
    content: "DevFox" !important;
  }
  /* 'Nightly' title */
  #main-window[tabsintitlebar] #AppMenuButton:is([label="Nightly"],[label="Firefox Nightly"])::after {
    content: "Nightly" !important;
  }
  /* 'Tor-Browser' title */
  #main-window[tabsintitlebar] #AppMenuButton:-moz-any([label="Tor Browser"],[label="Tor-Browser"])::after {
    content: "TorFox" !important;
  }
  /* orange (default) */
  #main-window[tabsintitlebar] #AppMenuButton {
    background-image: linear-gradient(rgb(247,182,82), rgb(215,98,10) 95%) !important;
    border-right-color:hsla(214,89%,21%,.5) !important;
    border-left-color: hsla(214,89%,21%,.5) !important;
    border-bottom-color: hsla(214,89%,21%,.5) !important;
    box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
  			  0 0 2px 1px hsla(0,0%,100%,.25) inset,
  			  0 1px 0 0px rgba(255,255,255,.6),
  			  0 -1px 0 0px rgba(255,255,255,.6),
  			  1px 0 0 0px rgba(255,255,255,.6),
  			  -1px 0 0 0px rgba(255,255,255,.6) !important;
  }
  #main-window[tabsintitlebar] #AppMenuButton:hover:not(:active):not([open]) {
    background-image: radial-gradient(farthest-side at center bottom, rgba(252,240,89,.5) 10%, rgba(252,240,89,0) 70%),
  					radial-gradient(farthest-side at center bottom, rgb(236,133,0), rgba(255,229,172,0)),
  					linear-gradient(rgb(246,170,69), rgb(209,74,0) 95%) !important;
    border-color: rgba(83,42,6,.9) !important;
    box-shadow: 0 1px 0 hsla(0,0%,100%,.15) inset,
  			  0 0 2px 1px hsla(0,0%,100%,.5) inset,
  			  0 -1px 0 hsla(0,0%,100%,.2),
  			  0 1px 0 0px rgba(255,255,255,.6),
  			  0 -1px 0 0px rgba(255,255,255,.6),
  			  1px 0 0 0px rgba(255,255,255,.6),
  			  -1px 0 0 0px rgba(255,255,255,.6) !important;
  }
  #main-window[tabsintitlebar] #AppMenuButton:is(:hover:active,[open]) {
    background-image: linear-gradient(rgb(246,170,69), rgb(209,74,0) 95%) !important;
    box-shadow: 0 2px 3px rgba(0,0,0,.4) inset,
      0 1px 1px rgba(0,0,0,.2) inset,
      0 1px 0 0px rgba(255,255,255,.6),
      0 -1px 0 0px rgba(255,255,255,.6),
      1px 0 0 0px rgba(255,255,255,.6),
      -1px 0 0 0px rgba(255,255,255,.6) !important;
  }
  /* Aurora */
  #main-window[tabsintitlebar] #AppMenuButton[label="Firefox Developer Edition"] {
    background-image: linear-gradient(hsl(208,99%,37%), hsl(214,90%,23%) 95%) !important;
  }
  #main-window[tabsintitlebar] #AppMenuButton[label="Firefox Developer Edition"]:hover:not(:active):not([open]){
    background-image: radial-gradient(farthest-side at center bottom, hsla(202,100%,85%,.5) 10%, hsla(202,100%,85%,0) 70%),
    radial-gradient(farthest-side at center bottom, hsla(205,100%,72%,.7), hsla(205,100%,72%,0)),
    linear-gradient(hsl(208,98%,34%), hsl(213,87%,20%) 95%) !important;
  }
  #main-window[tabsintitlebar] #AppMenuButton[label="Firefox Developer Edition"]:is(:hover:active,[open]) {
    background-image: linear-gradient(hsl(208,95%,30%), hsl(214,85%,17%) 95%) !important;
  }
  /* Nightly */
  #main-window[tabsintitlebar] #AppMenuButton:is([label="Nightly"],[label="Firefox Nightly"]) {
    background-image: linear-gradient(hsl(211,33%,32%), hsl(209,53%,10%) 95%) !important;
  }
  #main-window[tabsintitlebar] #AppMenuButton:is([label="Nightly"],[label="Firefox Nightly"]):hover:not(:active):not([open]){
    background-image: radial-gradient(farthest-side at center bottom, hsla(210,48%,90%,.5) 10%, hsla(210,48%,90%,0) 70%),
    radial-gradient(farthest-side at center bottom, hsla(211,70%,83%,.5), hsla(211,70%,83%,0)),
    linear-gradient(hsl(211,33%,32%), hsl(209,53%,10%) 95%) !important;
  }
  #main-window[tabsintitlebar] #AppMenuButton:is([label="Nightly"],[label="Firefox Nightly"]):is(:hover:active,[open]) {
    background-image: linear-gradient(hsl(211,33%,26%), hsl(209,53%,6%) 95%) !important;
  }
  /* Tor-Browser */
  #main-window[tabsintitlebar] #AppMenuButton:is([label="Tor Browser"],[label="Tor-Browser"]) {
    background-image: linear-gradient(rgb(153,38,211), rgb(105,19,163) 95%) !important;
  }
  #main-window[tabsintitlebar] #AppMenuButton:is([label="Tor Browser"],[label="Tor-Browser"]):hover:not(:active):not([open]){
    background-image: radial-gradient(farthest-side at center bottom, rgba(240,193,255,.5) 10%, rgba(240,193,255,0) 70%),
    radial-gradient(farthest-side at center bottom, rgb(192,81,247), rgba(236,172,255,0)),
    linear-gradient(rgb(144,20,207), rgb(95,0,158) 95%) !important;
  }
  #main-window[tabsintitlebar] #AppMenuButton:is([label="Tor Browser"],[label="Tor-Browser"]):is(:hover:active,[open]) {
    background-image: linear-gradient(rgb(144,20,207), rgb(95,0,158) 95%) !important;
  }
  /*private browsing - purple */
  #main-window[privatebrowsingmode=temporary][tabsintitlebar] #navigator-toolbox #AppMenuButton {
    background-image: linear-gradient(rgb(153,38,211), rgb(105,19,163) 95%) !important;
  }
  #main-window[privatebrowsingmode=temporary][tabsintitlebar] #navigator-toolbox #AppMenuButton:hover:not(:active):not([open]),
  #main-window[privatebrowsingmode=temporary][tabsintitlebar] #navigator-toolbox #PanelUI-button #PanelUI-menu-button:hover:not(:active):not([open]){
    background-image: radial-gradient(farthest-side at center bottom, rgba(240,193,255,.5) 10%, rgba(240,193,255,0) 70%),
    radial-gradient(farthest-side at center bottom, rgb(192,81,247), rgba(236,172,255,0)),
    linear-gradient(rgb(144,20,207), rgb(95,0,158) 95%) !important;
  }
  #main-window[privatebrowsingmode=temporary][tabsintitlebar] #navigator-toolbox #AppMenuButton:is(:hover:active,[open]) {
    background-image: linear-gradient(rgb(144,20,207), rgb(95,0,158) 95%) !important;
  }
}
    `,
    sss: Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
    subdirPopupHash: [],
    subdirMenuHash: [],
    iconsMenu: {
      "file-menu": `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity"><path fill-rule="evenodd" d="M1.25 10.255V14c0 .414.336.75.75.75h12a.75.75 0 0 0 .75-.75v-3.745h-3.534c-.46 0-.868.292-1.016.727-.716 2.1-3.684 2.1-4.4 0a1.074 1.074 0 0 0-1.016-.727H1.25Zm13.5-1.25h-3.534c-.995 0-1.879.633-2.2 1.574-.33.97-1.702.97-2.032 0a2.324 2.324 0 0 0-2.2-1.574H1.25V2A.75.75 0 0 1 2 1.25h12a.75.75 0 0 1 .75.75v7.005ZM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2Z" clip-rule="evenodd"/><path d="M3 3.625C3 3.28 3.28 3 3.625 3h8.75a.625.625 0 1 1 0 1.25h-8.75A.625.625 0 0 1 3 3.625ZM3 6.625C3 6.28 3.28 6 3.625 6h8.75a.625.625 0 1 1 0 1.25h-8.75A.625.625 0 0 1 3 6.625Z"/></svg>')`,
      "edit-menu": 'url("chrome://global/skin/icons/edit.svg")',
      "view-menu": `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity"><path fill-rule="evenodd" d="M14 1.25H2a.75.75 0 0 0-.75.75v12c0 .414.336.75.75.75h12a.75.75 0 0 0 .75-.75V2a.75.75 0 0 0-.75-.75ZM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2Z" clip-rule="evenodd"/><path fill-rule="evenodd" d="M4.25 4.25v3.5h7.5v-3.5h-7.5ZM4 3a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H4ZM10.25 11.25v.5h1.5v-.5h-1.5ZM10 10a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1v-1a1 1 0 0 0-1-1h-2Z" clip-rule="evenodd"/><path d="M3 10.375c0-.345.28-.625.625-.625h3.75a.625.625 0 1 1 0 1.25h-3.75A.625.625 0 0 1 3 10.375ZM3 12.375c0-.345.28-.625.625-.625h3.75a.625.625 0 1 1 0 1.25h-3.75A.625.625 0 0 1 3 12.375Z"/></svg>')`,
      "history-menu": 'url("chrome://browser/skin/history.svg")',
      "bookmarksMenu": 'url("chrome://browser/skin/bookmark.svg")',
      "tools-menu": `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity"><path fill-rule="evenodd" d="M1 6a2 2 0 0 1 2-2h1V3a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v1h1a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V6Zm3-.75H3a.75.75 0 0 0-.75.75v2H4v-.375a.625.625 0 1 1 1.25 0V8h5.5v-.375a.625.625 0 1 1 1.25 0V8h1.75V6a.75.75 0 0 0-.75-.75H4ZM2.25 13c0 .414.336.75.75.75h10a.75.75 0 0 0 .75-.75V9.25H12v1.125a.625.625 0 1 1-1.25 0V9.25h-5.5v1.125a.625.625 0 1 1-1.25 0V9.25H2.25V13ZM10 2.25H6a.75.75 0 0 0-.75.75v1h5.5V3a.75.75 0 0 0-.75-.75Z" clip-rule="evenodd"/></svg>')`,
      "helpMenu": 'url("chrome://global/skin/icons/help.svg")',
    },
    toolbar: {
        // Submenüs des Hauptmenüs definieren; Separator einfügen mit {name: 'separator'}
        subdirs: [{
            name: this.isDElang ? 'Firefox Verzeichnisse' : 'Firefox Folders',
            id: 'AMfolders',
      image: "chrome://browser/skin/save.svg"
        },
        {
            name: this.isDElang ? 'Firefox Profil-Dateien' : 'Firefox Profile',
            id: 'AMprofiles',
            image: "chrome://devtools/skin/images/folder.svg"
        },
        {
            name: this.isDElang ? 'Firefox Funktionen' : 'Firefox Features',
            id: 'AMfeatures',
      image: "chrome://branding/content/about-logo.svg"
        },
        {
            name: 'about:',
            id: 'AMabout',
            image: "chrome://global/skin/icons/developer.svg"
        }],
        
        apps: [{
        // Untermenü Firefox Profil-Dateien
            name: 'userChrome.css',
            root: 'ProfD',
            path: '\\chrome\\userChrome.css',
            subdir: this.isDElang ? 'Firefox Profil-Dateien' : 'Firefox Profile',
      image: 'data:image/svg+xml;utf8,<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity"><path d="M725.333333 85.333333l213.333334 213.333334v170.666666h-85.333334v-135.253333L689.92 170.666667H170.666667v298.666666H85.333333V85.333333zM256 768v42.666667a42.666667 42.666667 0 0 1-85.333333 0v-170.666667a42.666667 42.666667 0 0 1 85.333333 0v42.666667h85.333333v-42.666667a128 128 0 0 0-256 0v170.666667a128 128 0 0 0 256 0v-42.666667z m256-85.333333a42.666667 42.666667 0 1 1 42.666667-42.666667h85.333333a128 128 0 1 0-128 128 42.666667 42.666667 0 1 1-42.666667 42.666667h-85.333333a128 128 0 1 0 128-128z m298.666667 0a42.666667 42.666667 0 1 1 42.666666-42.666667h85.333334a128 128 0 1 0-128 128 42.666667 42.666667 0 1 1-42.666667 42.666667h-85.333333a128 128 0 1 0 128-128z" p-id="7385"/></svg>'
        },
        {
            name: 'userContent.css',
            root: 'ProfD',
            path: '\\chrome\\userContent.css',
            subdir: this.isDElang ? 'Firefox Profil-Dateien' : 'Firefox Profile',
      image: 'data:image/svg+xml;utf8,<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity"><path d="M725.333333 85.333333l213.333334 213.333334v170.666666h-85.333334v-135.253333L689.92 170.666667H170.666667v298.666666H85.333333V85.333333zM256 768v42.666667a42.666667 42.666667 0 0 1-85.333333 0v-170.666667a42.666667 42.666667 0 0 1 85.333333 0v42.666667h85.333333v-42.666667a128 128 0 0 0-256 0v170.666667a128 128 0 0 0 256 0v-42.666667z m256-85.333333a42.666667 42.666667 0 1 1 42.666667-42.666667h85.333333a128 128 0 1 0-128 128 42.666667 42.666667 0 1 1-42.666667 42.666667h-85.333333a128 128 0 1 0 128-128z m298.666667 0a42.666667 42.666667 0 1 1 42.666666-42.666667h85.333334a128 128 0 1 0-128 128 42.666667 42.666667 0 1 1-42.666667 42.666667h-85.333333a128 128 0 1 0 128-128z" p-id="7385"/></svg>'
        },
        {
            name: 'userChrome.js',
            root: 'ProfD',
            path: '\\chrome\\userChrome.js',
            subdir: this.isDElang ? 'Firefox Profil-Dateien' : 'Firefox Profile',
      image:'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity"><path d="M5 3.55h1.98v5.66c0 2.51-1.2 3.39-3.12 3.39-.47 0-1.07-.08-1.46-.21l.22-1.61c.28.1.64.16 1.02.16.84 0 1.36-.38 1.36-1.74V3.55zm3.7 6.87c.54.28 1.36.54 2.22.54.9 0 1.4-.37 1.4-.95 0-.54-.43-.87-1.49-1.24C9.37 8.24 8.4 7.44 8.4 6.15c0-1.5 1.27-2.65 3.33-2.65 1 0 1.73.21 2.26.46l-.45 1.58a4.13 4.13 0 00-1.83-.42c-.87 0-1.28.42-1.28.86 0 .56.49.81 1.63 1.26 1.56.57 2.28 1.37 2.28 2.63 0 1.48-1.13 2.73-3.55 2.73-1 0-1.99-.28-2.49-.55l.4-1.63z" /></svg>'
        },
        {
            name: 'prefs.js',
            root: 'ProfD',
            path: '\\prefs.js',
            subdir: this.isDElang ? 'Firefox Profil-Dateien' : 'Firefox Profile',
      image:'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity"><path d="M5 3.55h1.98v5.66c0 2.51-1.2 3.39-3.12 3.39-.47 0-1.07-.08-1.46-.21l.22-1.61c.28.1.64.16 1.02.16.84 0 1.36-.38 1.36-1.74V3.55zm3.7 6.87c.54.28 1.36.54 2.22.54.9 0 1.4-.37 1.4-.95 0-.54-.43-.87-1.49-1.24C9.37 8.24 8.4 7.44 8.4 6.15c0-1.5 1.27-2.65 3.33-2.65 1 0 1.73.21 2.26.46l-.45 1.58a4.13 4.13 0 00-1.83-.42c-.87 0-1.28.42-1.28.86 0 .56.49.81 1.63 1.26 1.56.57 2.28 1.37 2.28 2.63 0 1.48-1.13 2.73-3.55 2.73-1 0-1.99-.28-2.49-.55l.4-1.63z" /></svg>'
        },
        {
            name: 'user.js',
            root: 'ProfD',
            path: '\\user.js',
            subdir: this.isDElang ? 'Firefox Profil-Dateien' : 'Firefox Profile',
      image:'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity"><path d="M5 3.55h1.98v5.66c0 2.51-1.2 3.39-3.12 3.39-.47 0-1.07-.08-1.46-.21l.22-1.61c.28.1.64.16 1.02.16.84 0 1.36-.38 1.36-1.74V3.55zm3.7 6.87c.54.28 1.36.54 2.22.54.9 0 1.4-.37 1.4-.95 0-.54-.43-.87-1.49-1.24C9.37 8.24 8.4 7.44 8.4 6.15c0-1.5 1.27-2.65 3.33-2.65 1 0 1.73.21 2.26.46l-.45 1.58a4.13 4.13 0 00-1.83-.42c-.87 0-1.28.42-1.28.86 0 .56.49.81 1.63 1.26 1.56.57 2.28 1.37 2.28 2.63 0 1.48-1.13 2.73-3.55 2.73-1 0-1.99-.28-2.49-.55l.4-1.63z" /></svg>'
        },
        // Untermenü Firefox Verzeichnisse
        {
            name: this.isDElang ? 'Profil' : 'Profile',
            root: 'ProfD',
            path: '\\',
            subdir: this.isDElang ? 'Firefox Profil-Dateien' : 'Firefox Profile',
      image: "chrome://devtools/skin/images/folder.svg"
        },
        {
            name: 'chrome',
            root: 'ProfD',
            path: '\\chrome',
            subdir: this.isDElang ? 'Firefox Verzeichnisse' : 'Firefox Folders',
      image: 'chrome://devtools/skin/images/browsers/chrome.svg'
        },
        {
            name: 'CSS',
            root: 'ProfD',
            path: '\\chrome\\CSS',
            subdir: this.isDElang ? 'Firefox Verzeichnisse' : 'Firefox Folders',
      image: 'data:image/svg+xml;utf8,<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity"><path d="M725.333333 85.333333l213.333334 213.333334v170.666666h-85.333334v-135.253333L689.92 170.666667H170.666667v298.666666H85.333333V85.333333zM256 768v42.666667a42.666667 42.666667 0 0 1-85.333333 0v-170.666667a42.666667 42.666667 0 0 1 85.333333 0v42.666667h85.333333v-42.666667a128 128 0 0 0-256 0v170.666667a128 128 0 0 0 256 0v-42.666667z m256-85.333333a42.666667 42.666667 0 1 1 42.666667-42.666667h85.333333a128 128 0 1 0-128 128 42.666667 42.666667 0 1 1-42.666667 42.666667h-85.333333a128 128 0 1 0 128-128z m298.666667 0a42.666667 42.666667 0 1 1 42.666666-42.666667h85.333334a128 128 0 1 0-128 128 42.666667 42.666667 0 1 1-42.666667 42.666667h-85.333333a128 128 0 1 0 128-128z" p-id="7385"/></svg>'
        },
        {
            name: 'JS',
            root: 'ProfD',
            path: '\\chrome\\JS',
            subdir: this.isDElang ? 'Firefox Verzeichnisse' : 'Firefox Folders',
      image:'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity"><path d="M5 3.55h1.98v5.66c0 2.51-1.2 3.39-3.12 3.39-.47 0-1.07-.08-1.46-.21l.22-1.61c.28.1.64.16 1.02.16.84 0 1.36-.38 1.36-1.74V3.55zm3.7 6.87c.54.28 1.36.54 2.22.54.9 0 1.4-.37 1.4-.95 0-.54-.43-.87-1.49-1.24C9.37 8.24 8.4 7.44 8.4 6.15c0-1.5 1.27-2.65 3.33-2.65 1 0 1.73.21 2.26.46l-.45 1.58a4.13 4.13 0 00-1.83-.42c-.87 0-1.28.42-1.28.86 0 .56.49.81 1.63 1.26 1.56.57 2.28 1.37 2.28 2.63 0 1.48-1.13 2.73-3.55 2.73-1 0-1.99-.28-2.49-.55l.4-1.63z" /></svg>'
        },
        {
            name: 'Addons',
            root: 'ProfD',
            path: '\\extensions',
            subdir: this.isDElang ? 'Firefox Verzeichnisse' : 'Firefox Folders',
      image: 'chrome://mozapps/skin/extensions/category-extensions.svg'
         },
         {
            name: this.isDElang ? 'Programm' : "core/browser",
            root: 'CurProcD',
            path: '\\',
            subdir: this.isDElang ? 'Firefox Verzeichnisse' : 'Firefox Folders',
      image: 'chrome://branding/content/about-logo.svg'
         },
         {
            name: 'Startup Cache',
            root: 'ProfLD',
            path: '\\startupCache',
            subdir: this.isDElang ? 'Firefox Verzeichnisse' : 'Firefox Folders',
      image: 'chrome://mozapps/skin/extensions/category-discover.svg'
         }
         ],
        
        configs: [
        // Untermenü Firefox Funktionen
        {
            name: this.isDElang ? 'Symbolleiste anpassen…' : 'Customize toolbar…',
            command: "gCustomizeMode.enter()",
            subdir: this.isDElang ? 'Firefox Funktionen' : 'Firefox Features',
      image:'chrome://browser/skin/customize.svg'
        },

        {
            name: this.isDElang ? 'Neustart im abgesicherten Modus' : 'Reatart in Troubleshooting Mode',
            command: "safeModeRestart();",
            subdir: this.isDElang ? 'Firefox Funktionen' : 'Firefox Features',
      image:'chrome://devtools/skin/images/debugging-workers.svg'
        },
        {
            name: this.isDElang ? 'Browser-Konsole' : 'Browser Console',
            command: "var { require } = ChromeUtils.importESModule('resource://devtools/shared/loader/Loader.sys.mjs', {});\
                      var { BrowserConsoleManager } = require('resource://devtools/client/webconsole/browser-console-manager');\
                      BrowserConsoleManager.openBrowserConsoleOrFocus();",
            subdir: this.isDElang ? 'Firefox Funktionen' : 'Firefox Features',
      image:'chrome://devtools/skin/images/tool-webconsole.svg'
        },
        {
            name: this.isDElang ? 'Entwickler-Werkzeuge' : 'Web Developer Tools',
            command: "var { require } = ChromeUtils.importESModule('resource://devtools/shared/loader/Loader.sys.mjs', {});\
                var { gDevToolsBrowser } = require('devtools/client/framework/devtools-browser');\
                gDevToolsBrowser.toggleToolboxCommand(window.gBrowser, Cu.now());",
            subdir: this.isDElang ? 'Firefox Funktionen' : 'Firefox Features',
      image:'chrome://global/skin/icons/performance.svg',
        },	
        {
            name: this.isDElang ? 'Browser-Werkzeuge' : 'Browser Toolbox',
            command: "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();",
            subdir: this.isDElang ? 'Firefox Funktionen' : 'Firefox Features',
      image:'chrome://devtools/skin/images/command-frames.svg',
        },
        {
            name: this.isDElang ? 'Firefox synchronisieren' : 'Firefox synchronise',
            command: "gSync.openPrefs('menubar');",
            subdir: this.isDElang ? 'Firefox Funktionen' : 'Firefox Features',
      image:'chrome://browser/skin/sync.svg'
        },
        {
            name: this.isDElang ? 'Zugangsdaten und Passwörter' : 'Logins & Passwords',
            command: "LoginHelper.openPasswordManager(window, { entryPoint: 'mainmenu' })",
            tooltiptext: 'about:logins',
            subdir: this.isDElang ? 'Firefox Funktionen' : 'Firefox Features',
      image:'chrome://browser/skin/login.svg'
        },
        {
            name: this.isDElang ? 'Task Manager' : 'Task Manager',
            command: "switchToTabHavingURI('about:processes', true)",
            tooltiptext: 'about:processes',
            subdir: this.isDElang ? 'Firefox Funktionen' : 'Firefox Features',
      image:'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity"><path d="M5 5a3 3 0 0 1 6 0v7a3 3 0 1 1-6 0V5Z"/><path fill-rule="evenodd" d="M6.369 0c.345 0 .625.28.625.625v1.371a1.006 1.006 0 0 0 2.012 0V.626a.625.625 0 1 1 1.25 0v1.37a2.256 2.256 0 1 1-4.512 0V.626c0-.346.28-.626.625-.626ZM2.627 1c.345 0 .625.28.625.626v1.871c0 .76.616 1.376 1.376 1.376h6.745c.76 0 1.376-.616 1.376-1.376V1.626a.625.625 0 0 1 1.25 0v1.871a2.627 2.627 0 0 1-2.626 2.627H4.628A2.627 2.627 0 0 1 2 3.497V1.626c0-.345.28-.625.626-.625ZM0 8.63c0-.345.28-.625.625-.625h14.75a.625.625 0 1 1 0 1.25H.625A.625.625 0 0 1 0 8.63Zm4.628 3.498c-.76 0-1.376.616-1.376 1.375v1.872a.625.625 0 1 1-1.25 0v-1.872a2.627 2.627 0 0 1 2.626-2.626h6.745a2.627 2.627 0 0 1 2.626 2.626v1.872a.625.625 0 1 1-1.25 0v-1.872c0-.76-.616-1.375-1.376-1.375H4.628Z" clip-rule="evenodd"/></svg>'
        },
        {
            name: this.isDElang ? 'Offline arbeiten' : 'Work Offline',
            command: "BrowserOffline.toggleOfflineStatus();",
            subdir: this.isDElang ? 'Firefox Funktionen' : 'Firefox Features',
      image:'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity"><path fill-rule="evenodd" d="m12.499 9.154 1.326-1.326a4 4 0 0 0-5.657-5.656L6.842 3.497a.625.625 0 0 0 0 .884l4.773 4.773c.244.244.64.244.884 0ZM9.052 3.055a2.75 2.75 0 0 1 3.889 3.89l-.878.878-3.89-3.89.879-.878ZM3.497 6.842 2.172 8.168a4 4 0 0 0 5.656 5.657l1.326-1.326a.625.625 0 0 0 0-.884L4.381 6.842a.625.625 0 0 0-.884 0Zm3.448 6.099a2.75 2.75 0 0 1-3.89-3.89l.876-.875 3.889 3.89-.875.875Z" clip-rule="evenodd"/><path fill-rule="evenodd" d="M15.812.188a.625.625 0 0 1 0 .884l-2 2a.625.625 0 1 1-.884-.884l2-2a.625.625 0 0 1 .884 0Zm-8.37 6.37a.625.625 0 0 1 0 .884l-1.5 1.5a.625.625 0 0 1-.884-.884l1.5-1.5a.625.625 0 0 1 .884 0Zm2 2a.625.625 0 0 1 0 .884l-1.5 1.5a.625.625 0 1 1-.884-.884l1.5-1.5a.625.625 0 0 1 .884 0Zm-6.5 4.5a.625.625 0 0 1 0 .884l-1.87 1.87a.625.625 0 0 1-.884-.884l1.87-1.87a.625.625 0 0 1 .884 0Z" clip-rule="evenodd"/></svg>'
        },
        // Untermenü about:
        
        /* {
            name: 'separator'
        }, */
        {
            name: 'about:about',
            command: "openTrustedLinkIn('about:about', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://branding/content/about-logo.svg'
        },
        {
            name: 'about:cache',
            command: "openTrustedLinkIn('about:cache', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://global/skin/icons/developer.svg'
        },
        {
            name: 'about:certificate',
            command: "openTrustedLinkIn('about:certificate', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity"><path d="M25 2C12.296875 2 2 12.296875 2 25C2 37.703125 12.296875 48 25 48C37.703125 48 48 37.703125 48 25C48 12.296875 37.703125 2 25 2 Z M 25 4C36.578125 4 46 13.421875 46 25C46 36.578125 36.578125 46 25 46C13.421875 46 4 36.578125 4 25C4 13.421875 13.421875 4 25 4 Z M 25 8C20.035156 8 16 12.035156 16 17L16 21L22 21L22 17C22 15.347656 23.347656 14 25 14C26.652344 14 28 15.347656 28 17L28 21L34 21L34 17C34 12.035156 29.964844 8 25 8 Z M 25 10C28.867188 10 32 13.132813 32 17L32 19L30 19L30 17C30 14.238281 27.761719 12 25 12C22.238281 12 20 14.238281 20 17L20 19L18 19L18 17C18 13.132813 21.132813 10 25 10 Z M 16 22C13.792969 22 12 23.792969 12 26L12 36C12 38.207031 13.792969 40 16 40L34 40C36.207031 40 38 38.207031 38 36L38 26C38 23.792969 36.207031 22 34 22 Z M 16 24L34 24C35.105469 24 36 24.894531 36 26L36 36C36 37.105469 35.105469 38 34 38L16 38C14.894531 38 14 37.105469 14 36L14 26C14 24.894531 14.894531 24 16 24 Z M 17 26C16.449219 26 16 26.449219 16 27L16 35C16 35.550781 16.449219 36 17 36C17.550781 36 18 35.550781 18 35L18 27C18 26.449219 17.550781 26 17 26 Z M 25 26C23.894531 26 23 26.894531 23 28C23 28.714844 23.382813 29.375 24 29.730469L24 35L26 35L26 29.730469C26.617188 29.371094 27 28.714844 27 28C27 26.894531 26.105469 26 25 26Z" /></svg>'

            
        },
        {
            name: 'about:checkerboard',
            command: "openTrustedLinkIn('about:checkerboard', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://global/skin/icons/clipboard.svg'
        },
        {
            name: 'about:compat',
            command: "openTrustedLinkIn('about:compat', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'resource://devtools-shared-images/alert-small.svg'
        },
        {
            name: 'about:config',
            command: "openTrustedLinkIn('about:config', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://global/skin/icons/settings.svg'
        },
        {
            name: 'about:crashes',
            command: "openTrustedLinkIn('about:crashes', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://global/skin/icons/loading.svg'
        },
        {
            name: 'about:debugging',
            command: "openTrustedLinkIn('about:debugging', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity"><path d="M5 5a3 3 0 0 1 6 0v7a3 3 0 1 1-6 0V5Z"/><path fill-rule="evenodd" d="M6.369 0c.345 0 .625.28.625.625v1.371a1.006 1.006 0 0 0 2.012 0V.626a.625.625 0 1 1 1.25 0v1.37a2.256 2.256 0 1 1-4.512 0V.626c0-.346.28-.626.625-.626ZM2.627 1c.345 0 .625.28.625.626v1.871c0 .76.616 1.376 1.376 1.376h6.745c.76 0 1.376-.616 1.376-1.376V1.626a.625.625 0 0 1 1.25 0v1.871a2.627 2.627 0 0 1-2.626 2.627H4.628A2.627 2.627 0 0 1 2 3.497V1.626c0-.345.28-.625.626-.625ZM0 8.63c0-.345.28-.625.625-.625h14.75a.625.625 0 1 1 0 1.25H.625A.625.625 0 0 1 0 8.63Zm4.628 3.498c-.76 0-1.376.616-1.376 1.375v1.872a.625.625 0 1 1-1.25 0v-1.872a2.627 2.627 0 0 1 2.626-2.626h6.745a2.627 2.627 0 0 1 2.626 2.626v1.872a.625.625 0 1 1-1.25 0v-1.872c0-.76-.616-1.375-1.376-1.375H4.628Z" clip-rule="evenodd"/></svg>'
        },
        {
            name: 'about:downloads',
            command: "openTrustedLinkIn('about:downloads', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://browser/skin/downloads/downloads.svg'
        },
        {
            name: 'about:logging',
            command: "openTrustedLinkIn('about:logging', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://devtools/skin/images/tool-webconsole.svg'
        },
        {
            name: 'about:logins',
            command: "openTrustedLinkIn('about:logins', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://browser/skin/login.svg'
        },
        {
            name: 'about:memory',
            command: "openTrustedLinkIn('about:memory', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://devtools/skin/images/tool-memory.svg'
        },
        {
            name: 'about:networking',
            command: "openTrustedLinkIn('about:networking', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity"><path fill-rule="evenodd" d="m12.499 9.154 1.326-1.326a4 4 0 0 0-5.657-5.656L6.842 3.497a.625.625 0 0 0 0 .884l4.773 4.773c.244.244.64.244.884 0ZM9.052 3.055a2.75 2.75 0 0 1 3.889 3.89l-.878.878-3.89-3.89.879-.878ZM3.497 6.842 2.172 8.168a4 4 0 0 0 5.656 5.657l1.326-1.326a.625.625 0 0 0 0-.884L4.381 6.842a.625.625 0 0 0-.884 0Zm3.448 6.099a2.75 2.75 0 0 1-3.89-3.89l.876-.875 3.889 3.89-.875.875Z" clip-rule="evenodd"/><path fill-rule="evenodd" d="M15.812.188a.625.625 0 0 1 0 .884l-2 2a.625.625 0 1 1-.884-.884l2-2a.625.625 0 0 1 .884 0Zm-8.37 6.37a.625.625 0 0 1 0 .884l-1.5 1.5a.625.625 0 0 1-.884-.884l1.5-1.5a.625.625 0 0 1 .884 0Zm2 2a.625.625 0 0 1 0 .884l-1.5 1.5a.625.625 0 1 1-.884-.884l1.5-1.5a.625.625 0 0 1 .884 0Zm-6.5 4.5a.625.625 0 0 1 0 .884l-1.87 1.87a.625.625 0 0 1-.884-.884l1.87-1.87a.625.625 0 0 1 .884 0Z" clip-rule="evenodd"/></svg>'
        },
        {
            name: 'about:processes',
            command: "openTrustedLinkIn('about:processes', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            tooltiptext: 'Task Manager',
            subdir: 'about:',
            image:'chrome://global/skin/icons/performance.svg'
        },
        {
            name: 'about:policies',
            command: "openTrustedLinkIn('about:policies', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://browser/content/policies/policies-active.svg'
        },
        {
            name: 'about:profiles',
            command: "openTrustedLinkIn('about:profiles', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://global/skin/icons/info.svg'
        },
        {
            name: 'about:profiling',
            command: "openTrustedLinkIn('about:profiling', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://devtools/skin/images/profiler-stopwatch.svg'
        },
        {
            name: 'about:protections',
            command: "openTrustedLinkIn('about:protections', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://browser/skin/tracking-protection.svg'
        },
        {
            name: 'about:rights',
            command: "openTrustedLinkIn('about:rights', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://global/skin/illustrations/about-rights.svg'
        },
    {
            name: 'about:serviceworkers',
            command: "openTrustedLinkIn('about:serviceworkers', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://global/skin/icons/developer.svg'
        },
        {
            name: 'about:studies',
            command: "openTrustedLinkIn('about:studies', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://browser/skin/ion.svg'
        },
        {
            name: 'about:support',
            command: "openTrustedLinkIn('about:support', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://devtools/skin/images/browsers/firefox.svg'
        },
        {
            name: 'about:sync-log',
            command: "openTrustedLinkIn('about:sync-log', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://browser/skin/sync.svg'
        },
        {
            name: 'about:telemetry',
            command: "openTrustedLinkIn('about:telemetry', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://global/skin/icons/arrow-down.svg'
        },
        {
            name: 'about:third-party',
            command: "openTrustedLinkIn('about:third-party', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://browser/skin/library.svg'
        },
        {
            name: 'about:unloads',
            command: "openTrustedLinkIn('about:unloads', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            tooltiptext: 'Tabs entladen',
            subdir: 'about:',
            image:'chrome://mozapps/skin/extensions/category-available.svg'
        },
        {
            name: 'about:url-classifier',
            command: "openTrustedLinkIn('about:url-classifier', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://global/skin/icons/link.svg'
        },
        {
            name: 'about:webrtc',
            command: "openTrustedLinkIn('about:webrtc', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://browser/skin/notification-icons/screen.svg'
        },
        {
            name: 'about:windows-messages',
            command: "openTrustedLinkIn('about:windows-messages', gBrowser.selectedTab.isEmpty ? 'current' : 'tab')",
            subdir: 'about:',
            image:'chrome://browser/skin/window.svg'
        },

        // Hauptmenü  Einträge
        {
            name: this.isDElang ? 'Neues privates Fenster' : 'New Private Window',
            command: "OpenBrowserWindow({private: true});",
            id: 'AMprivate',
            image: "chrome://browser/skin/privateBrowsing.svg"
        },
        {
            name: 'separator'
        },
        {
            name: this.isDElang ? 'Einstellungen' : 'Firefox Settings',
            command: "openPreferences();",
            id: 'AMsettings',
      image: "chrome://devtools/skin/images/settings.svg",
        },
        {
            name: 'Add-ons',
            command: "BrowserAddonUI.openAddonsMgr();",
            id: 'AMaddons',
      image: "chrome://mozapps/skin/extensions/category-extensions.svg",
        },
        {
            name: 'separator'
        },

        {
            name: this.isDElang ? 'Lesezeichen-Verwaltung' : 'Manage Bookmarks',
            command: "PlacesCommandHook.showPlacesOrganizer('AllBookmarks');",
            id: 'AMbookmarks',
            image: "chrome://browser/skin/bookmark-star-on-tray.svg",
        },
/*         {
            name: 'separator'
        },
*/
        {
            name: this.isDElang ? 'Chronik' : 'History',
            command: "PlacesCommandHook.showPlacesOrganizer('History');",
            id: 'AMhistory',
            image: "chrome://browser/skin/history.svg",
        },
        {
            name: this.isDElang ? 'Downloads' : 'Downloads',
            command: "BrowserCommands.downloadsUI();",
            id: 'AMdownloads',
            image: "chrome://browser/skin/downloads/download-summary.svg",
        },
        {
            name: this.isDElang ? 'Seite speichern unter…' : 'Save Page as…',
            command: "saveBrowser(gBrowser.selectedBrowser)",
            id: 'AMsave',
            image: "chrome://browser/skin/save.svg",
        },
        {
            name: this.isDElang ? 'Chronik löschen' : 'Clear browsing data and cookies',
            command: "Sanitizer.showUI(window);",
            id: 'AMsanitize',
            image: "chrome://devtools/skin/images/clear.svg",
        },
        {
            name: 'separator',
        },
        {
            name: this.isDElang ? 'Neustart' : 'Restart',
            tooltiptext: this.isDElang ? 'userChrome.js-Cache wird geleert' : 'Restart and recreate the quick start cache.',
            // command: "Services.appinfo.invalidateCachesOnRestart(); BrowserUtils.restartApplication();",
        command: 'Services.appinfo.invalidateCachesOnRestart(); \
                      Services.startup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);',
            id: 'AMreboot',
            image: "chrome://devtools/skin/images/reload.svg",
        },
        {
            name: this.isDElang ? 'Beenden' : "Exit",
            command: "goQuitApplication(event);",
            id: 'AMquit',
      image: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity"><path d="M5.561 3.112c-.132-.32-.5-.474-.807-.314a7 7 0 1 0 6.492 0c-.306-.16-.675-.006-.807.314s.021.683.325.85a5.747 5.747 0 1 1-5.528 0c.303-.167.457-.53.325-.85Z"/><path fill-rule="evenodd" d="M8 1.375c.345 0 .625.28.625.625v6a.625.625 0 1 1-1.25 0V2c0-.345.28-.625.625-.625Z" clip-rule="evenodd"/></svg>'
        },

/*         {
            name: 'separator',
        },
 */        ]
    },
    _externalAppPopup: null,
    _isready: false,
    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.className = "toolbarbutton-1";
        ExternalAppBtn.setAttribute("label", AppConstants.MOZ_APP_DISPLAYNAME_DO_NOT_USE);
        ExternalAppBtn.setAttribute("onclick", "event.preventDefault();event.stopPropagation();");
        ExternalAppBtn.setAttribute("tooltiptext", AppConstants.MOZ_APP_DISPLAYNAME_DO_NOT_USE + " " + (this.isDElang ? "Menü" : "Menu"));
        ExternalAppBtn.setAttribute("type", "menu");
        ExternalAppBtn.setAttribute("removable", "true");

      if (Appmenu.isButton) {
        const newURIParam = {
          aURL: 'data:text/css,' + encodeURIComponent(this.style),
          aOriginCharset: null,
          aBaseURI: null
        };
        const cssUri = Services.io.newURI(newURIParam.aURL, newURIParam.aOriginCharset, newURIParam.aBaseURI);
        if (!this.sss.sheetRegistered(cssUri, this.sss.USER_SHEET))
          this.sss.loadAndRegisterSheet(cssUri, this.sss.USER_SHEET);

      } else {
        ExternalAppBtn.style.listStyleImage = 'url("chrome://browser/skin/menu.svg")';
        ExternalAppBtn.style.MozContextProperties = "fill";
        ExternalAppBtn.style.setProperty("fill", "currentColor");
      }
        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.setAttribute('onpopupshowing', 'event.stopPropagation(); Appmenu.onpopupshowing();');
        ExternalAppPopup.setAttribute('id', 'AMpopup');
        this._externalAppPopup = ExternalAppPopup;
        ExternalAppBtn.appendChild(ExternalAppPopup);
        Appmenu.onpopupshowing();
        
      // 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.setAttribute('oncommand', '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 {
                var subdirItem = ExternalAppPopup.appendChild(document.createXULElement('menu'));
                var subdirItemPopup = subdirItem.appendChild(document.createXULElement('menupopup'));
                if (subdir.id) subdirItem.setAttribute('id', subdir.id);
                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;
            }
        }

        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.setAttribute('oncommand', "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.setAttribute('oncommand', 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 i = 0; i < Appmenu.subdirPopupHash.length; i++) {
                if (Appmenu.subdirPopupHash[i].hasChildNodes()) {
                    continue;
                } else {
                    Appmenu.subdirMenuHash[i].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;
    },

    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()) {
            //Cu.reportError('Datei nicht gefunden: ' + path);
            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();
            }
        }
    },

    editmenu: async () => {  // ZUGEFÜGT!
      if (document.getElementById("main-menubar").querySelectorAll(":scope > script").length >= 1) {
        const _AMjs = {};
        _AMjs.uri = "data:application/x-javascript;charset=UTF-8,";
        _AMjs.res = await fetch(document.getElementById("main-menubar").querySelectorAll(":scope > script")[0].src);
        _AMjs.text = (await _AMjs.res.text()).replace(/main-menubar/, "AMpopup");
        const scriptloader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
        scriptloader.loadSubScript(_AMjs.uri + encodeURIComponent(_AMjs.text), this);
      };
      setTimeout(function() {
        var pane1 = document.getElementById('AMpopup');
        var item2 = document.getElementById('AMfolders');

        // Menüs einfügen
        for (var menu of Array.from(document.getElementById("main-menubar").querySelectorAll(":scope > menu"))) {
          var popup = menu.menupopup;
          popup.remove();
          menu.textContent = menu.renderedOnce = "";
          var img = Appmenu.iconsMenu[menu.id];
          if (img) {
            menu.className = "menu-iconic";
            menu.style.listStyleImage = img;
          }
          menu.render;
          menu.append(popup);
          menu.disablrd = false;
          pane1.insertBefore(menu, item2);
        }
        var separator = document.createXULElement('menuseparator');
        separator.setAttribute('flex', '1');
        pane1.insertBefore(separator, item2);   

        // Script-Menüs einfügen
        var ids = ['usercssloader-menu', 'ExtraConfigMenu', 'no-eom-button'];
        for (var id of ids) {
          var _id =  document.getElementById(id);
          if (_id)
            pane1.insertBefore(_id, item2);
        }
      }, 2e3);
    }  // ZUGEFÜGT!
};

if (window.gBrowser) {
    Appmenu.init();
    if (Appmenu.isEditMenu)
      Appmenu.editmenu();
}


ЗЫ: кому по настольгировать, но там ещё есть режим иконки гамбергера, как по мне компактно и удобно.


Жизнь иногда такое выкидывает, что хочется подобрать...

Отсутствует

 

№15601-09-2024 09:53:18

fuchsfan
Участник
 
Группа: Members
Зарегистрирован: 07-08-2023
Сообщений: 124
UA: Firefox 129.0

Re: userChrome.js

Farby пишет

В общем покопался и пересобрал рыжее меню для рыжего лиса,

Мощное меню, и все работает!

Отсутствует

 

№15728-09-2024 13:10:22

dinn
Участник
 
Группа: Members
Зарегистрирован: 28-09-2024
Сообщений: 10
UA: Firefox 130.0

Re: userChrome.js

Dumby посмотрите оконную виджет кнопочку-индикатор. Прослушки глобальные, действуют в любом месте окна, т.е. жестко с кнопкой не связаны. Цель: вместо этих прослушек добавить такую, чтобы кнопка делала opacity = 0.5 или disabled = true, если буфер обмена пуст и opacity = 1 или disabled = false? если буфер обмена не пуст.
Или с событием 'copy' такое не прокатит и нужно ждать поддержки такой фишки?

скрытый текст

Выделить код

Код:

location.href.endsWith("://browser/content/browser.xhtml") && (async () => CustomizableUI.createWidget({
	id: "test_button",
	localized: false,
	get icon() {
		let icon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAABY0lEQVR4nGNgwANeL2EofrWUoYiBXPBoHsMfECbbgLszGf6DMNkGXJvM8B+EyTYgODXuPwiTpit0FTNv0ip1noTltsJhU/6DsED0Ylve6MXqIDm8ennjl8fyxi39yh+35D9/7KL/ArEL/gvEzPsvGD33v2DU7P+CkTO/CodPi8VpAH/sglUCMfPhGoQiZ/0XipjxXzh8GtglIqGT/ouGTFiF04CP29T2f9qu/h8f/rhNbR9OA77sMXz5ZY/hf3z4826D51g1fzpkI/r9oPV/XPjjLhMEe7epMIYBv486+/w66vQfhL8fsgfTyPjtVn04+/dhJ09MA054tvw56fUfhD/uMgfTyPjNJk04+/cJryYMA/6e9j/+74z/fxB+s0kDTCPj1+tk//897Qtm/z3jdxTDgP/nQrL+nwua+/9c0KG368S//j8b9O7/uaBfYHw26N3HzfIffx9zPg1RE5KFMyZIBQA3pi1KgcfhAAAAAABJRU5ErkJggg";
		let subst = this.id.toLowerCase() + "-icon";
		Services.io.getProtocolHandler("resource")
			.QueryInterface(Ci.nsIResProtocolHandler)
			.setSubstitution(subst, Services.io.newURI(icon));
		delete this.icon;
		return this.icon = "resource://" + subst;
	},
	onCreated(btn) {
		btn.ownerGlobal.addEventListener('mousedown', () => btn.style.opacity = 0.5);
		btn.ownerGlobal.addEventListener('mouseup', () => btn.style.opacity = 1);
		btn.setAttribute("image", this.icon);
	},
}))();

На форуме

 

№15802-10-2024 09:53:32

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2229
UA: Firefox 78.0

Re: userChrome.js

dinn пишет

Или с событием 'copy' такое не прокатит

Какое «такое»? Событие "copy" наступит когда случится копирование
в этом окне, а значит в этом процессе, не в контентских процессах.
А даже если слушать и в них, то это всё равно всего лишь copy.

нужно ждать поддержки такой фишки?

Да, такая фишка была бы здесь полезна, только это настораживает:
«
    If the clipboard contents are changed outside the user agent,
    then the clipboardchange event MUST fire when the user agent regains focus.
»
Хотел попробовать записать какой-то аналог на ctypes,
но далеко не продвинулся, то ли в ctypes что-то сломано,
то ли руки кривые, но при попытке использовать функцию
(процедуру, как в осуществлении SetWindowsHookExW() или SetWindowLongA())
браузер валится с MozCrashReason: *** Compartment mismatch 0 vs. xxxxxxxx at argument 0


Ладно, если это так важно, то можно было бы и интервал подрядить на сколько не жалко.
Но как узнать что буфер обмена пуст? В смысле, какое состояние буфера считать пустым?
Непонятно.

Отсутствует

 

№15902-10-2024 13:59:40

dinn
Участник
 
Группа: Members
Зарегистрирован: 28-09-2024
Сообщений: 10
UA: Firefox 130.0

Re: userChrome.js

Dumby пишет

можно было бы и интервал подрядить на сколько не жалко.

Это интересно только в плане технической реализации

Dumby пишет

Но как узнать что буфер обмена пуст? В смысле, какое состояние буфера считать пустым?

Все упрощается тем, что я никогда не очищаю буфер вне браузера, т.е. это будет делать кнопка. А в плане реализации мне не подходит оконный readFromClipboard(). Это становится понятным, если в буфере несколько типов данных, например, мы сначала скопировали текст, а потом картинку. Подходит await navigator.clipboard.read().
В итоге сделал такую кнопку. Просьба посмотреть и более грамотно расписать с точки зрения гуру, ну и заменить readFromClipboard()

скрытый текст

Выделить код

Код:

location.href.endsWith("://browser/content/browser.xhtml") && (async (alertsService) => CustomizableUI.createWidget({
	id: "my-cleanClipbrd",
	label: "Clean clipbrd",
	tooltiptext: "Clean data from Clipboard",
	localized: false,
	get icon() {
		let icon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAABY0lEQVR4nGNgwANeL2EofrWUoYiBXPBoHsMfECbbgLszGf6DMNkGXJvM8B+EyTYgODXuPwiTpit0FTNv0ip1noTltsJhU/6DsED0Ylve6MXqIDm8ennjl8fyxi39yh+35D9/7KL/ArEL/gvEzPsvGD33v2DU7P+CkTO/CodPi8VpAH/sglUCMfPhGoQiZ/0XipjxXzh8GtglIqGT/ouGTFiF04CP29T2f9qu/h8f/rhNbR9OA77sMXz5ZY/hf3z4826D51g1fzpkI/r9oPV/XPjjLhMEe7epMIYBv486+/w66vQfhL8fsgfTyPjtVn04+/dhJ09MA054tvw56fUfhD/uMgfTyPjNJk04+/cJryYMA/6e9j/+74z/fxB+s0kDTCPj1+tk//897Qtm/z3jdxTDgP/nQrL+nwua+/9c0KG368S//j8b9O7/uaBfYHw26N3HzfIffx9zPg1RE5KFMyZIBQA3pi1KgcfhAAAAAABJRU5ErkJggg";
		let subst = this.id.toLowerCase() + "-icon";
		Services.io.getProtocolHandler("resource")
			.QueryInterface(Ci.nsIResProtocolHandler)
			.setSubstitution(subst, Services.io.newURI(icon));
		delete this.icon;
		return this.icon = "resource://" + subst;
	},
	onCreated(btn) {
		btn.setAttribute("image", this.icon);
		args11 = ["popuphiding", () => {
			console.log('popup close');
			if (!readFromClipboard()) return;
			btn.style.visibility = 'visible';
			PlacesToolbarItems.removeEventListener(...args11);
			console.log('remove listener');
		}];
		if (!readFromClipboard()) {
			btn.style.visibility = 'hidden';
			PlacesToolbarItems.addEventListener(...args11);
		}
	},
	onCommand(e) {
		Services.clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
		e.target.style.visibility = 'hidden';
		PlacesToolbarItems.addEventListener(...args11);
		alertsService.showAlertNotification("chrome://browser/skin/customizableui/whimsy.png", "Clipboard", "Буфер обмена растоптан!");
		setTimeout(() => alertsService.closeAlert(), 2000);
    },
}))(Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService));

На форуме

 

№16006-10-2024 09:51:35

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2229
UA: Firefox 78.0

Re: userChrome.js

dinn пишет

заменить readFromClipboard()

На await navigator.clipboard.read() что ли?
А в чём тут затруднение? Выражение вернёт массив,
либо пустой, либо не пустой, просто проверяем length


Другое дело, что navigator.clipboard берёт лишь немногое.
Например, в копируем файл в проводнике,
и в буфере торчит больше десятка форматов,
а await navigator.clipboard.read() отдаёт пустой массив.

Просьба посмотреть

Здесь виджет создаётся кодом, исполнившемся в окне,
и многое некоторое привязано к этому окну.
Например, PlacesToolbarItems вычисляется
как #PlacesToolbarItems того окна, в котором создан виджет.


Если открыть другое окно браузера, то это не изменится, листенеры
будут добавляться и удаляться для элемента в окне происхождения,
то есть, в новом окне код не будет работать как надо.


Также args11, мало того, что это ненужная глобальная переменная,
типа window.args11, так при открытии нового окна, код перепишет этот args11,
и если листенер из предыдущего args11 был добавлен и не удалён, то его уже не удалить.


setTimeout() это тоже setTimeout() окна происхождения,
если это окно закрыть, то setTimeout() работать перестанет.
И если это ещё можно поправить, то если в код добавить async-await,
то от отвала асинхронной машинерии при закрытии окна происхождения
уже не спасёт ничто.


Лучше создавать виджет в другом месте, вот, например, через SystemGlobal.eval()

скрытый текст

Выделить код

Код:

(async p => await p || window.__SSi == "window0" && Cu.getGlobalForObject(Cu)
	.eval(`(${(m, self, widget) => widget = m.CustomizableUI.createWidget(self = {

	id: "my-cleanClipbrd",
	label: "Clean clipbrd",
	tooltiptext: "Clean data from Clipboard",
	localized: false,
	get icon() {
		let icon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAABY0lEQVR4nGNgwANeL2EofrWUoYiBXPBoHsMfECbbgLszGf6DMNkGXJvM8B+EyTYgODXuPwiTpit0FTNv0ip1noTltsJhU/6DsED0Ylve6MXqIDm8ennjl8fyxi39yh+35D9/7KL/ArEL/gvEzPsvGD33v2DU7P+CkTO/CodPi8VpAH/sglUCMfPhGoQiZ/0XipjxXzh8GtglIqGT/ouGTFiF04CP29T2f9qu/h8f/rhNbR9OA77sMXz5ZY/hf3z4826D51g1fzpkI/r9oPV/XPjjLhMEe7epMIYBv486+/w66vQfhL8fsgfTyPjtVn04+/dhJ09MA054tvw56fUfhD/uMgfTyPjNJk04+/cJryYMA/6e9j/+74z/fxB+s0kDTCPj1+tk//897Qtm/z3jdxTDgP/nQrL+nwua+/9c0KG368S//j8b9O7/uaBfYHw26N3HzfIffx9zPg1RE5KFMyZIBQA3pi1KgcfhAAAAAABJRU5ErkJggg";
		let subst = this.id.toLowerCase() + "-icon";
		Services.io.getProtocolHandler("resource")
			.QueryInterface(Ci.nsIResProtocolHandler)
			.setSubstitution(subst, Services.io.newURI(icon));
		delete this.icon;
		return this.icon = "resource://" + subst;
	},
	show: async win => (await win.navigator.clipboard.read()).length,
	args11: ["popuphiding", async e => {
		console.log("popup closing");
		await self.show(e.view) && self.setState(
			"visible", "removeEventListener",
			console.log("remove listener(s)")
		);
	}],
	setState(visibility, method) {
		for(var {node} of widget.instances)
			node.style.visibility = visibility,
			node.trg[method](...this.args11);
	},
	async onCreated(btn) {
		btn.setAttribute("image", this.icon);
		btn.trg = btn.ownerDocument.getElementById("PlacesToolbarItems");

		if (await this.show(btn.ownerGlobal)) return;
		btn.style.visibility = "hidden";
		btn.trg.addEventListener(...this.args11);
		console.log("add listener");
	},
	onCommand(e) {
		Services.clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
		self.setState("hidden", "addEventListener");
		console.log("add listener(s)");
		self.notify(e.view);
	},
	notify(win) {
		var name = "whimsy_clipboard";
		var as = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
		var close = as.closeAlert.bind(null, name);
		(this.notify = win => {
			as.showAlertNotification(
				"chrome://browser/skin/customizableui/whimsy.png",
				"Clipboard", "Буфер обмена растоптан!", false, "", null, name
			);
			win.setTimeout(close, 2e3);
		})(win);
	},

})})(ChromeUtils.importESModule("resource:///modules/CustomizableUI.sys.mjs"));`))(window.delayedStartupPromise);

Отсутствует

 

№16107-10-2024 18:50:22

dinn
Участник
 
Группа: Members
Зарегистрирован: 28-09-2024
Сообщений: 10
UA: unknown 0.0

Re: userChrome.js

Dumby пишет

копируем файл в проводнике,
и в буфере торчит больше десятка форматов,
а await navigator.clipboard.read() отдаёт пустой массив

Да, так и есть, для .read() и readFromClipboard() - это неизвестный формат данных. Сможем ли где-то в браузере вставить такое? Вряд ли. Но и веб стандарт по буферу еще не до конца реализован в браузерах

виджет создаётся кодом, исполнившемся в окне,
и многое некоторое привязано к этому окну

Редко когда открываю window1, разве что случайно нажав Ctrl+N, и сразу закрываю. Отношусь к одноокошечникам.

args11, мало того, что это ненужная глобальная переменная

С моими познаниями даже не знаю как, например, в onCommand() получить значение переменной, созданной через let (var) в onCreated()

Лучше создавать виджет в другом месте, вот, например, через SystemGlobal.eval()

А если работать только в одном окне, то лучше тоже через SystemGlobal.eval()?

Спасибо за виджет и информацию, все работает как надо


Но главный вопрос, который меня интересует: возможно ли скриптом внедрить свой css на страницу about:preferences для ее стилизации?

Отредактировано dinn (07-10-2024 21:28:35)

На форуме

 

№16208-10-2024 09:15:38

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2229
UA: Firefox 78.0

Re: userChrome.js

dinn пишет

С моими познаниями даже не знаю как, например, в onCommand() получить значение переменной, созданной через let (var) в onCreated()

Неудивительно.
Такое не возможно ни с какими познаниями, просто потому что — никак.
Ну, вариант вытащить ссылку дебаггером мы здесь рассматривать не будем,
поскольку это лютая жесть.

А если работать только в одном окне, то лучше тоже через SystemGlobal.eval()?

Если так ставить вопрос, то получается, что не особо лучше.


Но, вот послушай.
Теретически, открыть окно браузера может и вэб-контент.
Допустим, например, в about:preferences#privacy снята галка
«Блокировать всплывающие окна».
Открываем адрес data:text/plain;charset=utf-8,test
и с веб-консоли (Ctrl+Shift+K) запускаем
open("about:logo", "_blank", "width=300,height=280");


Открывается окошко, которое не выглядит как окно браузера,
но, тем не менее, это именно оно.


Или, вот, например, ставим этот (замечательный, кстати) аддон.
Убеждаемся, что в настройках аддона стоит галка [✔] Открывать в окне.
Теперь, ПКМ на какой-нибудь ссылке —> «Свойства ссылки».


Открывается окно, которое выглядит ещё менее похожим на окно браузера,
тем не менее, это именно оно. И аддон здесь нипричём, просто таково
осуществление в браузере симуляции гуглячьего API.


Всё это, скорее, важно не само по себе,
а при наличии в коде чего-то деструктивного, вроде переопределения args11.


Короче, это я всё к тому, что делай как хочешь, но делай осознанно.
Типа да, я знаю, что args11 будет торчать в окне, но это так проще и удобнее.
И, имя args11 выглядит достаточно уникальным, чтобы не образовывать конфликта имён.
Ещё раз — сознательно, а не то, чтобы просто по запарке.

Но главный вопрос, который меня интересует: возможно ли скриптом внедрить свой css на страницу about:preferences для ее стилизации?

Ооо, здесь нужно железобетонное обоснование
чем «для ее стилизации» не угодил userContent.css


Почему именно «скриптом», почему именно «внедрить на страницу»,
и всякие иные прочие подробности.
И, если есть сам скрипт, пусть даже неудачный, то его тоже.
В любом случае, разумеется, ответ подразумевает начинаться с "Да, это возможно."

Отсутствует

 

№16308-10-2024 16:38:59

dinn
Участник
 
Группа: Members
Зарегистрирован: 28-09-2024
Сообщений: 10
UA: unknown 0.0

Re: userChrome.js

Dumby пишет

здесь нужно железобетонное обоснование

Его нет, но есть интерес альтернативного подхода. Если очень кратко, то какова вероятность того, что при переносе на четвертый уровень, а затем полного удаления документа из web стандарта, это не распространится на юзер стили agent, chrome и content? В поисках альтернативы был успешно опробован метод, а вот что делать с внутренними страницами about:*, chrome:* пока не знаю. Или слишком забегаю вперед?

На форуме

 

№16409-10-2024 08:37:36

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2229
UA: Firefox 78.0

Re: userChrome.js

dinn пишет

был успешно опробован метод

Это что ещё за monkey-offtopic?

что делать

Вот, развлекайся

скрытый текст

Выделить код

Код:

location == "chrome://browser/content/browser.xhtml"
&& addEventListener("DOMDocElementInserted", e => {
	var doc = e.target;
	if (!doc.documentURI.startsWith("about:preferences")) return;

	var css1 = "richlistitem {background-color: pink !important}";
	doc.documentElement.appendChild(doc.createElement("style")).append(css1);

	var win = doc.ownerGlobal;

	var css2 = "h1, h2 {background-color: limegreen !important;}";
	var sheet = new win.CSSStyleSheet();
	sheet.replaceSync(css2);
	doc.adoptedStyleSheets.push(sheet);

	var wu = win.windowUtils;

	var css3 = "label, description {background-color: yellow !important; color: red !important;}";
	wu.loadSheetUsingURIString("data:text/css," + encodeURIComponent(css3), wu.USER_SHEET);
});

Отсутствует

 

№16509-10-2024 20:29:41

dinn
Участник
 
Группа: Members
Зарегистрирован: 28-09-2024
Сообщений: 10
UA: unknown 0.0

Re: userChrome.js

Dumby пишет

Вот, развлекайся

ооо, спасибо, красота. Целых 3 способа. С конструктором больше понравилось + есть гордая надпись в правилах: constructed.

Это что ещё за monkey-offtopic?

Не совсем, если userChrome.js скрипт не умеет выборочно стилизовать http(s) страницы

На форуме

 

№16611-10-2024 22:06:53

dinn
Участник
 
Группа: Members
Зарегистрирован: 28-09-2024
Сообщений: 10
UA: unknown 0.0

Re: userChrome.js

Dumby, может перед push впаять wrappedJSObject? Не дает мне стилизовать меню и настройки одного из расширений

скрытый текст

Выделить код

Код:

location == "chrome://browser/content/browser.xhtml" && addEventListener("DOMDocElementInserted", e => {
	let doc = e.target;
	if (!doc.documentURI.startsWith("moz-extension://f6665cb1")) return;
	let win = doc.ownerGlobal;
	
	let file = Services.dirsvc.get("UChrm", Ci.nsIFile);
	file.initWithPath(file.path+"\\css\\test\\yt_dark.css");
	let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
	let sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
	fis.init(file, -1, 0, 0);
	sis.init(fis, "UTF-8");
	let data = sis.read(sis.available());

	let sheet = new win.CSSStyleSheet();
	sheet.replaceSync(data);
	doc.adoptedStyleSheets.push(sheet);
});


e.target выдает, что readyState находится на этапе loading, а значит title всегда будет пустым. Неужели нет способа как-то проверить, чтобы стилизовать именно это расширение, а не другое? приходится часто менять буквы цифры в moz-extension://

Отредактировано dinn (11-10-2024 22:07:37)

На форуме

 

№16713-10-2024 14:17:30

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2229
UA: Firefox 78.0

Re: userChrome.js

dinn пишет

расширений

Расширения запрещены со времён Firefox 57.

Неужели нет способа как-то проверить, чтобы стилизовать именно это расширение, а не другое?

Ну по id'шнику можно, только они тоже бывают uuid'ом.

e.target выдает, что readyState находится на этапе loading, а значит title всегда будет пустым

Это логично, однако, только что-то я тебя не пойму.
Звучит так, словно WebExtensions у тебя в родительском процессе.


Но разве такое сейчас возможно?
Когда-то давно было возможно, но уже тогда они,
в таком случае, работали криво, а теперь, вроде, вообще не работают.


WebExtensions живут в своём отдельном процессе.
А значит, бесполезно что-то слушать в окне браузера,
которое в родительском процессе, в котором
аддонского добра просто быть не может, никакого.


Чтобы действовать в аддонском процессе,
лучше всего подходит зарегистрировать JSWindowActor
то есть .mjs скрипт-модуль.
Но для этого нужен файл на диске, и адрес на него
по протоколу chrome: или resource:


Поскольку о своём uc-скриптоприёмнике ты не рассказал ничего
(ведь в некоторых может есть своя встроенная хром/ресурс регистрация),
то вот, например, регистрируем ресурс на папку css
и регистрируем actor созданный в этой папке css
под именем WebExtensionsStylerChild.mjs

скрытый текст

Выделить код

Код:

(async p => {
	if (await p || window.__SSi != "window0") return;

	var file = Services.dirsvc.get("UChrm", Ci.nsIFile);
	file.append("css");
	var subst = "uc-css-folder";
	Services.io.getProtocolHandler("resource")
		.QueryInterface(Ci.nsIResProtocolHandler)
		.setSubstitution(subst, Services.io.newFileURI(file));

	ChromeUtils.registerWindowActor("WebExtensionsStyler", {
		child: {
			events: {DOMDocElementInserted: {}},
			esModuleURI: `resource://${subst}/WebExtensionsStylerChild.mjs`
		},
		allFrames: true,
		remoteTypes: ["extension"]
	});
})(window.delayedStartupPromise);


Теперь про mjs'ку.
Аддонский процесс это процесс контентский, и оперирование файлами
в нём ограничено. Stream'ы воротят от файла нос. Services.dirsvc тоже.
PathUtils.profileDir — выдаёт ошибку. Cu.readUTF8URI() — тоже.


Cu.readUTF8File() — работает, и с ним попроще,
но в консоли есть предупреждение: «Use of nsIFile in content process is deprecated.»


А раз тебе «С конструктором больше понравилось», то надо читать с диска,
хотя, казалось бы, лучше использовать windowUtils
не только потому, что он сам будет читать, но и потому, что можно
заказать author, user или agent origin стиля, а для adopted — нельзя.


Ладно, вот, например, чтение через fetch()
и синхрон-костыль, потому что не хочется чего-то лишнего
в других частях кода, а читаться каждый стиль будет только раз.

скрытый текст

Выделить код

Код:

var data = {

	"uBlock0@raymondhill.net": {
		"popup-fenix.html": "ublock/popup",
		"dashboard.html": "ublock/prefs-root",
		"1p-filters.html": "ublock/prefs-my-filters",
		"whitelist.html": "ublock/prefs-test-non-existent-style-throws-once",
	},
	"linkPropertiesPlus@infocatcher": {
		"properties.html": "lpp/link-props"
	},
	"treestyletab@piro.sakura.ne.jp": {
		"sidebar/sidebar.html?style=photon&reloadMaskImage=true": "tst/two-sidebars",
		"sidebar/sidebar.html?style=highcontrast&reloadMaskImage=true": "tst/two-sidebars",
	},
};

var read = obj => {
	var folder = Services.io.newURI(import.meta.url).resolve("..");

	var text, thread = Services.tm.currentThread;
	var tick, ex, stop = () => tick = false, err = e => ex = e;
	var ftch = async url => text = await (await fetch(url)).text();

	return (read = obj => {
		var url = folder + obj.css + ".css";
		ftch(url).catch(err).finally(tick = stop);
		while(tick) thread.processNextEvent(true);
		if (ex)
			return delete data[obj.id][obj.path],
			console.error(`Fetch-Sheet-Error for ${obj.id}\n${url}\n${ex.message}`),
			ex = null;

		var res = text;
		text = null;
		return data[obj.id][obj.path] = res;
	})(obj);
}

var readSheet = function() {
	return read(this);
}

for(var [id, obj] of Object.entries(data)) {
	var dupes = {};
	for(var path in obj) {

		var css = obj[path];
		delete obj[path];
		path = "/" + path;

		if (css in dupes) {
			if (typeof dupes[css] == "string") {
				const parent = obj, link = dupes[css];
				dupes[css] = () => parent[link];
			}
			Object.defineProperty(obj, path, {
				get: dupes[css], configurable: true, enumerable: true
			});
		}
		else
			dupes[css] = path,
			(obj[path] = {css, path, id})[Symbol.toPrimitive] = readSheet;
	}
}

export class WebExtensionsStylerChild extends JSWindowActorChild {
	handleEvent(e) {
		var doc = e.target;
		var obj = data[doc.nodePrincipal.addonId];
		if (obj) {
			var u = doc.documentURIObject;
			var style =
				obj[u.pathQueryRef] ||
				u.hasRef && obj[u.specIgnoringRef.slice(52)] ||
				obj[u.filePath];

			if (style) {
				var sheet = new doc.ownerGlobal.CSSStyleSheet();
				sheet.replaceSync(style);
				doc.adoptedStyleSheets.wrappedJSObject.push(sheet);
			}
		}
	}
}


Кстати, можно выкинуть всё связанное со стилями,
и воткнуть проставление на <html> атрибутов "data-a-url" и "data-a-domain"
Тогда будет типа унификация с методом, который «был успешно опробован».

может перед push впаять wrappedJSObject?

Я сначала впаял перед doc, но да, перед push тоже работает.

Отсутствует

 

№168Вчера 18:01:56

dinn
Участник
 
Группа: Members
Зарегистрирован: 28-09-2024
Сообщений: 10
UA: unknown 0.0

Re: userChrome.js

Dumby пишет

WebExtensions живут в своём отдельном процессе.
А значит, бесполезно что-то слушать в окне браузера,
которое в родительском процессе, в котором
аддонского добра просто быть не может, никакого.

Ну почему бесполезно слушать? Пока еще не удалили эту настройку, а если она в false, то можно послушать


Поскольку о своём uc-скриптоприёмнике ты не рассказал ничего

Этот. Нет в нем никаких регистраций


Теперь про mjs'ку

В вашем первом коде все понятно, норм зарегилось, а во втором коде ничего не ясно. Это содержимое WebExtensionsStylerChild.mjs? Как этот mjs запускать? Что в нем за export .. extends? Не получилось ничего стилизовать таким способом, хотя бы на примере uMatrix


А раз тебе «С конструктором больше понравилось

Чтение из css файла я только с ним попробовал


Кстати, можно выкинуть всё связанное со стилями,
и воткнуть проставление на <html> атрибутов "data-a-url" и "data-a-domain"
Тогда будет типа унификация с методом, который «был успешно опробован»

Было бы круто, но раз не смог разобраться с тем, что понимает первоклассник, то  ...

Отредактировано dinn (Вчера 18:13:25)

На форуме

 

№169Сегодня 09:02:54

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2229
UA: Firefox 78.0

Re: userChrome.js

dinn пишет

Ну почему бесполезно слушать? Пока еще не удалили эту настройку, а если она в false, то можно послушать

Да, действительно, ты прав.
Я не ту настройку крутил, а эта работает.
Выходит, что здесь ничего особо не изменилось.


Но тогда непонятно в чём затруднение.
Событие приходит и с попапа, и со страницы.

скрытый текст

Выделить код

Код:

location == "chrome://browser/content/browser.xhtml" && addEventListener("DOMDocElementInserted", e => {
	let doc = e.target;

	if (doc.nodePrincipal.addonId == "uMatrix@raymondhill.net") {

		var uri = doc.documentURIObject;

		console.log("\u{1f7e9}".repeat(7) + " uMatrix DOCUMENT DETECTED\n" + uri.spec);

		var color;
		switch (uri.filePath) {
			case "/popup.html":     color = "deeppink"; break;
			case "/dashboard.html": color = "limegreen"; break;
			case "/settings.html":  color = "royalblue"; break;
			default: return;
		}

		doc.documentElement.style.cssText = `
			contain: paint !important;
			overflow: hidden !important;
			transform: translateX(64px) !important;
			box-shadow: -4px 0 yellow, -64px 0 ${color} !important;
		`;
	}
});

Этот. Нет в нем никаких регистраций

Кстати, там по событию "load".
Вроде как на этот момент window.__SSi уже есть,
поэтому delayedStartupPromise для него можно не ждать.

Это содержимое WebExtensionsStylerChild.mjs?

Да, это содержимое WebExtensionsStylerChild.mjs

Как этот mjs запускать?

Запускать ничего не надо, он зарегистрирован
в первом (оконном) коде через ChromeUtils.registerWindowActor()
там где esModuleURI

Что в нем за export .. extends?

Модуль должен экспортировать класс, с именем, заявленным при регистрации,
то есть, имя actor'а плюс "Child" — для контентской стороны,
и плюс "Parent" — для родительского процесса (если указан).


А extends, ну он extend'ит существующий класс JSWindowActorChild
чтобы пользоваться его свойствами и методами, да и вообще, похоже,
что он просто обязан это делать, а то будет молча проигнорирован.

Не получилось ничего стилизовать таким способом

Ещё бы, в регистрации написано: remoteTypes: ["extension"]
а у тебя такого процесса нет.
Можно заменить на matches: ["moz-extension://*"]
тогда будет работать.


Так-то, о подобных вещах поперёк мейнстрима,
типа WE в родительском процессе, лучше говорить сразу,
чтобы не приходилось гадать.

Было бы круто, но раз не смог разобраться

Ну так рассказывай, что делал, что не получается.
Только, желательно, доходчиво.

Отсутствует

 

№170Сегодня 17:24:07

dinn
Участник
 
Группа: Members
Зарегистрирован: 28-09-2024
Сообщений: 10
UA: unknown 0.0

Re: userChrome.js

Dumby пишет

Но тогда непонятно в чём затруднение

в том, но я не смог найти в e.target.... uMatrix@raymondhill.net


Так-то, о подобных вещах поперёк мейнстрима,
типа WE в родительском процессе, лучше говорить сразу,
чтобы не приходилось гадать.

Это со стороны выглядит, что я знал, а на самом деле узнал только после тестов перед написанием предыдущего сообщения, т.к. у меня в user.js extensions.webextensions.remote=false еще с FF91


Ещё бы, в регистрации написано: remoteTypes: ["extension"]
а у тебя такого процесса нет.
Можно заменить на matches: ["moz-extension://*"]
тогда будет работать.

Сократим mjs до

скрытый текст

Выделить код

Код:

export class WebExtensionsStylerChild extends JSWindowActorChild {
	handleEvent(e) {
		var doc = e.target;
		console.log(doc);
	}
}

Если extensions.webextensions.remote=true, то
remoteTypes: ["extension"]       // не пашет
matches: ["moz-extension://*"]  // не пашет


или в консоли уже не увидеть?


Если extensions.webextensions.remote=false, то
remoteTypes: ["extension"]       // не пашет
matches: ["moz-extension://*"]  // пашет

На форуме

 

№171Сегодня 20:24:59

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2229
UA: Firefox 78.0

Re: userChrome.js

dinn пишет

Если extensions.webextensions.remote=false, то
remoteTypes: ["extension"]       // не пашет

Да, я уже говорил, что не должен пахать.
remoteTypes — это массив префиксов типов процессов, где должно работать
(если отсутствует — тогда во всех DOM'ских процессах).
А раз процесса с remoteType "extension" нет, то ...

matches: ["moz-extension://*"]  // пашет

Это хорошо, значит хотя бы всё размещено и подключено верно.

Если extensions.webextensions.remote=true, то
remoteTypes: ["extension"]       // не пашет
matches: ["moz-extension://*"]  // не пашет


или в консоли уже не увидеть?

А вот это странно.
Если аддонский процесс есть (можно глянуть в about:processes),
то я даже не знаю что и предположить.


Ну, разве что, действительно,
в консоли браузера просто не включён многопроцессный режим
(devtools.browsertoolbox.scope = everything).

Отсутствует

 

Board footer

Powered by PunBB
Modified by Mozilla Russia
Copyright © 2004–2020 Mozilla Russia GitHub mark
Язык отображения форума: [Русский] [English]