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

В мире Mozilla происходит много интересных событий. Но вам не нужно постоянно посещать новостные сайты, чтобы быть в курсе всех изменений. Зайдите на ленту новостей Mozilla Россия.

№162622-05-2024 20:57:45

_zt
Участник
 
Группа: Members
Зарегистрирован: 10-11-2014
Сообщений: 1550
UA: Firefox 127.0

Re: UCF - ваши кнопки, скрипты…

Появилась тестовая [nightly] с вертикальными вкладками. Скачать можно здесь Directory Listing: /pub/firefox/nightly/latest-larch/

Отсутствует

 

№162723-05-2024 16:49:15

Vitaliy V.
Участник
 
Группа: Members
Зарегистрирован: 19-09-2014
Сообщений: 2158
UA: Firefox 127.0

Re: UCF - ваши кнопки, скрипты…

Dumby пишет

loadSubScript() ведь грузит data: адреса

Да но вроде это не рекомендуемый способ, впрочем сделал так для параметра func,
а для создания объектов ucf_custom_script_win, ucf_custom_script_all_win использовал методы Cu.createObjectIn и Cu.exportFunction,
что там по ним багов не завезли?

Dobrov пишет

Добавь пожалуйста! MJS скрипты нужны

Добавил проверь, только для фоновых скриптов, для оконных то скриптов вроде не требуется.
В параметре module кроме Boolean можно указать массив из строк ["importSymbol"]
это будет доступно в песочнице или так UcfPrefs.customSandbox.importSymbol
PS: Для модулей следует указать полный адрес chrome://user_chrome_files/content/custom_scripts/... в ospath
так как можно же не только из UCF импортировать но и браузера
UPD: впрочем добавил для модулей если вначеле есть %UCFDIR% то будет замена на chrome://user_chrome_files/content/custom_scripts/

Отредактировано Vitaliy V. (23-05-2024 17:33:54)

Отсутствует

 

№162823-05-2024 19:10:24

Vitaliy V.
Участник
 
Группа: Members
Зарегистрирован: 19-09-2014
Сообщений: 2158
UA: Firefox 127.0

Re: UCF - ваши кнопки, скрипты…

_zt пишет

рамку окна скрыть

Да вот скриптик для scriptschrome.domload чтобы скрыть совсем, у меня на [windows] 11 даже углы закругленные убрались

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

Выделить код

Код:

