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

Многие проблемы быстрее решаются поиском по форуму и чтением FAQ, чем созданием новой темы и томительным ожиданием ответа.

№1537630-03-2021 09:09:03

momo2000
Участник
 
Группа: Members
Зарегистрирован: 03-09-2015
Сообщений: 228
UA: Firefox 68.0

Re: Custom Buttons

Подправте кнопку Reload user{Chrome, Content}

https://forum.mozilla-russia.org/viewto … 24#p767224

Уже давно не работает Reload userContent по ПКМ
Возможно дело в строке
        var data = await this.reloadTab("chrome://extensions/content/dummy.xul", one ? false : {});
Меняю на
        var data = await this.reloadTab("about:config", one ? false : {});
или
        var data = await this.reloadTab("chrome://mozapps/content/extensions/aboutaddons.html", one ? false : {});
но тоже не канает(

Отредактировано momo2000 (30-03-2021 09:09:40)

Отсутствует

 

№1537730-03-2021 12:14:55

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

Re: Custom Buttons

momo2000 пишет

Подправте кнопку Reload user{Chrome, Content}
Уже давно не работает Reload userContent по ПКМ

Ну, попробую, так, разве что чисто формально, это весьма сложно тестировать.

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

Выделить код

Код:

(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);
	},
	re: /^(?:web.*|file|extension|privilegedabout)$/,
	get url() {
		delete this.url;
		return this.url = `chrome://extensions/content/dummy.x${
			parseInt(Services.appinfo.platformVersion) >= 74 ? "htm" : "u"
		}l`;
	},
	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(this.url, one ? false : {});
		if (one) this.reloadTab();
		else if (data) {
			var url = "data:," + encodeURIComponent(
				self.Help + this.contentSheetURL + '", ' + JSON.stringify(data) + ");"
			);
			for(var ind = 0; ind < count; ind++) {
				var child = Services.ppmm.getChildAt(ind);
				var rt = child.remoteType;
				rt && this.re.test(rt) && 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, triggeringPrincipal: document.nodePrincipal});
		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;
	}
});

Отсутствует

 

№1537830-03-2021 15:59:04

momo2000
Участник
 
Группа: Members
Зарегистрирован: 03-09-2015
Сообщений: 228
UA: Firefox 68.0

Re: Custom Buttons

Dumby
:beer:

Работает, спасибо!!!

Отсутствует

 

№1537931-03-2021 11:34:09

ds(ds)
Участник
 
Группа: Members
Зарегистрирован: 21-01-2010
Сообщений: 83
UA: Seamonkey 2.53

Re: Custom Buttons

подскажите пожалуйста
custom button 0.0.5.8.9.3 + seamonkey 2.53.7 + win10

уже давно, после одного из обновлений симанки, пропала возможность видеть установленные кнопки в разделе "custom button"
раздел "custom button" есть, пуст, но кнопки вынесенные на  панель работают
и не работает "добавить новую кнопку".

есть более свежая версия? или другие способы?

----------------------------------------------
снимаю вопрос, нашел версию 0.0.5.8.9.6pre
она все порешала

Отредактировано ds(ds) (31-03-2021 11:46:25)

Отсутствует

 

№1538031-03-2021 11:53:05

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 332
UA: Firefox 87.0

Re: Custom Buttons

Dumby
Здравствуйте, еще один код упал в мульти:

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

Выделить код

Код:

// ВКЛ / ВЫКЛ  js на странице + разрешить выделение
// Результат появляется сразу без перезагрузки.
  
      const sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);  
      var uri = makeURI("data:text/css," + encodeURIComponent( "*{ -moz-user-select: text !important;}" ));
// Для текущей вкладки:
      
           gBrowser.docShell.allowJavascript = !gBrowser.docShell.allowJavascript;
           
           
                      alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
                      alertsService.showAlertNotification("chrome://global/skin/icons/cpd_OK.png", "Javascript", "ОТКЛ" );
                      setTimeout(()=> alertsService.closeAlert(), 2000);


или как копировать,если выделяется, но не копируется?

Отредактировано ВВП (31-03-2021 21:00:09)

Отсутствует

 

№1538131-03-2021 22:53:42

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

Re: Custom Buttons

ВВП пишет

gBrowser.docShell.allowJavascript = !gBrowser.docShell.allowJavascript;

gBrowser.selectedBrowser.messageManager.loadFrameScript(
    "data:,docShell.allowJavascript=!docShell.allowJavascript", false
);

Отсутствует

 

№1538231-03-2021 23:50:09

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 332
UA: Firefox 87.0

Re: Custom Buttons

Dumby
Блеск!
Ввел в кнопку var btnActions = ["update-check", "preferences", "toggle-disabled", "remove", "install-update"];

update-check - имеет длинное название , как бы Label  на него внести?
В aboutaddons.html пункт я ввел и в popup его видно, но хочу и туда, можно просто значок , label не обязательно.
ddm7sdvx.jpg
А в list просто значок var btnActions = ["update-check", "preferences", "toggle-disabled", "remove", "install-update"]; ???

Отредактировано ВВП (01-04-2021 15:32:14)

Отсутствует

 

№1538303-04-2021 12:15:27

Stkvsky
Участник
 
Группа: Members
Зарегистрирован: 26-06-2012
Сообщений: 1700
UA: Firefox 68.0

Re: Custom Buttons

Dumby, здравствуйте, вы бы не могли помочь с кнопкой?
Если можно, добавить в контекстное меню вкладки пункт "Добавить контейнер в закладки"?
Чтобы все вкладки выбраного контейнера добавились в папку на панель закладок
Если можно название для папки брать такое же как и название вкладки

Отредактировано Stkvsky (03-04-2021 15:05:28)

Отсутствует

 

№1538403-04-2021 22:19:38

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

Re: Custom Buttons

ВВП пишет

В aboutaddons.html пункт я ввел и в popup его видно, но хочу и туда, можно просто значок , label не обязательно.

Ну, код на «значок» как бы не рассчитан.
И что значит «я ввел»? Типа теперь и я ввести должен?
Ладно, попробую что-нибудь сочинить.

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

Выделить код

Код:

((id, g, css) => {
	addDestructor(r => r[5] == "e" && g[id]?.destroy(true));
	if (g[id]) return;
	var btnActions = ["update-check", "preferences", "toggle-disabled", "remove", "install-update"];
	var noLabs = ["update-check", ];
	var icons = {
		"update-check": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAACVUlEQVQ4jXWT30vTYRTGP3Mb+ZbiXmm6DGUO0pkQGQR2URBdKZWWIHRlFHYhXnQRdVUEBUn/gBddFZERaalUoAUhYUglVIjO5TKbjMDtq2vDQ9t8u0jnr3Xgvfuch/M87zk2rTX/K+u05QROUMBVlrmkn+lvWxlHzsbjVj4uzlHFFec15/7UYCrFU6xcrF0ptbn5jNVADS9o47yvxed24yZRnchLz6dbpUSUlMhHNavSa3zeNskMIZzYOQChPyGmolNIXGz+Tn/lvu59d6jhtdVkZX1vm0AFVFSKpZfPNHKQ3SSBPsxCfMEWi8Rwtbkq5L3UqnH1OCtgNVleqRaf+MUjXrH0Sx2TUuklQAt+XPRykyAzFHNIfgkUUyV58k4FVOifhVLe0sUnGhknnyoAPaAjzHGUbkYxjOlHup0R7iPATqCI9vUMHHhwAR7SGCJrdnS/DjPOMd2nhwD4zS2CZEgCBRxZF8gQJgrkYwcqNmaiJ3QGMADMMMsyMeyAE/e6QII3TEP54XIbhXSufqfXarEebEwcH7swFBIDUqSyIYpPFrFzIV4ZhwLqBDGskOE6XUxwUsqkRwWVyF6xscw0P3lOgodqSgXRWqO1tnGZVwxiiGAYw3CbpWbTbDpMh+EGH2jDvcpuetk9EK8ME6UBQwkOoJUdc445RodHqb9YXxaeDJ8StwyogIrnXGUVUEkplx7mKWKJWn7gTH1PwQqEv4bBQRHzLKlJNbJRwJbrGq2zlps9fKEOD5MIEZ6Q5K7u1xNb2ZzXiEFYxDBEF8I9PaBDOTngLwkg8PzzO00cAAAAAElFTkSuQmCC",
		/*
		"toggle-disabled": [
			"chrome://browser/skin/preferences/face-sad.svg",
			"chrome://browser/skin/preferences/face-smile.svg",
		],
		*/
	};

	var {Array, Set} = Cu.getGlobalForObject(g);
	var {obs, focus, wm} = Services, cn = "cb-cloned-buttons-container";
	var topics = ["chrome-document-loaded", "quit-application-granted"];
	(g[id] = {
		init() {
			for(var topic of topics) obs.addObserver(this, topic);
			this.wins();
		},
		destroy(wins) {
			delete g[id];
			for(var topic of topics) obs.removeObserver(this, topic);
			wins && this.wins("destroyDoc");
		},
		isTarget: doc => doc.documentURI == "about:addons",
		wins(method = "initDoc") {
			for(var {document: doc} of new Set(Array.from(
				g.AddonManagerInternal.addonListeners, Cu.getGlobalForObject
			))) doc && this.isTarget(doc) && this[method](doc);
		},
		initDoc(doc) {
			this.btnActions = btnActions.map(action => `panel-list > panel-item[action="${action}"]`);
			var url = "cb" + (this.url =
				"data:text/css;charset=utf-8," + encodeURIComponent(css.replace(/;/g, " !important;"))
			);
			this.type = doc.ownerGlobal.windowUtils.USER_SHEET;

			(this.initDoc = doc => {
				doc.addEventListener("unload", this);
				doc.addEventListener("update", this, true);
				doc.ownerGlobal.windowUtils.loadSheetUsingURIString(url, this.type);
				for(var card of doc.getElementsByTagName("addon-card")) this.onCard(card);
			})(doc);
		},
		destroyDoc(doc) {
			for(var span of Array.from(doc.getElementsByClassName(cn))) span.remove();
			doc.ownerGlobal.windowUtils.removeSheetUsingURIString(this.url, this.type);
			this.unload(doc);
		},
		observe(doc, topic) {
			topic[0] == "q" ? this.destroy() : this.isTarget(doc) && this.initDoc(doc);
		},
		handleEvent(e) {
			this[e.type](e.target);
		},
		unload(doc) {
			doc.removeEventListener("update", this, true);
			doc.removeEventListener("unload", this);
		},
		update(card) {
			card.nodeName == "ADDON-CARD" && this.onCard(card);
		},
		onCard(card, again) {
			var btnsParent = card.querySelector("addon-options");
			if (!btnsParent) return again || card.ownerGlobal
				.requestAnimationFrame(() => this.onCard(card, true));
			var doc = card.ownerDocument;
			var [span] = card.getElementsByClassName(cn);
			if (span) span.textContent = "";
			else {
				card.querySelector("button.more-options-button")
					.before(span = doc.createElement("span"));
				span.className = cn;
			}
			for(var item of this.btnActions.map(this.btns, btnsParent)) if (item) {
				span.append(item);
				var btn = item.shadowRoot.querySelector("button");
				btn.classList.add("cb-cloned-button");
				let icons = this.imgs[item.action], icon;
				if (icons) {
					icon = icons[item.active] || icons[0];
					btn.style.setProperty("--icon", icon, "important");
				}
				if (icon || !item.lab) btn.classList.add("icon");
				item.lab && btn.classList.add("label");
			}
		},
		get imgs() {
			var array = [];
			for(var [key, val] of Object.entries(icons)) {
				var arr = [].concat(val);
				arr.forEach((icon, ind) => {
					if (!this.cspRe.test(icon)) {
						var chromeURL = `chrome://custombuttons/content/${id}-${key}${ind}`;
						array.push(["override", chromeURL, icon]);
						icon = chromeURL;
					}
					arr[ind] = `url("${icon}")`;
				});
				icons[key] = arr;
			}
			if (array.length) this.iconHelper = Cc["@mozilla.org/addons/addon-manager-startup;1"]
				.getService(Ci.amIAddonManagerStartup).registerChrome(
					Services.io.getProtocolHandler("resource")
						.getSubstitution("custombuttons-modules"),
					array
				);
			delete this.imgs;
			return this.imgs = icons;
		},
		cspRe: /^(?:chrome|file|jar|https?):/,
		btns(sel, ind) {
			var item, action = btnActions[ind];
			var lab = !noLabs.includes(action);
			var td = action == "toggle-disabled", card = this.parentNode;
			var active = card.getAttribute("active") == "true";
			if (td || action == "update-check") {
				if (td) {
					if (!card.querySelector('input[action="toggle-disabled"]')) return;
				} else {
					var a = card.parentNode.addon;
					if (!a.applyBackgroundUpdates || a.isBuiltin) return;
				}
				var doc = this.ownerDocument;
				var item = doc.createElement("panel-item");
				item.setAttribute("action", action);

				if (lab) {
					if (td) doc.l10n.setAttributes(item, `${
						active ? "dis" : "en"
					}able-addon-button`);
					else item.textContent = "Проверить обновление";
				}
			} else {
				item = this.querySelector(sel);
				if (!item) return;
				item = item.cloneNode(false),
				lab || item.removeAttribute("data-l10n-id");
			}
			item.lab = lab;
			item.action = action;
			item.active = +active;
			return item;
		}
	}).init();
})("CBAboutAddonsHTMLButtonizer", Cu.import("resource://gre/modules/AddonManager.jsm", {}), `

	span.cb-cloned-buttons-container {
		display: flex;
	}
	button.cb-cloned-button {
		appearance: none;
		padding: 1px 6px 3px 6px;
		margin: 0 1px;

		border: 1px solid var(--in-content-box-border-color);
		border-radius: 0px;

		font-size: 13px;
		font-family: Segoe UI;
	}
	button.cb-cloned-button:not(.icon) {
		background-image: none;
	}
	button.cb-cloned-button.icon {
		min-width: 2em;
		background-position: center;
	}
	button.cb-cloned-button.icon.label {
		padding-inline-start: 2em;
		background-position: .3em center;
	}
	button.cb-cloned-button:hover {
		background-color: gold;
	}
	button.cb-cloned-button:after,
	input[action="toggle-disabled"] {
		display: none;
	}
`);


