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

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

№127607-12-2023 12:32:35

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Dumby
Большое спасибо, то что нужно :beer:. Теперь можно выключить S3 :D


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

Отсутствует

 

№127707-12-2023 15:44:30

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Сделал отдельный скрипт на основе кнопки от Dumby «Быстрые опции about:config»: (меньше оригинала + некоторые улучшения)


Dumby, раз ты на связи, вот мои Хотелки и Проблемы к скрипту Быстрые опции:
1) сделать ввод значения текущей опции вручную через диалог ввода. Например в UserAgent > при клике по строке: "ваши данные…" нужно открыть диалог, где вводим нужные данные аналогично уже вшитым в другие строки этого подменю. После ввода или перезапуска браузера при открытии этого подменю строка "ваши данные…" должна быть выбрана флажком. Такой ввод данных пользователя нужен не для одной опции, а для многих: например в строке «Загрузки» нужна строка своих настроек…


2) надо, чтобы radio-строка подменю была выбрана (с флажком), если опция сброшена и отсутствует.
сделал костыль: pref.undef = [val,str] для pref: pref,lab,key,hint,[val,str],code
костыль делает строку меню такой: "Заголовок - str", но radio-строка подменю остаётся не выбранной.


3) при клике по родительской строке меню открывать эту опцию в about:config – функция about_config прилагается.
Это работает в ucf_hookClicks.js, но не пашет в этом коде, т.к. e.target определяется как кнопка, а не как текущая строка меню.


4) оригинальная кнопка "Быстрое переключение опций about:config" содержала два контекстных меню.
Прошу убрать код для нескольких меню: popups, popupshowing… (может попроще код станет).
Второе UserMenu другого формата и должно быть независимым, чтобы вызываться над разными кнопками.
0) странноcти кода – добавлял функцию switchTab через запятую в разной последовательности, но не
работает: ua = …}, switchTab = … Без запятой пашет: строка UserMenu не выдаст ошибку: no switchTab…

«Быстрые опции about:config» (не совместим с Custom Buttons)

Выделить код

Код:

/* Быстрые настройки меню опций about:config. Колёсико, Лев+Shift не закрывать
	Опция изменена: курсив; Цвет = ключ, по-умолчанию серый, иначе Red
	есть Def3el: несовпадения выделяются красной обводкой текста
	refresh=true ⟳ перечитать без кэша, restart=false ↯ без запроса 
pref: pref,lab,key,hint,[val,str],code | keys:val,lab,dat,+hint,code | icon:значок

	предыдущее значение: menu.pref.val
	Новое: newVal и trg.val данные
	trg.label метка keys:
*/