(async () => {
    if (AppConstants.platform !== "win") return;
    var margin = "0,0,0,0";
    if (TabsInTitlebar.enabled)
        document.documentElement.setAttribute("chromemargin", margin);
    TabsInTitlebar._update = eval(`(${`${TabsInTitlebar._update}`.replace(/^(async\s)?.*?\(/, `$1function ${TabsInTitlebar._update.name}(`)
        .replace(/\.setAttribute\("chromemargin",\s*"0,2,2,2"\)\;/g, `.setAttribute("chromemargin", "${margin}");`)})`);
})();

Отсутствует

 

№162923-05-2024 19:22:42

Алексей У.
Участник
 
Группа: Members
Зарегистрирован: 10-04-2021
Сообщений: 180
UA: Firefox 88.0

Re: UCF - ваши кнопки, скрипты…

Почему при внесении любых изменений в user_chrome.manifest браузер перестает "видеть" UserChromeFiles, как будто его нет вообще? Windows 7, Firefox 88.0.1, UserChromeFiles отсюда.

Отсутствует

 

№163023-05-2024 21:06:53

_zt
Участник
 
Группа: Members
Зарегистрирован: 10-11-2014
Сообщений: 1550
UA: Firefox 127.0

Re: UCF - ваши кнопки, скрипты…

Алексей У.
Вариантов несколько, возможно ваш блокнот кодировку ломает или добавляет расширение сохраняемому файлу, синтаксическая ошибка в тексте или вы добавляет свое до первой строки оригинала.
   
Добавлено 23-05-2024 21:20:29
Vitaliy V.
А хорошо, мне нравится. Спасибо.
Теперь можно свои рамки добавить только там где нужно и только для активного окна.

Отредактировано _zt (23-05-2024 21:20:38)

Отсутствует

 

№163124-05-2024 01:00:46

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

Re: UCF - ваши кнопки, скрипты…

Vitaliy V. пишет

В параметре module кроме Boolean можно указать массив из строк ["importSymbol"]

Спасибо! MJS работают, но как подключить mjs скрипт, который должен запускать функцию ?

Выделить код

Код:

export {registerUCFTitleChanged, UCFTitleChangedChild}; // Замены в именах вкладок
var reg = /^Скачать |-\sПоиск\sв\sGoogle$| \| Форум Mozilla Россия$/;

function registerUCFTitleChanged() {
	var esModuleURI = Components.stack.filename;
	ChromeUtils.registerWindowActor("UCFTitleChanged", {
		child: {
			esModuleURI,
			events: { DOMTitleChanged: { capture: true }},
		},
		matches: ["https://*"],
		messageManagerGroups: ["browsers"],
	});
}
class UCFTitleChangedChild extends JSWindowActorChild {
	handleEvent(e) {
		if (reg.test(this.document.title))
			this.document.title = this.document.title.replace(reg, "");
	}
}

Отсутствует

 

№163224-05-2024 08:45:22

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

Re: UCF - ваши кнопки, скрипты…

Vitaliy V. пишет

использовал методы Cu.createObjectIn и Cu.exportFunction,
что там по ним багов не завезли?

Ну, я не прям уж такой мёртвой хваткой вцепившись в багзиллу.
Просто иногда пытаюсь просматривать на предмет отвала.


Так что, более чем запросто, могу что-то пропустить, проворонить.
Поэтому, здесь на меня полагаться не следует.
А скажу так: само существование этих двух методов Cu виднелось,
но каких-то багов о них, лично мне, не попадалось. Вообще.


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


А если нет, то можно убрать «e».
То есть, просто catch {} а не catch (e) {}
Вроде, это называется «Optional catch binding».
Такой упрощённый синтаксис завезли с Firefox 58.

Отсутствует

 

№163324-05-2024 16:29:13

Vitaliy V.
Участник
 
Группа: Members
Зарегистрирован: 19-09-2014
Сообщений: 2158
UA: Firefox 127.0

Re: UCF - ваши кнопки, скрипты…

Dobrov пишет

как подключить mjs скрипт, который должен запускать функцию ?

Ну смотря откуда хочешь запускать, можешь так записать
{ ospath: "%UCFDIR%UCFTitleChangedChild.mjs", module: ["registerUCFTitleChanged"], func: "registerUCFTitleChanged();"},
или из другого background скрипта registerUCFTitleChanged();
или из оконного скрипта UcfPrefs.customSandbox.registerUCFTitleChanged();
или сделай как у Dumby типа ChromeUtils.domProcessChild.childID || ...

Dumby пишет

Кстати, было бы неплохо, если бы был какой-то репортинг
на ошибку исполнения func() добавленных в unloadMap.

Done!

Отсутствует

 

№163424-05-2024 18:25:36

Алексей У.
Участник
 
Группа: Members
Зарегистрирован: 10-04-2021
Сообщений: 180
UA: Firefox 88.0

Re: UCF - ваши кнопки, скрипты…

_zt пишет

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

Если не трудно, можно подробнее по каждому из пунктов.

Отсутствует

 

№163524-05-2024 20:47:36

_zt
Участник
 
Группа: Members
Зарегистрирован: 10-11-2014
Сообщений: 1550
UA: Firefox 127.0

Re: UCF - ваши кнопки, скрипты…

Алексей У.
1. Используйте Notepad++ или другой нормальный блокнот
2. Включите отображение зарегистрированных расширений файлов в Windows
3. Не пишите в манифест ничего, кроме данных вам строк
4. Не пишите ничего до первой оригинальной строки
Все остальное можно найти в гугле.

Отсутствует

 

№163624-05-2024 21:00:43

Алексей У.
Участник
 
Группа: Members
Зарегистрирован: 10-04-2021
Сообщений: 180
UA: Firefox 88.0

Re: UCF - ваши кнопки, скрипты…

_zt пишет

1. Используйте Notepad++ или другой нормальный блокнот
2. Включите отображение зарегистрированных расширений файлов в Windows
3. Не пишите в манифест ничего, кроме данных вам строк
4. Не пишите ничего до первой оригинальной строки

По пунктам 2-4 все в порядке. Что касается пункта 1, то обнаружил, что стандартный Блокнот предлагает при сохранении следующие варианты кодировки: ANSI, UTF-8, Юникод, Юникод Big Endian. Какую из них выбрать?
P.S. Раньше вообще не обращал внимания на такие тонкости.

Отсутствует

 

№163724-05-2024 21:12:40

_zt
Участник
 
Группа: Members
Зарегистрирован: 10-11-2014
Сообщений: 1550
UA: Firefox 127.0

Re: UCF - ваши кнопки, скрипты…

Алексей У.
Со "стандартный Блокнот" вы так для каждого файла спрашивать будете. Возьмите нормальный блокнот.
UTF-8 там.

Отсутствует

 

№163824-05-2024 22:20:47

egorsemenov06
Участник
 
Группа: Members
Зарегистрирован: 12-06-2018
Сообщений: 436
UA: Firefox 126.0

Re: UCF - ваши кнопки, скрипты…

Dumby посиотрите пожалуйста кнопку Check for Addons Updates на работает но при прверке обновлений в консоли пишет
TypeError: Property 'handleEvent' is not callable. browser-custom-element.js:1033:13
    construct chrome://global/content/elements/browser-custom-element.js:1033
    connectedCallback chrome://global/content/elements/browser-custom-element.js:328
    _insertBrowser chrome://browser/content/tabbrowser.js:2296
    addTab chrome://browser/content/tabbrowser.js:2695
    checkForAddonsUpdates chrome://user_chrome_files/content/custom_scripts/custom_script.js line 197 > Function:625
    checkForAddonsUpdates chrome://user_chrome_files/content/custom_scripts/custom_script.js line 197 > Function:970
    onclick chrome://user_chrome_files/content/custom_scripts/custom_script.js line 197 > Function:343

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

Выделить код

Код:

(async () => CustomizableUI.createWidget({
	label: "Дополнения",
	id: "ucf-cbbtn-ToggleRestartlessAddons",
	localized: false,
	get initCode() {
		this.event = Object.create(null);
		delete this.initCode;
		return this.initCode = Cu.readUTF8URI(Services.io.newURI(
			"chrome://user_chrome_files/content/custom_scripts/custom_script/toggleRestartlessAddons.js"
		));
	},
	get icon() {
		var icon = "data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'><path style='fill:none;stroke:context-fill rgb(39, 174, 129);stroke-opacity:context-fill-opacity;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;' d='M12.9 15.3H3.2c-.88 0-1.6-.6-1.6-1.4v-2.7c0-.4.33-.6.74-.6h1.72c.7 0 1.25-.64 1.25-1.2 0-.64-.55-1.15-1.25-1.15H2.34c-.41 0-.74-.32-.74-.68V5.84c0-.81.72-1.48 1.6-1.48h2.36V3.13c0-1.21.93-2.297 2.21-2.419C9.23.57 10.5 1.62 10.5 2.98v1.38h2.4c.9 0 1.5.67 1.5 1.48v8.06c0 .8-.6 1.4-1.5 1.4z'/></svg>";
		var subst = this.id.toLowerCase() + "-icon";
		Services.io.getProtocolHandler("resource")
			.QueryInterface(Ci.nsIResProtocolHandler)
			.setSubstitution(subst, Services.io.newURI(icon));
		delete this.icon;
		return this.icon = "resource://" + subst;
	},
	onCreated(btn) {
		btn.setAttribute("image", this.icon);
		new btn.ownerGlobal.Function("self,event,_phase", this.initCode)
			.call(btn, btn, this.event, "init");
	}
}))();

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

Выделить код

Код:

// http://infocatcher.ucoz.net/js/cb/toggleRestartlessAddons.js
// https://forum.mozilla-russia.org/viewtopic.php?id=57948
// https://github.com/Infocatcher/Custom_Buttons/tree/master/Toggle_Restartless_Add-ons

// Toggle Restartless Add-ons button for Custom Buttons
// (code for "initialization" section)
// Also the code can be used from main window context (as Mouse Gestures code, for example)

// Also you can check for add-ons updates using right-click:
// copy all code from
// https://github.com/Infocatcher/Custom_Buttons/blob/master/Check_for_Addons_Updates/checkForAddonsUpdates.js
// after "//== Check for Addons Updates begin"

// See "var style = " to modify styles for specific add-ons

// (c) Infocatcher 2013-2019
// version 0.1.3pre4 - 2020-01-01

var options = {
	addonTypes: ["extension", "plugin"],
	// Possible values: "extension", "plugin"
	// From extensions: "userstyle" (Stylish), "greasemonkey-user-script" (Greasemonkey), "userscript" (Scriptish)
	// (swap to reorder in the menu)
	showVersions: 1,
	// 0 - don't show versions
	// 1 - show after name: "Addon Name 1.2"
	// 2 - show as "acceltext" (in place for hotkey text)
	showHidden: 0,
	// 0  - don't show hidden add-ons
	// -1 - show only enabled hidden add-ons (e.g. to track new items)
	// 1  - show all hidden add-ons
	sort: {
		enabled:     0,
		clickToPlay: 0,
		disabled:    1
		// Sort order:
		// 0, 0, 0 - sort add-ons of each type alphabetically
		// 0, 0, 1 - show enabled add-ons (of each type) first
		// 0, 1, 2 - enabled add-ons, then click-to-play and then disabled
	},
	closeMenu: false, // Close menu after left-click
	closeMenuClickToPlay: false // Close menu after left-click, for click to play plugins
	// Use Shift+click to invert closeMenu* behavior
};

var xulns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

var mp = document.createElementNS(xulns, "menupopup");
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();");

var tb = this.parentNode;
if(tb && tb.getAttribute("orient") == "vertical") {
	// https://addons.mozilla.org/firefox/addon/vertical-toolbar/
	var isRight = tb.parentNode.getAttribute("placement") == "right";
	mp.setAttribute("position", isRight ? "start_before" : "end_before");
}

var cleanupTimer = 0;
mp.updateMenu = function() {
	clearTimeout(cleanupTimer);
	addStyle();
	getRestartlessAddons(options.addonTypes, function(addons) {
		var df = document.createDocumentFragment();
		var prevType;
		function sortPosition(addon) {
			if("STATE_ASK_TO_ACTIVATE" in AddonManager && addon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE)
				return options.sort.clickToPlay;
			if(addon.isActive)
				return options.sort.enabled;
			return options.sort.disabled;
		}
		function key(addon) {
			return options.addonTypes.indexOf(addon.type)
				+ "\n" + sortPosition(addon)
				+ "\n" + addon.name.toLowerCase();
		}
		addons.sort(function(a, b) {
			var ka = key(a);
			var kb = key(b);
			return ka == kb ? 0 : ka < kb ? -1 : 1;
		}).forEach(function(addon) {
			var type = addon.type;
			if(prevType && type != prevType)
				df.appendChild(document.createElementNS(xulns, "menuseparator"));
			prevType = type;
			var icon = addon.iconURL || addon.icon64URL;
			var mi = document.createElementNS(xulns, "menuitem");
			mi.className = "menuitem-iconic";
			var label = addon.name;
			if(options.showVersions == 1)
				label += " " + addon.version;
			else if(options.showVersions == 2)
				mi.setAttribute("acceltext", addon.version);
			mi.setAttribute("label", label);
			mi.setAttribute("image", icon || mp.icons[type] || "");
			if(!icon && mp.icons.useSVG)
				mi.style.fill = "#15c";
			var tip = addon.description || "";
			var delay = "delayedStartupAddons" in Services
				&& Services.delayedStartupAddons[addon.id] || null;
			var isDelayed = delay !== null;
			mi.classList.toggle("toggleRestartlessAddons-isDelayed", isDelayed);
			if(isDelayed)
				tip = "[Delayed Startup: " + delay.toLocaleString() + "]" + (tip ? "\n" + tip : "");
			tip && mi.setAttribute("tooltiptext", tip);
			mi.classList.toggle("toggleRestartlessAddons-isHidden", addon.hidden || false);
			setDisabled(mi, addon.userDisabled);
			mi._cbAddon = addon;
			df.appendChild(mi);
		});
		mp.textContent = "";
		mp.appendChild(df);
	});
};
mp.handleEvent = function(e) {
	var mi = e.target;
	if(!("_cbAddon" in mi))
		return;
	var addon = mi._cbAddon;
	if(e.type == "mousedown") {
		var closeMenu = isAskToActivateAddon(addon)
			? options.closeMenuClickToPlay
			: options.closeMenu;
		if(e.shiftKey)
			closeMenu = !closeMenu;
		mi.setAttribute("closemenu", closeMenu ? "auto" : "none");
		return;
	}
	var hasMdf = hasModifier(e);
	if(e.type == "command" && (!hasMdf || e.shiftKey)) {
		let newDis = setNewDisabled(addon);
		setDisabled(mi, newDis);
	}
	else if(e.type == "command" && hasMdf || e.type == "click" && e.button == 1) {
		openAddonPage(addon);
		closeMenus(mi);
	}
	else if(e.type == "click" && e.button == 2) {
		if(openAddonOptions(addon))
			closeMenus(mi);
	}
};
mp.destroyMenu = function() {
	removeStyle();
	clearTimeout(cleanupTimer);
	cleanupTimer = setTimeout(function() {
		mp.textContent = "";
	}, 5000);
};
mp.icons = {
	get platformVersion() {
		delete this.platformVersion;
		return this.platformVersion = parseFloat(Services.appinfo.platformVersion);
	},
	get useSVG() {
		delete this.useSVG;
		return this.useSVG = Services.appinfo.name == "Firefox" && this.platformVersion >= 57;
	},
	get plugin() {
		delete this.plugin;
		return this.plugin = this.useSVG
			? this.platformVersion >= 65
				? "chrome://global/skin/plugins/pluginGeneric.svg"
				: "chrome://mozapps/skin/plugins/pluginGeneric.svg"
			: "chrome://mozapps/skin/plugins/pluginGeneric-16.png";
	},
	get extension() {
		delete this.extension;
		return this.extension = this.useSVG
			? this.platformVersion >= 76
				? "chrome://mozapps/skin/extensions/extensionGeneric.svg" // Or chrome://mozapps/skin/extensions/extension.svg
				: "chrome://mozapps/skin/extensions/extensionGeneric-16.svg"
			: "chrome://mozapps/skin/extensions/extensionGeneric-16.png";
	}
};
function isAskToActivateAddon(addon) {
	return addon.type == "plugin"
		&& "STATE_ASK_TO_ACTIVATE" in AddonManager
		&& Services.prefs.getBoolPref("plugins.click_to_play", true);
}
function setNewDisabled(addon) {
	var newDis = getNewDisabled(addon);
	var oldDis = addon.userDisabled;
	if(Components.interfaces.nsIWebTransportHash) { // random, Fx 123+
		var func = function() {
			func = false;
		}
		var thread = Services.tm.currentThread;
		var meth = newDis ? "disable" : "enable";
		addon[meth]({allowSystemAddons: true}).finally(func);
		while(func) thread.processNextEvent(true);
	}
	else try {
		addon.userDisabled = newDis;
	}
	catch(e) { // Error: Cannot disable hidden add-on firefox@getpocket.com
		_log("Can't set addon.userDisabled to " + newDis + ", error:\n" + e);
		if(addon.hidden)
			setNewDisabledRaw(addon, newDis);
	}
	var realDis = addon.userDisabled;
	if(realDis != newDis && addon.type == "extension") { // Firefox 62+? Weird things happens
		setNewDisabledRaw(addon, newDis);
		realDis = addon.userDisabled;
	}
	if(realDis != newDis) { // We can't enable vulnerable plugins
		let err = "Can't set addon.userDisabled to " + newDis + ", real value: " + realDis;
		if(newDis) {
			_log(err + "\nSTATE_ASK_TO_ACTIVATE not supported?");
			newDis = false;
		}
		else {
			_log(err + "\nVulnerable plugin?");
			if(oldDis == AddonManager.STATE_ASK_TO_ACTIVATE)
				newDis = true;
			else
				newDis = AddonManager.STATE_ASK_TO_ACTIVATE;
		}
		addon.userDisabled = newDis;
	}
	ensureSpecialDisabled(addon, newDis);
	return addon.userDisabled;
}
function getNewDisabled(addon) {
	// disabled -> STATE_ASK_TO_ACTIVATE -> enabled -> ...
	var curDis = addon.userDisabled;
	var newDis;
	if("STATE_ASK_TO_ACTIVATE" in AddonManager && curDis == AddonManager.STATE_ASK_TO_ACTIVATE)
		newDis = false;
	else if(!curDis)
		newDis = true;
	else {
		if(isAskToActivateAddon(addon))
			newDis = AddonManager.STATE_ASK_TO_ACTIVATE;
		else
			newDis = false;
	}
	return newDis;
}
function setNewDisabledRaw(addon, newDis) {
	_log("Let's try set addon.userDisabled using raw hack");
	if("lazy" in g) g = g.lazy;
	if("XPIDatabase" in g && "updateAddonDisabledState" in g.XPIDatabase) { // Firefox 61+
		let rawAddon = g.XPIDatabase.getAddons().find(function(rawAddon) {
			return rawAddon.id == addon.id;
		});
		g.XPIDatabase.updateAddonDisabledState(
			rawAddon,
			g.XPIDatabase.updateAddonDisabledState.length == 1 // Firefox 74+
				? { userDisabled: newDis }
				: newDis
		);
	}
	else if("eval" in g) { // See "set userDisabled(val)"
		let addonFor = g.eval("addonFor");
		let rawAddon = addonFor(addon);
		//rawAddon.userDisabled = newDis;
		g.XPIProvider.updateAddonDisabledState(rawAddon, newDis);
	}
	else { // Firefox 57+? See https://forum.mozilla-russia.org/viewtopic.php?pid=745272#p745272
		updateAddonDisabledState(addon, newDis);
	}
}
function updateAddonDisabledState(addon, newDis) {
	var key = "_cbToggleRestartlessAddonsData";
	var url = URL.createObjectURL(new Blob([
		"XPIProvider.updateAddonDisabledState(addonFor(this." + key + "[0]), this." + key + "[1]); delete this." + key + ";"
	]));
	addDestructor(function() {
		URL.revokeObjectURL(url);
	});
	(updateAddonDisabledState = function(addon, newDis) {
		nsvo[key] = [addon, newDis];
		Services.scriptloader.loadSubScript(url, nsvo);
	})(addon, newDis);
}
function setDisabled(mi, disabled) {
	var askToActivate = "STATE_ASK_TO_ACTIVATE" in AddonManager && disabled == AddonManager.STATE_ASK_TO_ACTIVATE;
	var cl = mi.classList;
	cl.toggle("toggleRestartlessAddons-askToActivate", askToActivate);
	cl.toggle("toggleRestartlessAddons-disabled", disabled && !askToActivate);
}
function ensureSpecialDisabled(addon, newDis) {
	if(addon.id == "screenshots@mozilla.org")
		Services.prefs.setBoolPref("extensions.screenshots.disabled", newDis);
}

if(
	this instanceof XULElement // Custom Buttons
	&& typeof event == "object"
	&& !("type" in event) && typeof _phase == "string" && _phase == "init" // Initialization
) {
	this.type = "menu";
	this.orient = "horizontal";
	this.appendChild(mp);

	this.onmouseover = function(e) {
		if(e.target != this)
			return;
		Array.prototype.some.call(
			this.parentNode.getElementsByTagName("*"),
			function(node) {
				if(
					node != this
					&& node.namespaceURI == xulns
					// See https://github.com/Infocatcher/Custom_Buttons/issues/28
					//&& node.boxObject
					//&& node.boxObject instanceof Components.interfaces.nsIMenuBoxObject
					&& "open" in node
					&& node.open
					&& node.getElementsByTagName("menupopup").length
				) {
					node.open = false;
					this.open = true;
					return true;
				}
				return false;
			},
			this
		);
	};
	this.onmousedown = function(e) {
		if(e.target == this && e.button == 0 && hasModifier(e))
			e.preventDefault();
	};
	this.oncontextmenu = function(e) {
		if(e.target == this && !hasModifier(e) && hasUpdater())
			e.preventDefault();
	};
	this.onclick = function(e) {
		if(e.target != this)
			return;
		if(e.button == 0 && hasModifier(e) || e.button == 1)
			openAddonsManager();
		else if(e.button == 2 && !hasModifier(e) && hasUpdater())
			checkForAddonsUpdates.call(this);
	};
}
else { // Mouse gestures or something other...
	let e;
	if(typeof event == "object" && event instanceof Event && "screenX" in event) // FireGestures
		e = event;
	else if(
		this instanceof Components.interfaces.nsIDOMChromeWindow
		&& "mgGestureState" in window && "endEvent" in mgGestureState // Mouse Gestures Redox
	)
		e = mgGestureState.endEvent;
	else {
		let anchor = this instanceof XULElement && this
			|| window.gBrowser && gBrowser.selectedBrowser
			|| document.documentElement;
		if("boxObject" in anchor) {
			let bo = anchor.boxObject;
			e = {
				screenX: bo.screenX,
				screenY: bo.screenY
			};
			if(this instanceof XULElement)
				e.screenY += bo.height;
		}
	}
	if(!e || !("screenX" in e))
		throw new Error("[Toggle Restartless Add-ons]: Can't get event object");
	document.documentElement.appendChild(mp);
	mp.addEventListener("popuphidden", function destroy(e) {
		mp.removeEventListener(e.type, destroy, false);
		setTimeout(function() {
			mp.destroyMenu();
			mp.parentNode.removeChild(mp);
		}, 0);
	}, false);
	mp.openPopupAtScreen(e.screenX, e.screenY);
}

function getRestartlessAddons(addonTypes, callback, context) {
	if(!("AddonManager" in window));
	var then, promise = AddonManager.getAddonsByTypes(addonTypes, then = function(addons) {
		callback.call(context, addons.filter(function(addon) {
			var ops = addon.operationsRequiringRestart;
			return !addon.appDisabled
				&& !(ops & AddonManager.OP_NEEDS_RESTART_ENABLE || ops & AddonManager.OP_NEEDS_RESTART_DISABLE)
				&& (
					!addon.hidden
					|| options.showHidden > 0
					|| options.showHidden == -1 && !addon.userDisabled
				)
				&& (addon.iconURL || "").substr(0, 29) != "resource://search-extensions/";
		}));
	});
	promise && typeof promise.then == "function" && promise.then(then, Components.utils.reportError); // Firefox 61+
}
function openAddonOptions(addon) {
	// Based on code from chrome://mozapps/content/extensions/extensions.js
	// Firefox 21.0a1 (2013-01-27)
	var optionsURL = addon.optionsURL;
	if(!addon.isActive || !optionsURL)
		return false;
	if(addon.type == "plugin") // No options for now!
		return false;
	if(
		addon.optionsType == (AddonManager.OPTIONS_TYPE_INLINE || NaN)
		|| addon.optionsType == (AddonManager.OPTIONS_TYPE_INLINE_INFO || NaN)
		|| addon.optionsType == (AddonManager.OPTIONS_TYPE_INLINE_BROWSER || NaN)
	)
		openAddonPage(addon, true);
	else if(addon.optionsType == AddonManager.OPTIONS_TYPE_TAB && "switchToTabHavingURI" in window)
		switchToTabHavingURI(optionsURL, true);
	else {
		let windows = Services.wm.getEnumerator(null);
		while(windows.hasMoreElements()) {
			let win = windows.getNext();
			if(win.document.documentURI == optionsURL) {
				win.focus();
				return true;
			}
		}
		// Note: original code checks browser.preferences.instantApply and may open modal windows
		window.openDialog(optionsURL, "", "chrome,titlebar,toolbar,centerscreen,dialog=no");
	}
	return true;
}
function openAddonsManager(view) {
	var openAddonsMgr = window.BrowserOpenAddonsMgr // Firefox
		|| window.openAddonsMgr // Thunderbird
		|| window.toEM; // SeaMonkey
	openAddonsMgr(view);
}
function openAddonPage(addon, scrollToPreferences) {
	var platformVersion = parseFloat(
		Services.appinfo.name == "Pale Moon"
			? Services.appinfo.version
			: Services.appinfo.platformVersion
	);
	scrollToPreferences = scrollToPreferences && platformVersion >= 12
		? "/preferences"
		: "";
	openAddonsManager("addons://detail/" + encodeURIComponent(addon.id) + scrollToPreferences);
}

function hasModifier(e) {
	return e.ctrlKey || e.shiftKey || e.altKey || e.metaKey;
}

function addStyle() {
	if(addStyle.hasOwnProperty("_style"))
		return;
	var style = '\
		.toggleRestartlessAddons-isDelayed > .menu-iconic-text {\n\
			opacity: 0.75;\n\
			color: #070;\n\
		}\n\
		.toggleRestartlessAddons-isHidden > .menu-iconic-text {\n\
			color: #609;\n\
		}\n\
		.toggleRestartlessAddons-disabled > .menu-iconic-left {\n\
			opacity: 0.4;\n\
		}\n\
		.toggleRestartlessAddons-disabled > .menu-iconic-text,\n\
		.toggleRestartlessAddons-disabled > .menu-accel-container {\n\
			opacity: 0.5;\n\
		}\n\
		.toggleRestartlessAddons-askToActivate {\n\
			color: -moz-nativehyperlinktext;\n\
		}';
	addStyle._style = document.insertBefore(
		document.createProcessingInstruction(
			"xml-stylesheet",
			'href="' + "data:text/css,"
				+ encodeURIComponent(style) + '" type="text/css"'
		),
		document.documentElement
	);
}
function removeStyle() {
	if(!addStyle.hasOwnProperty("_style"))
		return;
	var s = addStyle._style;
	s.parentNode.removeChild(s);
	delete addStyle._style;
}
function closeMenus(node) {
	// Based on function closeMenus from chrome://browser/content/utilityOverlay.js
	for(; node && "tagName" in node; node = node.parentNode) {
		if(
			node.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
			&& (node.localName == "menupopup" || node.localName == "popup")
		)
			node.hidePopup();
	}
}
function _log(s) {
	if(typeof LOG == "function") // Custom Buttons
		LOG(s);
	else // Or something else
		Services.console.logStringMessage("Toggle Restartless Add-ons: " + s);
}

function hasUpdater() {
	var has = checkForAddonsUpdates.toString().indexOf("about:addons") != -1;
	hasUpdater = function() {
		return has;
	};
	return has;
}
function checkForAddonsUpdates() {
//== Check for Addons Updates begin
// http://infocatcher.ucoz.net/js/cb/checkForAddonsUpdates.js
// https://forum.mozilla-russia.org/viewtopic.php?id=57958
// https://github.com/Infocatcher/Custom_Buttons/tree/master/Check_for_Addons_Updates

// Check for Addons Updates button for Custom Buttons
// (code for "code" section)

// (c) Infocatcher 2012-2021
// version 0.1.6pre4 - 2021-03-28

// Button just open hidden tab with about:addons and trigger built-in "Check for Updates" function.
// And show tab, if found updates.

(function() {
var btn = this instanceof XULElement
	? this
	: { // Launched not from custom button
		image: "", // Base64-encoded icon (if empty, will be used "imgLoading")
		label: "Check for Addons Updates",
		tooltipText: ""
	};
if("_cb_disabled" in btn)
	return;
btn._cb_disabled = true;


var app = Services.appinfo.name;
var pv = parseFloat(Services.appinfo.platformVersion);

var ADDONS_URL = "about:addons";

var progressIcon = new ProgressIcon(btn);
var image = btn.image || progressIcon.imgLoading;
var tip = btn.tooltipText;
btn.tooltipText = "Open " + ADDONS_URL + "…";

var tab, browser, gBrowser;
var tbTabInfo, tbTab;

var trgWindow = Services.wm.getMostRecentWindow("navigator:browser")
	|| app == "Thunderbird" && Services.wm.getMostRecentWindow("mail:3pane")
	|| window;
var trgDocument = trgWindow.document;
var tabmail = trgDocument.getElementById("tabmail");

if(tabmail && app == "Thunderbird") { // Note: SeaMonkey doesn't support content tabs in mail window
	let addonsWin;
	let receivePong = function(subject, topic, data) {
		addonsWin = subject;
	};
	Services.obs.addObserver(receivePong, "EM-pong", false);
	Services.obs.notifyObservers(null, "EM-ping", "");
	Services.obs.removeObserver(receivePong, "EM-pong");
	if(addonsWin) {
		let rootWindow = addonsWin
			.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
			.getInterface(Components.interfaces.nsIWebNavigation)
			.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
			.rootTreeItem
			.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
			.getInterface(Components.interfaces.nsIDOMWindow);
		tabmail = rootWindow.document.getElementById("tabmail");
		tbTabInfo = tabmail.getBrowserForDocument(addonsWin);
		tbTab = tab = tbTabInfo.tabNode;
		processAddonsTab(addonsWin);
	}
	else {
		Services.obs.addObserver(function observer(subject, topic, data) {
			Services.obs.removeObserver(observer, topic);
			if(subject.document.readyState == "complete")
				processAddonsTab(subject);
			else {
				subject.addEventListener("load", function onLoad(e) {
					subject.removeEventListener(e.type, onLoad, false);
					processAddonsTab(subject);
				}, false);
			}
		}, "EM-loaded", false);
		// See openAddonsMgr() -> openContentTab()
		tbTabInfo = tabmail.openTab("contentTab", {
			contentPage: ADDONS_URL,
			clickHandler: "specialTabs.siteClickHandler(event, /addons\.mozilla\.org/);",
			background: true
		});
		tbTab = tab = tbTabInfo.tabNode;
		tbTab.collapsed = true;
		// Note: dontSelectHiddenTab() not implemented
	}
}
else if("gBrowser" in trgWindow && trgWindow.gBrowser.tabs) {
	let isPending = false;
	let ws = Services.wm.getEnumerator("navigator:browser");
	windowsLoop:
	while(ws.hasMoreElements()) {
		let w = ws.getNext();
		let tabs = w.gBrowser.tabs;
		for(let i = 0, l = tabs.length; i < l; ++i) {
			let t = tabs[i];
			if(
				!t.closing
				&& t.linkedBrowser
				&& t.linkedBrowser.currentURI.spec == ADDONS_URL
			) {
				tab = t;
				break windowsLoop;
			}
		}
	}

	gBrowser = trgWindow.gBrowser;
	if(!tab) {
		tab = gBrowser.addTab(ADDONS_URL, {
			triggeringPrincipal: "Services" in window // Firefox 63+
				&& Services.scriptSecurityManager
				&& Services.scriptSecurityManager.getSystemPrincipal()
		});
		tab.collapsed = true;
		tab.closing = true; // See "visibleTabs" getter in chrome://browser/content/tabbrowser.xml
		trgWindow.addEventListener("TabSelect", dontSelectHiddenTab, false);
	}
	else if(
		tab.getAttribute("pending") == "true" // Gecko >= 9.0
		|| tab.linkedBrowser.contentDocument.readyState == "uninitialized"
		// || tab.linkedBrowser.__SS_restoreState == 1
	)
		isPending = true;

	browser = tab.linkedBrowser;
	if(
		isPending
		|| browser.webProgress.isLoadingDocument
		|| browser.currentURI.spec == "about:blank" // Firefox 79+
	) {
		browser.addEventListener("load", processAddonsTab, true);
		if(isPending) {
			if(pv >= 41) {
				// Workaround to correctly restore pending tab
				// See https://github.com/Infocatcher/Custom_Buttons/issues/39
				let selTab = gBrowser.selectedTab;
				gBrowser.selectedTab = tab;
				gBrowser.selectedTab = selTab;
			}
			else {
				browser.reload();
			}
		}
	}
	else {
		processAddonsTab();
	}
}
else {
	progressIcon.restore();
	btn.tooltipText = tip;
	delete btn._cb_disabled;
	Services.prompt.alert(window, btn.label, "Error: Can't find supported window!");
	return;
}

function processAddonsTab(e, again) {
	var doc;
	if(e && e instanceof Components.interfaces.nsIDOMWindow) {
		doc = e.document;
	}
	else if(e) {
		doc = e.target;
		if(doc.location != ADDONS_URL)
			return;
		browser.removeEventListener(e.type, processAddonsTab, true);
	}
	else {
		doc = browser.contentDocument;
	}

	btn.tooltipText = "Process " + ADDONS_URL + "…";
	progressIcon.loading();

	var origAttr = "_cb_checkForAddonsUpdates_origImage";
	if(!tab.hasAttribute(origAttr)) {
		var link = doc.querySelector('link[rel="shortcut icon"]'); // Not loaded yet?
		tab.setAttribute(origAttr, link && link.href || tab.image);
	}
	tab.image = image;

	var fu = $("cmd_findAllUpdates");
	if(!fu) { // Firefox 72+
		var win = doc.defaultView;
		var vb = doc.getElementById("html-view-browser");
		if(!vb) {
			if(!HTMLHtmlElement.isInstance(doc.documentElement)) { // Firefox 87+
				win.setTimeout(processAddonsTab, 20, win);
				return;
			}
			vb = browser;
		}
		if(!again) { // Strange errors happens
			// chrome://mozapps/content/extensions/aboutaddons.js
			// getTelemetryViewName() -> el.closest(...) is null
			win.setTimeout(processAddonsTab, 20, win, true);
			return;
		}
		var vbDoc = vb.contentDocument;
		fu = vbDoc.querySelector('[action="check-for-updates"]');
		var um = vbDoc.getElementById("updates-message");
	}

	var notFound = $("updates-noneFound") || {
		get hidden() { return um.getAttribute("state") != "none-found"; }
	};
	var updated = $("updates-installed") || {
		get hidden() { return um.getAttribute("state") != "installed"; }
	};
	// Avoid getting false results from the past update check (may not be required for "noneFound")
	if(um) { // Firefox 72+
		um.hidden = true;
		um.removeAttribute("state");
	}
	else {
		notFound.hidden = updated.hidden = true;
	}

	//fu.doCommand();
	fu.click();

	function localize(node, key, callback) {
		if(um) { // Firefox 72+
			doc.l10n.formatValue(key).then(function(s) {
				callback(s || key);
			}, Components.utils.reportError);
			return;
		}
		callback(node.getAttribute("value") || key);
	}

	var inProgress = $("updates-progress") || {
		get hidden() { return um.getAttribute("state") != "updating"; }
	};
	localize(inProgress, "addon-updates-updating", function(s) {
		btn.tooltipText = s;
	});

	var waitTimer = setInterval(function() {
		if(!doc.defaultView || doc.defaultView.closed) {
			stopWait();
			notify("Tab with add-ons manager was closed!");
			return;
		}
		if(!inProgress.hidden)
			return;
		var autoUpdate = $("utils-autoUpdateDefault")
			|| vbDoc.querySelector('[action="set-update-automatically"]');
		var autoUpdateChecked = autoUpdate.getAttribute("checked") == "true"
			|| autoUpdate.checked;

		var found = $("updates-manualUpdatesFound-btn") || {
			get hidden() { return um.getAttribute("state") != "manual-updates-found"; }
		};
		if(
			autoUpdateChecked
				? notFound.hidden && updated.hidden
				: notFound.hidden && found.hidden
		) // Too early?
			return;

		stopWait();
		if(!tbTab)
			tab.closing = false;
		function removeTab() {
			if(!tab.collapsed)
				return;
			if(tbTab) {
				tabmail.closeTab(tbTabInfo, true /*aNoUndo*/);
				return;
			}
			gBrowser.removeTab(tab);
			(function forgetClosedTab(isSecondTry) {
				var ss = "nsISessionStore" in Components.interfaces
					? (
						Components.classes["@mozilla.org/browser/sessionstore;1"]
						|| Components.classes["@mozilla.org/suite/sessionstore;1"]
					).getService(Components.interfaces.nsISessionStore)
					: trgWindow.SessionStore; // Firefox 61+ https://bugzilla.mozilla.org/show_bug.cgi?id=1450559
				if(!("forgetClosedTab" in ss))
					return;
				var closedTabs = (ss.getClosedTabDataForWindow(window));
				for(let i = 0, l = closedTabs.length; i < l; ++i) {
					let closedTab = closedTabs[i];
					let state = closedTab.state;
					if(state.entries[state.index - 1].url == ADDONS_URL) {
						ss.forgetClosedTab(window, i);
						return;
					}
				}
				if(!isSecondTry) // May be needed in SeaMonkey
					setTimeout(forgetClosedTab, 0, true);
			})();
		}

		if(!notFound.hidden) {
			removeTab();
			localize(notFound, "addon-updates-none-found", function(s) {
				notify(s);
			});
			return;
		}
		if(autoUpdateChecked) {
			removeTab();
			localize(updated, "addon-updates-installed", function(s) {
				notify(s);
			});
			return;
		}

		tab.collapsed = false;

		var cats = $("categories");
		var upds = $("category-availableUpdates");
		if(cats && upds) {
			if(vb && cats.selectedItem == upds) // Only for Firefox 72+
				cats.selectedItem = $("category-extension"); // Trick to force update
			cats.selectedItem = upds;
		}
		else { // Firefox 76+ ?
			vbDoc.querySelector('.category[name="available-updates"]').click();
		}

		var tabWin = tab.ownerDocument.defaultView;
		if(tbTab)
			tabmail.switchToTab(tbTabInfo);
		else
			tabWin.gBrowser.selectedTab = tab;
		setTimeout(function() {
			tabWin.focus();
			doc.defaultView.focus();
			var al = $("addon-list") || vb;
			al.focus();
		}, 0);
	}, 50);
	function $(id) {
		return doc.getElementById(id);
	}
	function stopWait() {
		clearInterval(waitTimer);
		progressIcon.restore();
		btn.tooltipText = tip;
		if(tab.image == image)
			tab.image = tab.getAttribute(origAttr);
		tab.removeAttribute(origAttr);
		trgWindow.removeEventListener("TabSelect", dontSelectHiddenTab, false);
		setTimeout(function() {
			delete btn._cb_disabled;
		}, 500);
	}
	function notify(msg) {
		Components.classes["@mozilla.org/alerts-service;1"]
			.getService(Components.interfaces.nsIAlertsService)
			.showAlertNotification(
				app == "Firefox" && pv >= 57
					? "chrome://mozapps/skin/extensions/extensionGeneric.svg"
					: "chrome://mozapps/skin/extensions/extensionGeneric.png",
				btn.label,
				msg, false, "", null
			);
	}
}
function dontSelectHiddenTab(e) {
	// <tab /><tab collapsed="true" />
	// Close first tab: collapsed tab becomes selected
	var trgTab = e.originalTarget || e.target;
	if(trgTab != tab)
		return;

	if(/\n(?:BrowserOpenAddonsMgr|toEM)@chrome:\/\//.test(new Error().stack)) {
		// User open Add-ons Manager, show tab
		trgWindow.removeEventListener("TabSelect", dontSelectHiddenTab, false);
		setTimeout(function() { // Hidden tab can't be selected, so select it manually...
			tab.collapsed = tab.closing = false;
			gBrowser.selectedTab = tab;
		}, 0);
	}

	function done(t) {
		if(!t.hidden && !t.closing) {
			e.preventDefault();
			e.stopPropagation();
			return gBrowser.selectedTab = t;
		}
		return false;
	}
	for(var t = tab.nextSibling; t; t = t.nextSibling)
		if(done(t))
			return;
	for(var t = tab.previousSibling; t; t = t.previousSibling)
		if(done(t))
			return;
}
function ProgressIcon(btn) {
	var app = Services.appinfo.name;
	var pv = parseFloat(Services.appinfo.platformVersion);
	if(app == "SeaMonkey")
		this.imgConnecting = this.imgLoading = "chrome://communicator/skin/icons/loading.gif";
	else if(app == "Thunderbird") {
		this.imgConnecting = "chrome://messenger/skin/icons/connecting.png";
		this.imgLoading = "chrome://messenger/skin/icons/loading.png";
	}
	else {
		this.imgConnecting = app == "Firefox" && pv >= 58
			? "chrome://browser/skin/tabbrowser/tab-connecting.png"
			: "chrome://browser/skin/tabbrowser/connecting.png";
		this.imgLoading = app == "Firefox" && pv >= 48
			? "chrome://global/skin/icons/loading.png"
			: "chrome://browser/skin/tabbrowser/loading.png";
	}
	if(!(btn instanceof XULElement)) {
		this.loading = this.restore = function() {};
		return;
	}
	var useAnimation = app == "Firefox" && pv >= 32 && pv < 48;
	var btnIcon = btn.icon
		|| btn.ownerDocument.getAnonymousElementByAttribute(btn, "class", "toolbarbutton-icon");
	var origIcon = btnIcon.src;
	btnIcon.src = this.imgConnecting;
	if(useAnimation) {
		let cs = btnIcon.ownerDocument.defaultView.getComputedStyle(btnIcon, null);
		let s = btnIcon.style;
		s.margin = [cs.marginTop, cs.marginRight, cs.marginBottom, cs.marginLeft].join(" ");
		s.padding = [cs.paddingTop, cs.paddingRight, cs.paddingBottom, cs.paddingLeft].join(" ");
		s.width = cs.width;
		s.height = cs.height;
		s.boxShadow = "none";
		s.borderColor = s.background = "transparent";
		btnIcon.setAttribute("fadein", "true");
		btnIcon.setAttribute("busy", "true");
		btnIcon.classList.add("tab-throbber");
		btnIcon._restore = function() {
			delete btnIcon._restore;
			btnIcon.removeAttribute("busy");
			btnIcon.removeAttribute("progress");
			setTimeout(function() {
				btnIcon.classList.remove("tab-throbber");
				btnIcon.removeAttribute("style");
				btnIcon.removeAttribute("fadein");
			}, 0);
		};
	}
	this.loading = function() {
		btnIcon.src = this.imgLoading;
		if(useAnimation)
			btnIcon.setAttribute("progress", "true");
	};
	this.restore = function() {
		btnIcon.src = origIcon;
		if(useAnimation)
			btnIcon._restore();
	};
}
}).call(this);
//== Check for Addons Updates end
}              

this.tooltipText = "Переключатель джетпаков" 
                   + "\nПКМ – проверить обновления"
                   + "\nСКМ – открыть страницу дополнений"
                   + "\nShift+ПКМ – меню кнопки"
                   + "\n\nВ меню: \nЛКМ – включить/выключить дополнение без закрытия меню"
                   + "\nShift+ЛКМ – включить/выключить дополнение"   
                   + "\nСКМ – открыть страницу дополнения в управлении дополнениями"                    
                   + "\nПКМ – открыть настройки дополнения (если есть)";     
// Autoopen/close feature
var openDelay = 200;
var closeDelay = 350;

var _openTimer = 0;
var _closeTimer = 0;
this.onmouseover = function(e) {
	clearTimeout(_closeTimer);
	if(e.target == this && closeOtherMenus()) {
		this.open = true;
		return;
	}
	_openTimer = setTimeout(function() {
		self.open = true;
	}, openDelay);
};
this.onmouseout = function(e) {
	clearTimeout(_openTimer);
	_closeTimer = setTimeout(function() {
		if(!isContextOpened())
			self.open = false;
	}, closeDelay);
};
function closeOtherMenus() {
	return Array.prototype.some.call(
		self.parentNode.getElementsByTagName("*"),
		function(node) {
			if(
				node != self
				&& node.namespaceURI == xulns
				// See https://github.com/Infocatcher/Custom_Buttons/issues/28
				//&& node.boxObject
				//&& node.boxObject instanceof Components.interfaces.nsIMenuBoxObject
				&& "open" in node
				&& node.open
				&& node.getElementsByTagName("menupopup").length
			) {
				node.open = false;
				return true;
			}
			return false;
		}
	);
}
function isContextOpened() {
	return inBtn(document.popupNode);
}
function inBtn(node) {
	for(; node; node = node.parentNode)
		if(node == self)
			return true;
	return false;
}

Отсутствует

 

№163925-05-2024 08:56:40

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

Re: UCF - ваши кнопки, скрипты…

Доработал ucf_hookClicks.js и исправил неоткрытие менюшек в многооконом режиме.
Сделал две настраиваемых команды в Меню пользователя, которое открывается правым кликом на unified-extensions и add-ons-button.
Ещё при наведении на них мыши показывается содержимое буфера обмена.
Можно задать имена строк меню и js-код, сохраняемые при рестарте [firefox].
По правому клику на 2-х последних строках открывается опция about:config с вашими командами или строкой по-умолчанию.
Дополнил подсказки – на кнопках, строках меню и в статусе достаточно подробные подсказки.

Отсутствует

 

№164025-05-2024 09:59:48

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

Re: UCF - ваши кнопки, скрипты…

Vitaliy V. пишет

Done!

Похоже, здесь не всё так просто.
Добавил в custom_script_win.js строку
ucf_custom_script_win.setUnloadMap("bbbla", () => bbbla());


Рестарт, Ctrl+N, Alt+F4 — и получаю в консоли две записи
«can't access property "destructor", this.ucfo[key] is undefined»
и «bbbla is not defined».


Немного странно что две, но вполне приемлимо.
Больше репортинга — скорее понуждает к исправлению кривого деструктора.
Иначе говоря — две записи лучше, чем ноль.


Но, рассмотрим такой код:

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

Выделить код

Код:

((key, ucf) => {
	ucf[key] = {
		destructor() {
			bbbla();
		}
	};
	ucf.unloadlisteners.push(key);

})("bbbla", ucf_custom_script_win);


Те же действия, но получаю уже две одинаковые записи
«bbbla is not defined».


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


egorsemenov06 пишет

Dumby посиотрите пожалуйста кнопку Check for Addons Updates на работает но при прверке обновлений в консоли пишет
TypeError: Property 'handleEvent' is not callable. browser-custom-element.js:1033:13

Попробовал посмотреть на 128. Жму ПКМ — в консоли куча всяких
«addons.update-checker    WARN    HTTP Request failed for an unknown reason»
но, в моём случае, это совершенно нормально и ожидаемо.
А вот такой странной ошибки как у тебя — увидеть не смог.
Скажу так: если для воспроизводства нужен выход в сеть,
то тогда, увы, здесь я ничем помочь не смогу.

Отсутствует

 

№164125-05-2024 10:19:51

egorsemenov06
Участник
 
Группа: Members
Зарегистрирован: 12-06-2018
Сообщений: 436
UA: Firefox 126.0

Re: UCF - ваши кнопки, скрипты…

Dumby пишет
egorsemenov06 пишет

Dumby посиотрите пожалуйста кнопку Check for Addons Updates на работает но при прверке обновлений в консоли пишет
TypeError: Property 'handleEvent' is not callable. browser-custom-element.js:1033:13

Попробовал посмотреть на 128. Жму ПКМ — в консоли куча всяких
«addons.update-checker    WARN    HTTP Request failed for an unknown reason»
но, в моём случае, это совершенно нормально и ожидаемо.
А вот такой странной ошибки как у тебя — увидеть не смог.
Скажу так: если для воспроизводства нужен выход в сеть,
то тогда, увы, здесь я ничем помочь не смогу.

очень жаль.но в любом случае спасибо!!!

Отсутствует

 

№164225-05-2024 13:24:02

Vitaliy V.
Участник
 
Группа: Members
Зарегистрирован: 19-09-2014
Сообщений: 2158
UA: Firefox 127.0

Re: UCF - ваши кнопки, скрипты…

Dumby пишет

получается, что кривой деструктор вызывается дважды.
А это уже нехорошо.

А чего такого нехорошего, ну вызвало два раза на что это повлияет, на скорость закрытия окна, вряд ли.
Кстати а зачем нужны кривые деструкторы, и потом вот эту часть в user_chrome.js
try { this.ucfo[key].destructor(); } catch (e) {Cu.reportError(e);}
можно было вообще не добавлять, но например https://forum.mozilla-russia.org/viewto … 44#p806144
destructor не существует когда добавляется unloadlisteners.push

egorsemenov06 пишет

TypeError: Property 'handleEvent' is not callable

А это похоже моя ошибка, но кроме мусора ни на что не влияет, можно добавить пока не обновил UCF
в user_chrome/StylesScriptsChild.mjs
export class UcfCustomStylesScriptsChild extends JSWindowActorChild {
    actorCreated() {
        this.handleEvent = () => {}
        ...

Отредактировано Vitaliy V. (25-05-2024 13:39:13)

Отсутствует

 

№164325-05-2024 14:34:34

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

Re: UCF - ваши кнопки, скрипты…

Vitaliy V. пишет

TypeError: Property 'handleEvent' is not callable
А это похоже моя ошибка, но кроме мусора ни на что не влияет, можно добавить пока не обновил UCF

Ещё SaveHTML.mjs при сохранении страницы about:newtab эту же ошибку выводит в консоль.

Отсутствует

 

№164425-05-2024 14:53:46

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

Re: UCF - ваши кнопки, скрипты…

Vitaliy V. пишет

А чего такого нехорошего, ну вызвало два раза на что это повлияет

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

Кстати а зачем нужны кривые деструкторы

Как зачем? В тестовых целях, посмотреть что случится.

destructor не существует когда добавляется unloadlisteners.push

Может проверять как-то так, даже не знаю

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

Выделить код

Код:

/*
                try { val.func.apply(val.context); } catch (e) {
                    try { this.ucfo[key].destructor(); } catch (e) {Cu.reportError(e);}
                    Cu.reportError(e);
                }
*/
                if (val.func)
                    try {val.func.apply(val.context);} catch(ex) {Cu.reportError(ex);}
                else if (this.ucfo[key]?.destructor)
                    try {this.ucfo[key].destructor();} catch(ex) {Cu.reportError(ex);}
                else
                    Cu.reportError("Missing destructor for key " + key);

Отсутствует

 

№164525-05-2024 15:06:11

egorsemenov06
Участник
 
Группа: Members
Зарегистрирован: 12-06-2018
Сообщений: 436
UA: Firefox 126.0

Re: UCF - ваши кнопки, скрипты…

Vitaliy V. пишет
egorsemenov06 пишет

TypeError: Property 'handleEvent' is not callable

А это похоже моя ошибка, но кроме мусора ни на что не влияет, можно добавить пока не обновил UCF
в user_chrome/StylesScriptsChild.mjs
export class UcfCustomStylesScriptsChild extends JSWindowActorChild {
    actorCreated() {
        this.handleEvent = () => {}
        ...

Спасибо!тогда лучше подождать обновление UCF

Отсутствует

 

№164625-05-2024 16:18:01

Vitaliy V.
Участник
 
Группа: Members
Зарегистрирован: 19-09-2014
Сообщений: 2158
UA: Firefox 127.0

Re: UCF - ваши кнопки, скрипты…

Dobrov пишет

Ещё SaveHTML.mjs при сохранении страницы about:newtab эту же ошибку выводит в консоль

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

Dumby пишет

Может проверять как-то так

Или так, сообщение об ошибке, побуждает её исправить, ну и заменить на setUnloadMap

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

Выделить код

Код:

try { val.func.apply(val.context); } catch (e) {
                    if (!val.func)
                        try { this.ucfo[key].destructor(); } catch (e) {Cu.reportError(e);}
                    Cu.reportError(e);
                }


кстати не вижу толку от getUnloadMap наверное заменю или добавлю deleteUnloadMap в следующем обновлении
UPD: обновил на getDelUnloadMap(key, del)
del удаляет если true

Отредактировано Vitaliy V. (26-05-2024 00:56:37)

Отсутствует

 

№164725-05-2024 18:15:31

Алексей У.
Участник
 
Группа: Members
Зарегистрирован: 10-04-2021
Сообщений: 180
UA: Firefox 88.0

Re: UCF - ваши кнопки, скрипты…

Подскажите, пожалуйста, нет ли скрипта (или любого другого способа) вернуть системный вид скроллбаров на ВСЕХ сайтах?

скрытый текст
__________.jpg
Настройки layout.css.scrollbar-color.enabled - false и layout.css.scrollbar-width.enabled - false работают не везде. Например на mozilla.org и youtube.com они не действуют, а собственные скроллбары этих сайтов совершенно не вписываются в цельный интерфейс браузера.
скрытый текст
____________2_.jpg____________3_.jpg

Отсутствует

 

№164825-05-2024 20:08:43

xrun1
Участник
 
Группа: Members
Зарегистрирован: 12-12-2013
Сообщений: 1181
UA: Firefox 126.0

Re: UCF - ваши кнопки, скрипты…

Алексей У.
https://github.com/Aris-t2/CustomJSforFx/blob/master/scripts/old/custom_scrollbars_fx112.uc.js

Отсутствует

 

№164925-05-2024 21:15:03

Алексей У.
Участник
 
Группа: Members
Зарегистрирован: 10-04-2021
Сообщений: 180
UA: Firefox 88.0

Re: UCF - ваши кнопки, скрипты…

xrun1 пишет

https://github.com/Aris-t2/CustomJSforFx/blob/master/scripts/old/custom_scrollbars_fx112.uc.js

Это нужно в custom_script_win.js добавить?

Отсутствует

 

№165026-05-2024 06:09:31

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

Re: UCF - ваши кнопки, скрипты…

Добавляю текст буфера обмена к подсказке url в строке адреса, но получается изменить только tooltip рамки. Там «aHTMLTooltip» и на http без шифрования подсказки адреса нет.
Помогите сделать правильно! (включая подсказку для http://…… сайтов)

скрипт для окна, событие mouseenter на urlbar-input-box

Выделить код

Код:

(async id => { // добавить текст буфера обмена к подсказке url в строке адреса

var listener = { // изменить aHTMLTooltip
	handleEvent(e){
		let trg = e.target, clip = readFromClip();
// let box = document.getElementById("urlbar-input-container").childNodes[6]; //"urlbar-input-box"
		trg.tooltipText = gBrowser.currentURI.spec + "\n\nбуфер обмена (текст)\n" + crop(clip, 88 ,'…\n', 1);
		console.log(trg.tooltipText);
	},
}
var events = ["mouseenter"],
els = document.getElementById("urlbar-input");
els.addEventListener(events,listener,true);

ucf_custom_script_win.unloadlisteners.push(id);
ucf_custom_script_win[id] = {
	destructor(){
		el.removeEventListener(events,listener,true);
	}
}
var addDestructor = nextDestructor => {
	var {destructor} = ucf_custom_script_win[id];
	ucf_custom_script_win[id].destructor =()=> {
		try {destructor();} catch(ex){Cu.reportError(ex)}
		nextDestructor();
	}
}
var readFromClip = ({clipboard} = Services, data = {}) => {
	try {let trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable),
		flavor = `text/${parseInt(Services.appinfo.platformVersion) >= 111 ? "plain" : "unicode"}`;
		trans.init(docShell.QueryInterface(Ci.nsILoadContext));
		trans.addDataFlavor(flavor);
		clipboard.getData(trans, clipboard.kGlobalClipboard);
		trans.getTransferData(flavor, data);
		if (data.value)
			return data.value.QueryInterface(Ci.nsISupportsString).data;
	} catch {return ""}
},
crop = (z = "",cut = 30,ch = '…\n',g = 0) => { //обрезать/разбить текст
	z = z.match(new RegExp('.{1,'+ cut +'}','g')); cut = z.slice(-1);
	return g ? z.join(ch) : z[0] == cut ? z[0] : z[0] + ch +'…'+ cut;
}
})("ucf_clipboard_in_url");

Отредактировано Dobrov (26-05-2024 06:18:30)

Отсутствует

 

Board footer

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