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

Пользователи не любят читать документацию. Станьте оригинальным, будьте не как все. Ознакомьтесь с нашей базой знаний.

№1722608-02-2025 15:17:48

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

Re: Custom Buttons

Garalf пишет

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

А чего это там код
два раза два раза
повторяется?


Исправь, если у тебя так.


А правка, может такую попробуй

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

Выделить код

Код:

/*
mp.setAttribute("onpopupshowing", "this.updateMenu();");
mp.setAttribute("oncommand", "if(!event.button) this.handleEvent(event);"); // Ignore middle-click in Firefox 89+
mp.setAttribute("onmousedown", "if(event.button == 0) this.handleEvent(event);");
mp.setAttribute("onclick", "if(event.button > 0) this.handleEvent(event);");
mp.setAttribute("oncontextmenu", "return false;");
mp.setAttribute("onpopuphidden", "this.destroyMenu();");
*/
addEventListener("popupshowing", () => mp.updateMenu(), false, mp);
addEventListener("command", mp.onmousedown = mp.onclick = e => {
	if (!e.button || e.type.endsWith("k")) mp.handleEvent(e);
}, false, mp);
mp.toggleAttribute("context");
addEventListener("popuphidden", () => mp.destroyMenu(), false, mp);

Отсутствует

 

№1722708-02-2025 21:22:48

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 338
UA: Firefox 133.0

Re: Custom Buttons

Dumby
Спасибо! Кнопка заработала.
Огромная просьба. Посмотри еще раз код
Дополнительные пункты в контекстном меню кнопки из моего
предыдущего поста. Очень полезная кнопка. Твоя правка к сожалению не сработала.
Ни один пункт меню не работает.

Отредактировано Garalf (08-02-2025 23:31:32)

Отсутствует

 

№1722809-02-2025 21:47:01

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

Re: Custom Buttons

Garalf пишет

Огромная просьба. Посмотри еще раз код
Дополнительные пункты в контекстном меню кнопки

Посмотрел.
На сей раз на 137.0a1 (2025-02-09).


Создал кнопку с предоставленным кодом инициализации.
Сделал предложенные правки. Рестарт.


Пункты «Показать Id кнопки» и «Переместить кнопку...» точно работают.
Остальные не проверял, поскольку, таким образом, утверждение
«Ни один пункт меню не работает» уже не подтвердилось.

Отсутствует

 

№1722909-02-2025 23:58:26

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 338
UA: Firefox 136.0

Re: Custom Buttons

Dumby
Да, все верно. Перегрузил лису и кнолка зареботала.

Dumby пишет

Остальные не проверял

Проверь пожалуйста пункт меню Редактирование кнопки.
У меня не работает.

Отсутствует

 

№1723010-02-2025 09:59:59

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

Re: Custom Buttons

Garalf пишет

Проверь пожалуйста пункт меню Редактирование кнопки.

Это не представляется возможным,
поскольку меня такого пункта вообще нет.


Есть пункт «Редактировать…».
#custombuttons-contextpopup-edit,
ну тот, который самый первый сверху.


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


Если имееется в виду именно он, и если не работает именно он,
то, может, обновление встало криво,
или startupCache при этом, после рестарта не очистился,
или, даже не знаю что ещё.

Отсутствует

 

№1723111-02-2025 10:18:29

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 338
UA: Firefox 136.0

Re: Custom Buttons

Dumby
Раз теме тишина попрошу полечить еще одну кнопку.
UserCSSLoader

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

Выделить код

Код:

(obj => {
    this.onclick = obj.click.bind(obj);
    this.oncontextmenu = obj.contextmenu.bind(obj);
    this.tooltipText = "L: Reload userChrome.css\nM: CB Menu\nR: Reload userContent.css";
})({
    async click(e) {
        if (e.button == 1) return gShowPopup(self);
        if (e.button || !this.chromeSheet) return;
        await this.reload(this.chromeSheet);
        this.restyle(0);
    },
    async contextmenu(e) {
        if (e.ctrlKey || e.shiftKey || e.detail != 1 || !this.contentSheetURL) return;
        e.preventDefault();

        var count = Services.ppmm.childCount, one = count == 1;
        var data = await this.reloadTab("chrome://extensions/content/dummy.xul", one ? false : {});
        if (one) this.reloadTab();
        else if (data) {
            var url = "data:," + encodeURIComponent(
                self.Help + this.contentSheetURL + '", ' + JSON.stringify(data) + ");"
            );
            var types = ["web", "file", "extension"];
            for(var ind = 0; ind < count; ind++) {
                var child = Services.ppmm.getChildAt(ind);
                types.includes(child.remoteType) && child.loadProcessScript(url, false);
            }
        }
        this.restyle(250);
    },
    async reload(sheet, obj) {
        try {var style = await (await fetch(sheet.href)).text();}
        catch (ex) {return obj;}
        InspectorUtils.parseStyleSheet(sheet, style);
        if (obj) obj[sheet.href] = style;
        for(var ind = 0, len = sheet.cssRules.length; ind < len; ind++) {
            var rule = sheet.cssRules.item(ind);

            rule.type == rule.IMPORT_RULE
            && rule.styleSheet.href.startsWith("file:///")
            && await this.reload(rule.styleSheet, obj);
        }
        return obj;
    },
    reloadTab(url, obj) {
        var tab = gBrowser.addTab(url, {skipAnimation: true});
        tab.style.setProperty("display", "none", "important");
        return new Promise(resolve => {
            var result, stop, destroy = () => {
                if (!stop) resolve(result), gBrowser.removeTab(tab), stop = true;
            }
            setTimeout(destroy, 500);
            try {
                tab.linkedBrowser.addEventListener("DOMContentLoaded", async e => {
                    var sheet = this.getSheet(e.target, this.contentSheetURL);
                    if (sheet) result = await this.reload(sheet, obj);
                    destroy();
                }, {once: true});
            } catch(ex) {
                destroy();
            }
        });
    },
    getSheet(doc, href) {
        var sheets = InspectorUtils.getAllStyleSheets(doc);
        return sheets.find(sheet => sheet.href == href);
    },
    get contentSheetURL() {
        var file = Services.dirsvc.get("UChrm", Ci.nsIFile);
        file.append("userContent.css");
        if (!file.exists()) return null;
        delete this.contentSheetURL;
        return this.contentSheetURL = Services.io.newFileURI(file).spec;
    },
    get restyle() {
        var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
        var uri = Services.io.newURI("data:text/css,:root{}"), type = sss.USER_SHEET;
        delete this.restyle; return this.restyle = delay => setTimeout(() => {
            sss.loadAndRegisterSheet(uri, type);
            sss.unregisterSheet(uri, type);
        }, delay);
    },
    get chromeSheet() {
        var file = Services.dirsvc.get("UChrm", Ci.nsIFile);
        file.append("userChrome.css");
        if (!file.exists()) return null;

        var href = Services.io.newFileURI(file).spec;
        var sheet = this.getSheet(document, href);
        if (!sheet) return null;

        delete this.chromeSheet; return this.chromeSheet = sheet;
    }
});