(async id =>{ var {prefs} = Services, db = prefs.getDefaultBranch("");
Pref = (key, set)=>{ //или key = [key,default]
	if (!Array.isArray(key)) key = [key];
	var t = prefs.getPrefType(key[0]), m = {b:"Bool",n:"Int",s:"String"};
	t = m[t == 128 ? "b" : t == 64 ? "n" : t == 32 ? "s" : ""];
	if (set == "get")
		return t; //тип опции
	if (!t)
		t = m[set != undefined ? (typeof set)[0] : (typeof key[1])[0]];
	if (t)
		if (set != undefined)
			prefs[`set${t}Pref`](key[0],set)
		else
			set = prefs[`get${t}Pref`](...key);
	return set;
}
Icon = (c = '0c0')=>"data:image/svg+xml;charset=utf-8,<svg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'><defs><linearGradient id='a' x1='16' x2='16' y1='32' gradientUnits='userSpaceOnUse'><stop stop-color='%23"+ c +"'/><stop stop-color='%23fff' offset='.8'/></linearGradient><linearGradient id='b' x2='32' y1='16' gradientTransform='matrix(1 0 0 1 2 2)'><stop stop-opacity='.5'/></linearGradient></defs><circle cx='16' cy='16' r='15' fill='url(%23a)' stroke='url(%23b)' stroke-width='2'/></svg>";
about_config = (filter) => { //на опцию
	if (gURLBar.value.startsWith("about:config")) switchTab(gURLBar.value);
	var setFilter = (e,input = (e?.target || window.content.document).getElementById("about-config-search")) => {	try {
		if (e || input.value != filter) input.setUserInput(filter);} catch{}
	},
	found = window.switchToTabHavingURI("about:config",true, {relatedToCurrent: true,
		triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()});
	if (found) setFilter(null,window);
	else gBrowser.selectedBrowser.addEventListener("pageshow",setFilter, {once: true});
};
ua = (real = false, ua_my = "general.useragent.override")=>{ //текущий или вшитый ЮзерАгент
	ttt = Pref(ua_my); prefs.clearUserPref(ua_my);
	ua = Cc["@mozilla.org/network/protocol;1?name=http"].getService(Ci.nsIHttpProtocolHandler).userAgent; //костыль
	ttt && Pref(ua_my, ttt);
	ttt ||= ua;
	if (real) ttt = ua;
	return ttt;
}
switchTab = (url = 'about:config', go)=>{ //открыть вкладку | закрыть её | выбрать
	for(var tab of gBrowser.visibleTabs)
		if (tab.linkedBrowser.currentURI.spec == url)
			{go ? gBrowser.selectedTab = tab : gBrowser.removeTab(tab); return;}
	gBrowser.addTrustedTab(url);
	gBrowser.selectedTab = gBrowser.visibleTabs[gBrowser.visibleTabs.length -1];
}
var uar = ua(true), //real ЮзерАгент
fonts = arr => arr.map(n => [(n == arr[arr.length-1] ? null : n), n]), //array с вложениями
serif = fonts("Arial|Roboto|Cantarell|Segoe UI|Cambria|Calibri".split('|')),
sans = [["Times","Times"], ...serif],
hints = new Map([ //опция отсутствует ? вернуть строку
	["general.useragent.override", "UserAgent"]]);

UserMenu = { //массив команд пользователя, alt() клик правой кнопкой
	"Настройки профайлера": {
		cmd(){switchTab('about:profiling')}
	},
	DwDir: {lab: `папка Загрузки`,
		cmd(){
			Downloads.getSystemDownloadsDirectory().then(path => FileUtils.File(path).launch(),Cu.reportError)},
		img: "chrome://devtools/skin/images/folder.svg"
	},
}
AboutCfg = [{
	pref: ["dom.disable_open_during_load", "Всплывающие окна"], Def3el: true, Yellow: false,
	keys: [[true, "Блокировать"], [false, "Разрешить"]],
},null,{
	pref: ["extensions.user_chrome_files.savedirs", "Загрузки",,'Пути сохранения Страниц и Графики\nСинтаксис «_Html/subdir|_Pics/subdir»\nsubdir: пусто | 0 заголовок | 1 домен',
		["", "всё в общей папке"]],
	Blue: "_Web|1|_Images|0", Gray: "",
	keys: [
		["_Сайты||_Фото|0", "_Сайты|_Фото/имя…"],
		["_Web|1|_Images|0", "_Web/сайт|_Images/имя"],
		["Сайт||Фото|", "ваши данные…",,"ключ в about:config", `console.log("введите ваши данные…")`]]
},{
	pref: ["general.useragent.override", "User Agent",,"Изменяет вид сайта", [uar,"встроенный"]],
		refresh: true, Def3el: uar,
	keys: [
	["Windows", "ваши данные…",,,`console.log("введите ваши данные…")`],
	["Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36", "Chrome 118 Win10"],
	["Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12 Version/12.16", "Opera12 W8"],
	["Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", "GoogleBot"],
	[uar, "по-умолчанию"]] //родной ЮзерАгент
}];

CustomizableUI.createWidget({ defaultArea: CustomizableUI.AREA_NAVBAR,
	label: "Журнал, Меню опций", localized: false, id: id,
	onCreated(btn) {
		btn.setAttribute("image", "chrome://devtools/skin/images/settings.svg");
		var doc = btn.ownerDocument, m = nn => doc.createXULElement(nn);
		btn.domParent = null;
		btn.popups = new btn.ownerGlobal.Array();
		this.createPopup(doc, btn, "config", AboutCfg);
		btn.linkedObject = this;
		for(var type of ["contextmenu", "command"])
			btn.setAttribute("on"+ type, `linkedObject.${type}(event)`);
		var popup = m("menupopup"), menu = m("menuitem");
		menu.m = m;
		menu.fill = this.fill;
		menu.render = this.render;
		popup.append(menu);
		btn.prepend(popup);
	},
	render(){
		var popup = this.parentNode;
		this.remove();
		this.fill(UserMenu, popup);
	},
	fill(o, popup){if (typeof o == "object") for (key in o){
		var {lab, sep, sub, cmd, alt, inf, img} = o[key];
		var name = sub ? "menu" : "menuitem";
		sep && popup.append(this.m("menuseparator"));
		var item = this.m(name);
		item.setAttribute("label", lab || key);
		if (img)
			item.className = name +"-iconic", item.setAttribute("image",img);
		if (inf) item.tooltipText = inf;
		item.alt = alt; //cmd2
		sub || cmd && item.setAttribute("oncommand", cmd.toString().replace(/cmd\(.*?\)/,''));
		/^(sub|sep|inf|lab|img)$/.test(key) || popup.append(item);
		sub && this.fill(o[key], item.appendChild(this.m("menupopup")));
	}},
	createPopup(doc, btn, prop, data) {
		var popup = doc.createXULElement("menupopup");
		btn.popups.push(btn[prop] = popup);
		popup.id = this.id +"-"+ prop;
		for (var type of ["popupshowing"])
			popup.setAttribute("on"+ type, `parentNode.linkedObject.${type}(event)`);
		for(var obj of data) popup.append(this.createElement(doc, obj));
		btn.append(popup);
	},
	createElement(doc, obj) { //pref
		if (!obj) return doc.createXULElement("menuseparator");
		var pref = doc.ownerGlobal.Object.create(null), node, bool, img;
		for(var [key, val] of Object.entries(obj)) {
			if (key == "pref") {
				var [apref, lab, akey, hint, undef, code] = val; //строка меню
				pref.pref = apref; pref.lab = lab || apref;
				if (hint) {
					if (RegExp(/\p{L}/,'u').test(hint[0]) && (hint[0] === hint[0].toUpperCase()))
						hint = '\n'+ hint;
					pref.hint = hint;
				}
				if (undef) pref.undef = undef; //если не массив: undef || undef == ""
				if (code) pref.code = code;
			}
			else if (key == "icon") img = val, pref.img = true;
			else if (key != "keys") pref[key] = val;
			else pref.hasVals = true;
		}
		var t = prefs.getPrefType(pref.pref), m = {b: "Bool", n: "Int", s: "String"};
		var str = m[t == prefs.PREF_INVALID ? obj.keys ? (typeof obj.keys[0][0])[0] : "b" : t == prefs.PREF_BOOL ? "b" : t == prefs.PREF_INT ? "n" : "s"]; //String по-умолчанию
		pref.get = prefs[`get${str}Pref`];
		var map, set = prefs[`set${str}Pref`];
		if (pref.hasVals) {
			for(var [val,,,,code] of obj.keys)
				code && (map || (map = new Map())).set(val, code);
			if (map) pref.set = (key, val) => {
				set(key, val);
				map.has(val) && eval(map.get(val)); //код2 если pref изменён
			}
		}
		if (!map) pref.set = set;
		node = doc.createXULElement("menu");
		node.className = "menu-iconic";
		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.keys,
			node.appendChild(doc.createXULElement("menupopup"))
		);
		if ("Def3el" in obj) pref.noAlt = !("Yellow" in obj);
		return node;
	},
	createRadios(doc, vals, popup) {
		for(var arr of vals) {
			var [val, lab, key, hint] = arr;
			var menuitem = doc.createXULElement("menuitem");
			with (menuitem)
				setAttribute("type","radio"), setAttribute("closemenu","none"), setAttribute("label", popup.parentNode.pref.vals[val] = lab), key && setAttribute("accesskey", key);
			var tip = menuitem.val = val === "" ? "[ пустая строка ]" : val;
			if (hint) tip += "\n" + hint;
			menuitem.tooltipText = `${tip != undefined ? tip + "\n\n" : ""}клик с Shift блокирует авто-закрытие`;
			popup.append(menuitem);
		}
	},
	regexpRefresh: /^(?:view-source:)?(?:https?|ftp)/,
	upd(node) {
		var {pref} = node, def = false, user = false, val; //если опция не найдена
		if (prefs.getPrefType(pref.pref) != prefs.PREF_INVALID) {
			try {
				val = pref.defVal = db[pref.get.name](pref.pref); def = true; //опция по-умолчанию получена
			} catch {def = false}
			user = prefs.prefHasUserValue(pref.pref);
			if (user) try {val = pref.get(pref.pref, undefined);} catch {}
		}
		if (val == pref.val && def == pref.def && user == pref.user) return;
		pref.val = val; pref.def = def; pref.user = user;
		var exists = def || user;
		if (!exists && pref.undef) //опции нет ? вернуть default
			val = pref.undef[0];
		var hint = hints.get(pref.pref);
		hint ||= val != undefined ? val : "Эта опция не указана";
		if (hint === "") hint = "[ пустая строка ]";
		hint += "\n" + pref.pref;
		if (pref.hint) hint += "\n"+ pref.hint;
		node.tooltipText = hint; //+ текст
		var img = Icon("999"), alt = "Yellow" in pref && val == pref.Yellow, clr = "Gray" in pref && val == pref.Gray, blu = "Blue" in pref && val == pref.Blue;
		if (blu) img = Icon("a0f");
		if (alt) img = Icon("f80");
		if ("Def3el" in pref)
			if (val == pref.Def3el)
				img = Icon(), node.style.removeProperty('filter');
			else if (val != pref.defVal) {
				if (!alt && !clr && !blu)
					img = Icon("f26"); // Red
				node.style.filter = "drop-shadow(1px 1px 1px #B8F)";
			}
		pref.img || node.setAttribute("image", img); //нет Def3el ? серый
		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 += ` ${"restart" in pref ? "↯-" : "refresh" in pref ? "-⟳" : "—"} ${sfx}`;
		}
		lab = exists ? lab : '['+ lab + `${"restart" in pref ? " ↯" : "refresh" in pref ? " ⟳" : ""}` +']'+ `${pref.undef ? " - "+ pref.undef[1] : ""}`;
		node.setAttribute("label", lab); //имя = [имя] если преф не существует
	},
	openPopup(popup) {
		var btn = popup.parentNode;
		if (btn.domParent != btn.parentNode) {
			btn.domParent = btn.parentNode;
			if (btn.matches(".widget-overflow-list > :scope"))
				var 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) {
		if (conf && !Services.prompt.confirm(null, this.label, "Перезапустить браузер?")) return;
		var cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
		Services.obs.notifyObservers(cancel, "quit-application-requested", "restart");
		return cancel.data ? Services.prompt.alert(null, this.label, "Запрос на выход отменён.") : this.restart();
	},
	async restart() {
		var meth = Services.appinfo.inSafeMode ? "restartInSafeMode" : "quit";
		Services.startup[meth](Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
	},
	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.shiftKey || e.button == 1) || trg.parentNode.hidePopup();
	},
	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 (!pref.val && pref.val != "" && pref.undef)
					pref.val = pref.undef[0]; //опции нет ? вернуть default
				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;
				}
			}
	},
	command(e, trg = e.target) { //LMB
		if (trg.id == id) {
			if (trg.config.state != "open")
				trg.menupopup.openPopup(trg, "after_start")
			else
				console.log("Здесь нужен переход на опцию about:config");
			return;
		}
		var menu = trg.closest("menu"), newVal = trg.val;
		if (!menu || !menu.pref) return;
		this.maybeClosePopup(e, menu);
		menu.pref.code && eval(menu.pref.code); //run1
		if (newVal != menu.pref.val)
			menu.pref.set(menu.pref.pref, newVal), this.maybeRe(menu, true);
	},
	contextmenu(e, trg = e.target) { //RMB
		if ((trg.id == id) && (!e.ctrlKey && !e.altKey && !e.shiftKey))
			if (trg.config.state != "open")
				this.openPopup(trg.config);
			else
			  trg.config.hidePopup();
		else if ("pref" in trg) {
			this.maybeClosePopup(e, trg);
			if (trg.pref.user)
				prefs.clearUserPref(trg.pref.pref), this.maybeRe(trg);
			trg.pref.code && eval(trg.pref.code); //run
		}
		e.preventDefault();
	}
});
})("ucf_AboutConfig");