Stkvsky
Может так подойдёт
скрытый текст

Выделить код

Код:

(async id => {
	var menuitem = document.createXULElement("menuitem");
	document.getElementById(id).after(menuitem);
	typeof addDestructor == "function"
		&& addDestructor(() => menuitem.remove());
	menuitem.render = function() {
		this.id = "context_bookmarkContainer";
		this.label = "Добавить контейнер в закладки";
		this.setAttribute("oncommand", "bookmark()");

		var bm = PlacesUtils.bookmarks, attr = "usercontextid";
		var {toolbarGuid: parentGuid, TYPE_FOLDER: type} = bm;
		this.bookmark = async () => {
			var tab = TabContextMenu.contextTab;
			var title = tab.label, id = tab.getAttribute(attr);
			var {guid} = await bm.insert({title, parentGuid, type});
			for(tab of gBrowser.visibleTabs)
				tab.getAttribute(attr) == id
				&& await bm.insert({
					parentGuid: guid, title: tab.label,
					url: tab.linkedBrowser.currentURI.spec
				});
		}
		var raf = () => menuitem.hidden =
			!TabContextMenu.contextTab.hasAttribute(attr);
		var {render} = this.constructor.prototype;
		(this.render = () => {
			requestAnimationFrame(raf);
			render.call(menuitem);
		})();
	}
})("context_reopenInContainer");

Отсутствует

 

№1538503-04-2021 23:51:40

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 332
UA: Firefox 87.0

Re: Custom Buttons

Dumby
Так. Самой иконки не видать.
wx9gx9ui.jpg
Не есть , мой косяк///А tooltipText нельзя на значок ?

Отредактировано ВВП (04-04-2021 02:23:02)

Отсутствует

 

№1538604-04-2021 02:26:56

Stkvsky
Участник
 
Группа: Members
Зарегистрирован: 26-06-2012
Сообщений: 1700
UA: Firefox 68.0

Re: Custom Buttons

Dumby пишет

Может так подойдёт

Ооо, супер, спасибо
Блин, забыл еще, можете добавить? чтобы вкладки контейнера после добавления закрывались все

Отсутствует

 

№1538704-04-2021 04:18:55

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 395
UA: Firefox 84.0

Re: Custom Buttons

как получить текущее значение userAgent из JS-кода, если ключ general.useragent.override сброшен ?
Например, у меня это: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:84.0) Gecko/20100101 Firefox/84.0"

Выделить код

Код:

// В этом примере не работает получение ЮзерАгента, а также показ строки статуса
var agent = navigator.userAgent;
StatusPanel._label = agent;
setTimeout(()=> StatusPanel._label = '',3000);

На форуме

 

№1538804-04-2021 09:38:57

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

Re: Custom Buttons

ВВП пишет

А tooltipText нельзя на значок ?

скрытый текст
                if (lab) {
                    if (td) doc.l10n.setAttributes(item, `${
                        active ? "dis" : "en"
                    }able-addon-button`);
                    else item.textContent = "Проверить обновление";
                }
                else if (!td) item.setAttribute("title", "Tooltip Text");

Stkvsky пишет

чтобы вкладки контейнера после добавления закрывались все

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

Выделить код

Код:

(async id => {
	var menuitem = document.createXULElement("menuitem");
	document.getElementById(id).after(menuitem);
	typeof addDestructor == "function"
		&& addDestructor(() => menuitem.remove());
	menuitem.render = function() {
		this.id = "context_bookmarkContainer";
		this.label = "Добавить контейнер в закладки";
		this.setAttribute("oncommand", "bookmark()");

		var bm = PlacesUtils.bookmarks, attr = "usercontextid";
		var {toolbarGuid: parentGuid, TYPE_FOLDER: type} = bm;
		this.bookmark = async () => {
			var tab = TabContextMenu.contextTab;
			var title = tab.label, id = tab.getAttribute(attr);
			var {guid} = await bm.insert({title, parentGuid, type});
			var tabs = [];
			for(tab of gBrowser.visibleTabs)
				tab.getAttribute(attr) == id
				&& tabs.unshift(tab) && await bm.insert({
					parentGuid: guid, title: tab.label,
					url: tab.linkedBrowser.currentURI.spec
				});
			gBrowser.removeTabs(tabs);
		}
		var raf = () => menuitem.hidden =
			!TabContextMenu.contextTab.hasAttribute(attr);
		var {render} = this.constructor.prototype;
		(this.render = () => {
			requestAnimationFrame(raf);
			render.call(menuitem);
		})();
	}
})("context_reopenInContainer");

Dobrov пишет

как получить текущее значение userAgent из JS-кода, если ключ general.useragent.override сброшен ?

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

Выделить код

Код:

Cc["@mozilla.org/network/protocol;1?name=http"].getService(Ci.nsIHttpProtocolHandler).userAgent

Отсутствует

 

№1538904-04-2021 11:33:54

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 332
UA: Firefox 87.0

Re: Custom Buttons

Dumby
От теперь класс! Благодарю!
jgolzk27.jpg

Отсутствует

 

№1539004-04-2021 12:41:39

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 395
UA: Firefox 84.0

Re: Custom Buttons

Dumby проверь мой код QuickToggleAboutConfig со строки 144,
добавил переключение UserAgent, но параметр не меняется, почему-то тип general.useragent.override всегда логический, а не строковый…

Выделить код

Код:

// Quick Toggle https://forum.mozilla-russia.org/viewtopic.php?pid=784139#p784139
// https://forum.mozilla-russia.org/viewtopic.php?pid=784165#p784165
// Быстрое переключение параметров about:config
// Ctrl+Click или правый клик - сброс параметра по-умолчанию
// стиль иконки: #QuickToggleAboutConfigSettings .toolbarbutton-icon{ padding: 2px !important;}