Напомню - это 136.b3  Кстати, пункт меню Edit в контекстном меню кнопки
неожиданно заработал.

Отредактировано Garalf (11-02-2025 10:19:25)

Отсутствует

 

№1723211-02-2025 14:47:20

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

Re: Custom Buttons

Garalf пишет

еще одну кнопку

Содержимое вкладки «Справка» предлагается угадать?

Отсутствует

 

№1723311-02-2025 16:27:54

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 338
UA: Firefox 133.0

Re: Custom Buttons

Dumby
Справка

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

Выделить код

Код:

((href, data) => {
	var en = Services.ww.getWindowEnumerator(null);
	if (!en.hasMoreElements()) return;
	var doc = en.getNext().document;

	var du = Components.classes["@mozilla.org/inspector/dom-utils;1"]
		.getService(Components.interfaces.inIDOMUtils);
	var reload = sheet => {
		var style = data[sheet.href]; if (!style) return;

		du.parseStyleSheet(sheet, style);
		for(var ind = 0, len = sheet.cssRules.length; ind < len; ind++) {
			var rule = sheet.cssRules.item(ind);

			rule.type == rule.IMPORT_RULE
			&& rule.styleSheet.href.startsWith("file:///")
			&& reload(rule.styleSheet);
		}
	}
	var sheet = du.getAllStyleSheets(doc).find(sheet => sheet.href == href);
	if (sheet) reload(sheet);
})("

Отсутствует

 

№1723412-02-2025 11:36:42

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

Re: Custom Buttons

Garalf пишет

Справка

Другое дело.

Напомню - это 136.b3

Что-то я не вижу в кнопке
ни использования «on…» атрибутов, ни импорта модулей.


Но многовато чего-то совсем древнего,
поэтому попробую чуть переделать.
Код со Справки перенёс в Инициализацию.

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

Выделить код

Код:

(code => {
	this._handleClick = () => {
		var href = getHref("hrome");
		if (!href) return;
		var sheet = getSheet(document, href);
		sheet && (this._handleClick = () => reload(sheet).then(restyle))();
	}
	this.onauxclick = e => e.button > 1 || gShowPopup(this);
	this.oncontextmenu = e => {
		if (e.ctrlKey || e.shiftKey || e.detail != 1) return;
		e.preventDefault();
		reloadContentSheet();
	}
	this.tooltipText = "L: Reload userChrome.css\nM: CB Menu\nR: Reload userContent.css";

	var getHref = str => {
		var file = Services.dirsvc.get("UChrm", Ci.nsIFile);
		file.append(`userC${str}.css`);
		if (file.exists()) return Services.io.newFileURI(file).spec;
	}
	var getSheet = (doc, href) =>
		InspectorUtils.getAllStyleSheets(doc).find(sheet => sheet.href == href);

	var reload = async (sheet, obj) => {
		try {var style = await (await fetch(sheet.href)).text();}
		catch {return obj;}

		InspectorUtils.parseStyleSheet(sheet, style);
		if (obj) obj[sheet.href] = style;
		for(var ind = 0, len = sheet.cssRules.length; ind < len; ind++) {
			var rule = sheet.cssRules.item(ind);

			rule.type == rule.IMPORT_RULE
			&& rule.styleSheet.href.startsWith("file:///")
			&& await reload(rule.styleSheet, obj);
		}
		return obj;
	}
	var restyle = delay => {
		var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
		var uri = Services.io.newURI("data:text/css,:root{}"), type = sss.USER_SHEET;
		var regUnreg = () => {
			sss.loadAndRegisterSheet(uri, type);
			sss.unregisterSheet(uri, type);
		};
		(restyle = delay => setTimeout(regUnreg, delay))(delay);
	}
	var reloadContentSheet = async () => {
		var href = getHref("ontent");
		if (!href) return;

		var {br} = this;
		if (!br) {
			br = this.br = document.createXULElement("browser");
			br.setAttribute("type", "content");
			this.append(br);
			await new Promise(resolve => br.addEventListener("pageshow", resolve, {once: true}));
		}
		var sheet = getSheet(br.contentDocument, href);
		if (!sheet) return;

		br.remove();
		delete this.br;
		var {ppmm} = Services;
		var re = /^(?:web|file|extension|privileged)/;
		var prfx = "data:," + encodeURIComponent(code.trim() + sheet.href + '", ');

		(reloadContentSheet = async () => {
			var data = await reload(sheet, Object.create(null));
			var url = prfx + encodeURIComponent(JSON.stringify(data)) + ");"
			for(var ind = 0, count = ppmm.childCount; ind < count; ind++) {
				var child = ppmm.getChildAt(ind);
				re.test(child.remoteType) && child.loadProcessScript(url, false);
			}
			restyle(350);
		})();
	}
})(`

((href, data) => {
	var en = Services.ww.getWindowEnumerator(null);
	if (!en.hasMoreElements()) return;

	var doc = en.getNext().document;

	var reload = sheet => {
		var style = data[sheet.href];
		if (!style) return;

		InspectorUtils.parseStyleSheet(sheet, style);
		for(var ind = 0, len = sheet.cssRules.length; ind < len; ind++) {
			var rule = sheet.cssRules.item(ind);

			rule.type == rule.IMPORT_RULE
			&& rule.styleSheet.href.startsWith("file:///")
			&& reload(rule.styleSheet);
		}
	}
	var sheet = InspectorUtils.getAllStyleSheets(doc).find(sheet => sheet.href == href);
	sheet && reload(sheet);
})("
`);

Отсутствует

 

№1723520-02-2025 18:00:22

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 338
UA: Firefox 136.0

Re: Custom Buttons

Dumby
Нашел еще две удобные неработающие кнопки
1. "Два в одном"

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

Выделить код

Код:

//Настройка функций кликов мыши для кнопки ....................
this.onclick =e=> {if(e.button==0)BrowserOpenAddonsMgr();//ЛКМ
                   if(e.button==1)gShowPopup(this);      //СКМ
                   if(e.button==2 && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){//ПКМ
                   setTimeout(function(){document.getElementById("custombuttons-contextpopup").hidePopup();},0);openPreferences();}};
                   this.tooltipText="Л: Addons\nС: CBMenu\nП: Preferences";
//data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAABuwAAAbsBOuzj4gAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAMJSURBVDiNdVPNa1N5FD2/30uMeX1IPjFmE3BKERdhRKqgwyBqibsuZqGYRRf2H3Ax0J28je22XcRCwwhNKh0ki24GSn20iE3TNMKjONKkHyYUokmbMR++F/Oa966baUkVL9zNvfdc7jmHy4gIP4uFhcUFABgejgz/dIiITjKZTF3JZtXKzEziPgC+tbV3tLW1dwSAz8wk7mezaiWZTF3pxZxaEI2O3mk2NSoWy918/kO73e5Qu92hQuFDu1gsd5tNjaLR0Tu9GEZEiMdf/Orz+Ry6rndu3rz21u/3ciLCp08VAEAgcB6MMRwc1KzV1exVURQdh4eHndHRhyoDwBYXX38Mhy+f17S26fW6hHR6HUtLKzBNEwAgCAKGhm7hxo3rqNXqZl+fU9jcfF+JRH6/wImIEolZeX+/bElSn5DLqUins0TUKXBuRDk3okSdQjqdpVxOhST1Cfv7ZSuRmJXpRAiAK0pGL5UqNDUVt2T5ab6XJxFBlp/mp6biVqlUIUVZ0wFwIgKfnIwnl5fXW8FgwKlpOiRJZB6PW/7eLY/HLUuSyDRNRzB4wbm8vN6anIwnbaq6yTWtaw+FfoHLJcHn8+PsWdsPdnu9XkiSG3t7H1Gvf0GptGvf3n7PTyiMj0+35uaWqFAoWoqy8gMFRVnJFwpFa35eofHx6dYxBRsAxGKz94jsgig6oOsGGxi41K+qm3nLIhkAOGdPBgYu9TcaGjt3ToTH4xZisdl7AP7hjDFWLldjLpfHqesNq15v4etXg4dCF/sDgeBcIBCcC4Uu9h8ddXmzqUHXm5bf73dWq7UYY4zZiIgikeEHq6uvXA6Hvf748Z9vOh2XcHBQ46LoAGMMnz/XuWmaMIwv5vPnz34zDMNltzvqRESs95mmp/+6Ojh4faPR+K9rWQaFw+EzjDG8e/evYbefYW63z5bJpAcfPRp5e4zhvUpnMmlbLpepplJ/jwwN3XXu7u5oOzvb2u3bt5wvX86PbGysVTOZtVMWnboAABhjjP4vTkxMpABgbGzsj+97x/ENhTvQG3f/6bsAAAAASUVORK5CYII=
//forum.mozilla-russia.org/viewtopic.php?pid=704725#p704725
//openWebPanel("Downloads","about:downloads");


Страница настроек - вызывается, расширения - нет.


2. Поиск по изображению

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

Выделить код

Код:

/*Initialization Code*/
// Добавить подменю "Поиск изображения в" в контекстном меню изображений, от 31.05.2019. .............
(()=> {
   var copyimage = document.getElementById("context-copyimage-contents");
   var contextMenu = copyimage.parentNode;

    var array = [
      ['Google', 'https://www.google.lv/favicon.ico', 'http://www.google.com/searchbyimage?image_url='],
      ['Яндекс', 'http://yastatic.net/morda-logo/i/favicon_islands.ico', 'https://yandex.com/images/search?rpt=imageview&img_url='],
      ['Bing', 'https://www.bing.com/s/a/bing_p.ico', 'https://www.bing.com/images/searchbyimage?FORM=IRSBIQ&cbir=sbi&imgurl='],
      ['Tineye', 'http://tineye.com/favicon.ico', 'http://tineye.com/search?pluginver=bookmark_1.0&url='],
      ['SauceNao', 'https://saucenao.com/favicon.ico', 'https://saucenao.com/search.php?url='],
      ['IQDB', 'https://iqdb.org/favicon.ico', 'https://iqdb.org/?url='],
   ];
   var menu = contextMenu.insertBefore(document.createXULElement("menu"), copyimage); 
   menu.setAttribute("label", "Поиск изображения в ...");
   menu.setAttribute("class", "menu-iconic");
   
   
   menu.onclick =e=> { e.target.nodeName == 'menu' && search(array[0][2]); setTimeout(()=> contextMenu.hidePopup(), 20) };
   addEventListener("popupshowing", ()=> menu.hidden = copyimage.hidden, true, contextMenu);
    addDestructor(() => menu.remove());
   var menuPopup = menu.appendChild(document.createXULElement("menupopup"));              
   array.forEach(m=> {
      var mItem = menuPopup.appendChild(document.createXULElement("menuitem"));
      mItem.setAttribute("label", m[0]);       
      mItem.setAttribute("image", m[1]);
      mItem.setAttribute("class", "menuitem-iconic");
      mItem.onclick =()=> search(m[2]);
   });
  function search(finder) { gBrowser.selectedTab = gBrowser.addTrustedTab(finder + encodeURIComponent(gContextMenu.imageURL)) };
  
   var mItem = menuPopup.appendChild(document.createXULElement("menuitem"));
   mItem.setAttribute("label", 'Искать во всех поисковиках');
     mItem.setAttribute("class","menuitem-iconic");
        mItem.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADZElEQVR42oXSe0xbVRwH8N8597a35e7SAmUFukGhY66AMiNzw4GvTCQLCssc4pQsmTOa+ERMlrktW1zigpnEuWn8x2eMmiVGMBDCFjS+cJHEDIk8RoSNV1+3tLWX3t72nnO8sETJFrfvP7/k5Pw+Ob9fDoLrYi8ow9GFUbq+5aRLrGraqQcX6hlF2wkFEWn6EDIJAyQy9+3VT58cWb6PrmvmjGZS/FSHlxbXtbtLobGqJlPKMhNepWb0V8hKpi8FNd/gzCCogbdmvtg/8C9gz9+Eor5x5nn2tDOZ98Dx2i3C/uYai9mOGCxiDQIIg1/PgUCEhyvDMox9PXYBkPzaaoAzAFL0yle7ShtqO/eWJ9w1vJ1oGsVzYhTNATMQG4Q1G40ldDw6PB339fs7VgMmA0jnHfioo6F9Z3tDYYJzKSZKMYcDvAILiICfZUNYEYFixMKpKBk8MfTTasBsACnngU/6Wg4+VL/VFSOmBHAYY1BAhzAvgmyMEIkh0EUOBD1Eu49eStwA5D3z4TcPv9TYdHvxEhXSGgaEIMkJkKAS+ONmSKYolOVqMBlRSd8bv8v/AQXlJoiHUE5rZ1tFa/Nhj1uVrCaNMoQxYSaIqDxAGqAuQ2XZ1iS8HUTpkZMXe1eATOdtiCcJblGe1a3PnWp0uEvfv3tbeX5RhSet/q3wxh6xgAncZUmw2hxEryQx9/LHE7I2RV5HNudGFAtcZsuQd919u/kiz56JOwobcjd6xerqKnB4HIB4RvMzCM1DGj8X0GD64pL2Xdf850z+4djKC8wl24XUpj1P75sdfe/+sSHoq3uQnSuwa+s2Vy5uubd2jQWUTAYchJK8HpyIzvv7p/rMkV/OzPeeGEWi+x6LufiR573h8VO7Zr4n9fEZNeiqXHOofFvPsKPkS1fKsX5JU6uNZQh8Wh/hRcuvOC3/fLXrcGj52yOo7zzU9udvbzbN9uglggK2MhsnvfiE0tY9tfed7vM98D+x53tx1DdG0Z2b97Ejf3SRSiGGCysyENvdoipZa4+/8NmPp8+N+Ei2ZEVpQhG71rdcqFFozD+xcoQugFUvlDS8wWsl8Uebk5C79ujjHwyc6R/309ysDBRauEzhJkG9ErAdG0xEe6yVkwqcr+549/zZgcmQ7pAEkH2TDG6RfwCoJI0uEWJP5QAAAABJRU5ErkJggg==");   
   mItem.onclick =()=> { array.forEach(m=> {  gBrowser.selectedTab = gBrowser.addTrustedTab(m[2] + encodeURIComponent(gContextMenu.imageURL)) }) };
  
})();

var style = custombutton.buttonGetHelp(self).replace(/id/g, _id);
var uri = makeURI('data:text/css,'+ encodeURIComponent(style));
var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
sss.loadAndRegisterSheet(uri, 0);

Отредактировано Garalf (20-02-2025 18:45:49)

Отсутствует

 

№1723620-02-2025 18:55:55

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

Re: Custom Buttons

Garalf пишет

Страница настроек - вызывается, расширения - нет.

BrowserOpenAddonsMgr
BrowserAddonUI.openAddonsMgr

2. Поиск по изображению

Может (в двух местах)
imageURL
imageInfo.currentSrc

Отсутствует

 

№1723720-02-2025 21:08:16

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 338
UA: Firefox 136.0

Re: Custom Buttons

Dumby
Спасибо! Все работает.

Отсутствует

 

№1723801-03-2025 12:41:31

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 338
UA: Firefox 136.0

Re: Custom Buttons

Dumby
В 136 пререлизе у меня не устанавливаются CB и ATB
Появляется сообщение: Дополнение не может быть установлено,
так как оно не было проверено.
Может, что то в config.js не так?

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

Выделить код

Код:

//
try {(jsval => {
	var dbg, gref, genv = func => {
		var sandbox = new Cu.Sandbox(g, {freshCompartment: true});
		Cc["@mozilla.org/jsdebugger;1"].createInstance(Ci.IJSDebugger).addClass(sandbox);
		(dbg = new sandbox.Debugger()).addDebuggee(g);
		gref = dbg.makeGlobalObjectReference(g);
		return (genv = func => func && gref.makeDebuggeeValue(func).environment)(func);
	}
	var g = Cu.getGlobalForObject(jsval), o = g.Object, {freeze} = o, disleg;

	var AC = "AppConstants", uac = `resource://gre/modules/${AC}.`;
	var lexp = () => lockPref("extensions.experiments.enabled", true);
	if (o.isFrozen(o)) { // Fx 102.0b7+
		lexp(); disleg = true;
		var env, def = g.ChromeUtils.defineModuleGetter;
		g.ChromeUtils.defineModuleGetter = (...args) => {
			try {
				genv();
				dbg.addDebuggee(globalThis);
				var e = dbg.getNewestFrame().older.environment;
				var obj = e.parent.type == "object" && e.parent.object;
				if (obj && obj.class.startsWith("N")) // JSM, NSVO
					obj.unsafeDereference().Object = {
						freeze: ac => (ac.MOZ_REQUIRE_SIGNING = false) || freeze(ac)
					};
				else env = e; // ESM, Lexy "var"(?)
			}
			catch(ex) {Cu.reportError(ex);}
			(g.ChromeUtils.defineModuleGetter = def)(...args);
		}
		ChromeUtils.import(uac + "jsm");
		// (?)
		env && env.setVariable(AC, gref.makeDebuggeeValue(freeze(o.assign(
			new o(), env.getVariable(AC).unsafeDereference(), {MOZ_REQUIRE_SIGNING: false}
		))));
	}
	else o.freeze = obj => {
		if (!Components.stack.caller.filename.startsWith(uac)) return freeze(obj);
		obj.MOZ_REQUIRE_SIGNING = false;

		if ((disleg = "MOZ_ALLOW_ADDON_SIDELOAD" in obj)) lexp();
		else
			obj.MOZ_ALLOW_LEGACY_EXTENSIONS = true,
			lockPref("extensions.legacy.enabled", true);

		return (o.freeze = freeze)(obj);
	}
	lockPref("extensions.experiments.enabled", true);
	lockPref("xpinstall.signatures.required", false);
	lockPref("extensions.langpacks.signatures.required", false);

	var useDbg = true, xpii = "resource://gre/modules/addons/XPIInstall.jsm";
	if (Ci.nsINativeFileWatcherService) { // Fx < 100
		jsval = Cu.import(xpii, {});
		var shouldVerify = jsval.shouldVerifySignedState;
		if (shouldVerify.length == 1)
			useDbg = false,
			jsval.shouldVerifySignedState = addon => !addon.id && shouldVerify(addon);
	}
	if (useDbg) {
		jsval = g.ChromeUtils.import(xpii);

		var env = genv(jsval.XPIInstall.installTemporaryAddon);
		var ref = name => {try {return env.find(name).getVariable(name).unsafeDereference();} catch {}}
		jsval.XPIDatabase = (ref("lazy") || {}).XPIDatabase || ref("XPIDatabase");

		var proto = ref("Package").prototype;
		var verify = proto.verifySignedState;
		proto.verifySignedState = function(id) {
			return id ? {cert: null, signedState: undefined} : verify.apply(this, arguments);
		}
		dbg.removeAllDebuggees();
	}
	if (disleg) jsval.XPIDatabase.isDisabledLegacy = () => false;
})(
	"permitCPOWsInScope" in Cu ? Cu.import("resource://gre/modules/WebRequestCommon.jsm", {}) : Cu
);}
catch(ex) {Cu.reportError(ex);}
//
//
(async xp => {
	var imp, ids = [
		"custombuttons@xsms.org",
	];
	if (Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).inSafeMode) return;

	if (Cr.NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
		var {XPIInternal} = (imp = url => Cu.import(url, {}))(xp + "jsm");

	else { // Fx 101+
		var g = Cu.getGlobalForObject(Cu), te = new g.TextEncoder();
		var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
		var rph = ios.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);

		var impJSM = g.ChromeUtils.import, impESM = g.ChromeUtils.importESModule;
		try {var exp = impESM(xp + "sys.mjs");} catch {exp = impJSM(xp + "jsm");}
		var {XPIInternal} = exp;

		var ss = (subst, uri, ext) => rph.setSubstitution(
			subst, ios.newURI(uri.resolve("startup." + ext))
		);
		try {var useESM = parseInt(Services.appinfo.platformVersion) >= 108;} catch {}

		imp = (uri, id) => {
			var subst = te.encode(id).join("");
			var url = `resource://${subst}/`;
			if (useESM) try {
				ss(subst, uri, "mjs");
				return impESM(url);
			} catch(ex) {
				if (!ex || ex.message != "Failed to load " + url)
					return Cu.reportError(ex);
			}
			ss(subst, uri, "jsm");
			return impJSM(url);
		}
	}
	var load = async (file, id) => {
		var rootURI = XPIInternal.getURIForResourceInFile(file, "");
		imp(rootURI, id).start(rootURI);
	}
	var proto = XPIInternal.BootstrapScope.prototype;
	var func = proto._beforeCallBootstrapMethod;

	proto._beforeCallBootstrapMethod = () => {
		proto._beforeCallBootstrapMethod = func;
		for(var {id, loader, file} of XPIInternal.XPIStates.enabledAddons())
			ids.includes(id) && !loader && load(file, id);
	}
})("resource://gre/modules/addons/XPIProvider.");
//