Отсутствует

 

№127810-12-2023 19:48:49

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Dobrov пишет

1) сделать ввод значения текущей опции вручную через диалог ввода. Например в UserAgent > при клике по строке: "ваши данные…" нужно открыть диалог, где вводим нужные данные аналогично уже вшитым в другие строки этого подменю. После ввода или перезапуска браузера при открытии этого подменю строка "ваши данные…" должна быть выбрана флажком.

Попробовал это записать, но как-бы слегка снаружи.
Задержка, и, если ничего не выбрано и преф имеет пользовательское значение,
тогда выбираем строку "ваши данные…".


Врезка в createRadios() перед строкой popup.append(menuitem);
добавляем lab == "ваши данные…" && this.asInput(menuitem, val);


дополнительный стафф в объект

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

Выделить код

Код:

//
	asInput(menuitem, val) {
		menuitem.ttsfx = (menuitem.ittt = menuitem.tooltipText)
			.slice(String(menuitem.ival = val).length);
		menuitem.linkedObject = this;
		menuitem.setAttribute("oncommand", "linkedObject.input(event)");
		menuitem.render = this.renderInputOnce;
	},
	input(e) {
		e.stopImmediatePropagation();
		var trg = e.target, {pref} = trg.parentNode.parentNode;
		var res = {value: trg.tt ? pref.val : trg.ival};

		if (Services.prompt.prompt(
			null, `Введите значение (${pref.isInt ? "целое" : "строка"})`, pref.pref, res, null, {}
		)) {
			if (pref.isInt) {
				// from old about:config
				var val = res.value | 0;
				if (val != res.value - 0) return Services.prompt.alert(
					null, "Недействительное значение", 
					"Введённый вами текст не является числом."
				);
			}
			else val = res.value;
			pref.set(pref.pref, val);
		}
	},
	renderInputOnce() {
		delete this.render;
		this.render();
		var {pref} = this.parentNode.parentNode;
		pref.isInt = pref.get.name[3] == "I";
		if (!("val" in pref)) try {pref.val = pref.get(pref.pref);} catch {}

		this.linkedObject.hookUncheck(this); // for Shif+Click outside
		(this.render = this.linkedObject.renderInput).call(this);
	},
	hookUncheck(menuitem) {
		var rtt = function() {
			this.tt = false;
			this.tooltipText = this.ittt;
		}
		var desc = {configurable: true, enumerable: true, value(attr) {
			this.ownerGlobal.Element.prototype.removeAttribute.call(this, attr);
			attr.startsWith("c") && this.popup.state.startsWith("o") && this.parentNode.rtt();
		}};
		(this.hookUncheck = menuitem => {
			menuitem.rtt = rtt;
			var box = menuitem.firstChild;
			box.popup = menuitem.parentNode;
			menuitem.ownerGlobal.Object.defineProperty(box, "removeAttribute", desc);
		})(menuitem);
	},
	get renderInput() {
		delete this.renderInput;
		return this.renderInput = Cu.getGlobalForObject(Cu).eval(`(${async function() {
			await new Promise(this.ownerGlobal.requestAnimationFrame);

			var popup = this.parentNode, menu = popup.parentNode;
			menu.hasAttribute("_moz-menuactive") || this.linkedObject.popupshowing(null, popup, false); // force

			var checked = popup.querySelector("[checked]");
			var {pref} = menu, checkedThis = checked == this;

			if (checked && !checkedThis || !pref.user) return this.tt && this.rtt();

			this.tt = true;
			this.tooltipText = pref.val + this.ttsfx;
			if (checkedThis) return;

			menu.label = menu.label.replace(/другое$/, this.label);
			this.setAttribute("checked", true);
		}})`);
	},


и чуть модифицировать popupshowing()
чтобы была возможность пропустить проверку state
скрытый текст

Выделить код

Код:

/*
	popupshowing(e, trg = e.target) {
		if (trg.state == "closed") return;
*/
	popupshowing(e, trg = e.target, checkstate = true) {
		if (checkstate && trg.state == "closed") return;

2) надо, чтобы radio-строка подменю была выбрана (с флажком), если опция сброшена и отсутствует.
сделал костыль: pref.undef = [val,str] для pref: pref,lab,key,hint,[val,str],code
костыль делает строку меню такой: "Заголовок - str", но radio-строка подменю остаётся не выбранной.