(async (name, id, func) => {
	if (name == "Object") return CustomizableUI.createWidget(func());
	var win = name == "Window", g = Components.utils.import("resource://gre/modules/Services.jsm", {});
	if (g[id]) {if (win) return;} else g[id] = func();
	if (win) return CustomizableUI.createWidget(g[id]);
	addDestructor(r => r[5] == "e" && delete g[id]);
	g[id].onCreated(this);
})(this.constructor.name, "QuickToggleAboutConfigSettings", () => { // BEGIN (this.constructor… {код кнопки});

	var {prefs} = Services, db = prefs.getDefaultBranch("");
	var pv = parseInt(Services.appinfo.platformVersion);
	var xul_ns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
	var icon_vpn = "hue-rotate(270deg) brightness(95%)";
	function Notify(title, text, time){ Components.classes['@mozilla.org/alerts-service;1'].getService(Components.interfaces.nsIAlertsService).showAlertNotification(null, title, text, false, '', null, time);
	}
	function Antizapret(trg){
		if (Services.prefs.getIntPref('network.proxy.type') == 2) { // выключить
			Services.prefs.setIntPref('network.proxy.type', 0);
			Services.prefs.setStringPref("network.proxy.autoconfig_url", "127.0.0.1");
			trg.style.filter = '';
			Notify('Proxy', 'Режим по-умолчанию отключен', 2000);
		} else {
			Services.prefs.setIntPref('network.proxy.type', 2);
			Services.prefs.setStringPref("network.proxy.autoconfig_url", "https://antizapret.prostovpn.org/proxy.pac");
			trg.style.filter = icon_vpn;
			Notify('Proxy', 'Работаем через VPN Антизапрет', 2000);
		}
	}

	var useragent = Components.classes["@mozilla.org/network/protocol;1?name=http"].getService(Components.interfaces.nsIHttpProtocolHandler).userAgent; // текущий юзерагент

//=====================================================================================

	// refresh:
	//	false - reload current tab
	//	true - reload current tab skip cache
	//
	// restart:
	//	false - restart browser
	//	true - restart browser with confirm

//=====================================================================================

	var secondary = [{

			pref: ["network.proxy.autoconfig_url", "Прокси (VPN) URL"],
			userChoice: 0, userAlt: 1, refresh: true,
			values: [
				["127.0.0.1", "отключен…", "0", "", `Services.prefs.setIntPref('network.proxy.type', 0); node.parentNode.parentNode.style.filter = '';`],
				["https://antizapret.prostovpn.org/proxy.pac", "АнтиЗапрет", "1", "Надёжный доступ на заблокированные сайты\n\n«Режим прокси» меняется на 2", `Services.prefs.setIntPref('network.proxy.type', 2); node.parentNode.parentNode.style.filter = icon_vpn;`],
				[prefs.getStringPref("user.pacfile", "file:///etc/proxy.pac"), "user .pac файл", "2"],
				["https://git.io/ac-anticensority-pac", "ac-anticensority", "3"],
				["localhost", "Tor Browser", "4"]
	]},{
			pref: ["network.proxy.type", "Режим прокси"],
			userChoice: 0, userAlt: 2, refresh: true,
			values: [
				[0, "Без прокси", "0", "по-умолчанию"],
				[5, "Системные (из IE)", "5"],
				[2, "Автонастройка", "2", "about:config — user.pacfile"],
				[1, "Ручная настройка", "1", "вторая строка"],
				[4, "Автоопределение", "4"]
	]},{
			pref: ["network.proxy.share_proxy_settings", "Прокси для всех протоколов"],
			userChoice: true, refresh: true,
			values: [[true, "Да", "", "Прокси для всех протоколов при ручной настройке"], [false, "Нет"]]
	},{
			pref: ["network.trr.mode", "DNS через HTTPS"],
			userChoice: 2, userAlt: 0, refresh: true,
			values: [
				[0, "Выключен", "0"], [2, "TRR + мой", "2"], [3, "только TRR", "3"]
	]},null,{
			pref: ["permissions.default.image", "Загрузка изображений"],
			userChoice: 1, userAlt: 3, refresh: true,
			values: [[1, "Разрешена"], [3, "Только с сайта"], [2, "Отключить"]]
	},{
			pref: ["image.animation_mode", "Анимация изображений"],
			userChoice: "none", refresh: true,
			values: [["none", "Выключена"], ["normal", "По циклу"], ["once", "Единожды"]]
	},{
			pref: ["browser.display.document_color_use", "Использовать цвета сайтов"],
			userChoice: 0,
			values: [[0, "Авто", "0"], [1, "Всегда", "1"], [2, "Никогда", "2"]]
	},{
			pref: ["browser.display.use_document_fonts", "Загружать web-шрифты"],
			userChoice: 1, refresh: true,
			values: [[1, "Да"], [0, "Нет"]]
	},null,{
			pref: ["media.autoplay.default", "Авто-play аудио/видео"],
			userChoice: 5, refresh: true,
			values: [
				[0, "Разрешить", "0"],
				[1, "Запретить", "1"],
				[2, "Спрашивать", "2"],
				[5, "Блокировать", "5"]
	]},{
			pref: ["media.autoplay.blocking_policy", "Автозапуск (политика)"],
			userChoice: 1, userAlt: 2, refresh: true,
			values: [
				[1, "Временная", "1"],
				[2, "По действию", "2"],
				[0, "Постоянная", "0"]
	]},{
			pref: ["plugin.state.flash", "Flash-plugin"],
			userChoice: 2, refresh: true,
			values: [
				[2, "Всегда включать", "2"],
				[1, "Включать по запросу", "1"],
				[0, "Никогда не включать", "0"]
	]},{
			pref: ["gfx.webrender.all", "WebRender для всего"],
			userChoice: false, refresh: true,
			values: [[true, "Да"], [false, "Нет"]]
	},null,{
			pref: ["javascript.enabled", "Выполнять скрипты Java"],
			userChoice: true, refresh: true,
			values: [[true, "Да"], [false, "Нет"]]
	},{
			pref: ["network.cookie.cookieBehavior", "Cookies"],
			userChoice: 1, userAlt: 3, refresh: false,
			values: [
				[1, "Не принимать сторонние"], [3, "Не принимать с не посещенных"], [4, "Не принимать от трекеров"],
				[2, "Не принимать со всех"], [0, "Принимать со всех"]
	]},{
			pref: ["dom.enable_performance", "Статус загрузки страницы"],
			userChoice: false
	},{
			pref: ["dom.storage.enabled", "Локальное хранилище"],
			userChoice: true
	},{
			pref: ["network.http.sendRefererHeader", "Referer - для чего"],
			userChoice: 1,
			values: [[0, "Ни для чего", "0"], [1, "Только ссылки", "1"], [2, "Ссылки и изобр.", "2"]]
	},{
			pref: ["media.peerconnection.enabled", "WebRTC утечка IP"],
			userChoice: false
	},{
			pref: ["general.useragent.override", "User Agent"],
			userChoice: true, refresh: true,
			values: [
				[useragent, "По-умолчанию", "", "", `Services.prefs.setStringPref('general.useragent.override', '')`],
				["Mozilla/5.0 (Windows NT 6.1; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0", "Firefox 56"],
				["Mozilla/5.0 (X11; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0", "Firefox 56 Linux"],
				["Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:68.0) Gecko/20100101 Firefox/68.0", "Firefox 68 MacOSX"],
				["Mozilla/5.0 (Windows; U; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)", "MSIE 6.0 Windows"],
				["Mozilla/5.0 (Linux; Android 7.0; PLUS Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", "Chrome61 Android7"],
				["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.1 Safari/603.1.30", "Safari 6 MacOSX"],
				["Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12 Version/12.16", "Opera12 W8"],
				["Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", "Chrome57 W7"],
				["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", "Chrome61 W10"],
				["Mozilla/5.0 (Linux; Android 5.1.1; SM-G928X Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.83 Mobile Safari/537.36", "Samsung Galaxy S6"],
				["Mozilla/5.0 (PlayStation 4 3.11) AppleWebKit/537.73 (KHTML, like Gecko)", "Playstation 4"],
				["Xbox (Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586", "Xbox One (mobile)"],
				["Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586", "Microsoft Lumia 950"],
				["Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; GT-I8350)", "Windows Phone"],
				["Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", "GoogleBot"]
	]}
	];

	return {
		label: "Quick Toggle Settings",
		id: "QuickToggleAboutConfigSettings",
		tooltiptext:
`Quick Toggle Settings

ЛКМ	Боковая панель: Журнал
ПКМ	Меню основных настроек
Long	Антизапрет proxy`,
		localized: false,
		image: "data:image/png;base64,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",
		onCreated(btn) {
			btn.setAttribute("image", this.image);
			var doc = btn.ownerDocument;

			btn.btn = true;
			btn.domParent = null;
			btn.popups = new btn.ownerGlobal.Array();
			this.createPopup(doc, btn, "secondary", secondary);
			this.createCloseMenusOption(doc, btn);

			if (Services.prefs.getIntPref('network.proxy.type') == 2)
				btn.style.filter = icon_vpn; // btn.style.cssText = "background-image: -moz-linear-gradient(#c0c8c0, #c0c8c0, #c0c8c0) !important";

			btn.linkedObject = this;
			for(var type of ["command", "contextmenu", "mousedown", "auxclick"])
				btn.setAttribute("on" + type, `linkedObject.${type}(event)`);

		},
		createPopup(doc, btn, name, data) {
			var popup = doc.createElementNS(xul_ns, "menupopup");
			var prop = name + "Popup";
			btn.popups.push(btn[prop] = popup);
			popup.id = this.id + "-" + prop;
			for (var type of ["popupshowing", "click"])
				popup.setAttribute("on" + type, `parentNode.linkedObject.${type}(event)`);
			for(var obj of data) popup.append(this.createElement(doc, obj));
			btn.append(popup);
		},
		map: {b: "Bool", n: "Int", s: "String"},
		createElement(doc, obj) {
			if (!obj) return doc.createElementNS(xul_ns, "menuseparator");
			var pref = doc.ownerGlobal.Object.create(null), node, img, bool;
			for(var [key, val] of Object.entries(obj)) {
				if (key == "pref") {
					var [apref, lab, akey, ttt] = val;
					pref.pref = apref; pref.lab = lab || apref;
					if (ttt) pref.ttt = ttt;
				}
				else if (key == "image") img = val, pref.img = true;
				else if (key != "values") pref[key] = val;
				else pref.hasVals = true;
			}
			var type = prefs.getPrefType(pref.pref);
			var str = this.map[type == prefs.PREF_INVALID
				? obj.values ? (typeof obj.values[0][0])[0] : "b"
				: type == prefs.PREF_BOOL ? "b" : type == prefs.PREF_INT ? "n" : "s"
			];
			pref.get = prefs[`get${str}Pref`];
			var map, set = prefs[`set${str}Pref`];
			if (pref.hasVals) {
				for(var [val, , , , code] of obj.values)
					code && (map || (map = new Map())).set(val, code);
				if (map) pref.set = (key, val) => {
					set(key, val);
					map.has(val) && eval(map.get(val)); // выполнить код
				}
			}
			if (!map) pref.set = set;

			node = doc.createElementNS(xul_ns, "menu");
			node.className = "menu-iconic";
			node.setAttribute("closemenu", "none");
			img && node.setAttribute("image", img);
			akey && node.setAttribute("accesskey", akey);
			(node.pref = pref).vals = doc.ownerGlobal.Object.create(null);
			this.createRadios(doc,
				str.startsWith("B") && !pref.hasVals ? [[true, "true"], [false, "false"]] : obj.values,
				node.appendChild(doc.createElementNS(xul_ns, "menupopup"))
			);
			if ("userChoice" in obj) pref.noAlt = !("userAlt" in obj);
			return node;
		},
		createCloseMenusOption(doc, btn) {
			var pn = this.closePref = "QuickToggleAboutConfigSettings.closeMenus";
			var data = [null, {
				pref: [pn, "Закрывать меню этой кнопки"], values: [[true, "Да"], [false, "Нет"]]
			}];
			var setCloseMenus = e => {
				e.stopPropagation();
				var trg = e.target, {pref, val} = trg, updPopup = true, clear;
				switch(e.type) {
					case "command": pref = (trg = trg.closest("menu")).pref; updPopup = false; break;
					case "click": if (e.button) return; break;
					case "contextmenu": e.preventDefault(); clear = pref;
				}
				if (!pref) return;
				if (clear) prefs.clearUserPref(pn);
				else if (!updPopup && val === pref.val) return;
				else pref.set(pn, val !== undefined ? val : !pref.val);
				this.upd(trg);
				updPopup && this.popupshowing(null, trg.querySelector("menupopup"));
			}
			(this.createCloseMenusOption = (doc, btn) => {
				for(var obj of data)
					btn.secondaryPopup.append(this.createElement(doc, obj));
				var m = btn.secondaryPopup.lastChild;
				m.style.cssText = "fill: lightblue !important; list-style-image: url(chrome://browser/skin/menu.svg) !important;";
				m.setAttribute("oncommand", "setCloseMenus(event)");
				m.onclick = m.oncontextmenu = m.setCloseMenus = setCloseMenus;
			})(doc, btn);
		},
		UserChoiceImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACRUlEQVR42qWTS2gTQRjH/zPJZo2BDfgkB62vYg5CjQdvRUE8WB8HKyahYotIQQOeFKGCF7EgvQlBqOCjWFKlevBRDyL4uHloLXhYqWJroaEqlETSptndGb+ZPDH0ojN8O8vA98vv+/Itw38u1nSRYRE6UhKyg4FF1R292/Q+xhhLi4TIrgjgIzwe4MbgmR2nrZMtxxEN63zYORuPZp7gzpehvCu9XjfuPmwCUHIiEtw4fK89zVvD2+FHAD56quXBpV3CVO4ret6nxHzxZxdBRuqADCKmz7RHD9y2tlmbYbBVfwE8DXBkEd/y39H5+mze8ZyoSIpsFXC9u/VE3/ldpyg5AAMEoJMTQi2hANKBgyKdy0h/eoChqcf9MimvVAHjd/fdiG0NRwgQpDAp1agBpDZwdHKJLKZzc+h5e3kCSexh5c5j8fmhW0HGpNZXFkqfsQpAKgcFKGmAlAxHXp5bkkmsrhosjh4cCIJ5pG5qfQXgtMslqO1qgEMWTPrR+eriEhoA4wN7L8TWh0KVXzfgY2RQAUjVBenWLH4UCrj04Wa9BNXEo5va+w63xCiJ6WRVP2MVgNQIgjgEA17MTODZ7Lt+AtSaGDG4377a1m2FAkKrc11/dUwIID1dSKHEcW3yft4RbpR6kK1PYgaJtaY1nNp5jIeMsjKNbs1AWRUcjvTnp2Kh9LtLJGTDINUhcTIZ3L+hzdq9ZgvWmSF9/Wu5gI8L03gzP5l3hddL/3/zKDdA9MdE0UERrdzaFGMUaap75Y/pX9Yfap76EQYaCeEAAAAASUVORK5CYII=",
		notUserChoiceImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACNUlEQVR42qXTT2jTUBwH8G9e0ta2ks5ND0Ww/qX1oGyevEwQnOBA6EHXwLwoUh3eRGRs501RPE6xgp6KrexQECZY8DBPXmbRS4Z/K0gRtmmDa2yb5PlLX7p2Gwpi4EfCy8sn3/dPwn9e0saGnCRF6XYFnA9DkhKtRs51ep6jmtEcp/JHIM9Yivl9mf0XNDV2Ngn1YLzVxdB1lJ8U8P5hzuCWnR6xrPwmIM8kLRjdkT326BaLHNgLKAFA9ouXdhOw6qi++4j589cd89vSaMqyc2sAPUXlgF8fyt9WI3t2Av4w4NsCMJ8AHAKav6hqqH76iuLINcNuNhOawyttYCp+7tRE/6XT9GFQAG4CpniATQkIaNQIMVG6/xSL2WfTGueTbWDh5L2rA9t29QGBrQQEPUDuAuoEmFSr+P5lGc8v33mtAUfaQO3M4/GgDOoYCIkUin8D0BDDoBQ2ZMxqN0wCQh0gMxaUnYb4uzt+dwIZ8wBHTGQbYAHMpu+uAxaGxpMDvSr3AHcFaAIlD+BtoN6ag5WqhOLNwrohTMWPH5roP7pdLIwb3wW6EziWGAZhpVdLWHzxdpqAyc4yKrJ+4uKg2oMV+lgRK9CdwAVsG1WpF8UH84Zt2QkCKmsbiRAtFAllB5OHWQ9fpr81OwlcgBL9kPrwsvDGMQ1zNMV5ZyN1ISlZYZl9/TE1tjuMSFgA1VWO8uef+FAqG47tpFMcm7dyFyIOEzBMlfCadao5qhk39l9P479evwFbiOcRSXKueAAAAABJRU5ErkJggg==",
		UserAltImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVDhPpVM9b9NQFD02cSKKFVGKIFFREFsmFiCA1AEQQrQjC0gssLCkC0jJj0iFWFoGdiT4Ay0SEmJBhPI5FBokikL4SCC0Te2UxInt13Mdu1CVrVc6713fe86x/T6w09DCeTNKJ7Q0pzyUmoCmZYOiUhXms8RMcd6vB7UwthhM5fTLWix2L3PmYjKdOwdz9DDFGtr1KuovnqD29JGlfO9Goew9DCV/DaZy2pXE8PD9Y/mbupk6xE6cVWPQhEujHo2+4fXdO76ztnq1UPYfSCcwKB1HWjeMyunCraSZOsDqbkBPsBOTNoMGvkOTLto/f+F56bble262OK/qesiYzIydTJojFLjrgEe4bcIOEdXWYe6LITN2KgmFSRFGBuPpo0eAngX0SexTJHD5LOgLpEZTcgKuUuMijAyy5l7+r0NSb21g5LQI5gGYSy2AjYBLjQyRAUniTnJXsBoayBzm3RBBndwwIoOK3fgNdIREQYCV/0DqLdiNZqCRITKYayx85RfQuUNiZ3k7IgO+vfGeXGpkiAyma++WLHtZhZ8o5H/FEVpos1V7u8TFwLQId8nw+Afa51Oq2vyycmlk9KCW0GXFZeu63IUO8z88Bx5s28SbuUXfddzrxVcobxpI0GTh7H734/dPzQt9d0/CGBpCPB7nbhmwbAPVxR4+PPtsuU7/WuElth/lKORUcsoTE8TgMg0WbJaY4Zu3XKYdBrABARUk+ls4DfQAAAAASUVORK5CYII=",
		upd(node) {
			var {pref} = node, def = false, user = false, val;
			if (prefs.getPrefType(pref.pref) != prefs.PREF_INVALID) {
				var pn = pref.pref;
				try {val = pref.defVal = db[pref.get.name](pn); def = true}
				catch(ex) {def = false;}
				var user = prefs.prefHasUserValue(pn);
				if (user) try {val = pref.get(pn, undefined);} catch(ex) {}
			}
			if (val == pref.val && def == pref.def && user == pref.user) return;
			pref.val = val; pref.def = def; pref.user = user;
			var exists = def || user;

			var ttt = exists ? val : "Этого префа не существует";
			if (ttt === "") ttt = "[ empty_string ]";
			ttt += "\n" + pref.pref;
			if (pref.ttt) ttt += "\n" + pref.ttt;
			node.tooltipText = ttt;

			var img, alt = "userAlt" in pref && val == pref.userAlt;
			if (alt) img = this.UserAltImg;
			if ("userChoice" in pref)
				if (val == pref.userChoice)
					//node.style.removeProperty("color"),
					img = this.UserChoiceImg;
				else {
					//node.style.setProperty("color", "maroon", "important");
					if (!alt) img = this.notUserChoiceImg;
				}
			if (!pref.img) img
				? node.setAttribute("image", img)
				: node.removeAttribute("image");
			user
				? node.style.setProperty("font-style", "italic", "important")
				: node.style.removeProperty("font-style");

			var {lab} = pref;
			if (exists && pref.hasVals) {
				if (val in pref.vals) var sfx = pref.vals[val] || val;
				else var sfx = user ? "Другое" : "По умолчанию";
				lab += ` — "${sfx}"`;
			}
			node.setAttribute("label", lab);
		},
		createRadios(doc, vals, popup) {
			for(var arr of vals) {
				if (!arr) {
					popup.append(doc.createElementNS(xul_ns, "menuseparator"));
					continue;
				}
				var [val, lab, key, ttt] = arr;
				var menuitem = doc.createElementNS(xul_ns, "menuitem");
				menuitem.setAttribute("type", "radio");
				menuitem.setAttribute("closemenu", "none");
				menuitem.style.setProperty("font-style", "italic", "important"),
				menuitem.setAttribute("label", popup.parentNode.pref.vals[val] = lab);
				key && menuitem.setAttribute("accesskey", key);
				var tip = menuitem.val = val;
				if (ttt) tip += "\n" + ttt;
				menuitem.tooltipText = tip;
				popup.append(menuitem);
			}
		},
		openPopup(popup) {
			var btn = popup.parentNode;
			if (btn.domParent != btn.parentNode) {
				btn.domParent = btn.parentNode;
				var pos;
				if (btn.matches(".widget-overflow-list > :scope"))
					pos = "after_start";
				else var win = btn.ownerGlobal, {width, height, top, bottom, left, right} =
					btn.closest("toolbar").getBoundingClientRect(), pos = width > height
						? `${win.innerHeight - bottom > top ? "after" : "before"}_start`
						: `${win.innerWidth - right > left ? "end" : "start"}_before`;
				for(var p of btn.popups) p.setAttribute("position", pos);
			}
			popup.openPopup(btn);
		},
		maybeRestart(node, conf) {
			var msgRest = "Перезапустить браузер?", msgAbort = "Запрос на выход отменен.";
			if (pv >= 77) {
				var title = node.closest("toolbarbutton").label;
				var pp = domWin => Services.prompt.wrappedJSObject.pickPrompter({
					domWin, modalType: Ci.nsIPrompt.MODAL_TYPE_WINDOW
				});
				var confirm = win => pp(win).confirm(title, msgRest);
				var alert = win => pp(win).alert(title, msgAbort);
			} else {
				var confirm = win => win.confirm(msgRest);
				var alert = win => win.alert(msgAbort);
			}
			return (this.mayBeRestart = (node, conf) => {
				var win = node.ownerGlobal;
				if (conf && !confirm(win)) return;
				if (win.BrowserUtils.restartApplication() === false) alert(win);
				else return true;
			})(node, conf);
		},
		regexpRefresh: /^(?:view-source:)?(?:https?|ftp)/,
		maybeRe(node, fe) {
			var {pref} = node;
			if ("restart" in pref) {
				if (this.maybeRestart(node, pref.restart)) return;
			}
			else this.popupshowing(fe, node.parentNode);
			if ("refresh" in pref) {
				var win = node.ownerGlobal;
				if (this.regexpRefresh.test(win.gBrowser.currentURI.spec)) pref.refresh
					? win.BrowserReloadSkipCache() : win.BrowserReload();
			}
		},
		maybeClosePopup(e, trg) {
			!e.ctrlKey && prefs.getBoolPref(this.closePref, undefined)
				&& trg.parentNode.hidePopup();
		},
		command(e) {
			var trg = e.target; 			// if (trg.btn) return this.openPopup(trg.primaryPopup);
			if (trg.btn) {
				var doc = e.target.ownerDocument; // Переключить боковую панель
				var win = doc.defaultView;
				var bar = doc.querySelector("#add-additional-vertical-bar");
				if (bar)
					win.setToolbarVisibility(bar, bar.collapsed);
				bar.collapsed ? win.SidebarUI.hide('viewHistorySidebar') : win.SidebarUI.show('viewHistorySidebar');
				return;
			}
			var menu = trg.closest("menu"), newVal = trg.val;
			this.maybeClosePopup(e, menu);
			if (newVal != menu.pref.val)
				menu.pref.set(menu.pref.pref, newVal),
				this.maybeRe(menu, true);
		},
		popupshowing(e, trg = e.target) {
			if (trg.state == "closed") return;
			if (trg.id) {
				for(var node of trg.children) {
					if (node.nodeName.endsWith("r")) continue;
					this.upd(node);
					!e && node.open && this.popupshowing(null, node.querySelector("menupopup"));
				}
				return;
			}
			var {pref} = trg.closest("menu"), findChecked = true;

			var findDef = "defVal" in pref;
			var checked = trg.querySelector("[checked]");
			if (checked) {
				if (checked.val == pref.val) {
					if (findDef) findChecked = false;
					else return;
				}
				else checked.removeAttribute("checked");
			}
			if (findDef) {
				var def = trg.querySelector("menuitem:not([style*=font-style]");
				if (def)
					if (def.val == pref.defVal) {
						if (findChecked) findDef = false;
						else return;
					}
					else def.style.setProperty("font-style", "italic", "important");
			}
			for(var node of trg.children) if ("val" in node) {
				if (findChecked && node.val == pref.val) {
					node.setAttribute("checked", true);
					if (findDef) findChecked = false;
					else break;
				}
				if (findDef && node.val == pref.defVal) {
					node.style.removeProperty("font-style");
					if (findChecked) findDef = false;
					else break;
				}
			}
		},
		contextmenu(e) {
			var trg = e.target;
			if (trg.btn) {
				if (e.ctrlKey || e.shiftKey) return;
				if (e.detail == 2) return trg.secondaryPopup.hidePopup();
				this.openPopup(trg.secondaryPopup);
			}
			else if ("pref" in trg) {
				this.maybeClosePopup(e, trg);
				if (trg.pref.user)
					prefs.clearUserPref(trg.pref.pref),
					this.maybeRe(trg);
			}
			e.preventDefault();
		},
		click(e) {
			if (e.button) return;
			var trg = e.target, {pref} = trg;
			if (!pref) return;
		},
		auxclick(e) {
			if (e.button != 1 || !e.target.btn) return;
			e.view.alert("MMB");
			// PlacesCommandHook.showPlacesOrganizer('BookmarksToolbar');
		},
		mousedown(e) {
			var reset = e => e.target.linkedObject = this;
			var id, lo = {command: reset, mousedown: reset};

			var lin = /macos|linux/.test(e.view.AppConstants.platform);
			var stop = e => reset(e) && e.preventDefault();

			lo.contextmenu = lin
				? e => e.ctrlKey || e.shiftKey ? dsp(e) : stop(e) : stop;
			var context = lin
				? e => e.button == 2 && e.type.endsWith("p") && this.contextmenu(e) : () => {};

			var dsp = (e, timeout) => {
				var trg = e.target;
				trg.onmouseup = trg.onmouseleave = null;
				if (timeout) return this.londPress(e);
				e.view.clearTimeout(id);
				reset(e);
				context(e);
			}
			(this.mousedown = e => {
				var trg = e.target;
				if (!trg.btn) return;
				trg.linkedObject = lo;
				trg.onmouseup = trg.onmouseleave = dsp;
				id = e.view.setTimeout(dsp, 500, e, true);
			})(e);
		},
		londPress(e) { // удержание кнопки мыши, выбирать команды, отводящие мышь от кнопки
			var msg = "QuickSettings\nLONG PRESS: e.button = " + e.button;
			// Components.utils.reportError(msg);
			// StatusPanel._label = 'text'; setTimeout(()=> StatusPanel._label = '',3000);
			// e.view.alert(msg);
			Antizapret(e.target);
		}
	};
}); // END код кнопки