// version, date year-month-day: 2024-6-12
(async () => {
    var file = Services.dirsvc.get("UChrm", Ci.nsIFile), iname;
    file.append("user_chrome_files");
    file.append("user_chrome.manifest");
    if (!file.exists() || !file.isFile())
        return;
    switch (Services.appinfo.name) {
        case "Firefox":
            iname = "user_chrome.js";
            break;
        case "Thunderbird":
            iname = "user_chrome_tb.js";
            break;
        default:
            return;
    }
    Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
    .autoRegister(file);
    var sandbox = Cu.Sandbox(Services.scriptSecurityManager.getSystemPrincipal(), {
        wantComponents: true,
        sandboxName: "UserChromeFiles",
        wantGlobalProperties: ["ChromeUtils"],
    });
    Services.scriptloader.loadSubScript(`chrome://user_chrome_files/content/user_chrome/${iname}`, sandbox, "UTF-8");
})();

policies.json

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

Выделить код

Код:

{
	"policies": {
		"BlockAboutAddons": false,
		"BlockAboutConfig": false,
		"BlockAboutProfiles": false,
		"BlockAboutSupport": false,
		"DisableSetDesktopBackground": true,
		"DisableMasterPasswordCreation": true,
		"DisableFeedbackCommands": true,
		"DisableFirefoxStudies": true,
		"DisableProfileRefresh": true,
		"DisableTelemetry": true,
		"NoDefaultBookmarks": false,
		"OverrideFirstRunPage": "",
		"OverridePostUpdatePage": "",
    "SearchEngines": {
      "Add": [
				{
					"Name": "Google RU",
					"URLTemplate": "https://www.google.com/search?q={searchTerms}&region=ru-RU",
					"Method": "GET",
					"Description": "metager",
					"IconURL": "https://www.google.com/favicon.ico"
				},
				{
					"Name": "Metager",
					"URLTemplate": "https://metager.de/meta/meta.ger3?eingabe={searchTerms}",
					"Description": "metager",
					"IconURL": "https://metager.de/favicon.ico"
				}
			],
			"Default": "Google RU"
		},
				"Preferences": {
			"browser.search.update": false,
			"browser.search.newSearchConfig.enabled": false,
			"browser.warnOnQuitShortcut": false,
			"datareporting.policy.dataSubmissionPolicyBypassNotification": true,
			"extensions.blocklist.enabled": false,
			"extensions.getAddons.showPane": false,
			"extensions.experiments.enabled": true,
			"xpinstall.signatures.required": false,
			"extensions.legacy.enabled": true,
			"extensions.htmlaboutaddons.recommendations.enabled": false,
			"intl.accept_languages": "ru-RU,ru,en-US,en",
			"print.more-settings.open": true,
			"security.ssl.errorReporting.enabled": false,
			"browser.newtabpage.activity-stream.feeds.telemetry": false,
			"toolkit.legacyUserProfileCustomizations.stylesheets": true,
			"widget.macos.native-context-menus": false
		}
	}
}