Не понял. Какая radio-строка остаётся не выбранной?


Вот для extensions.user_chrome_files.savedirs есть pref.undef
и есть три radio-строки, но ни одна из них
не подходит быть выбранной если преф отсутствует.


И, даже если бы подходящая radio-строка была,
то что должно было бы происходить при её активации кликом?

3) при клике по родительской строке меню открывать эту опцию в about:config – функция about_config прилагается.
Это работает в ucf_hookClicks.js, но не пашет в этом коде, т.к. e.target определяется как кнопка, а не как текущая строка меню.

У себя вижу, что на кликнутое ссылается e.explicitOriginalTarget

4) оригинальная кнопка "Быстрое переключение опций about:config" содержала два контекстных меню.
Прошу убрать код для нескольких меню: popups, popupshowing… (может попроще код станет).

Да нет, особо попроще код не станет. В popupshowing здесь менять нечего,
а popups — да, не используется, можно почистить

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

Выделить код

Код:

....
		//btn.popups = new btn.ownerGlobal.Array();
....
		//btn.popups.push(btn[prop] = popup);
		btn[prop] = popup;
....
			//for(var p of btn.popups) p.setAttribute("position", pos);
			btn.config.setAttribute("position", pos);

0) странноcти кода – добавлял функцию switchTab через запятую в разной последовательности, но не
работает: ua = …}, switchTab = … Без запятой пашет: строка UserMenu не выдаст ошибку: no switchTab…

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


А вот если перед ua добавить var
то запятая станет частью var-синтаксиса
и switchTab перестанет быть глобальной переменной.
То есть, из атрибута "oncommand" его видно не будет.

Отсутствует

 

№127915-12-2023 17:46:47

b0ttle
Участник
 
Группа: Members
Зарегистрирован: 22-10-2020
Сообщений: 182
UA: Firefox 120.0

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Можно в ucf_aom-button.js как-то добавить функцию, как у unified_extensions_button, чтобы при клике вылазило окно, не настройки? Можно эти дополнения с меню, отдельно выделять используя тот шарик с цветом. Во, или на ПКМ посадить unified_extensions_button, а саму кнопку скрыть.

Отредактировано b0ttle (15-12-2023 17:55:26)

Отсутствует

 

№128016-12-2023 05:48:28

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

b0ttle пишет

Можно эти дополнения с меню, отдельно выделять используя тот шарик с цветом.