На форуме

 

№1539104-04-2021 12:47:28

Stkvsky
Участник
 
Группа: Members
Зарегистрирован: 26-06-2012
Сообщений: 1700
UA: Firefox 68.0

Re: Custom Buttons

Dumby
Класс, спасибо огромное

Отсутствует

 

№1539204-04-2021 13:07:05

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

Re: Custom Buttons

Dobrov пишет

параметр не меняется, почему-то тип general.useragent.override всегда логический, а не строковый…

Не вижу такого.


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

Отсутствует

 

№1539304-04-2021 15:49:46

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 332
UA: Firefox 87.0

Re: Custom Buttons

Dumby
Посмотрите как спец https://forum.mozilla-russia.org/viewto … 32#p789732
А то там тишина...

Отсутствует

 

№1539404-04-2021 17:25:12

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 395
UA: Firefox 84.0

Re: Custom Buttons

Dumby - Да, после удаления-перезапуска ЮзерАгент меняется.
А как сделать, чтобы строка меню стала зелёной, если "преф не существует"?

Выделить код

Код:

pref: ["general.useragent.override", "User Agent"], userChoice: true, refresh: true,
	values: [
	[useragent, "По-умолчанию", "", "", `Services.prefs.setStringPref('general.useragent.override', '')`],
	["Mozilla/5.0 (Windows NT 6.1; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0", "Firefox 56"],………

Второй вопрос: как выполнить команду меню: "Показать все закладки"
PlacesCommandHook.showPlacesOrganizer('BookmarksToolbar') // это не работает…

На форуме

 

№1539504-04-2021 21:39:34

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

Re: Custom Buttons

ВВП пишет

А то там тишина...

Тоже особо сказать нечего.
Для многострочности вкладок мне известен только этот проект.
Ещё Tab Mix Plus, но там (пока?) не готово.


Dobrov пишет

А как сделать, чтобы строка меню стала зелёной, если "преф не существует"?

Можно в upd() дописать, если цвет внешним стилем не приколочен
(без if (...) если не только для этой настройки, а для всех)

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

Выделить код

Код:

...
			if (pref.pref == "general.useragent.override") exists
				? node.style.removeProperty("color")
				: node.style.setProperty("color", "green", "important");

Dobrov пишет

Второй вопрос: как выполнить команду меню: "Показать все закладки"
PlacesCommandHook.showPlacesOrganizer('BookmarksToolbar') // это не работает…

Работает. И в 84.0.2, и в 89.0a1
А команда пункта меню "Показать все закладки" запускает
PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');

Отсутствует

 

№1539605-04-2021 01:56:49

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 395
UA: Firefox 84.0

Re: Custom Buttons

Dumby - спасибо, сделал имя меню в скобках, если преф сброшен.
Есть баг: если изменить цвет текста меню, то он не меняется при наведении мыши и плохо различим.
Как вернуть "белый" цвет для строк, подсвеченых курсором?

Выделить код

Код:

if ("userChoice" in pref)
	if (val == pref.userChoice)
		node.style.removeProperty("color"),
		img = this.UserChoiceImg;
	else {
		node.style.setProperty("color", "maroon", "important");
		if (!alt) img = this.notUserChoiceImg;……

FF-QT.jpg


2) У меня команда открытия "Библиотеки" не работает, ничего не происходит…
log: Uncaught ReferenceError: PlacesCommandHook is not defined Windows x86, Firefox 84.0.2

Выделить код

Код:

auxclick(e) {
	if (e.button != 1 || !e.target.btn) return;
	e.view.alert("MMB"); // эта строка работает нормально
	PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks'); // эта строка ничего не открывает

3) И всё таки, как выбрать "галочкой" пункт под-меню «По-умолчанию», если преф не существует? (хотя-бы в под-меню выбора ЮзерАгента)

Выделить код

Код:

pref: ["general.useragent.override", "User Agent"],
			userChoice: true, refresh: true,
			values: [
				[useragent, "По-умолчанию", "", "", `Services.prefs.setStringPref('general.useragent.override', '')`],……

Весь код кнопки:

Выделить код

Код:

// Quick Toggle https://forum.mozilla-russia.org/viewtopic.php?pid=784139#p784139
// https://forum.mozilla-russia.org/viewtopic.php?pid=784165#p784165
// Быстрое переключение параметров about:config
// Ctrl+Click или правый клик - сброс параметра по-умолчанию
// стиль иконки: #QuickToggleAboutConfigSettings .toolbarbutton-icon{ padding: 2px !important;}

(async (name, id, func) => {
	if (name == "Object") return CustomizableUI.createWidget(func());
	var win = name == "Window", g = Components.utils.import("resource://gre/modules/Services.jsm", {});
	if (g[id]) {if (win) return;} else g[id] = func();
	if (win) return CustomizableUI.createWidget(g[id]);
	addDestructor(r => r[5] == "e" && delete g[id]);
	g[id].onCreated(this);
})(this.constructor.name, "QuickToggleAboutConfigSettings", () => { // BEGIN (this.constructor… {код кнопки});

	var {prefs} = Services, db = prefs.getDefaultBranch("");
	var pv = parseInt(Services.appinfo.platformVersion);
	var xul_ns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
	var icon_vpn = "hue-rotate(270deg) brightness(95%)";
	function Notify(title, text, time){ Components.classes['@mozilla.org/alerts-service;1'].getService(Components.interfaces.nsIAlertsService).showAlertNotification(null, title, text, false, '', null, time);
	}
	function Antizapret(trg){
		if (Services.prefs.getIntPref('network.proxy.type') == 2) { // выключить
			Services.prefs.setIntPref('network.proxy.type', 0);
			Services.prefs.setStringPref("network.proxy.autoconfig_url", "127.0.0.1");
			trg.style.filter = '';
			Notify('Proxy', 'Режим по-умолчанию отключен', 2000);
		} else {
			Services.prefs.setIntPref('network.proxy.type', 2);
			Services.prefs.setStringPref("network.proxy.autoconfig_url", "https://antizapret.prostovpn.org/proxy.pac");
			trg.style.filter = icon_vpn;
			Notify('Proxy', 'Работаем через VPN Антизапрет', 2000);
		}
	}
	var useragent = Components.classes["@mozilla.org/network/protocol;1?name=http"].getService(Components.interfaces.nsIHttpProtocolHandler).userAgent; // текущий юзерагент

//=====================================================================================

	// refresh:
	//	false - reload current tab
	//	true - reload current tab skip cache
	//
	// restart:
	//	false - restart browser
	//	true - restart browser with confirm

//=====================================================================================

	var secondary = [{

			pref: ["network.proxy.autoconfig_url", "Прокси (VPN) URL"],
			userChoice: 0, userAlt: 1, refresh: true,
			values: [
				["127.0.0.1", "отключен…", "0", "", `Services.prefs.setIntPref('network.proxy.type', 0); node.parentNode.parentNode.style.filter = '';`],
				["https://antizapret.prostovpn.org/proxy.pac", "АнтиЗапрет", "1", "Надёжный доступ на заблокированные сайты\n\n«Режим прокси» меняется на 2", `Services.prefs.setIntPref('network.proxy.type', 2); node.parentNode.parentNode.style.filter = icon_vpn;`],
				[prefs.getStringPref("user.pacfile", "file:///etc/proxy.pac"), "user .pac файл", "2"],
				["https://git.io/ac-anticensority-pac", "ac-anticensority", "3"],
				["localhost", "Tor Browser", "4"]
	]},{
			pref: ["network.proxy.type", "Режим прокси"],
			userChoice: 0, userAlt: 2, refresh: true,
			values: [
				[0, "Без прокси", "0", "по-умолчанию"],
				[5, "Системные (из IE)", "5"],
				[2, "Автонастройка", "2", "about:config — user.pacfile"],
				[1, "Ручная настройка", "1", "вторая строка"],
				[4, "Автоопределение", "4"]
	]},{
			pref: ["network.proxy.share_proxy_settings", "Прокси для всех протоколов"],
			userChoice: true, refresh: true,
			values: [[true, "Да", "", "Прокси для всех протоколов при ручной настройке"], [false, "Нет"]]
	},{
			pref: ["network.trr.mode", "DNS через HTTPS"],
			userChoice: 2, userAlt: 0, refresh: true,
			values: [
				[0, "Выключен", "0"], [2, "TRR + мой", "2"], [3, "только TRR", "3"]
	]},null,{
			pref: ["permissions.default.image", "Загрузка изображений"],
			userChoice: 1, userAlt: 3, refresh: true,
			values: [[1, "Разрешена"], [3, "Только с сайта"], [2, "Отключить"]]
	},{
			pref: ["image.animation_mode", "Анимация изображений"],
			userChoice: "none", refresh: true,
			values: [["none", "Выключена"], ["normal", "По циклу"], ["once", "Единожды"]]
	},{
			pref: ["browser.display.document_color_use", "Использовать цвета сайтов"],
			userChoice: 0,
			values: [[0, "Авто", "0"], [1, "Всегда", "1"], [2, "Никогда", "2"]]
	},{
			pref: ["browser.display.use_document_fonts", "Загружать web-шрифты"],
			userChoice: 1, refresh: true,
			values: [[1, "Да"], [0, "Нет"]]
	},null,{
			pref: ["media.autoplay.default", "Авто-play аудио/видео"],
			userChoice: 5, refresh: true,
			values: [
				[0, "Разрешить", "0"],
				[1, "Запретить", "1"],
				[2, "Спрашивать", "2"],
				[5, "Блокировать", "5"]
	]},{
			pref: ["media.autoplay.blocking_policy", "Автозапуск (политика)"],
			userChoice: 1, userAlt: 2, refresh: true,
			values: [
				[1, "Временная", "1"],
				[2, "По действию", "2"],
				[0, "Постоянная", "0"]
	]},{
			pref: ["plugin.state.flash", "Flash-plugin"],
			userChoice: 2, refresh: true,
			values: [
				[2, "Всегда включать", "2"],
				[1, "Включать по запросу", "1"],
				[0, "Никогда не включать", "0"]
	]},{
			pref: ["gfx.webrender.all", "WebRender для всего"],
			userChoice: false, refresh: true,
			values: [[true, "Да"], [false, "Нет"]]
	},null,{
			pref: ["javascript.enabled", "Выполнять скрипты Java"],
			userChoice: true, refresh: true,
			values: [[true, "Да"], [false, "Нет"]]
	},{
			pref: ["network.cookie.cookieBehavior", "Cookies"],
			userChoice: 1, userAlt: 3, refresh: false,
			values: [
				[1, "Не принимать сторонние"], [3, "Не принимать с не посещенных"], [4, "Не принимать от трекеров"],
				[2, "Не принимать со всех"], [0, "Принимать со всех"]
	]},{
			pref: ["dom.enable_performance", "Статус загрузки страницы"],
			userChoice: false
	},{
			pref: ["dom.storage.enabled", "Локальное хранилище"],
			userChoice: true
	},{
			pref: ["network.http.sendRefererHeader", "Referer - для чего"],
			userChoice: 1,
			values: [[0, "Ни для чего", "0"], [1, "Только ссылки", "1"], [2, "Ссылки и изобр.", "2"]]
	},{
			pref: ["media.peerconnection.enabled", "WebRTC утечка IP"],
			userChoice: false
	},{
			pref: ["general.useragent.override", "User Agent"],
			userChoice: true, refresh: true,
			values: [
				[useragent, "По-умолчанию", "", "", `Services.prefs.setStringPref('general.useragent.override', '')`],
				["Mozilla/5.0 (Windows NT 6.1; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0", "Firefox 56"],
				["Mozilla/5.0 (X11; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0", "Firefox 56 Linux"],
				["Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:68.0) Gecko/20100101 Firefox/68.0", "Firefox 68 MacOSX"],
				["Mozilla/5.0 (Windows; U; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)", "MSIE 6.0 Windows"],
				["Mozilla/5.0 (Linux; Android 7.0; PLUS Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", "Chrome61 Android7"],
				["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.1 Safari/603.1.30", "Safari 6 MacOSX"],
				["Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12 Version/12.16", "Opera12 W8"],
				["Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", "Chrome57 W7"],
				["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", "Chrome61 W10"],
				["Mozilla/5.0 (Linux; Android 5.1.1; SM-G928X Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.83 Mobile Safari/537.36", "Samsung Galaxy S6"],
				["Mozilla/5.0 (PlayStation 4 3.11) AppleWebKit/537.73 (KHTML, like Gecko)", "Playstation 4"],
				["Xbox (Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586", "Xbox One (mobile)"],
				["Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586", "Microsoft Lumia 950"],
				["Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; GT-I8350)", "Windows Phone"],
				["Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", "GoogleBot"]
	]}
	];

	return {
		label: "Quick Toggle Settings",
		id: "QuickToggleAboutConfigSettings",
		tooltiptext:
`Quick Toggle Settings

ЛКМ	Боковая панель: Журнал
ПКМ	Меню основных настроек
Long	Антизапрет proxy`,
		localized: false,
		image: "data:image/png;base64,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",
		onCreated(btn) {
			btn.setAttribute("image", this.image);
			var doc = btn.ownerDocument;

			btn.btn = true;
			btn.domParent = null;
			btn.popups = new btn.ownerGlobal.Array();
			this.createPopup(doc, btn, "secondary", secondary);
			this.createCloseMenusOption(doc, btn);

			if (Services.prefs.getIntPref('network.proxy.type') == 2)
				btn.style.filter = icon_vpn; // btn.style.cssText = "background-image: -moz-linear-gradient(#c0c8c0, #c0c8c0, #c0c8c0) !important";

			btn.linkedObject = this;
			for(var type of ["command", "contextmenu", "mousedown", "auxclick"])
				btn.setAttribute("on" + type, `linkedObject.${type}(event)`);

		},
		createPopup(doc, btn, name, data) {
			var popup = doc.createElementNS(xul_ns, "menupopup");
			var prop = name + "Popup";
			btn.popups.push(btn[prop] = popup);
			popup.id = this.id + "-" + prop;
			for (var type of ["popupshowing", "click"])
				popup.setAttribute("on" + type, `parentNode.linkedObject.${type}(event)`);
			for(var obj of data) popup.append(this.createElement(doc, obj));
			btn.append(popup);
		},
		map: {b: "Bool", n: "Int", s: "String"},
		createElement(doc, obj) {
			if (!obj) return doc.createElementNS(xul_ns, "menuseparator");
			var pref = doc.ownerGlobal.Object.create(null), node, img, bool;
			for(var [key, val] of Object.entries(obj)) {
				if (key == "pref") {
					var [apref, lab, akey, ttt] = val;
					pref.pref = apref; pref.lab = lab || apref;
					if (ttt) pref.ttt = ttt;
				}
				else if (key == "image") img = val, pref.img = true;
				else if (key != "values") pref[key] = val;
				else pref.hasVals = true;
			}
			var type = prefs.getPrefType(pref.pref);
			var str = this.map[type == prefs.PREF_INVALID
				? obj.values ? (typeof obj.values[0][0])[0] : "b"
				: type == prefs.PREF_BOOL ? "b" : type == prefs.PREF_INT ? "n" : "s"
			];
			pref.get = prefs[`get${str}Pref`];
			var map, set = prefs[`set${str}Pref`];
			if (pref.hasVals) {
				for(var [val, , , , code] of obj.values)
					code && (map || (map = new Map())).set(val, code);
				if (map) pref.set = (key, val) => {
					set(key, val);
					map.has(val) && eval(map.get(val)); // выполнить код
				}
			}
			if (!map) pref.set = set;

			node = doc.createElementNS(xul_ns, "menu");
			node.className = "menu-iconic";
			node.setAttribute("closemenu", "none");
			img && node.setAttribute("image", img);
			akey && node.setAttribute("accesskey", akey);
			(node.pref = pref).vals = doc.ownerGlobal.Object.create(null);
			this.createRadios(doc,
				str.startsWith("B") && !pref.hasVals ? [[true, "true"], [false, "false"]] : obj.values,
				node.appendChild(doc.createElementNS(xul_ns, "menupopup"))
			);
			if ("userChoice" in obj) pref.noAlt = !("userAlt" in obj);
			return node;
		},
		createCloseMenusOption(doc, btn) {
			var pn = this.closePref = "QuickToggleAboutConfigSettings.closeMenus";
			var data = [null, {
				pref: [pn, "Закрывать меню этой кнопки"], values: [[true, "Да"], [false, "Нет"]]
			}];
			var setCloseMenus = e => {
				e.stopPropagation();
				var trg = e.target, {pref, val} = trg, updPopup = true, clear;
				switch(e.type) {
					case "command": pref = (trg = trg.closest("menu")).pref; updPopup = false; break;
					case "click": if (e.button) return; break;
					case "contextmenu": e.preventDefault(); clear = pref;
				}
				if (!pref) return;
				if (clear) prefs.clearUserPref(pn);
				else if (!updPopup && val === pref.val) return;
				else pref.set(pn, val !== undefined ? val : !pref.val);
				this.upd(trg);
				updPopup && this.popupshowing(null, trg.querySelector("menupopup"));
			}
			(this.createCloseMenusOption = (doc, btn) => {
				for(var obj of data)
					btn.secondaryPopup.append(this.createElement(doc, obj));
				var m = btn.secondaryPopup.lastChild;
				m.style.cssText = "fill: lightblue !important; list-style-image: url(chrome://browser/skin/menu.svg) !important;";
				m.setAttribute("oncommand", "setCloseMenus(event)");
				m.onclick = m.oncontextmenu = m.setCloseMenus = setCloseMenus;
			})(doc, btn);
		},
		UserChoiceImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACRUlEQVR42qWTS2gTQRjH/zPJZo2BDfgkB62vYg5CjQdvRUE8WB8HKyahYotIQQOeFKGCF7EgvQlBqOCjWFKlevBRDyL4uHloLXhYqWJroaEqlETSptndGb+ZPDH0ojN8O8vA98vv+/Itw38u1nSRYRE6UhKyg4FF1R292/Q+xhhLi4TIrgjgIzwe4MbgmR2nrZMtxxEN63zYORuPZp7gzpehvCu9XjfuPmwCUHIiEtw4fK89zVvD2+FHAD56quXBpV3CVO4ret6nxHzxZxdBRuqADCKmz7RHD9y2tlmbYbBVfwE8DXBkEd/y39H5+mze8ZyoSIpsFXC9u/VE3/ldpyg5AAMEoJMTQi2hANKBgyKdy0h/eoChqcf9MimvVAHjd/fdiG0NRwgQpDAp1agBpDZwdHKJLKZzc+h5e3kCSexh5c5j8fmhW0HGpNZXFkqfsQpAKgcFKGmAlAxHXp5bkkmsrhosjh4cCIJ5pG5qfQXgtMslqO1qgEMWTPrR+eriEhoA4wN7L8TWh0KVXzfgY2RQAUjVBenWLH4UCrj04Wa9BNXEo5va+w63xCiJ6WRVP2MVgNQIgjgEA17MTODZ7Lt+AtSaGDG4377a1m2FAkKrc11/dUwIID1dSKHEcW3yft4RbpR6kK1PYgaJtaY1nNp5jIeMsjKNbs1AWRUcjvTnp2Kh9LtLJGTDINUhcTIZ3L+hzdq9ZgvWmSF9/Wu5gI8L03gzP5l3hddL/3/zKDdA9MdE0UERrdzaFGMUaap75Y/pX9Yfap76EQYaCeEAAAAASUVORK5CYII=",
		notUserChoiceImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACNUlEQVR42qXTT2jTUBwH8G9e0ta2ks5ND0Ww/qX1oGyevEwQnOBA6EHXwLwoUh3eRGRs501RPE6xgp6KrexQECZY8DBPXmbRS4Z/K0gRtmmDa2yb5PlLX7p2Gwpi4EfCy8sn3/dPwn9e0saGnCRF6XYFnA9DkhKtRs51ep6jmtEcp/JHIM9Yivl9mf0XNDV2Ngn1YLzVxdB1lJ8U8P5hzuCWnR6xrPwmIM8kLRjdkT326BaLHNgLKAFA9ouXdhOw6qi++4j589cd89vSaMqyc2sAPUXlgF8fyt9WI3t2Av4w4NsCMJ8AHAKav6hqqH76iuLINcNuNhOawyttYCp+7tRE/6XT9GFQAG4CpniATQkIaNQIMVG6/xSL2WfTGueTbWDh5L2rA9t29QGBrQQEPUDuAuoEmFSr+P5lGc8v33mtAUfaQO3M4/GgDOoYCIkUin8D0BDDoBQ2ZMxqN0wCQh0gMxaUnYb4uzt+dwIZ8wBHTGQbYAHMpu+uAxaGxpMDvSr3AHcFaAIlD+BtoN6ag5WqhOLNwrohTMWPH5roP7pdLIwb3wW6EziWGAZhpVdLWHzxdpqAyc4yKrJ+4uKg2oMV+lgRK9CdwAVsG1WpF8UH84Zt2QkCKmsbiRAtFAllB5OHWQ9fpr81OwlcgBL9kPrwsvDGMQ1zNMV5ZyN1ISlZYZl9/TE1tjuMSFgA1VWO8uef+FAqG47tpFMcm7dyFyIOEzBMlfCadao5qhk39l9P479evwFbiOcRSXKueAAAAABJRU5ErkJggg==",
		UserAltImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVDhPpVM9b9NQFD02cSKKFVGKIFFREFsmFiCA1AEQQrQjC0gssLCkC0jJj0iFWFoGdiT4Ay0SEmJBhPI5FBokikL4SCC0Te2UxInt13Mdu1CVrVc6713fe86x/T6w09DCeTNKJ7Q0pzyUmoCmZYOiUhXms8RMcd6vB7UwthhM5fTLWix2L3PmYjKdOwdz9DDFGtr1KuovnqD29JGlfO9Goew9DCV/DaZy2pXE8PD9Y/mbupk6xE6cVWPQhEujHo2+4fXdO76ztnq1UPYfSCcwKB1HWjeMyunCraSZOsDqbkBPsBOTNoMGvkOTLto/f+F56bble262OK/qesiYzIydTJojFLjrgEe4bcIOEdXWYe6LITN2KgmFSRFGBuPpo0eAngX0SexTJHD5LOgLpEZTcgKuUuMijAyy5l7+r0NSb21g5LQI5gGYSy2AjYBLjQyRAUniTnJXsBoayBzm3RBBndwwIoOK3fgNdIREQYCV/0DqLdiNZqCRITKYayx85RfQuUNiZ3k7IgO+vfGeXGpkiAyma++WLHtZhZ8o5H/FEVpos1V7u8TFwLQId8nw+Afa51Oq2vyycmlk9KCW0GXFZeu63IUO8z88Bx5s28SbuUXfddzrxVcobxpI0GTh7H734/dPzQt9d0/CGBpCPB7nbhmwbAPVxR4+PPtsuU7/WuElth/lKORUcsoTE8TgMg0WbJaY4Zu3XKYdBrABARUk+ls4DfQAAAAASUVORK5CYII=",
		upd(node) {
			var {pref} = node, def = false, user = false, val;
			if (prefs.getPrefType(pref.pref) != prefs.PREF_INVALID) {
				var pn = pref.pref;
				try {val = pref.defVal = db[pref.get.name](pn); def = true}
				catch(ex) {def = false;}
				var user = prefs.prefHasUserValue(pn);
				if (user) try {val = pref.get(pn, undefined);} catch(ex) {}
			}
			if (val == pref.val && def == pref.def && user == pref.user) return;
			pref.val = val; pref.def = def; pref.user = user;
			var exists = def || user;

			var ttt = exists ? val : "Этого префа не существует";
			if (ttt === "") ttt = "[ empty_string ]";
			ttt += "\n" + pref.pref;
			if (pref.ttt) ttt += "\n" + pref.ttt;
			node.tooltipText = ttt;

			var img, alt = "userAlt" in pref && val == pref.userAlt;
			if (alt) img = this.UserAltImg;
			if ("userChoice" in pref)
				if (val == pref.userChoice)
					node.style.removeProperty("color"),
					img = this.UserChoiceImg;
				else {
					node.style.setProperty("color", "maroon", "important");
					if (!alt) img = this.notUserChoiceImg;
				}

			if (!pref.img) img
				? node.setAttribute("image", img)
				: node.removeAttribute("image");
			user
				? node.style.setProperty("font-style", "italic", "important")
				: node.style.removeProperty("font-style");

			var {lab} = pref;
			if (exists && pref.hasVals) {
				if (val in pref.vals) var sfx = pref.vals[val] || val;
				else var sfx = user ? "Другое" : "По умолчанию";
				lab += ` — "${sfx}"`;
			}

			lab = exists ? lab : '['+ lab +']'; // имя = [имя] если преф не существует
			node.setAttribute("label", lab);
		},
		createRadios(doc, vals, popup) {
			for(var arr of vals) {
				if (!arr) {
					popup.append(doc.createElementNS(xul_ns, "menuseparator"));
					continue;
				}
				var [val, lab, key, ttt] = arr;
				var menuitem = doc.createElementNS(xul_ns, "menuitem");
				menuitem.setAttribute("type", "radio");
				menuitem.setAttribute("closemenu", "none");
				menuitem.style.setProperty("font-style", "italic", "important"),
				menuitem.setAttribute("label", popup.parentNode.pref.vals[val] = lab);
				key && menuitem.setAttribute("accesskey", key);
				var tip = menuitem.val = val;
				if (ttt) tip += "\n" + ttt;
				menuitem.tooltipText = tip;
				popup.append(menuitem);
			}
		},
		openPopup(popup) {
			var btn = popup.parentNode;
			if (btn.domParent != btn.parentNode) {
				btn.domParent = btn.parentNode;
				var pos;
				if (btn.matches(".widget-overflow-list > :scope"))
					pos = "after_start";
				else var win = btn.ownerGlobal, {width, height, top, bottom, left, right} =
					btn.closest("toolbar").getBoundingClientRect(), pos = width > height
						? `${win.innerHeight - bottom > top ? "after" : "before"}_start`
						: `${win.innerWidth - right > left ? "end" : "start"}_before`;
				for(var p of btn.popups) p.setAttribute("position", pos);
			}
			popup.openPopup(btn);
		},
		maybeRestart(node, conf) {
			var msgRest = "Перезапустить браузер?", msgAbort = "Запрос на выход отменен.";
			if (pv >= 77) {
				var title = node.closest("toolbarbutton").label;
				var pp = domWin => Services.prompt.wrappedJSObject.pickPrompter({
					domWin, modalType: Ci.nsIPrompt.MODAL_TYPE_WINDOW
				});
				var confirm = win => pp(win).confirm(title, msgRest);
				var alert = win => pp(win).alert(title, msgAbort);
			} else {
				var confirm = win => win.confirm(msgRest);
				var alert = win => win.alert(msgAbort);
			}
			return (this.mayBeRestart = (node, conf) => {
				var win = node.ownerGlobal;
				if (conf && !confirm(win)) return;
				if (win.BrowserUtils.restartApplication() === false) alert(win);
				else return true;
			})(node, conf);
		},
		regexpRefresh: /^(?:view-source:)?(?:https?|ftp)/,
		maybeRe(node, fe) {
			var {pref} = node;
			if ("restart" in pref) {
				if (this.maybeRestart(node, pref.restart)) return;
			}
			else this.popupshowing(fe, node.parentNode);
			if ("refresh" in pref) {
				var win = node.ownerGlobal;
				if (this.regexpRefresh.test(win.gBrowser.currentURI.spec)) pref.refresh
					? win.BrowserReloadSkipCache() : win.BrowserReload();
			}
		},
		maybeClosePopup(e, trg) {
			!e.ctrlKey && prefs.getBoolPref(this.closePref, undefined)
				&& trg.parentNode.hidePopup();
		},
		command(e) {
			var trg = e.target; 			// if (trg.btn) return this.openPopup(trg.primaryPopup);
			if (trg.btn) {
				var doc = e.target.ownerDocument; // Переключить боковую панель
				var win = doc.defaultView;
				var bar = doc.querySelector("#add-additional-vertical-bar");
				if (bar)
					win.setToolbarVisibility(bar, bar.collapsed);
				bar.collapsed ? win.SidebarUI.hide('viewHistorySidebar') : win.SidebarUI.show('viewHistorySidebar');
				return;
			}
			var menu = trg.closest("menu"), newVal = trg.val;
			this.maybeClosePopup(e, menu);
			if (newVal != menu.pref.val)
				menu.pref.set(menu.pref.pref, newVal),
				this.maybeRe(menu, true);
		},
		popupshowing(e, trg = e.target) {
			if (trg.state == "closed") return;
			if (trg.id) {
				for(var node of trg.children) {
					if (node.nodeName.endsWith("r")) continue;
					this.upd(node);
					!e && node.open && this.popupshowing(null, node.querySelector("menupopup"));
				}
				return;
			}
			var {pref} = trg.closest("menu"), findChecked = true;

			var findDef = "defVal" in pref;
			var checked = trg.querySelector("[checked]");
			if (checked) {
				if (checked.val == pref.val) {
					if (findDef) findChecked = false;
					else return;
				}
				else checked.removeAttribute("checked");
			}
			if (findDef) {
				var def = trg.querySelector("menuitem:not([style*=font-style]");
				if (def)
					if (def.val == pref.defVal) {
						if (findChecked) findDef = false;
						else return;
					}
					else def.style.setProperty("font-style", "italic", "important");
			}
			for(var node of trg.children) if ("val" in node) {
				if (findChecked && node.val == pref.val) {
					node.setAttribute("checked", true);
					if (findDef) findChecked = false;
					else break;
				}
				if (findDef && node.val == pref.defVal) {
					node.style.removeProperty("font-style");
					if (findChecked) findDef = false;
					else break;
				}
			}
		},
		contextmenu(e) {
			var trg = e.target;
			if (trg.btn) {
				if (e.ctrlKey || e.shiftKey) return;
				if (e.detail == 2) return trg.secondaryPopup.hidePopup();
				this.openPopup(trg.secondaryPopup);
			}
			else if ("pref" in trg) {
				this.maybeClosePopup(e, trg);
				if (trg.pref.user)
					prefs.clearUserPref(trg.pref.pref),
					this.maybeRe(trg);
			}
			e.preventDefault();
		},
		click(e) {
			if (e.button) return;
			var trg = e.target, {pref} = trg;
			if (!pref) return;
		},
		auxclick(e) {
			if (e.button != 1 || !e.target.btn) return;
			PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');
		},
		mousedown(e) {
			var reset = e => e.target.linkedObject = this;
			var id, lo = {command: reset, mousedown: reset};

			var lin = /macos|linux/.test(e.view.AppConstants.platform);
			var stop = e => reset(e) && e.preventDefault();

			lo.contextmenu = lin
				? e => e.ctrlKey || e.shiftKey ? dsp(e) : stop(e) : stop;
			var context = lin
				? e => e.button == 2 && e.type.endsWith("p") && this.contextmenu(e) : () => {};

			var dsp = (e, timeout) => {
				var trg = e.target;
				trg.onmouseup = trg.onmouseleave = null;
				if (timeout) return this.londPress(e);
				e.view.clearTimeout(id);
				reset(e);
				context(e);
			}
			(this.mousedown = e => {
				var trg = e.target;
				if (!trg.btn) return;
				trg.linkedObject = lo;
				trg.onmouseup = trg.onmouseleave = dsp;
				id = e.view.setTimeout(dsp, 500, e, true);
			})(e);
		},
		londPress(e) { // удержание кнопки мыши, выбирать команды, отводящие мышь от кнопки
			var msg = "QuickSettings\nLONG PRESS: e.button = " + e.button;
			if (e.button == 0) Antizapret(e.target);
		}
	};
}); // END код кнопки

Отредактировано Dobrov (05-04-2021 15:11:00)

На форуме

 

№1539705-04-2021 11:48:41

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 332
UA: Firefox 87.0

Re: Custom Buttons

Dumby
На это никто и ничего

скрытый текст
Что делать, этот код бьет по https://hdrezka-ag.com/
@-moz-document url("about:newtab") {
    body:empty {
        background-color: #222 !important;
    }
}

@-moz-document url("about:blank") {
    body:empty {
        background-color: #222 !important;
    }
}


Пришлось кнопку делать с гор.клавишей... гемморно,а что делать?
скрытый текст

Выделить код

Код:

/*CODE*/
var s = "browser.display.background_color";
cbu.setPrefs(s, cbu.getPrefs(s) == "#fff" ? "#222" : "#fff"); 

function toggleImage() {
   var val = (cbu.getPrefs(s) == "#222");
   
   var {icon} = self;
   icon.src = val ? self.image : "data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAy0lEQVR42t2TWw6DIBBFL1L/mrACH/Gx/wUpPj+bpivQ6QC2NaZppfGrN4GQyXC4wIwgoiuAM48TnAReWq/fSjDgFoahSpIE0zRBSmliJFjrRA7BhOZ5RhAEaNvW5ltAWZaqqiqzgfacapSmKbquc4Asy1TTNGvbX0FRFGEcRwcoikLVde3lwFy573sHyPNcaa29AHEcYxiGgxz8AcDzEW0OA+g4B5tC2qXlG+mXUrY5XMr0LGVuDmWIj0b5uHtpNLZPtsF4unh53+gONs64twYOr4EAAAAASUVORK5CYII="; 
   

   
};
toggleImage();
this.oncontextmenu =e=> { e.button && !e.ctrlKey && e.preventDefault() };
Services.prefs.addObserver(s, toggleImage, false);
addDestructor(()=> Services.prefs.removeObserver(s, toggleImage));

Отсутствует

 

№1539805-04-2021 14:38:23

toxa
Участник
 
Группа: Members
Зарегистрирован: 11-04-2012
Сообщений: 261
UA: Firefox 85.0

Re: Custom Buttons

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

Выделить код

Код:

gBrowser.addEventListener('mousedown', function(){....})

Если после инициализации я открою кнопку подредактировать, а потом закрою, то листнер дублируется. Помогает только перезапуск браузера.


Можно как то сделать, чтоб если листнер уже есть, новый не добавлялся?


Заодно хочу спросить. Вот эта строчка

Выделить код

Код:

const x = (await (await fetch(url)).text());

в консоли работает нормально. А в кнопке дает ошибку. Или если написать это в редакторе кода, скажем, АСЕ - тоже пишет ошибку. Что там ему не нравится?

Отредактировано toxa (05-04-2021 17:30:40)

Отсутствует

 

№1539905-04-2021 22:08:07

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 332
UA: Firefox 87.0

Re: Custom Buttons

Dumby
Ну, что делать, как background задать на новую и пустую без кода этого?
может в tabbrowser.js  типа:
const FAVICON_DEFAULTS = {
    "about:newtab": "chrome://global/skin/icons/Portrait.png",
    "about:home": "chrome://global/skin/icons/Portrait.png",
    "about:blank": "chrome://global/skin/icons/Portrait.png",
};   
Ну, и background тоже?

Отсутствует

 

№1540006-04-2021 09:07:40

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

Re: Custom Buttons

Dobrov пишет

Как вернуть "белый" цвет для строк, подсвеченых курсором?

Наверно можно стилем.
Дописать вызов регистрации стиля в onCreated(), и, далее, сам метод.
Как-то так

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

Выделить код

Код:

...
		onCreated(btn) {
			...

			this.addSheet(btn);
		},
		addSheet(btn) {
			var cb = Array.isArray(btn._destructors);
			var id = cb ? btn.id : "QuickToggleAboutConfigSettings";
			var css = `#${id} menu[_moz-menuactive] {
				color: unset /*white*/ !important;
			}`;
			var args = [
				"data:text/css;charset=utf-8," + encodeURIComponent(css),
				Ci.nsIDOMWindowUtils.USER_SHEET
			];
			if (cb) var destructor = function() {
				this.removeSheetUsingURIString(...args);
			}
			var add = b => b.ownerGlobal.windowUtils.loadSheetUsingURIString(...args);
			(this.addSheet = !cb ? add : btn => {
				add(btn);
				btn._destructors.push({destructor, context: btn.ownerGlobal.windowUtils});
			})(btn);
		},

Dobrov пишет

PlacesCommandHook is not defined

e.view.PlacesCommandHook должен быть defined


Dobrov пишет

3) И всё таки, как выбрать "галочкой" пункт под-меню «По-умолчанию», если преф не существует? (хотя-бы в под-меню выбора ЮзерАгента)
[useragent, "По-умолчанию", "", "", `Services.prefs.setStringPref('general.useragent.override', '')`],

Это что угодно, но только не "По-умолчанию".
Если прям так уж надо поперёк концепции, то можно так попробовать

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

Выделить код

Код:

...
			pref: ["general.useragent.override", "User Agent"],
			userChoice: true, refresh: true,
			values: [				
				(arr => {
					var pref = "general.useragent.override";
					var has = Services.prefs.prefHasUserValue(pref);
					if (has) {
						var val = Services.prefs.getStringPref(pref);
						Services.prefs.clearUserPref(pref);
					}
					var ua = Cc["@mozilla.org/network/protocol;1?name=http"]
						.getService(Ci.nsIHttpProtocolHandler).userAgent;
					has && Services.prefs.setStringPref(pref, val);

					var find = node => node.pref && node.pref.pref == pref;
					var redef = (doc, ttt) => {
						var popup = doc.getElementById("QuickToggleAboutConfigSettings-secondaryPopup");
						var menuitem = Array.from(popup.children).find(find).menupopup.firstChild;
						menuitem.tooltipText = ttt ? ua + "\n" + ttt : ua;
						menuitem.setAttribute("oncommand",
							`event.stopPropagation();
							this.closest("toolbarbutton").linkedObject.contextmenu({
								preventDefault: Boolean,
								target: this.parentNode.parentNode
							});`
						);
					}
					Object.defineProperty(arr, "0", {enumerable: true, get() {
						if (Components.stack.formattedStack.includes("createRadios")) {
							var win = Services.wm.getMostRecentWindow("navigator:browser");
							win.setTimeout(redef, 0, win.document, this[3]);
						}
						else return "";
					}});
					return arr;
				})([null, "По-умолчанию"]),

toxa пишет

Если после инициализации я открою кнопку подредактировать, а потом закрою, то листнер дублируется. Помогает только перезапуск браузера.
Можно как то сделать, чтоб если листнер уже есть, новый не добавлялся?

Ну флаг можно поставить куда-нибудь,
в окно или иное подобное надёжное место.
Если флаг есть, то не добавляем листенер, иначе добавляем.


Редактирование кода самого листенера без перезапуска браузера
тогда всё ещё идёт лесом, но, каков вопрос...


toxa пишет

А в кнопке дает ошибку.

Оператор await валиден только
в асинхронных функциях и асинхронных генераторах
(ну, ещё и это будет).

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

Выделить код

Код:

var url = "data:,757";
(async () => {
	const x = (await (await fetch(url)).text());
	alert(x);
})();

ВВП пишет

Ну, что делать, как background задать на новую и пустую без кода этого?

Даже близко не представляю
как этот код может быть связан с hdrezka-ag.com

Отсутствует

 

Board footer

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