Отсутствует

 

№1723901-03-2025 16:54:05

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

Re: Custom Buttons

Garalf пишет

Может, что то в config.js не так?

Антиподписячий код не выглядит как последний выкладывавшийся.
Проверил с последним на 136.0 RC build3, CB и ATB установились нормально.
Ещё, UCF-стафф не последний, но это к вопросу отношения не имеет.

Отсутствует

 

№1724001-03-2025 21:01:33

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 338
UA: Firefox 136.0

Re: Custom Buttons

Dumby
Спасибо за подсказку. Теперь все работает.
Ну и нашел еще одну кнопку, которая перестала работать в 136
Консоль браузера

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

Выделить код

Код:

/*Initialization Code*/
({
	title: "Browser Console",
	url: "chrome://devtools/content/webconsole/index.html",

	icon: "chrome://devtools/skin/images/tool-webconsole.svg",
	init() {
		var trg = document.getElementById("browser");
		trg && addEventListener("DOMContentLoaded", this, false, trg);
		var id = "viewBrowserConsoleSidebar";

		var menuitem = this.element("menuitem", {
			type: "checkbox",
			label: this.title,
			id: "menu_browserConsoleSidebar",
			oncommand: `(globalThis.SidebarController || globalThis.SidebarUI).toggle("${id}");`
		}, document.getElementById("viewSidebarMenu"));

		var btn = this.element("toolbarbutton", {
			type: "checkbox",
			label: this.title,
			id: "sidebar-switcher-browserConsole",
			oncommand: `(globalThis.SidebarController || globalThis.SidebarUI).show("${id}");`,
			class: "subviewbutton subviewbutton-iconic"
		});
		document.querySelector(
			parseInt(Services.appinfo.platformVersion) >= 116
			? 'menuitem[id^="sidebar-switcher-"] + menuseparator'
			: 'toolbarbutton[id^="sidebar-switcher-"] + toolbarseparator'
		).before(btn);

		(globalThis.SidebarController || globalThis.SidebarUI).sidebars.set(id, {
			url: this.url,
			buttonId: btn.id,
			title: this.title,
			menuId: menuitem.id
		});
		(globalThis.SidebarController || globalThis.SidebarUI).isOpen && (globalThis.SidebarController || globalThis.SidebarUI).currentID == id && (globalThis.SidebarController || globalThis.SidebarUI).selectMenuItem(id);

		var popupset = this.popupset = this.element("popupset", {
			id: `CB${_id.slice(20)}-browserConsole-popupset`
		}, document.documentElement);

		var css = `\
			#${btn.id} > .toolbarbutton-icon,
			#sidebar-box[sidebarcommand="${id}"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon {
				list-style-image: url(${this.icon});
			}`;
		var str = (cbu.cb || "") + "data:text/css," + encodeURIComponent(css), type = windowUtils.USER_SHEET;
		windowUtils.loadSheetUsingURIString(str, type);

		addDestructor(() => {
			(globalThis.SidebarController || globalThis.SidebarUI).sidebars.delete(id);
			btn.remove(); menuitem.remove(); popupset.remove();
			windowUtils.removeSheetUsingURIString(str, type);
		});
		parseInt(Services.appinfo.platformVersion) < 73 
			&& "insertFTLIfNeeded" in MozXULElement
			&& MozXULElement.insertFTLIfNeeded("toolkit/main-window/editmenu.ftl");

		self.onclick = e => {
			if (e.button == 2) return;
			if (!e.button && !e.shiftKey) return (globalThis.SidebarController || globalThis.SidebarUI).toggle(id);
			var st = gBrowser.selectedTab, tab;
			if (!e.ctrlKey) tab = gBrowser.visibleTabs.find(tab => {
				var br = gBrowser.getBrowserForTab(tab);
				return br.currentURI.spec == this.url || (
					"_cachedCurrentURI" in br
					&& br._cachedCurrentURI.spec == this.url
				)
			});
			if (tab == st) return;
			if (!tab) tab = gBrowser.addTrustedTab(this.url);
			gBrowser.moveTabTo(tab, st._tPos + 1);
			gBrowser.selectedTab = tab;
		}
		for(var br of gBrowser.browsers) {
			if (br.currentURI.spec != this.url) continue;
			var doc = br.contentDocument;
			if (doc && (
				doc.readyState == "complete" ||
				doc.readyState == "interactive"
			))
				doc.querySelector(
					"main#app-wrapper,div#output-container"
				).childElementCount
					? this.defineDocPopupset(doc)
					: this.handleEvent({target: doc});
		}
		if (!btn.hasAttribute("checked")) return;
		var doc = (globalThis.SidebarController || globalThis.SidebarUI).browser.contentDocument;
		if (doc.documentURI != this.url) btn.doCommand();
		else if (doc.readyState == "complete") this.defineDocPopupset(doc);
	},
	defineDocPopupset(doc) {
		this.definePopupset(
			doc.querySelector("popupset") ||
			doc.documentElement.appendChild(doc.createXULElement("popupset"))
		);
	},
	get definePopupset() {
		var append = customElements.get("menuitem")
			? popup => {
				this.popupset.appendChild(popup);
				popup.setAttribute("oncommand", "event.target.cmd()");
				for(var node of [...popup.querySelectorAll("menuitem")]) {
					var menuitem = document.importNode(node, true);
					menuitem.cmd = Services.els.getListenerInfoFor(node)
						.find(inf => inf.type == "command").listenerObject;
					popup.replaceChild(menuitem, node);
				}
				return popup;
			}
			: this.popupset.appendChild.bind(this.popupset);

		delete this.definePopupset;
		return this.definePopupset = popupset => popupset.appendChild = append;
	},
	lss: Services.scriptloader.loadSubScript,
	async handleEvent({target: doc}) {
		if (!doc || doc.documentURI != this.url) return;

		var win = doc.defaultView;
		if (
			win.docShell.name == "toolbox-panel-iframe-webconsole" ||
			doc.DOMContentLoadedEventHandled
		)
			return;
		doc.DOMContentLoadedEventHandled = true;
		if (this instanceof XULElement) // Custom Buttons
		"custombuttonsConsole" in win || this.lss(
			"chrome://custombuttons/content/consoleOverlay.js", win
		);
		var cw = win.isChromeWindow, bc;
		if (!cw) {
			if (doc.visibilityState == "hidden") {
				var {focus} = win;
				win.focus = () => win.focus = focus;
			}
			doc.title = this.title;
			var link = doc.createElement("link");
			link.setAttribute("rel", "shortcut icon");
			link.setAttribute("href", this.icon);
			doc.head.prepend(link);

			var br = win.docShell.chromeEventHandler;
			var cmAttr = br.getAttribute("contextmenu");
			cmAttr && br.removeAttribute("contextmenu");
			win.onbeforeunload = () => {
				if (bc) bc.chromeWindow = {close() {}};
				cmAttr && br.setAttribute("contextmenu", cmAttr);
			}
		}
		bc = await this.console(win);
	},
	get console() {
		// Bug 1579090 - WebConsole should handle ObjectFront when needed (for non-primitive Console API args + Evaluation results) (Firefox 73+)
		https://bugzilla.mozilla.org/show_bug.cgi?id=1579090
		var vers = parseInt(Services.appinfo.platformVersion);
		this.bug1579090 = vers > 73 || (vers == 73 && !(
			"_setCurrentURI" in gBrowser.selectedBrowser // https://bugzil.la/1431214
		));
		delete this.console;
		return this.console = this.bug1579090 ? async win => {
			//await this.loader.bcm._browserConsoleInitializing;
			var key = "CBBrowserConsolePromise", {wins} = this.loader;
			win[key] = win.Object.create(null);
			win[key].promise = new win.Promise(resolve => win[key].resolve = resolve);
			win[key].destroy = () => {
				win[key].resolve();
				delete win[key];
				wins.splice(wins.indexOf(win), 1);
			}
			wins.unshift(win);
			wins.length > 1 && await wins[1][key].promise;

			var bc = await new this.loader.console(win).toggleBrowserConsole();
			win[key].destroy();
			return bc;

		} : async win => {
			this.loader.Services.ww.wins.push(win);
			return await new this.loader.HUDService().toggleBrowserConsole();
		}
	},
	get loader() {
		delete this.loader;
		var url = parseInt(Services.appinfo.platformVersion) >= 96
			? "resource://devtools/shared/loader/Loader.jsm"
			: "resource://devtools/shared/Loader.jsm";
		if (this.bug1579090) {
			var g = Cu.import(url, {}), key = "CBBrowserConsoleLoader";
			addDestructor(reason => reason[5] == e && key in g && g[key].destroy());
			if (key in g) return this.loader = g[key];
			var {BrowserConsoleManager} = g.require(
				"devtools/client/webconsole/browser-console-manager"
			);
			return this.loader = g[key] = {
				wins: [],
				bcm: BrowserConsoleManager,
				console: class extends BrowserConsoleManager.constructor {
					constructor(win) {
						super();
						this.win = win;
					}
					openWindow() {
						var {win} = this;
						win.addEventListener("unload", () => {
							win.CBBrowserConsolePromise &&
								win.CBBrowserConsolePromise.destroy();
							this.closeBrowserConsole.call(this);
						}, {once: true});
						delete this.win;
						return win;
					}
				},
				destroy() {
					this.wins = null;
					delete g[key];
				}
			};
		}
		var id = _id + "-browser-console";
		url += "?" + id;
		var loader = {exports: {}}, nsvo = Cu.import(url, loader);
		addDestructor(reason => reason[5] == "e" && Cu.unload(url));

		if (id in nsvo) return this.loader = nsvo[id];

		var dir = "resource://devtools/client/webconsole/";
		try {
			this.lss(dir + "hudservice.js", loader);
		} catch(ex) {
			// Bug 1570320 - Rename hudservice.js into browser-console-manager.js (Firefox 70+)
			// https://bugzilla.mozilla.org/show_bug.cgi?id=1570320
			this.lss(dir + "browser-console-manager.js", loader);
			this.lss("data:,this.HUDService=BrowserConsoleManager", loader);
		}
		var e = new CustomEvent("DOMContentLoaded", {bubbles: false}), ww = loader.Services.ww;
		loader.Services.ww = Cu.getGlobalForObject(nsvo).Object.create(ww, {
			wins: {value: []},
			openWindow: {value: function() {
				var win = this.wins.shift();
				win.setTimeout(() => win.dispatchEvent(e), 0);
				return win;
			}}
		});
		return this.loader = nsvo[id] = loader;
	},
	element(name, attrs, parent) {
		var node = document.createXULElement(name);
		for(var attr in attrs) node.setAttribute(attr, attrs[attr]);
		parent && parent.append(node);
		return node;
	}
}).init();
this.tooltipText = "Консоль браузера" +"\n"+"\n"+
                   "ЛКМ: В боковой панели" +"\n"+
                   "СКМ: В новой вкладке" +"\n"+
                   "ПКМ: Стандартное меню "