Не понял, нужен скриншот или подробные разьяснения.
Сделал, но пока не публиковал (ucf_hookClicks.js в процессе отладки):
Дополнения к меню опций от Dumby (работает, но переделываю по-своему, ещё изменю формат Setup = [{…)
Меню пользователя и прочие клики для unified_extensions_button работают и на старой кнопке Расширений "add-ons-button"


b0ttle пишет

Можно в ucf_aom-button.js как-то добавить функцию, как у unified_extensions_button, чтобы при клике вылазило окно, не настройки?

Вообще-то удобнее иконку скрипта ucf_aom-button.js убрать, а на правый клик unified_extensions_button назначить меню управления расширениями от ucf_aom-button (но не разбирался, как в этом скрипте привязать клики по меню, открытому из другой кнопки).

Отредактировано Dobrov (16-12-2023 06:30:12)

Отсутствует

 

№128116-12-2023 12:15:14

b0ttle
Участник
 
Группа: Members
Зарегистрирован: 22-10-2020
Сообщений: 182
UA: Firefox 120.0

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

 

Отредактировано b0ttle (29-12-2023 15:22:52)

Отсутствует

 

№128216-12-2023 15:37:58

b0ttle
Участник
 
Группа: Members
Зарегистрирован: 22-10-2020
Сообщений: 182
UA: Firefox 120.0

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

 

Отредактировано b0ttle (29-12-2023 15:23:02)

Отсутствует

 

№128317-12-2023 19:00:50

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

b0ttle пишет

попап таких расширений как ublock, tampermonkey, про это меню имелось ввиду, чтобы вместо двух кнопок была одна.

Нет, менюшки расширений не рассматриваются, и я не проверял их открытие над другой кнопкой, если кнопка расширения не закреплена на панели инструментов.
Правым кликом на unified-extensions-button открывается меню пользовательских команд (отлажу скрипт и для "add-ons-button" это меню добавлю)

Отсутствует

 

№128431-12-2023 13:27:12

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Обновил скрипта перехвата кликов-нажатий ucf_hookClicks.js — исправил ошибки несрабатывания некоторых команд пользовательского меню по клику из кнопок.


Cкрипт сохранения страниц SingleHTML.jsm исправлена связка Путь сохранения <-> установка пути из Опций быстрых настроек.


Всех с наступающим праздником!

Отсутствует

 

№128531-12-2023 15:23:29

Northtech
Участник
 
Группа: Members
Зарегистрирован: 16-04-2011
Сообщений: 261
UA: Firefox 121.0

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Dobrov
в новой версии ucf_hookClicks.js пропадает блок кнопок закрытия окна (#minimize-button, #restore-button, #close-button).

Отсутствует

 

№128631-12-2023 16:19:51

b0ttle
Участник
 
Группа: Members
Зарегистрирован: 22-10-2020
Сообщений: 182
UA: Firefox 121.0

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Northtech
Обычно скрываю эти кнопки, пользуюсь через PanelUI. Всех с новым годом.

Отредактировано b0ttle (19-01-2024 13:21:26)

Отсутствует

 

№128731-12-2023 19:37:43

Northtech
Участник
 
Группа: Members
Зарегистрирован: 16-04-2011
Сообщений: 261
UA: Firefox 121.0

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

b0ttle
Спасибо, помогло :)
я у себя их просто уменьшил, чтобы не такие огромные были.

#titlebar-buttonbox > .titlebar-button, .titlebar-buttonbox > :-moz-any(.titlebar-min,.titlebar-max,.titlebar-close,.titlebar-restore), #minimize-button, #restore-button, #close-button {
margin: 0 !important;
padding: 4px 8px !important;
}

Всех с праздником, наступившим и наступающим! :beer:

Отредактировано Northtech (31-12-2023 19:39:18)

Отсутствует

 

№128831-12-2023 22:03:49

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Northtech пишет

в новой версии ucf_hookClicks.js пропадает блок кнопок закрытия окна (#minimize-button, #restore-button, #close-button).

Попробуй включить "Кнопки управления окна" в диалоге "Настройки UserChromeFiles"

Отсутствует

 

№128919-02-2024 14:53:09

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Dumby посмотрите пожалуйста эти две кнопки  первая не работает

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

Выделить код

Код:

//Восстановить фавиконки закладок
(async () => {
    var id = "ucf-loads-favicons",
    label = "Восстановить фавиконки",
    tooltiptext = "Восстановить фавиконки закладок",
	    img = (rph => {
        var subst = "ucf-loads-favicons-btn-img";
        rph.setSubstitution(subst, Services.io.newURI(
           "data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16'><path style='fill:none;stroke:context-fill rgb(142, 142, 152);stroke-opacity:context-fill-opacity;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;' d='M3.6.6v14.8L8 11l4.4 4.4V.6z'/></svg>"    
		   ));
        return `resource://${subst}/`;
    })(Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler));
    maxrequests = 50, // Максимальное количество параллельных запросов
    maxtimeout = 30, // Длительность до прерывания запроса в секундах
    alertnotification = true; // Уведомление о завершении поиска фавиконок для закладок

    var favicons = {
        _favrunning: false,
        get alertsService() {
            delete this.alertsService;
            return this.alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
        },
        showAlert(title, val) {
            try {
                this.alertsService.showAlertNotification(img, title, val, false);
            } catch(e) {}
        },
        favSearchStart() {
            if (this._favrunning) return;
            this._favrunning = true;
            this.callWithEachWindow(id, {fill: "color-mix(in srgb, currentColor 20%, #e31b5d)"});
            PlacesUtils.promiseBookmarksTree(PlacesUtils.bookmarks.rootGuid).then(root => {
                var urlsList = [];
                var convert = (node, url) => {
                    if (node.children)
                        node.children.map(convert);
                    else if ((url = node.uri) && /^(?:https?|ftp|file):/.test(url))
                        urlsList.push(url);
                };
                convert(root);
                var favForPage = siteURI => {
                    return new Promise(resolve => {
                        try {
                            siteURI = Services.io.newURI(siteURI);
                        } catch(e) {
                            resolve(null);
                        }
                        PlacesUtils.favicons.getFaviconURLForPage(siteURI, uri => {
                            if (uri === null)
                                resolve(siteURI);
                            else
                                resolve(null);
                        });
                    });
                };
                Promise.all(urlsList.map(favForPage)).then(results => this.favSearchResults(results.filter(url => url !== null)));
            });
        },
        favComplete(favsuccesslength, favmaxlength) {
            this._favrunning = false;
            this.callWithEachWindow(id, {fill: ""});
            if (alertnotification)
                this.showAlert("Поиск фавиконок", `Успешно обработано - ${favsuccesslength}, не удалось обработать - ${favmaxlength - favsuccesslength}`);
        },
        favSearchResults(results) {
            var favmaxlength = results.length;
            var favsuccesslength = 0;
            if (!favmaxlength) {
                this.favComplete(0, 0);
                return;
            }
            var favmaxtimeout = maxtimeout * 1000;
            var _favmaxlength = favmaxlength;
            var splice = results.splice(0, maxrequests);
            var favSearchPage = siteURI => {
                (new Promise(resolve => {
                    try {
                        let req = new XMLHttpRequest();
                        req.mozBackgroundRequest = true;
                        req.open("GET", siteURI.spec, true);
                        req.responseType = "document";
                        req.overrideMimeType("text/html");
                        req.timeout = favmaxtimeout;
                        req.onload = () => {console.log(req)
                            try {
                                let doc = req.responseXML, favURI;
                                if (doc) {
                                    let links = doc.querySelectorAll("head link[href][rel~='icon']"), lastlink, is16, is32, isany;
                                    for (let link of links) {
                                        if (link.sizes.length === 1) {
                                            let size = link.sizes[0];
                                            if (/any/i.test(size))
                                                isany = link;
                                            else if (/32x32/i.test(size))
                                                is32 = link;
                                            else if (/16x16/i.test(size))
                                                is16 = link;
                                        }
                                        lastlink = link;
                                    }
                                    links = isany || is32 || is16 || lastlink;
                                    if (links)
                                        favURI = links.href;
                                }
                                if (!favURI)
                                    favURI = `${req.responseURL ? Services.io.newURI(req.responseURL).prePath : siteURI.prePath}/favicon.ico`;
                                let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
                                let request = PlacesUtils.favicons.setAndFetchFaviconForPage(siteURI, Services.io.newURI(favURI), false, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, {
                                    onComplete() {
                                        ++favsuccesslength;
                                        resolve();
                                        timer.cancel();
                                        timer = null;
                                        request = null;
                                    },
                                }, Services.scriptSecurityManager.getSystemPrincipal());
                                if (!request) {
                                    resolve();
                                    timer = null;
                                    return;
                                }
                                timer.initWithCallback(() => {
                                    resolve();
                                    try {
                                        request.cancel();
                                    } catch(e) {}
                                    timer = null;
                                    request = null;
                                }, favmaxtimeout, timer.TYPE_ONE_SHOT);
                            } catch(e) {
                                resolve();
                            }
                        };
                        req.onabort = () => {
                            resolve();
                        };
                        req.onerror = req.ontimeout = () => {
                            resolve();
                            req.abort();
                        };
                        req.send(null);
                    } catch(e) {
                        resolve();
                    }
                })).then(() => {
                    if (!(--_favmaxlength)) {
                        this.favComplete(favsuccesslength, favmaxlength);
                        return;
                    }
                    if (!results.length) return;
                    favSearchPage(results.shift());
                });
            };
            splice.map(favSearchPage);
        },
        callWithEachWindow(buttonID, atr) {
            var getW = CustomizableUI.getWidget(buttonID);
            if (getW.instances.length)
                for (let {node} of getW.instances) {
                    if (!node) continue;
                    for (let a in atr)
                        node.style.setProperty(a, atr[a]);
                }
            else
                for (let win of CustomizableUI.windows) {
                    let node = getW.forWindow(win).node;
                    if (!node) continue;
                    for (let a in atr)
                        node.style.setProperty(a, atr[a]);
                }
        },
    };
    CustomizableUI.createWidget({
        id: id,
        label: label,
        tooltiptext: tooltiptext,
        localized: false,
        defaultArea: CustomizableUI.AREA_NAVBAR,
        onCreated(btn) {
            btn.style.setProperty("list-style-image", `url("${img}")`, "important");
            if (favicons._favrunning)
                btn.style.setProperty("fill", "color-mix(in srgb, currentColor 20%, #e31b5d)");
        },
        onCommand(e) {
            favicons.favSearchStart();
        },
    });
})();

и в этой не оторажаються иконки поисковых систем
скрытый текст

Выделить код

Код:

//Искать в...............
(this.contextsearch = {
            topic: "browser-search-engine-modified",
            hide: "browser.search.hiddenOneOffs",
            defaultImg: "chrome://browser/skin/search-engine-placeholder.png",
            searchSelect: null,
            popup: null,
            init(that) {
                var searchSelect = this.searchSelect = document.querySelector("#context-searchselect");
                if (!searchSelect)
                    return;
                var popup = this.popup = searchSelect.closest("menupopup");
                popup.addEventListener("popupshowing", this);
                that.unloadlisteners.push("contextsearch");
            },
            destructor() {
                this.popup.removeEventListener("popupshowing", this);
                if (this.popupshowing == this.handler) {
                    this.popup.removeEventListener("popuphidden", this);
                    Services.obs.removeObserver(this, this.topic);
                    Services.prefs.removeObserver(this.hide, this);
                }
            },
            handleEvent(e) {
                this[e.type](e);
            },
            popupshowing(e) {
                var popup = this.popup;
                var searchSelect = this.searchSelect;
                if (e.target != popup || searchSelect.hidden) return;

                var menu = document.createXULElement("menu");
                menu.className = "menu-iconic";
                var menupopup = document.createXULElement("menupopup");
                menu.append(menupopup);
                menu.ePopup = menupopup;
                searchSelect.collapsed = true;
                searchSelect.before(menu);
                menu.onclick = this.search.bind(this);
                this.handler = ev => {
                    if (ev.target != popup) return;
                    menu.hidden = searchSelect.hidden;
                };
                this.handlerRebuild = () => this.handler(e) || this.rebuild(menu);
                this.popuphidden = ev => {
                    if (ev.target != popup) return;
                    menu.hidden = true;
                };
                this.popup.addEventListener("popuphidden", this);
                this.rebuild(menu);
            },
    getEngines() {
        var args = "hideOneOffButton" in Services.search.defaultEngine
            ? [e => !e.hideOneOffButton]
            : Object.defineProperty(
                [function(e) {return !this.includes(e.name);}], "1", {
                    get: () => Services.prefs.getStringPref(this.hide)?.split(",") || []
                }
            );
        return (this.getEngines = async () =>
            (await Services.search.getVisibleEngines()).filter(...args)
        )();
    },
    async rebuild(menu) {
        var de = Services.search.defaultEngine;
        de = de.wrappedJSObject || de;
        this.setAttrs(menu, de, `Искать в ${de.name} или в ...`);
        menu.ePopup.textContent = "";
        for(let engine of await this.getEngines()) {
                    if (engine == de) continue;
                    var menuitem = document.createXULElement("menuitem");
                    menuitem.className = "menuitem-iconic";
                    this.setAttrs(menuitem, engine);
                    menu.ePopup.append(menuitem);
                }
                this.popupshowing = this.handler;
                Services.obs.addObserver(this, this.topic, false);
                Services.prefs.addObserver(this.hide, this);
            },
            setAttrs(node, engine, label = engine.name) {
                node.engine = engine;
                node.setAttribute("label", label);
                node.setAttribute("image", engine.iconURI ? engine.iconURI.spec : this.defaultImg);
            },
            observe() {
                this.popupshowing = this.handlerRebuild;
                Services.obs.removeObserver(this, this.topic);
                Services.prefs.removeObserver(this.hide, this);
            },
            search(e) {
                var {engine} = e.target;
                if (!engine) return;
                var searchSelect = this.searchSelect;
                var submission = engine.getSubmission(
                    searchSelect.searchTerms, null, "contextmenu"
                );
                if (submission) {
                    let tab = gBrowser.addTab(submission.uri.spec, {
                        postData: submission.postData,
                        index: (gBrowser.selectedTab._tPos + 1),
                        triggeringPrincipal: searchSelect.principal
                    });
                    if (e.button == 0)
                        gBrowser.selectedTab = tab;
                }
                var popup = this.popup;
                e.button != 1 && popup.state == "open" && popup.hidePopup();
            }
        }).init(this);

  [firefox] 123.0

Отредактировано egorsemenov06 (19-02-2024 15:56:33)

Отсутствует

 

№129019-02-2024 15:40:28

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

egorsemenov06
У меня кнопка
//Искать в...............
от Vitaliy V. отвалилась давно. Перешёл на вариант Dumby, работает прекрасно ссылка. Хотя, как там на 123-й не знаю, не обновлялся.

Отредактировано xrun1 (19-02-2024 15:48:33)

Отсутствует

 

№129119-02-2024 17:32:09

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

egorsemenov06
Пробуйте..

Browser search engine

Выделить код

Код:

// ==UserScript==
// @name      Browser search engine
// @author    Vitaliy V.
// @include   main
// @shutdown  window.contextsearch.destructor();
// @note      https://forum.mozilla-russia.org/viewtopic.php?pid=780283#p780283
// ==/UserScript==

(this.contextsearch = {
    topic: "browser-search-engine-modified",
    hide: "browser.search.hiddenOneOffs",
    defaultImg: "chrome://browser/skin/search-engine-placeholder.png",
    searchSelect: null,
    popup: null,
    init(that) {
        var searchSelect = this.searchSelect = document.querySelector("#context-searchselect");
        if (!searchSelect)
            return;
        var popup = this.popup = searchSelect.closest("menupopup");
        popup.addEventListener("popupshowing", this);
        that.unloadlisteners?.push("contextsearch");
    },
    destructor() {
        this.popup.removeEventListener("popupshowing", this);
        if (this.popupshowing == this.handler) {
            this.popup.removeEventListener("popuphidden", this);
            Services.obs.removeObserver(this, this.topic);
            Services.prefs.removeObserver(this.hide, this);
        }
    },
    handleEvent(e) {
        this[e.type](e);
    },
    popupshowing(e) {
        var popup = this.popup;
        var searchSelect = this.searchSelect;
        if (e.target != popup || searchSelect.hidden) return;

        var menu = document.createXULElement("menu");
        menu.className = "menu-iconic";
        var menupopup = document.createXULElement("menupopup");
        menu.append(menupopup);
        menu.ePopup = menupopup;
        searchSelect.style.setProperty("display", "none", "important");
        searchSelect.before(menu);
        menu.onclick = this.search.bind(this);
        this.handler = e => e.target != popup || (menu.hidden = searchSelect.hidden);
        this.handlerRebuild = e => this.handler(e) || this.rebuild(menu);
        this.popuphidden = ev => {
            if (ev.target != popup) return;
            menu.hidden = true;
        };
        this.popup.addEventListener("popuphidden", this);
        this.rebuild(menu);
    },
    getEngines() {
        var args = "hideOneOffButton" in Services.search.defaultEngine
            ? [e => !e.hideOneOffButton]
            : Object.defineProperty(
                [function(e) {return !this.includes(e.name);}], "1", {
                    get: () => Services.prefs.getStringPref(this.hide)?.split(",") || []
                }
            );
        return (this.getEngines = async () =>
            (await Services.search.getVisibleEngines()).filter(...args)
        )();
    },
    async rebuild(menu) {
        var de = Services.search.defaultEngine;
        de = de.wrappedJSObject || de;
        this.setAttrs(menu, de, `Искать в ${de.name} или в ...`);
        menu.ePopup.textContent = "";
        for(let engine of await this.getEngines()) {
            if (engine == de) continue;
            var menuitem = document.createXULElement("menuitem");
            menuitem.className = "menuitem-iconic";
            this.setAttrs(menuitem, engine);
            menu.ePopup.append(menuitem);
        }
        this.popupshowing = this.handler;
        Services.obs.addObserver(this, this.topic, false);
        Services.prefs.addObserver(this.hide, this);
    },
    setAttrs(node, engine, label = engine.name) {
        node.engine = engine;
        node.setAttribute("label", label);
        node.setAttribute("image", engine._iconURI ? engine._iconURI.spec : engine.iconURI ? engine.iconURI.spec : this.defaultImg);
    },
    observe() {
        this.popupshowing = this.handlerRebuild;
        Services.obs.removeObserver(this, this.topic);
        Services.prefs.removeObserver(this.hide, this);
    },
    search(e) {
        var {engine} = e.target;
        if (!engine) return;
        var searchSelect = this.searchSelect;
        var submission = engine.getSubmission(
            searchSelect.searchTerms, null, "contextmenu"
        );
        if (submission) {
            let tab = gBrowser.addTab(submission.uri.spec, {
                postData: submission.postData,
                index: (gBrowser.selectedTab._tPos + 1),
                triggeringPrincipal: searchSelect.principal
            });
            if (e.button == 0)
                gBrowser.selectedTab = tab;
        }
        var popup = this.popup;
        e.button != 1 && popup.state == "open" && popup.hidePopup();
    }
}).init(this);


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

Отсутствует

 

№129219-02-2024 17:44:40

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Farby пишет

egorsemenov06
Пробуйте..

Browser search engine

Выделить код

Код:

// ==UserScript==
// @name      Browser search engine
// @author    Vitaliy V.
// @include   main
// @shutdown  window.contextsearch.destructor();
// @note      https://forum.mozilla-russia.org/viewtopic.php?pid=780283#p780283
// ==/UserScript==

(this.contextsearch = {
    topic: "browser-search-engine-modified",
    hide: "browser.search.hiddenOneOffs",
    defaultImg: "chrome://browser/skin/search-engine-placeholder.png",
    searchSelect: null,
    popup: null,
    init(that) {
        var searchSelect = this.searchSelect = document.querySelector("#context-searchselect");
        if (!searchSelect)
            return;
        var popup = this.popup = searchSelect.closest("menupopup");
        popup.addEventListener("popupshowing", this);
        that.unloadlisteners?.push("contextsearch");
    },
    destructor() {
        this.popup.removeEventListener("popupshowing", this);
        if (this.popupshowing == this.handler) {
            this.popup.removeEventListener("popuphidden", this);
            Services.obs.removeObserver(this, this.topic);
            Services.prefs.removeObserver(this.hide, this);
        }
    },
    handleEvent(e) {
        this[e.type](e);
    },
    popupshowing(e) {
        var popup = this.popup;
        var searchSelect = this.searchSelect;
        if (e.target != popup || searchSelect.hidden) return;

        var menu = document.createXULElement("menu");
        menu.className = "menu-iconic";
        var menupopup = document.createXULElement("menupopup");
        menu.append(menupopup);
        menu.ePopup = menupopup;
        searchSelect.style.setProperty("display", "none", "important");
        searchSelect.before(menu);
        menu.onclick = this.search.bind(this);
        this.handler = e => e.target != popup || (menu.hidden = searchSelect.hidden);
        this.handlerRebuild = e => this.handler(e) || this.rebuild(menu);
        this.popuphidden = ev => {
            if (ev.target != popup) return;
            menu.hidden = true;
        };
        this.popup.addEventListener("popuphidden", this);
        this.rebuild(menu);
    },
    getEngines() {
        var args = "hideOneOffButton" in Services.search.defaultEngine
            ? [e => !e.hideOneOffButton]
            : Object.defineProperty(
                [function(e) {return !this.includes(e.name);}], "1", {
                    get: () => Services.prefs.getStringPref(this.hide)?.split(",") || []
                }
            );
        return (this.getEngines = async () =>
            (await Services.search.getVisibleEngines()).filter(...args)
        )();
    },
    async rebuild(menu) {
        var de = Services.search.defaultEngine;
        de = de.wrappedJSObject || de;
        this.setAttrs(menu, de, `Искать в ${de.name} или в ...`);
        menu.ePopup.textContent = "";
        for(let engine of await this.getEngines()) {
            if (engine == de) continue;
            var menuitem = document.createXULElement("menuitem");
            menuitem.className = "menuitem-iconic";
            this.setAttrs(menuitem, engine);
            menu.ePopup.append(menuitem);
        }
        this.popupshowing = this.handler;
        Services.obs.addObserver(this, this.topic, false);
        Services.prefs.addObserver(this.hide, this);
    },
    setAttrs(node, engine, label = engine.name) {
        node.engine = engine;
        node.setAttribute("label", label);
        node.setAttribute("image", engine._iconURI ? engine._iconURI.spec : engine.iconURI ? engine.iconURI.spec : this.defaultImg);
    },
    observe() {
        this.popupshowing = this.handlerRebuild;
        Services.obs.removeObserver(this, this.topic);
        Services.prefs.removeObserver(this.hide, this);
    },
    search(e) {
        var {engine} = e.target;
        if (!engine) return;
        var searchSelect = this.searchSelect;
        var submission = engine.getSubmission(
            searchSelect.searchTerms, null, "contextmenu"
        );
        if (submission) {
            let tab = gBrowser.addTab(submission.uri.spec, {
                postData: submission.postData,
                index: (gBrowser.selectedTab._tPos + 1),
                triggeringPrincipal: searchSelect.principal
            });
            if (e.button == 0)
                gBrowser.selectedTab = tab;
        }
        var popup = this.popup;
        e.button != 1 && popup.state == "open" && popup.hidePopup();
    }
}).init(this);

Большое Спасибо эта рабоьает как надо !!!!!А с первой не поможите?

Отсутствует

 

№129319-02-2024 19:18:10

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

egorsemenov06 пишет

А с первой не поможите?

Это баг 1872673 - Remove 'console' export from Console.sys.mjs
То есть, дело не в коде кнопки, а в само́м UCF.


Но держать отладочный консольский стафф в кнопке постоянно
не требуется, можешь просто удалить console.log(req)


Однако, вернуть в укфский сандбокс консоль не помешает.
Я тут в user_chrome.js так переставлял

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

Выделить код

Код:

/*
                if ("defineLazyModuleGetters" in XPCOMUtils)
                    XPCOMUtils.defineLazyModuleGetters(scope, {
                        console: "resource://gre/modules/Console.jsm",
                        AddonManager: "resource://gre/modules/AddonManager.jsm",
                        AppConstants: "resource://gre/modules/AppConstants.jsm",
                        E10SUtils: "resource://gre/modules/E10SUtils.jsm",
                        FileUtils: "resource://gre/modules/FileUtils.jsm",
                        OS: "resource://gre/modules/osfile.jsm",
                        PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
                        setTimeout: "resource://gre/modules/Timer.jsm",
                        setTimeoutWithTarget: "resource://gre/modules/Timer.jsm",
                        clearTimeout: "resource://gre/modules/Timer.jsm",
                        setInterval: "resource://gre/modules/Timer.jsm",
                        setIntervalWithTarget: "resource://gre/modules/Timer.jsm",
                        clearInterval: "resource://gre/modules/Timer.jsm",
                    });
*/
                var data = {
                    AddonManager: null, AppConstants: null, E10SUtils: null, FileUtils: null, PlacesUtils: null,
                    Timer: ["setTimeout", "setTimeoutWithTarget", "clearTimeout", "setInterval", "setIntervalWithTarget", "clearInterval"]
                };
                var sfx, def, modules = {};
                var vers = parseInt(Services.appinfo.platformVersion);
                if (vers <= 114) data.osfile = "OS";
                if (vers <= 122) def = XPCOMUtils.defineLazyModuleGetters, sfx = "jsm", data.Console = "console";
                else def = ChromeUtils.defineESModuleGetters, sfx = "sys.mjs",
                    ChromeUtils.defineLazyGetter(scope, "console", () => Cu.getGlobalForObject(Cu).console.createInstance());
                var set = (key, val) => modules[key] = `resource://gre/modules/${val}.${sfx}`;
                for(var key in data) {
                    var val = data[key] || key;
                    if (Array.isArray(val)) for(var str of val) set(str, key);
                    else set(val, key);
                }
                def(scope, modules);

Отсутствует

 

№129419-02-2024 19:31:38

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

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

А с первой не поможите?

Это баг 1872673 - Remove 'console' export from Console.sys.mjs
То есть, дело не в коде кнопки, а в само́м UCF.


Но держать отладочный консольский стафф в кнопке постоянно
не требуется, можешь просто удалить console.log(req)


Однако, вернуть в укфский сандбокс консоль не помешает.
Я тут в user_chrome.js так переставлял

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

Выделить код

Код:

/*
                if ("defineLazyModuleGetters" in XPCOMUtils)
                    XPCOMUtils.defineLazyModuleGetters(scope, {
                        console: "resource://gre/modules/Console.jsm",
                        AddonManager: "resource://gre/modules/AddonManager.jsm",
                        AppConstants: "resource://gre/modules/AppConstants.jsm",
                        E10SUtils: "resource://gre/modules/E10SUtils.jsm",
                        FileUtils: "resource://gre/modules/FileUtils.jsm",
                        OS: "resource://gre/modules/osfile.jsm",
                        PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
                        setTimeout: "resource://gre/modules/Timer.jsm",
                        setTimeoutWithTarget: "resource://gre/modules/Timer.jsm",
                        clearTimeout: "resource://gre/modules/Timer.jsm",
                        setInterval: "resource://gre/modules/Timer.jsm",
                        setIntervalWithTarget: "resource://gre/modules/Timer.jsm",
                        clearInterval: "resource://gre/modules/Timer.jsm",
                    });
*/
                var data = {
                    AddonManager: null, AppConstants: null, E10SUtils: null, FileUtils: null, PlacesUtils: null,
                    Timer: ["setTimeout", "setTimeoutWithTarget", "clearTimeout", "setInterval", "setIntervalWithTarget", "clearInterval"]
                };
                var sfx, def, modules = {};
                var vers = parseInt(Services.appinfo.platformVersion);
                if (vers <= 114) data.osfile = "OS";
                if (vers <= 122) def = XPCOMUtils.defineLazyModuleGetters, sfx = "jsm", data.Console = "console";
                else def = ChromeUtils.defineESModuleGetters, sfx = "sys.mjs",
                    ChromeUtils.defineLazyGetter(scope, "console", () => Cu.getGlobalForObject(Cu).console.createInstance());
                var set = (key, val) => modules[key] = `resource://gre/modules/${val}.${sfx}`;
                for(var key in data) {
                    var val = data[key] || key;
                    if (Array.isArray(val)) for(var str of val) set(str, key);
                    else set(val, key);
                }
                def(scope, modules);

Большое Спасибо!!!!теперь отлично

Отсутствует

 

№129519-02-2024 21:43:04

b0ttle
Участник
 
Группа: Members
Зарегистрирован: 22-10-2020
Сообщений: 182
UA: Firefox 122.0

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

В шапке бы поправить ссылку на рабочую - "Восстановить фавиконки закладок".
Похож чем-то, с тем что выше. Тоже рабочий, пользуюсь. ucf_contextsearch.js
Да они идентичны, с мелкими различиями в коде)

Отредактировано b0ttle (19-02-2024 21:44:24)

Отсутствует

 

№129619-02-2024 22:12:42

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

b0ttle пишет

В шапке бы поправить ссылку

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

b0ttle пишет

Да они идентичны, с мелкими различиями в коде)

Если у вас все работает,

b0ttle пишет

Тоже рабочий, пользуюсь. ucf_contextsearch.js

пользуйтесь... Речь шла про 1945 год, ой про 123 найди различия...

Отредактировано Farby (19-02-2024 22:22:14)


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

Отсутствует

 

№129719-02-2024 23:25:44

b0ttle
Участник
 
Группа: Members
Зарегистрирован: 22-10-2020
Сообщений: 182
UA: Firefox 122.0

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Farby
Сорри, этот момент упустил. Вы его сами подправили, вроде разбирайтесь в коде?
Надеюсь, что обновят некоторые ссылки с первого поста, а так скорее затеряется.

Отредактировано b0ttle (19-02-2024 23:27:47)

Отсутствует

 

№129825-02-2024 06:52:58

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

b0ttle пишет

В шапке бы поправить ссылку на рабочую - "Восстановить фавиконки закладок".

Раз это не в скрипте проблема, шапку пока не менял.


Dumby пишет

Это баг 1872673 - Remove 'console' export from Console.sys.mjs
То есть, дело не в коде кнопки, а в само́м UCF.