Отсутствует

 

№17241Вчера 19:14:34

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

Re: Custom Buttons

Garalf пишет

Ну и нашел еще одну кнопку, которая перестала работать в 136
Консоль браузера

Нее, от кнопки я решил отказаться.


На новых версиях, перехожу на скрипт для UCF.
Для сандбокса, custom_script.js, scriptsbackground
(в окна не совать!)


Локализация там, по сути, особо не нужна,
просто эксперимент с mock-fluent'ом.

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

Выделить код

Код:

(async url => {

	var img = "chrome://devtools/skin/images/tool-webconsole.svg";

	var strings = {
		ru: {
			label: "Консоль браузера",
			tooltip: [
				"Л: Сайдбар",
				"С: Вкладка",
				"П: Окно"
			]
		},
		def: {
			label: "Browser console",
			tooltip: [
				"L: Sidebar",
				"M: Tab",
				"R: Window"
			]
		},
	};

	var fluentLabel = "browser-console-label";
	var fluentButton = "browser-console-button";
	var fluentFile = "user/browser-console.ftl";

	var version = parseInt(Services.appinfo.platformVersion);

	for (var [loc, data] of Object.entries(strings)) {
		var lab = data.label;
		strings[loc] = `${
			fluentButton
		} =\n.label = ${lab}\n.tooltiptext = ${
			data.tooltip.map(str => "\n " + str).join("")
		}\n${
			fluentLabel
		} =\n.label = ${lab}`;
	}
	var registry = L10nRegistry.getInstance();
	var sourceName = sfx => "u-browser-console-" + sfx;

	var getSource = (locs, meta, name) => {
		var sources = Array.from(locs, loc => ({
			path: `/localization/${loc}/${fluentFile}`,
			source: strings[loc] || strings.def
		}));
		return L10nFileSource.createMock(
			name || sourceName("pkg"), meta,
			locs, "/localization/{locale}/", sources
		);
	}
	registry.registerSources([
		getSource(Services.locale.packagedLocales, "app")
	]);

	var fileSources = new Map();
	var register = langpacks => {
		var sourcesToReg = [];
		for(var langpack of langpacks) {

			var {langpackId, languages} = langpack.startupData;
			var name = sourceName(langpackId);
			if (registry.hasSource(name)) continue;

			var fileSource = fileSources.get(langpackId);
			fileSource || fileSources.set(
				langpackId, fileSource = getSource(languages, langpackId, name)
			);
			sourcesToReg.push(fileSource);
		}
		registry.registerSources(sourcesToReg);
	}

	var file = Services.dirsvc.get("ProfD", Ci.nsIFile);
	file.append("extensions.json");
	try {
		var langpacks = JSON.parse(Cu.readUTF8File(file))
			.addons.filter(a => a.startupData?.langpackId && a.active);
		langpacks?.length && register(langpacks);
	} catch {}

	var unreg = addon => {
		if (addon.type != "locale") return;
		var name = sourceName(addon.__AddonInternal__.startupData.langpackId);
		registry.hasSource(name) && registry.removeSources([name]);
	}
	var addonListener = Object.create(null);
	for(var p of ["onDisabled", "onUninstalling", "onUninstalled"]) addonListener[p] = unreg;
	AddonManager.addAddonListener(addonListener);

	var topicLng = "webextension-langpack-startup";
	var topicWin = "browser-delayed-startup-finished";
	var {addObserver: add, removeObserver: rem} = Services.obs;

	var reg = subj => register([subj.wrappedJSObject.langpack]);

	add(reg, topicLng);
	add(onBrowserWin, topicWin);
	add(function quit(s, topic) {
		rem(quit, topic);
		rem(reg, topicLng);
		rem(onBrowserWin, topicWin);
	}, "quit-application-granted");


	var addFtlLink = (doc, href) => {
		var link = doc.createElement("link");
		link.rel = "localization";
		link.href = href;
		doc.head.prepend(link);
	}
	var maybeInsertFTL = doc => !(
		doc.head.querySelector(`[href="${fluentFile}"]`) || addFtlLink(doc, fluentFile)
	);

	var impl;
	CustomizableUI.createWidget(impl = {
		l10nId: fluentButton,
		id: "browser-console-button",
		defaultArea: CustomizableUI.AREA_NAVBAR,
		onCreated(btn) {
			maybeInsertFTL(btn.ownerDocument);
			btn.image = img;
			for(var type of this.events)
				btn.addEventListener(type, this);
		},
		events: ["command", "auxclick", "contextmenu"],
		handleEvent(e) {
			this[e.type](e);
		},
		command(e) {
			e.view.SidebarController.toggle(id);
		},
		auxclick(e) {
			if (e.button != 1) return;
			var gb = e.view.gBrowser;
			if (!e.ctrlKey && !e.shiftKey) for(var tab of gb.visibleTabs)
				if (tab.linkedBrowser?.currentURI.spec == url)
					return gb.selectedTab = tab;

			gb.selectedTab = gb.addTrustedTab(url, {index: gb.selectedTab._tPos + 1});
		},
		contextmenu(e) {
			if (!e.ctrlKey && !e.shiftKey)
				e.preventDefault(),
				this.bcm.openBrowserConsoleOrFocus();
		},
		get bcm() {
			delete this.bcm;
			return this.bcm = ChromeUtils.importESModule(
				"resource://devtools/shared/loader/Loader.sys.mjs"
			).require(
				"devtools/client/webconsole/browser-console-manager"
			).BrowserConsoleManager;
		}
	});

	var revamp = true, pref = "sidebar.revamp";
	if (Services.prefs.prefHasDefaultValue(pref)) {
		var obs = () => revamp = Services.prefs.getBoolPref(pref);
		Services.prefs.addObserver(pref, obs);
		obs();
	}

	var id = "viewBrowserConsoleSidebar";
	var addSidebar = version >= 135
		? (bars, sb) => bars.set(id, sb)
		: (bars, sb) => {
			// viewCustomizeSidebar breaks iteration in SidebarController.selectMenuItem()
			var arr = Array.from(bars);
			bars.clear();
			bars.set(id, sb);
			for(var args of arr) bars.set(...args);
		}
	var maybeAddSidebar = (sc, sb) => {
		var bars = sc.sidebars;
		bars.has(id) || addSidebar(bars, sb);
	}
	var addFluentRes = sm => sm.fluentStrings.addResourceIds([fluentFile]);
	var ce = {configurable: true, enumerable: true};

	function onBrowserWin(win) {
		win.addEventListener("DOMContentLoaded", onDOMContentLoaded);

		var doc = win.document;
		maybeInsertFTL(doc);
		var sc = win.SidebarController;

		var sep = doc.querySelector("#sidebarMenu-popup > menuseparator");
		if (sep) {
			var switcher = doc.createXULElement("menuitem");
			switcher.dataset.l10nId = fluentLabel;
			switcher.id = "sidebar-switcher-browser-console";
			switcher.addEventListener("command", () => sc.toggle(id));
			sep.before(switcher);
		}
		var sb = sc.makeSidebar({
			url,
			iconUrl: img,
			elementId: switcher?.id,
			menuL10nId: fluentLabel,
			revampL10nId: fluentLabel,
			menuId: "menu_browserConsoleSidebar"
		});
		var popup = doc.getElementById("viewSidebarMenu");
		popup.insertBefore(
			sc.createMenuItem(id, sb),
			popup.querySelector(".webextension-menuitem")
		);
		var o = win.Object;
		var def = (obj, prop, desc) => o.defineProperty(obj, prop, o.assign(desc, ce));

		def(sb, "hasOwnProperty", {value(prop) {
			prop == "extensionId" && win.setTimeout(maybeAddSidebar, 0, sc, sb);
			return o.hasOwn(sb, prop);
		}});
		addSidebar(sc.sidebars, sb);

		var br = sc.browser;
		def(UcfPrefs.dbg.ref("defaultTools", sc.init, win), id, {get() {
			var doc = br.contentDocument;
			var cust = doc?.querySelector("sidebar-customize");
			cust && maybeInsertFTL(doc) &&
				UcfPrefs.dbg.ref("l10nMap", cust.constructor, 0).set(id, fluentLabel);
			return "browserconsole";
		}});
		sc._toolsAndExtensions = null;
		var sm = sc.sidebarMain;
		if (revamp) addFluentRes(sm), sm.requestUpdate();
		else win.customElements.whenDefined("sidebar-main").then(() => addFluentRes(sm));
	}

	var noop = () => {};

	var setSmall = hdr => hdr.shadowRoot
		.querySelector("moz-button").setAttribute("size", "small");

	var addCloseBtn = async (doc, win) => {
		var main = doc.body.querySelector("main");
		var {promise, resolve} = win.Promise.withResolvers();
		var mo = new win.MutationObserver(resolve);

		mo.observe(main, {childList: true});
		await promise;
		mo.disconnect();

		var header = main.querySelector("header");
		addFtlLink(doc, "browser/sidebar.ftl");

		var url = "chrome://browser/content/sidebar/sidebar-panel-header.mjs";
		UcfPrefs.dbg.makeGlobalObjectReference(win).executeInGlobal(
			`ChromeUtils.importESModule("${url}", {global: "current"});`
		);
		var sph = doc.createElement("sidebar-panel-header");
		header.append(sph);
		win.setTimeout(setSmall, 50, sph);

		var sheet = new win.CSSStyleSheet();
		sheet.replaceSync(`
			h4 {
				display: none !important
			}
			:host {
				flex-grow: 1 !important;
				display: flex !important;
				justify-content: end !important;
			}
			moz-button, moz-button::part(button) {
				display: flex !important;
				height: 100% !important;
				min-height: 100% !important;
			}
		`);
		sph.shadowRoot.adoptedStyleSheets.push(sheet);
	}

	var onDOMContentLoaded = e => {
		var doc = e.target;
		if (doc?.documentURI != url) return;
		var win = doc.ownerGlobal, ds = win.docShell;
		ds.name != "toolbox-panel-iframe-webconsole"
			&& onConsoleDOMContentLoaded(doc, win, ds);
	}
	var onConsoleDOMContentLoaded = async (doc, win, ds) => {
		try {Services.scriptloader.loadSubScript(
			"chrome://custombuttons/content/consoleOverlay.js", win
		)} catch {}

		var tabWin = !win.isChromeWindow;
		if (tabWin) {
			if (doc.visibilityState == "hidden") {
				var {focus} = win;
				win.focus = () => win.focus = focus;
			}
			win.browsingContext
				.currentWindowGlobal.windowGlobalChild
				.getActor("ContextMenu").handleEvent = noop;

			var br = ds.chromeEventHandler;
			var cmAttr = br.getAttribute("contextmenu");

			var gb = br.ownerGlobal.gBrowser;
			gb.setIcon(gb.getTabForBrowser(br), img);
		}
		else if (revamp) addCloseBtn(doc, win);

		var bc = await getConsole(win);
		if (tabWin) {
			if (cmAttr)
				bc.cmAttr = cmAttr,
				(bc.br = br).removeAttribute("contextmenu");
			bc.updateWindowTitle(win);
		}
	}


	var resolvers = [];
	var find = function(resolver) {
		return resolver.id == this;
	}
	var destroy = function() {
		this.resolve();
		resolvers.splice(resolvers.indexOf(this), 1);
	}
	var getConsole = async win => {
		var resolver = Promise.withResolvers();
		resolver.destroy = destroy;
		resolver.id = win.browsingContext.id;
		resolvers.unshift(resolver);
		resolvers.length > 1 && await resolvers[1].promise;

		var bc = await constructConsole(win);
		resolver.destroy();
		return bc;
	}
	var constructConsole = win => {
		var closer = {close: noop};
		var cc = class extends impl.bcm.constructor {
			constructor(win) {
				super();
				this.win = win;
			}
			openWindow() {
				var {win} = this;
				win.addEventListener("unload", this, {once: true});
				delete this.win;
				return win;
			}
			handleEvent(e) {
				resolvers.find(find, e.target.ownerGlobal.browsingContext.id)?.destroy();
				var bc = this.getBrowserConsole();
				bc.chromeWindow = closer;
				this.closeBrowserConsole();
				bc.br?.isConnected && bc.br.setAttribute("contextmenu", bc.cmAttr);
			}
		}
		return (constructConsole = win => new cc(win).toggleBrowserConsole())(win);
	}
})("chrome://devtools/content/webconsole/index.html");

Отредактировано Dumby (Вчера 19:15:11)

Отсутствует

 

№17242Вчера 20:35:25

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 338
UA: Firefox 136.0

Re: Custom Buttons

Dumby
Великолепно! Благодарю.
А ты случайно не делал скрипт UserCSSLoader,
чето кнопка уменя не работает.

Отсутствует

 

№17243Вчера 21:55:38

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

Re: Custom Buttons

Garalf пишет

А ты случайно не делал скрипт UserCSSLoader,
чето кнопка уменя не работает.

Нет. Я даже не знаю что это такое.
А не работает, скорее всего, из-за «on…» атрибутов
и/или C{u, hromeUtils}.import(). Это основной отвал на 136.

Отсутствует

 

№17244Вчера 22:12:51

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 338
UA: Firefox 136.0

Re: Custom Buttons

"Ну и нашел еще одну кнопку, которая перестала работать в 136
Консоль браузера"

Прошу прощения, кнопка рабочая. Там был конфликт с одним раширением.

Отредактировано Garalf (Вчера 22:14:43)

Отсутствует

 

№17245Сегодня 15:13:59

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 7
UA: unknown 0.0

Re: Custom Buttons

Dumby
toggleRestartlessAddons.js    В 115  не того,сдох ?
И Dom inspector  тоже...?

Отсутствует

 

Board footer

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