Dumby - Благодарю! :beer:
Обновил на гитхабе chrome/user_chrome_files/user_chrome.js
в Demo-профиле - сборке полезных скриптов немного поправил:
user_chrome.js, UcfPrefs.jsm, ucf_UrlTooltip, ucf_contextmenuopenwith, ucf_contextsearch, ucf_hookClicks

Отсутствует

 

№129925-02-2024 12:00:42

b0ttle
Участник
 
Группа: Members
Зарегистрирован: 22-10-2020
Сообщений: 182
UA: Firefox 123.0

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Dobrov. Ура, ждал обновы)

Отсутствует

 

№130026-02-2024 08:26:11

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

Re: UCF - ваши кнопки, темы, дополнения, скрипты…

Dobrov пишет

Раз это не в скрипте проблема

Кстати, скрипт под багом ходит (1552815).
Движуха там затихла, но в любой момент это дело могут пнуть,
и баг вывалится как "FIXED". Прикинь тогда разгребать.

.jsm

А вот и баг о временах и сроках.


Может завести какую-нибудь папку с любым условным названием типа «129».
Запилить на неё readme, мол здесь вам (пока) не что-то готовое,
но всего лишь WIP-полигон миграции JSM —> ESM.


Это я в том смысле, что время пока есть,
и «подстелить соломку», а не чтобы как «снег на голову».
Совместимость, разумеется, может и должна быть сброшена.

Отсутствует

 

Board footer

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