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

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

№130117-03-2024 13:24:36

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

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

Dobrov пишет

добавить подключение стилей по имени в зависимости от OS

Да, но для стилей есть медиа запросы, например:
@media (-moz-platform: macos) {
   код для macos
}
@media (-moz-platform: linux) {
   код для linux
}
@media (-moz-platform: windows) {
   код для windows
}
Скрипты же тем более могут определить OS, я не против добавить но в каких случаях это необходимо?

Отсутствует

 

№130217-03-2024 13:57:49

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

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

Vitaliy V. пишет

Скрипты же тем более могут определить OS, я не против добавить но в каких случаях это необходимо?

Для портабельного или личного профиля, запускаемого и используемого на всяких OS.
В идеале лучше так: грузим стили из custom_styles, затем дополнительные CSS из папки, соответствующий имени операционки.
если браузер на MacOS находит папку custom_styles/macosx, догружаем custom_styles_all_agent.css и прочие CSS из неё.


Примеры стилей обычно только для винды, я пробовал @media (-moz-platform:, но неудобство в том, что придётся править стили при каждом их обновлении.
В стилях от aris-t2 есть совместимость для разных OS, но для Linux и MacOS всё же требуются дополнительные правки.
Проще разные CSS держать, т.к. CSS для MacOS и Windows слишком различаются, да и разные стили для AGENT_SHEET и USER_SHEET увеличивают число файлов.
из-за несовместимости версий Firefox я держу разные папки, например aris-t2-115+ и aris-t2-97…, но это уже другая история

Отредактировано Dobrov (17-03-2024 15:15:09)

Отсутствует

 

№130318-03-2024 20:30:25

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

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

_zt пишет

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

Не понял. Если сделал как написано в первой строке
конвертированного скрипта — значит изменился.


Неизменившийся у меня не работает, хотя мне казалось, что будет.
Но зачем искать себе приключений?
Для сконвертированных модулей следует использовать метод,
который сейчас в браузере для этого предназначен — ChromeUtils.importESModule("……….mjs");

И, пожалуйста, переделайте в mjs jsm-ки:

Хорошо, попробую.

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

Выделить код

Код:

var clickInterval = 5*60;
var intervals = [
	10, 15, 30, 60, 3*60,/* 5*60,*/ 15*60, 30*60, 60*60,
];
var name = "TreeStyleTabAutoReloader";
var addonId = "treestyletab@piro.sakura.ne.jp";
var sfx = "ucf-tst-tab-autoreload", id = `extension:${addonId}:${sfx}`;
var sheets = {
	def(name, css) {
		Object.defineProperty(this, name, {configurable: true, get() {
			delete this[name]; return this[name] = this.pre(name, css);
		}});
	},
	pre(name, css) {
		var ios = Services.io;
		var rph = ios.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
		var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
		var type = "USER_SHEET";
		return (this.pre = (name, css) => {
			var subst = "tst-autoreload-stylesheet-" + name;
			rph.setSubstitution(subst, ios.newURI("data:text/css," + encodeURIComponent(css)));
			return [sss.preloadSheet(ios.newURI(`resource://${subst}/`), sss[type]), Ci.nsIDOMWindowUtils[type]];
		})(name, css);
	}
};
if (!ChromeUtils.domProcessChild.childID) {

	var ep = "resource://gre/modules/ExtensionParent.sys.mjs";
	var manager = ChromeUtils.importESModule(ep).ExtensionParent.apiManager;
	var tt = manager.global.tabTracker;
	var ss = "resource:///modules/sessionstore/SessionStore.sys.mjs";
	ss = ChromeUtils.importESModule(ss).SessionStore;
	var gsec = tab => ss.getCustomTabValue(tab, id);

	var webExt, addonUUID;
	
	var waitAddon = (e, isAppShutdown) => isAppShutdown || (
		webExt = null, manager.on("ready", onReady)
	);
	var onReady = (e, addon) => {
		if (addon.id != addonId) return;
		manager.off("ready", onReady);
		addon.once("shutdown", waitAddon);
		onAddon(addon);				
	}
	var onAddon = addon => {
		webExt = addon;
		if (addonUUID == addon.uuid) return;

		addonUUID && ChromeUtils.unregisterWindowActor(name);

		var esModuleURI = Components.stack.filename;
		ChromeUtils.registerWindowActor(name, {
			parent: {esModuleURI},
			remoteTypes: ["extension"],
			messageManagerGroups: ["webext-browsers"],
			child: {esModuleURI, events: {pageshow: {}}},
			matches: [`moz-extension://${addonUUID = addon.uuid}/sidebar/sidebar.html?*`]
		});
	}
	var format = sec => {
		var map = new Map();
		// resource://gre/modules/PluralForm.jsm
		var f = n => n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
		var hh = ["", "а", "ов"], ms = ["а", "ы", ""];
		return (format = sec => {
			var res = map.get(sec = +sec);
			if (!res) {
				var num, arr = [];
				if ((num = Math.floor(sec / 3600)) > 0)
					sec -= num * 3600,
					arr.push(`${num} час${hh[f(num)]}`);
				if ((num = Math.floor(sec / 60)) > 0)
					sec -= num * 60,
					arr.push(`${num} минут${ms[f(num)]}`);
				sec > 0 && arr.push(`${sec} секунд${
					sec > Math.floor(sec) ? "ы" : ms[f(sec)]
				}`);
				map.set(sec, res = arr.join(" "));
			}
			return res;
		})(sec);
	}
	var hasDef = intervals.includes(clickInterval);
	hasDef || intervals.push(clickInterval);
	sheets.def("sb", `
		#context_autoreloadTab:not([checked]) > .menu-iconic-left,${
			hasDef ? "" : "\n\t\t#context_autoreloadTab[checked][def=true] > menupopup > :nth-child(2),"
		}
		#context_autoreloadTab:not([checked]) > menupopup > :first-child {
			fill: gray !important;
			-moz-context-properties: fill !important;
			list-style-image: url("chrome://global/skin/icons/reload.svg") !important;
		}
		#context_autoreloadTab[checked] > .menu-iconic-left > image {
			fill: currentColor !important;
			-moz-context-properties: fill !important;
			list-style-image: url("chrome://global/skin/icons/check.svg") !important;
		}
	`);
	clickInterval = String(clickInterval);

	var sym = Symbol(name);
	var TreeStyleTabAutoReloaderParent = class extends JSWindowActorParent {
		actorCreated() {
			var win = this.browsingContext.embedderElement.ownerGlobal;
			var mo = win[sym];
			if (!mo) {
				win.windowUtils.addSheet(...sheets.sb);
				mo = win[sym] = new win.MutationObserver(this.handleMutations);
				var popup = win.document.getElementById("contentAreaContextMenu");
				mo.obs = mo.observe.bind(mo, popup, {childList: true});
				mo.win = win;
			}
			((mo.actor = this).mo = mo).obs();
		}
		didDestroy() {
			this.mo.disconnect();
		}
		get menu() {
			var value = this.mo.menu;
			if (!value) {
				value = this.mo.win.MozXULElement.parseXULToFragment(
					`<menu id="context_autoreloadTab"
						class="menu-iconic"
						onclick="if (event.target == this) linkedObject.click(this);"
					>
						<menupopup oncommand="parentNode.linkedObject.cmd(event);"/>
					</menu>`
				);
				(value = this.mo.menu = value.firstChild).remove();
				value.linkedObject = this;
				(value.popup = value.firstChild).initShadowDOM = this.initShadowDOM;
			}
			return Object.defineProperty(this, "menu", {value}).menu;
		}
		initShadowDOM() {
			delete this.initShadowDOM;
			this.initShadowDOM();

			var df = this.ownerGlobal.MozXULElement.parseXULToFragment(
				`<menuitem closemenu="single" label="Не перезагружать"
					oncommand="event.stopPropagation(); parentNode.parentNode.click();"/>
				<menuitem label="Другой…"
					oncommand="event.stopPropagation(); parentNode.parentNode.linkedObject.prompt();"/>
				<menuseparator/>`
			);
			var doc = this.ownerDocument;

			for(var sec of intervals) {
				var menuitem = doc.createXULElement("menuitem");
				menuitem.setAttribute("type", "radio");
				menuitem.setAttribute("closemenu", "single");
				menuitem.setAttribute("value", sec);
				menuitem.setAttribute("label", format(sec));
				df.append(menuitem);
			}
			hasDef || df.firstChild.after(df.lastChild);
			this.append(df);
			this.parentNode.linkedObject.updMenupopup(this);
			this.setAttribute("onpopupshowing", "parentNode.linkedObject.updMenupopup(this);");
		}
		handleMutations(muts) {
			var cm = this.win.gContextMenu;
			if (cm) for(var mut of muts) for(var node of mut.addedNodes)
				if (node.id == "treestyletab_piro_sakura_ne_jp-menuitem-_context_duplicateTab") {
					var {tabId} = cm.contentData.webExtContextData;
					var tab = tt.getTab(tabId);
					//if (tab?.linkedBrowser.currentURI.scheme.startsWith("http")) {
					if (tab) {
						var {menu} = this.actor;
						menu.tabId = tabId;
						node.after(menu);
						this.actor.maybeSetLabel(tab);
						webExt.apiManager.global.gMenuBuilder.itemsToCleanUp.add(menu);
					}
					break;
				}
		}
		maybeSetLabel(tab) {
			var sec = gsec(tab);
			var has = this.menu.hasAttribute("checked");
			if (Boolean(sec) ^ has)
				has = !has, this.menu.toggleAttribute("checked");

			var curr = has && sec;
			curr !== this.menu.sec && this.setLabel(curr);
		}
		setLabel(sec) {
			this.menu.setAttribute("label", (this.menu.sec = sec)
				? `Интервал перезагрузки:   ${format(sec)}`
				: "Задать интервал перезагрузки"
			);
			hasDef || this.menu.setAttribute("def", sec == clickInterval);
		}
		click(menu) {
			var {tabId} = menu;
			var has = menu.toggleAttribute("checked");
			has
				? this.initTab(tabId, clickInterval)
				: this.destroyTab(tabId);

			var w = menu.clientWidth;
			this.setLabel(has && clickInterval);

			if (menu.popup.state == "open")
				this.updMenupopup(menu.popup),
				menu.clientWidth != w && menu.ownerGlobal.setTimeout(this.move, 50, menu);
		}
		cmd(e) {
			var {value} = e.target;
			if (value == this.menu.sec) return;

			var {tabId} = this.menu;
			this.setLabel(value);

			if (this.menu.hasAttribute("checked"))
				this.changeInterval(tt.getTab(tabId), value);
			else
				this.menu.toggleAttribute("checked"),
				this.initTab(tabId, value);
		}
		changeInterval(tab, sec) {
			var win = tab.ownerGlobal;
			win.clearInterval(tab.getAttribute(sfx));
			ss.setCustomTabValue(tab, id, sec);
			tab.setAttribute(sfx, win.setInterval(bro.reload, sec * 1e3, tab));
		}
		async prompt(val) {
			var {menu} = this, {sec} = menu, {prompt} = Services;
			var res = await prompt.asyncPrompt(
				null, prompt.MODAL_TYPE_WINDOW,
				val ? "ЕЩЁ РАЗ:" : "Задать интервал обновления",
				"Введите число секунд авто-обновления",
				val || sec || clickInterval, null, null
			);
			if (!res.get("ok")) return;

			var val = res.get("value");
			if (!val) return;
			if (!isFinite(val)) return this.prompt(val);

			var {tabId} = menu, val = String(Math.round(val) || 1);
			sec ? this.changeInterval(tt.getTab(tabId), val) : this.initTab(tabId, val);
		}
		move(menu) {
			menu.popup.moveToAnchor(menu, "end_before");
		}
		updMenupopup(popup) {
			var old = popup.querySelector("[checked=true]");
			var {sec} = this.menu;
			var cur = sec && popup.querySelector(`[value="${sec}"]`);
			if (old != cur)
				old?.removeAttribute("checked"),
				cur && cur.setAttribute("checked", true);
		}
		initTab(tabId, sec, skipSet) {
			bro.initTab(tt.getTab(tabId), sec);
			this.sendAsyncMessage(tabId, true);
		}
		destroyTab(tabId) {
			bro.destroyTab(tt.getTab(tabId));
			this.sendAsyncMessage(tabId);
		}
		receiveMessage(msg) {
			msg.name && bro.destroyTab(tt.getTab(+msg.name));
		}
	}
	var bro = {
		async observe(win) {
			var tc = win.document.getElementById("tabbrowser-tabs");
			var tp = win.document.getElementById("tabbrowser-tabpanels")
			var types = ["EndSwapDocShells", "TabClose", "SSTabRestored"];

			var destructor = (meth = "removeEventListener") => types.forEach(
				(type, ind) => (ind ? tc : tp)[meth](type, this, ind == 0)
			);
			destructor("addEventListener");

			win.ucf_custom_script_win[id] = {destructor};
			win.ucf_custom_script_win.unloadlisteners.push(id);

			await ss.promiseAllWindowsRestored;
			for(var tab of win.gBrowser.tabs)
				tab.linkedPanel || this.maybeInitTab(tab);
		},
		maybeInitTab(tab) {
			var sec = gsec(tab);
			sec && this.initTab(tab, sec, true);
		},
		handleEvent(e) {
			this[e.type](e);
		},
		reload(tab) {
			tab.ownerGlobal.gBrowser.reloadTab(tab);
		},
		initTab(tab, sec, skipSet) {
			skipSet || ss.setCustomTabValue(tab, id, sec);
			tab.setAttribute(sfx, tab.ownerGlobal.setInterval(this.reload, sec * 1e3, tab));
		},
		destroyTab(tab) {
			tab.ownerGlobal.clearInterval(tab.getAttribute(sfx));
			ss.deleteCustomTabValue(tab, id);
			tab.removeAttribute(sfx);
		},
		TabClose(e) {
			var intervalId = e.target.getAttribute(sfx);
			if (!intervalId) return;
			e.target.ownerGlobal.clearInterval(intervalId);

			var tab = e.detail.adoptedBy;
			tab && this.initTab(tab, gsec(e.target));
		},
		SSTabRestored(e) {
			var tab = e.target;
			tab.hasAttribute(sfx) || this.maybeInitTab(tab);
		},
		async EndSwapDocShells(e) {
			var br = e.detail, trg = e.target, win = br.ownerGlobal;
			await new Promise(win.requestAnimationFrame);

			if (!win.closed) return;
			var tab = win.gBrowser.getTabForBrowser(br);
			if (!tab) return;

			var sec = gsec(tab);
			if (sec)
				tab = trg.ownerGlobal.gBrowser.getTabForBrowser(trg),
				tab.hasAttribute(sfx) || this.initTab(tab, sec);
		}
		
	};
	var topic = "browser-delayed-startup-finished";
	var {obs} = Services;

	obs.addObserver(bro, topic);
	obs.addObserver(function quit(s, t) {
		obs.removeObserver(quit, t);
		obs.removeObserver(bro, topic);
	}, "quit-application-granted");

	var policy = WebExtensionPolicy.getByID(addonId);
	if (policy)
		onAddon(policy.extension),
		policy.extension.once("shutdown", waitAddon);
	else
		waitAddon();

} else {
	sheets.def("tst", `
		:root {
			--ar-ind-width: 22px;
		}
		.autoreload-indicator {
			height: 14px !important;
			position: relative !important;
			z-index: var(--tab-ui-z-index) !important;

			opacity: .6 !important;
			fill: currentColor !important;
			-moz-context-properties: fill !important;
			min-width: var(--ar-ind-width) !important;
			background: no-repeat center/60% url("chrome://global/skin/icons/reload.svg") !important;
		}
		.autoreload-indicator:hover {
			opacity: 1 !important;
		}
		tab-item-substance[autoreload] > .extra-items-container.front {
			right: calc(var(--tab-label-end-offset) + var(--ar-ind-width)) !important;
		}
		tab-item.faviconized .autoreload-indicator {
			min-width: 12px !important;
			background-size: 100% !important;
		}
		tab-item.faviconized > tab-item-substance[autoreload] {
			padding-inline-start: 0 !important;
		}
	`);
	var opts = {childList: true};

	var TreeStyleTabAutoReloaderChild = class extends JSWindowActorChild {
		handleEvent(e) {
			this.sendAsyncMessage("");
			this.stopReload = this.stopReload.bind(this);

			var doc = e.target, win = doc.ownerGlobal;
			win.windowUtils.addSheet(...sheets.tst);
			var mos = this.mos = new Set();

			for(var div of doc.querySelectorAll(
				"#pinned-tabs-container, #normal-tabs-container > .virtual-scroll-container"
			)) {
				var mo = new win.MutationObserver(this.catchUL);
				mos.add(mo);
				mo.actor = this;
				mo.observe(mo.div = div, opts);
			}
		}
		catchUL() {
			var ul = this.div.querySelector(":scope > ul");
			if (!ul) return;
			this.disconnect();
			this.actor.mos.delete(this);

			var mo = new this.constructor(this.actor.catchTabItem);
			(mo.actor = this.actor).mos.add(mo);
			mo.observe(ul, opts);
			for(var node of ul.children) mo.actor.check(node);
		}
		catchTabItem(muts) {
			for(var mut of muts) for(var node of mut.addedNodes) this.actor.check(node);
		}
		check(node) {
			node.nodeName == "TAB-ITEM" && this.onTab(node);
		}
		async onTab(tab, tabId) {
			var subs = tab.querySelector("tab-item-substance");
			var win = tab.ownerDocument.defaultView.wrappedJSObject;
			if (!tabId) {
				if (subs.hasAttribute("autoreload"))
					subs.removeAttribute("autoreload"),
					subs.querySelector(".autoreload-indicator")?.remove();

				var {tabId} = subs.dataset;
				var sec = await win.browser.sessions.getTabValue(+tabId, sfx);
				if (!sec) return;
			}
			subs.toggleAttribute("autoreload", true);
			var ind = win.document.createElement("span");
			ind.className = "autoreload-indicator";
			ind.title = "Остановить перезагузку";
			ind.tabId = tabId;
			ind.onmousedown = this.stopReload;
			subs.querySelector("tab-closebox").before(ind);
		}
		stopReload(e) {
			if (e.button) return;
			e.stopImmediatePropagation();
			var trg = e.target.wrappedJSObject;
			this.sendAsyncMessage(trg.tabId);
			this.removeIndicator(trg);
		}
		removeIndicator(ind) {
			ind.closest("tab-item-substance").removeAttribute("autoreload");
			ind.remove();
		}
		receiveMessage(msg) {
			var tab = this.contentWindow.document.getElementById("tab-" + msg.name);
			if (tab) msg.data
				? this.onTab(tab, msg.name)
				: this.removeIndicator(tab.querySelector(".autoreload-indicator"));
		}
		didDestroy() {
			var {mos} = this;
			if (!mos) return;
			for(var mo of mos) mo.disconnect();
			mos.clear();
		}
	}
}
export {TreeStyleTabAutoReloaderParent, TreeStyleTabAutoReloaderChild};

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

Выделить код

Код:

var timeout = 500;

if (!ChromeUtils.domProcessChild.childID) {

	var popupWidth = 300;

	var label = "Some Label";
	var tooltiptext = "Some Tooltip Text";
	var imgEnabled = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" height="16"><rect fill="limegreen" width="16" height="16"/></svg>';
	var imgDisabled = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" height="16"><rect fill="orangered" width="16" height="16"/></svg>';


	var btnImage, popupPosition, enabled, addonUUID, registeredUUID;
	var mo = (p, r = "gre") => ChromeUtils.importESModule(`resource://${r}/modules/${p}.sys.mjs`)[p];

	//-------[ Addon ]------------------------------------------------------

	var addonId = "treestyletab@piro.sakura.ne.jp";
	var manager = mo("ExtensionParent").apiManager;
	var tt = manager.global.tabTracker;

	var waitAddon = (e, isAppShutdown) => isAppShutdown || (
		addonUUID = null, manager.on("ready", onReady)
	);
	var onReady = (e, addon) => {
		if (addon.id != addonId) return;
		manager.off("ready", onReady);
		addon.once("shutdown", waitAddon);
		addonUUID = addon.uuid;
		checkRegistration();
	}
	waitAddon();

	//-------[ Actor registration ]------------------------------------------------------

	var name = "TreeStyleTabPreviewPopup";

	var esModuleURI = Components.stack.filename;
	var reg = () => ChromeUtils.registerWindowActor(name, {
		parent: {esModuleURI},
		remoteTypes: ["extension"],
		messageManagerGroups: ["webext-browsers"],
		child: {esModuleURI, events: {mouseover: {}}},
		matches: [`moz-extension://${registeredUUID = addonUUID}/sidebar/sidebar.html*`]
	});
	var unreg = () => {
		registeredUUID = null;
		ChromeUtils.unregisterWindowActor(name);
	}
	var checkRegistration = () => {
		if (enabled) {
			if (registeredUUID) {
				if (registeredUUID == addonUUID) return;
				addonUUID && unreg();
			}
			addonUUID && reg();
		}
		else if (registeredUUID && addonUUID) unreg();
	}

	//------[ Observer ]------------------------------------------------------

	var {prefs, obs} = Services;
	var pref = "ucf_tst_preview_popup";
	var branch = prefs.getBranch("sidebar.");

	var prefObs = {
		observe(b, t, data) {
			this[data]?.(branch.getBoolPref(data, true));
		},
		position_start: val => popupPosition = val ? "end_before" : "start_before",
		[pref](val) {
			btnImage = (enabled = val) ? imgEnabled : imgDisabled;
			this.setBtnsImg();
			checkRegistration();
		},
		setBtnsImg: () => prefObs.setBtnsImg = () => {
			var widget = cui.getWidget(btnId);
			for(var win of cui.windows)
				widget.forWindow(win).node?.setAttribute("image", btnImage);
		}
	};
	for (let p of [pref, "position_start"]) prefObs.observe(null, null, p);

	branch.addObserver("", prefObs);
	obs.addObserver(function quit(s, topic) {
		obs.removeObserver(quit, topic);
		branch.removeObserver("", prefObs);
	}, "quit-application-granted");

	//-------[ Widget ]------------------------------------------------------

	var popupId = "ucf-tst-preview-popup";
	var btnId = popupId + "-button";
	var cui = mo("CustomizableUI", "");
	var toggle = () => branch.setBoolPref(pref, !enabled);

	cui.createWidget({
		id: btnId, label, tooltiptext, localized: false,
		onCreated(btn) {
			btn._handleClick = toggle;
			btn.setAttribute("image", btnImage);
		}
	});

	//-------[ Actor ]------------------------------------------------------

	var TreeStyleTabPreviewPopupParent = class extends JSWindowActorParent {
		actorCreated() {
			var doc = this.browsingContext.topChromeWindow.document;
			var popup = doc.getElementById(popupId);
			if (!popup) {
				popup = doc.createXULElement("menupopup");
				popup.id = popupId;
				popup.setAttribute("ignorekeys", true);
				popup.setAttribute("rolluponmousewheel", true);
				popup.setAttribute("consumeoutsideclicks", "never");
				popup.shadowRoot.querySelector("style").append(`
					:host {
						padding: 0 !important;
						-moz-appearance: none !important;
					}
					arrowscrollbox::part(scrollbutton-up),
					arrowscrollbox::part(scrollbutton-down) {
						display: none !important;
					}
				`);
				(popup.canvas = popup.appendChild(doc.createElement("canvas")))
					.width = popupWidth;
				popup.context = popup.canvas.getContext("2d", {alpha: false});
				doc.getElementById("mainPopupSet").append(popup);
			}
			this.popup = popup;
		}
		receiveMessage(msg) {
			var id = msg.data;
			if (!id) return this.popup.hidePopup();

			var tab = tt.getTab(+id.slice(4));
			if (tab/* && !tab.selected*/) {
				var cwg = tab.linkedBrowser.browsingContext?.currentWindowGlobal;
				cwg && this.drawSnapshot(tab.ownerGlobal, cwg, id);
			}
		}
		async drawSnapshot(win, cwg, id) {
			var {width, height} = await cwg.getActor("Thumbnails")
				.sendQuery("Browser:Thumbnail:ContentInfo");
			if (width < 200) return;

			var k = popupWidth / width;
			try {var bitmap = await cwg.drawSnapshot(
				new DOMRect(0, 0, width, height), k, "white"
			);} catch {}

			if (!bitmap) return;
			var data = await this.sendQuery(id, win.devicePixelRatio);
			if (!data) return;

			this.popup.canvas.height = k * height;
			this.popup.context.drawImage(bitmap, 0, 0);
			bitmap.close();
			this.popup.openPopupAtScreenRect(popupPosition, ...data);

		}
		didDestroy() {
			this.popup.hidePopup();
			this.popup = null;
		}
	}
}
export {TreeStyleTabPreviewPopupParent};

export class TreeStyleTabPreviewPopupChild extends JSWindowActorChild {
	actorCreated() {
		this.args = ["mouseleave", () => {
			this.tab = null;
			this.tid || this.sendAsyncMessage("");
			this.tid = this.clearTimeout();
		}, {once: true}];
	}
	mult(val) {
		return this * val;
	}
	receiveMessage(msg) {
		var tab = this.document.getElementById(msg.name);
		var res = tab?.matches(":hover");
		if (res) {
			var {x, y, width, height} = tab.getBoundingClientRect();
			var win = tab.ownerGlobal;
			res = [
				x + win.mozInnerScreenX,
				y + win.mozInnerScreenY,
				width, height
			];
			var z = win.devicePixelRatio;
			if (z != 1 || msg.data != 1)
				res = res.map(this.mult, z / msg.data);
		}
		return res;
	}
	handleEvent(e) {
		var tab = e.target.closest("tab-item");
		if (!tab || tab == this.tab) return;
		this.clearTimeout();
		this.tid = this.contentWindow
			.setTimeout(this.onTab, timeout, this.tab = tab, this);
		tab.addEventListener(...this.args);
	}
	clearTimeout() {
		this.tid && this.contentWindow.clearTimeout(this.tid);
	}
	onTab(tab, self) {
		self.tid = null;
		tab.wrappedJSObject.apiTab.discarded
			|| self.sendAsyncMessage("", tab.id);
	}
	didDestroy() {
		this.tab = null;
	}
}

Dobrov пишет

такой глупый вопрос: JS скрипты будут дóльше поддерживаться в Firefox, чем JSM-ки?

Ну почему, не такой уж глупый, если имеются в виду
ChromeMessageBroadcaster.loadFrameScript()
и ParentProcessMessageManager.loadProcessScript()


Увы, в обозримом прошлом и настоящем,
мне как-то не попадалось ничего об их судьбе, так что сказать нечего.

возможно переделать в JS скрипт сохранения страниц SingleHTML.JSM

А вот это уже глупее.
Вместо простой конвертации в ESM, нахлобучиться затеять такую затею.


Кстати, а чего там win до сих пор торчит? fp.init(win, "", fp.modeSave);
Разве это не видел?
Для Fifefox 125+ вместо win уже нужен win.browsingContext


Vitaliy V.
Просто информационное сообщение, раз уж на глаза попалось.
Bug 1884792 - Consider making -moz-lwtheme a media query.


Удаление псевдокласса :-moz-lwtheme уже пошло в autoland,
а он используется в vertical_top_bottom_bar.css в двух местах.

Отсутствует

 

№130419-03-2024 01:47:00

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

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

Dumby пишет

Для Fifefox 125+ вместо win уже нужен win.browsingContext (Bug 1878401)

А как сделать, чтоб скрипт SingleHTML.mjs был совместим с FF115+ …… FF125+ ?
не понимаю, как этот win.browsingContext прописывать! SingleHTML править или из других скриптов вызывать иначе ?
1) fp.init(win || win.browsingContext, "", fp.modeSave);
2) Cu.getGlobalForObject(Cu)[Symbol.for("SingleHTML")](to, window.browsingContext)


посмотрел custom_buttons-0.0.7.0.0.33-fx. У тебя в SelfHelper.jsm:
picker(doc) { ……… var win = doc.ownerGlobal;
в SingleHTML (почти весь код твой): async SingleHTML(to, win = this.ownerGlobal)

SingleHTML.mjs (или JSM, если child: {moduleURI: __URI__})

Выделить код

Код:

/* SingleHtml © Лекс, правка Dumby, mod Dobrov
вызов: Cu.getGlobalForObject(Cu)[Symbol.for("SingleHTML")](to, window)
scriptsbackground [System Principal], «to» пуст: выбор пути */

var self, name = "SingleHTML", EXPORTED_SYMBOLS = [name + "Child"];
var {io, focus, obs, prefs, dirsvc} = globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services;

export class SingleHTMLChild extends JSWindowActorChild { //класс = name + Child
	receiveMessage() { return htmlAndName(this.contentWindow);}
}
ChromeUtils.domProcessChild.childID || ({
	init(topic) {
		ChromeUtils.registerWindowActor(name, {
			allFrames: true,
			child: {esModuleURI: Components.stack.filename},
			messageManagerGroups: ["browsers"]
		});
		obs.addObserver(self = this, topic);
		obs.addObserver(function quit(s, t) {
			obs.removeObserver(quit, t);
			obs.removeObserver(self, topic);
		}, "quit-application-granted");
		this.handleEvent = e => this[e.type](e);
		globalThis[Symbol.for(name)] = this.SingleHTML; //общие функции
		globalThis[Symbol.for('TitlePath')] = this.TitlePath;
	},
	observe(win) {
		win.document.getElementById("appMenu-popup").addEventListener("popupshowing", this);
		win.addEventListener("unload", this);
	},
	popupshowing(e) {
		this.unload(e);
		var popup = e.target;
		var btn = popup.ownerDocument.createXULElement("toolbarbutton");
		btn.id = "appMenu-ucf-save-html-button";
		btn.setAttribute("label", "Всё или выбранное в единый HTML");
		var before = "appMenu-save-file-button2", subviewbutton = "subviewbutton";
		btn.className = subviewbutton;
		btn.setAttribute("oncommand", "SingleHTML();");
		btn.SingleHTML = this.SingleHTML;
		popup.querySelector('toolbarbutton[id^="'+ before +'"]').before(btn);
	},
	unload(e) {
		var win = e.target.ownerGlobal;
		win.removeEventListener("unload", this);
		win.document.getElementById("appMenu-popup").removeEventListener("popupshowing", this);
	},
	TitlePath(win, to, f, u, n = 0, h = 99) { //global
		if(parseInt(to) > 0) [n,to] = [to,n]; if(parseInt(to) < 0) h = Math.abs(to);
		if (typeof(to) != 'string' || !/.*\|/.test(to)) to = prefs.getStringPref("extensions.user_chrome_files.savedirs","|||0");
		to = to.split('|').slice(0 + n, 2 + n); //Dir/Sub|[empty|0 title|1 url]
		f ||= win.gBrowser.selectedTab.label;
		f = f.replace(/\s+/g,' ').replace(/[\\\/?*\"'`]+/g,'').replace(/[|<>]+/g,'_').replace(/:/g,'։').slice(0,h).trim();
		u ||= decodeURIComponent(win.gURLBar.value); n = f, h = u;
		u = /^file:\/\//.test(u) ? 'file' : u.replace(/^.*u=|https?:\/\/|www\.|\/.*/g,'').replace(/^ru\.|^m\./,'').replace(/\/.*/,'');
		to[1] = (to[1] == "0") ? f : (to[1] == "1") ? u : "";
		f += "_"+ new Date().toLocaleDateString('ru', {day: 'numeric',month: 'numeric',year: '2-digit'}) +'-'+ new Date().toLocaleTimeString('en-GB').replace(/:/g,"։"); //дата-часы
		try {var dir = dirsvc.get("DfltDwnld",Ci.nsIFile);} catch {dir = prefs.getComplexValue("browser.download.dir",Ci.nsIFile)}
		var map = l => win.DownloadPaths.sanitize(l); //FIX имён
		to.map(map).forEach(dir.append);
		to = dir.clone(); to.append(f +'.html');
		return [dir, to.path, n, f, h, u]; //… имя, +дата, URL, домен
	},
	async Succes(win, dir, dw = true, bg) {
		var {setTimeout} = ChromeUtils.import("resource://gre/modules/Timer.jsm");
		var d = await win.Downloads.createDownload({source: "about:blank",target: win.FileUtils.File(dir)});
		(await win.Downloads.getList(win.Downloads.ALL)).add(d);
		if (dw) await d.refresh(d.succeeded = true); //flash DWButton
		d = win.document.getElementById('urlbar-input-container');
		d.style.background = dw ? 'rgba(0,200,0,0.3)' : 'rgba(250,0,0,0.2)';
		setTimeout(() => {d.style.removeProperty('background-color')}, 350);
	},
	async SingleHTML(to, win = this.ownerGlobal) {
		var br = win.gBrowser.selectedBrowser, bc = focus.focusedContentBrowsingContext;
		if (bc?.top.embedderElement != br) bc = br.browsingContext;
		var actor = bc?.currentWindowGlobal?.getActor(name);
		actor && self.save(win, ...await actor.sendQuery(""), to); //htmlAndName
		},
	async save(win, data, fname, host, to) {
		var path = this.TitlePath(win, to, fname, host); //путь в зависимости от опций
		var dir = path[0], path = path[1];
		dir.exists() && dir.isDirectory() || dir.create(dir.DIRECTORY_TYPE, 0o777);
		if (!to) { // диалог выбора папки
			var fp = Cc['@mozilla.org/filepicker;1'].createInstance(Ci.nsIFilePicker);
			fp.init(win, "", fp.modeSave);
			fp.defaultString = path.split(/.*[\/|\\]/)[1];
			fp.appendFilters(fp.filterHTML); fp.appendFilters(fp.filterAll);
			var res = await new Promise(fp.open);
			if (res == fp.returnOK || res == fp.returnReplace)
				path = fp.file.path
			else return;
		}
		this.write(path, data); //нужна проверка на ошибки записи
		await this.Succes(win, path);
	},
	write(path, html) { //без Ff 79-84 в save() IOUtils.writeUTF8 вместо this.write
		if (typeof IOUtils == "object")
			var write = IOUtils.writeUTF8 || IOUtils.writeAtomicUTF8; // Fx 85+ || 82-84
		if (!write) { // Fx 79-81
			var {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
			write = (path, txt) => OS.File.writeAtomic(path, new TextEncoder().encode(txt));
		}
		(this.write = write)(path, html);
	}
}).init("browser-delayed-startup-finished");

var htmlAndName = async mainWin => { //не сохраняет SVG

	var resolveURL = function (url, base) {
		try { return io.newURI(url, null, io.newURI(base)).spec;} catch {}
	},
	getSelWin = function (w) {
		if (w.getSelection().toString()) return w;
		for (var i = 0, f, r; f = w.frames[i]; i++) {
			try { if (r = getSelWin(f)) return r;} catch(e) {}
		}
	},
	encodeImg = function (src, obj) {
		var canvas, img, ret = src;
		if (/^https?:\/\//.test(src)) {
			canvas = doc.createElement('canvas');
			if (!obj || obj.nodeName.toLowerCase() != 'img') {
				img = doc.createElement('img');
				img.src = src;
			} else
				img = obj;
			if (img.complete) try {
				canvas.width = img.width;
				canvas.height = img.height;
				canvas.getContext('2d').drawImage(img, 0, 0);
				ret = canvas.toDataURL((/\.jpe?g/i.test(src) ? 'image/jpeg' : 'image/png'));
			} catch (e) {};
			if (img != obj) img.src = 'about:blank';
		};
		return ret;
	},
	toSrc = function (obj) {
		var strToSrc = function (str) {
			var chr, ret = '', i = 0, meta = {'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','\x22':'\\\x22','\\':'\\\\'};
			while (chr = str.charAt(i++)) {
				ret += meta[chr] || chr;
			};
			return '\x22' + ret + '\x22';
		},
		arrToSrc = function (arr) {
			var ret = [];
			for (var i = 0; i < arr.length; i++) {
				ret[i] = toSrc(arr[i]) || 'null';
			};
			return '[' + ret.join(',') + ']';
		},
		objToSrc = function (obj) {
			var val, ret = [];
			for (var prop in obj) {
				if (obj.hasOwnProperty(prop) && (val = toSrc(obj[prop]))) ret.push(strToSrc(prop) + ': ' + val);
			};
			return '{' + ret.join(',') + '}';
		};
		switch (Object.prototype.toString.call(obj).slice(8, -1)) {
			case 'Array': return arrToSrc(obj);
			case 'Boolean':
			case 'Function':
			case 'RegExp': return obj.toString();
			case 'Date': return 'new Date(' + obj.getTime() + ')';
			case 'Math': return 'Math';
			case 'Number': return isFinite(obj) ? String(obj) : 'null';
			case 'Object': return objToSrc(obj);
			case 'String': return strToSrc(obj);
			default: return obj ? (obj.nodeType == 1 && obj.id ? 'document.getElementById(' + strToSrc(obj.id) + ')' : '{}') : 'null';
		}
	},
	selWin = getSelWin(mainWin), win = selWin || mainWin, doc = win.document, loc = win.location,
	ele, pEle, clone, reUrl = /(url\(\x22)(.+?)(\x22\))/g;

	if (selWin) {
		var rng = win.getSelection().getRangeAt(0);
		pEle = rng.commonAncestorContainer;
		ele = rng.cloneContents();
	} else {
		pEle = doc.documentElement;
		ele = (doc.body || doc.getElementsByTagName('body')[0]).cloneNode(true);
	};
	while (pEle) {
		if (pEle.nodeType == 1) {
			clone = pEle.cloneNode(false);
			clone.appendChild(ele);
			ele = clone;
		};
		pEle = pEle.parentNode
	};
	var sel = doc.createElement('div');
	sel.appendChild(ele);

	for (var el, all = sel.getElementsByTagName('*'), i = all.length; i--;) {
		el = all[i];
		if (el.style && el.style.backgroundImage) el.style.backgroundImage = el.style.backgroundImage.replace(reUrl, function (a, prev, url, next) {
			if (!/^[a-z]+:/.test(url)) url = resolveURL(url, loc.href);
			return prev + encodeImg(url) + next;
		});
		switch (el.nodeName.toLowerCase()) {
			case 'link':
			case 'style':
			case 'script': el.parentNode.removeChild(el); break;
			case 'a':
			case 'area': if (el.hasAttribute('href') && el.getAttribute('href').charAt(0) != '#') el.href = el.href; break;
			case 'img':
			case 'input': if (el.hasAttribute('src')) el.src = encodeImg(el.src, el); break;
			case 'audio':
			case 'video':
			case 'embed':
			case 'frame':
			case 'iframe': if (el.hasAttribute('src')) el.src = el.src; break;
			case 'object': if (el.hasAttribute('data')) el.data = el.data; break;
			case 'form': if (el.hasAttribute('action')) el.action = el.action; break;
		}
	};
	var head = ele.insertBefore(doc.createElement('head'), ele.firstChild), meta = doc.createElement('meta'), sheets = doc.styleSheets;
	meta.httpEquiv = 'content-type';
	meta.content = 'text/html; charset=utf-8';
	head.appendChild(meta);
	var title = doc.getElementsByTagName('title')[0];
	if (title) head.appendChild(title.cloneNode(true));

	head.copyScript = function (unsafeWin) {
		if ('$' in unsafeWin) return;
		var f = doc.createElement('iframe');
		f.src = 'about:blank';
		f.setAttribute('style', 'position:fixed;left:0;top:0;visibility:hidden;width:0;height:0;');
		doc.documentElement.appendChild(f);
		var str, script = doc.createElement('script');
		script.type = 'text/javascript';
		for (var name in unsafeWin) {
			if (name in f.contentWindow || !/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) continue;
			try {
				str = toSrc(unsafeWin[name]);
				if (!/\{\s*\[native code\]\s*\}/.test(str)) {
					script.appendChild(doc.createTextNode('var ' + name + ' = ' + str.replace(/<\/(script>)/ig, '<\\/$1') + ';\n'));
				}
			} catch (e) {};
		};
		f.parentNode.removeChild(f);
		if (script.childNodes.length) this.nextSibling.appendChild(script);
	};
	head.copyScript(win.wrappedJSObject || win);

	head.copyStyle = function (s) {
		if (!s) return;
		var style = doc.createElement('style');
		style.type = 'text/css';
		if (s.media && s.media.mediaText) style.media = s.media.mediaText;
		try {
			for (var i = 0, rule; rule = s.cssRules[i]; i++) {
				if (rule.type != 3) {
					if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) {
						var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) {
							if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href);
							if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url);
							return prev + url + next;
						});
						style.appendChild(doc.createTextNode(css + '\n'));
					}
				} else { this.copyStyle(rule.styleSheet);}
			}
		} catch(e) {
			if (s.ownerNode) style = s.ownerNode.cloneNode(false);
		};
		this.appendChild(style);
	};
	for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]);
	head.appendChild(doc.createTextNode('\n'));

	var doctype = '', dt = doc.doctype;
	if (dt && dt.name) {
		doctype += '<!DOCTYPE ' + dt.name;
		if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22';
		if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22';
		doctype += '>\n';
	};
	var onlyName = selWin ? win.getSelection().toString() : (title && title.text ? title.text : loc.pathname.split('/').pop());
	return [doctype + sel.innerHTML +'\n<a href='+ (loc.protocol != 'data:' ? loc.href : 'data:uri') +'><small><blockquote>источник: '+ new Date().toLocaleString("ru") +'</blockquote></small></a>', onlyName, loc.hostname];
}

Отсутствует

 

№130519-03-2024 15:22:08

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

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

Dobrov пишет

не понимаю, как этот win.browsingContext прописывать!

.browsingContext нужен только для случая Cc['@mozilla.org/filepicker;1'].createInstance(Ci.nsIFilePicker);, посему я придумал такой вариант:

nsIFilePicker

Выделить код

Код:

// fp.init(win
 fp.init((parseInt(Services.appinfo.platformVersion) >= 125 ? win.browsingContext : win)


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

Отсутствует

 

№130619-03-2024 16:34:41

unter_officer
Участник
 
Группа: Members
Откуда: Санкт-Петербург
Зарегистрирован: 27-03-2011
Сообщений: 599
UA: Firefox 115.0

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

Dumby
Пока работает, но если не трудно, переделайте пожалуйста JSM'ку в MJS.

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

Выделить код

Код:

//
// Открывать ссылки длинным кликом ..........
// Dumby: https://forum.mozilla-russia.org/viewtopic.php?pid=797864#p797864 .....
//
var delay = 500;               // время удержания в мс
var inBackground = false;      // открывать в фоновой вкладке
var relatedToCurrent = false;  // открывать рядом с related вкладкой

var name = "LPA", EXPORTED_SYMBOLS = [name + "Child", name + "Parent"];

var u = {get timer() {
    delete this.timer;
    return this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
}};
inBackground == null
    ? Object.defineProperty(u, "bg", {
        get: Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch)
            .getBoolPref.bind(null, "browser.tabs.loadInBackground")
    })
    : u.bg = inBackground;

if (!ChromeUtils.domProcessChild.childID) {
    var triggeringPrincipal = Cu.getObjectPrincipal(Cu);
    var LPAParent = class extends JSWindowActorParent {
        receiveMessage(msg) {
            var [link, inBackground, ref] = msg.data;
            this.manager.browsingContext.top
                .embedderElement.ownerGlobal.gBrowser.addTab(link, {
                    triggeringPrincipal, relatedToCurrent, inBackground,
                });
        }
    }
    ChromeUtils.registerWindowActor(name, {
        allFrames: true,
        parent: {moduleURI: __URI__},
        messageManagerGroups: ["browsers"],
        child: {moduleURI: __URI__, events: {mousedown: {}}}
    });
}

class LPAChild extends JSWindowActorChild {
    handleEvent(e) {
        if (e.type == "mousedown") {
            if (e.button || e.shiftKey || e.altKey || e.detail != 1) return;

            var a = e.originalTarget.closest("a[href]");
            if (!a || a.href.startsWith("javascript:")) return;

            this.ctrl = e.ctrlKey;
            this.initLongPress(a);
        }
        else
            e.type == "click" && !this.link && e.preventDefault(),
            this.destroyLongPress();
    }
    timeout() {
        var bg = this.ctrl != u.bg;
        var data = [this.link.href, bg];

        this.sendAsyncMessage("", data);
        this.link = null;
        bg || this.destroyLongPress()
        //|| this.contentWindow.windowUtils.sendMouseEventToWindow("mouseup", -1, -1, 0, 1, 0); // Linux (?)
    }
    initLongPress(a) {
        this.contentWindow.addEventListener("click", this, true);
        this.contentWindow.addEventListener("dragstart", this, false);
        u.timer.initWithCallback(() => this.timeout(), delay, u.timer.TYPE_ONE_SHOT);
        this.link = a;
    }
    destroyLongPress() {
        this.contentWindow.removeEventListener("click", this, true);
        this.contentWindow.removeEventListener("dragstart", this, false);
        this.link && u.timer.cancel();
        this.link = null;
    }
    didDestroy() {
        this.link && this.destroyLongPress();
    }
}


«The Truth Is Out There»

Отсутствует

 

№130719-03-2024 17:49:49

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

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

Dumby пишет

Не понял. Если сделал как написано в первой строке
конвертированного скрипта — значит изменился.

Сделал давно, и уже забыл.

Хорошо, попробую.

Спасибо, на 115esr работают.
   
ChromeUtils.importESModule("……….mjs"); - это вариант импорта? Типа так -

(async url => ChromeUtils.importESModule("chrome://user_chrome_files/content/custom_scripts/.....mjs"
));

Отсутствует

 

№130820-03-2024 09:46:42

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

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

Farby пишет

.browsingContext нужен только для случая Cc['@mozilla.org/filepicker;1'].createInstance(Ci.nsIFilePicker);

Тут — да.
Но, в общем случае, наверно стоит сказать,
что, теоретически, где-то ещё,
может использоваться функция окна браузера, именуемая makeFilePicker()

// fp.init(win
fp.init((parseInt(Services.appinfo.platformVersion) >= 125 ? win.browsingContext : win)

Да, суть выражена верно.
Разве что заключение выражения
образующего первый аргумент для fp.init()
в круглые скобки здесь представляется избыточным.


Dobrov пишет

А как сделать, чтоб скрипт SingleHTML.mjs был совместим с FF115+

Не вижу какой-то несовместимости с FF115+
Наоборот, для такой совместимости можно кое-что зачистить, например:


Там, где Services, просто сразу пишем Services.


Метод write() подлежит удалению,
тогда, в save(), как и прокомментировано, «IOUtils.writeUTF8 вместо this.write».


Модуль Timer.jsm в 115 уже сконвертирован в Timer.sys.mjs
можно сразу использовать ChromeUtils.importESModule()


Но, нужен ли этот импорт как таковой?
В методе Succes() мы имеем win,
и с него уже берутся win.FileUtils и win.Downloads


Вот точно так же, вместо setTimeout можно написать win.setTimeout
и ничего не импортировать.


unter_officer пишет

переделайте пожалуйста JSM'ку в MJS

Чисто формально, достаточно заменить парочку
moduleURI: __URI__
на
esModuleURI: Components.stack.filename


и перед class LPAChild extends JSWindowActorChild {
добавить
export {LPAParent};

export


Но сам код какой-то неполноценный,
весьма нуждается в некоем переосмыслении.


_zt пишет

Типа так -
(async url => ChromeUtils.importESModule("chrome://user_chrome_files/content/custom_scripts/.....mjs"
));

Так ты определил асинхронную функцию импрота модуля.
Вникуда и внизачем.


Но если добавить перед оконечной точкой с запятой «;»
круглые скобки «()», оператор вызова этой функции,
то импорт произойдёт.


url тоже можно заменить на круглые скобки, раз не используется. (не обязательно)


Vitaliy V.
Ну вот, с кода

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

Выделить код

Код:

@supports selector(:-moz-lwtheme) {
	* {
		color: green !important;
	}
}
@supports not selector(:-moz-lwtheme) {
	* {
		color: red !important;
	}
}


В 115 и 125 — всё зелёное.
А в 126 — уже всё красное.

Отсутствует

 

№130920-03-2024 10:46:28

unter_officer
Участник
 
Группа: Members
Откуда: Санкт-Петербург
Зарегистрирован: 27-03-2011
Сообщений: 599
UA: Firefox 115.0

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

Dumby пишет

Чисто формально, достаточно заменить парочку
moduleURI: __URI__
на
esModuleURI: Components.stack.filename


и перед class LPAChild extends JSWindowActorChild {
добавить
export {LPAParent};

export


Но сам код какой-то неполноценный,
весьма нуждается в некоем переосмыслении.

Dumby, большое спасибо. Всё работает.


«The Truth Is Out There»

Отсутствует

 

№131020-03-2024 18:38:38

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

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

Dumby
У меня сейчас так

(async url => ChromeUtils.importESModule(url))("chrome://user_chrome_files/content/custom_scripts/....mjs"
);

вы выше написали про встроенный метод, вот я и подумал, что это пример импорта.
   
Вы как то делали переключалку доп панелей, так она теперь по ПКМ еще и меню вызывает, можете поправить?

Отсутствует

 

№131120-03-2024 22:52:54

unter_officer
Участник
 
Группа: Members
Откуда: Санкт-Петербург
Зарегистрирован: 27-03-2011
Сообщений: 599
UA: Firefox 115.0

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

Dumby
Вот эту JSM'ку не поможете переделать в MJS?

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

Выделить код

Код:

//
// Кнопка сохраняет страницу с картинками или её часть, если она выделена, в html одним файлом ..........
// Dumby: https://forum.mozilla-russia.org/viewtopic.php?pid=796993#p796993 .....
//
var name = "UCFSaveSnapshotToHTML", EXPORTED_SYMBOLS = [name + "Child"];

if (!ChromeUtils.domProcessChild.childID) {
    ChromeUtils.import("resource:///modules/CustomizableUI.jsm").CustomizableUI.createWidget({
        label: "Cохранить страницу в html",
        tooltiptext: "Cохранить страницу в html",

        id: "ucf_SaveSnapshotToHTML",
        localized: false,
        onCreated(btn) {
            btn._handleClick = click;
            btn.setAttribute("image", "chrome://devtools/skin/images/tool-application.svg");
        }
    });
    var click = async function() {
        var win = this.ownerGlobal;
        var bc = win.gBrowser.selectedBrowser.browsingContext;
        var fbc = win.Services.focus.focusedContentBrowsingContext;
        if (!fbc || fbc.top.id != bc.id) fbc = bc;

        var cwg = fbc.currentWindowGlobal;
        var fp = picker(win, "", Ci.nsIFilePicker.modeSave);
        var [fileContent, fileName] =
            await cwg.domProcess.getActor(name).sendQuery("", cwg.innerWindowId);

        fp.defaultString = fileName;
        fp.appendFilters(fp.filterHTML);
        fp.appendFilters(fp.filterAll);

        await new Promise(fp.open) != fp.returnCancel &&
            IOUtils.writeUTF8(fp.file.path, fileContent, {mode: "overwrite"});
    }
    var picker = (...args) => {
        ChromeUtils.registerProcessActor(name, {
            includeParent: true,
            child: {moduleURI: __URI__}
        });
        return (picker = Components.Constructor(
            "@mozilla.org/filepicker;1", "nsIFilePicker", "init"
        ))(...args);
    }
}
class UCFSaveSnapshotToHTMLChild extends JSProcessActorChild {
    receiveMessage(msg) {
        return snap(WindowGlobalChild.getByInnerWindowId(msg.data).browsingContext.window);
    }
}

var snap = mainWin => {

    var resolveURL = function (url, base) {
        try {
            return (new URL(url, base)).href;
        } catch {}
    };

    var getSelWin = function (w) {
        if (w.getSelection().toString()) return w;
        for (var i = 0, f, r; f = w.frames[i]; i++) {
            try {
                if (r = getSelWin(f)) return r;
            } catch(e) {}
        }
    };

    var encodeImg = function (src, obj) {
        var canvas, img, ret = src;
        if (/^https?:\/\//.test(src)) {
            canvas = doc.createElement('canvas');
            if (!obj || obj.nodeName.toLowerCase() != 'img') {
                img = doc.createElement('img');
                img.src = src;
            } else {
                img = obj;
            };
            if (img.complete) try{
                canvas.width = img.width;
                canvas.height = img.height;
                canvas.getContext('2d').drawImage(img, 0, 0);
                ret = canvas.toDataURL((/\.jpe?g/i.test(src) ? 'image/jpeg' : 'image/png'));
            } catch (e) {};
            if (img != obj) img.src = 'about:blank';
        };
        return ret;
    };

    var toSrc = function (obj) {
        var strToSrc = function (str) {
            var chr, ret = '', i = 0, meta = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\x22' : '\\\x22', '\\': '\\\\'};
            while (chr = str.charAt(i++)) {
                ret += meta[chr] || chr;
            };
            return '\x22' + ret + '\x22';
        },
        arrToSrc = function (arr) {
            var ret = [];
            for (var i = 0; i < arr.length; i++) {
                ret[i] = toSrc(arr[i]) || 'null';
            };
            return '[' + ret.join(',') + ']';
        },
        objToSrc = function (obj) {
            var val, ret = [];
            for (var prop in obj) {
                if (obj.hasOwnProperty(prop) && (val = toSrc(obj[prop]))) ret.push(strToSrc(prop) + ': ' + val);
            };
            return '{' + ret.join(',') + '}';
        };

        switch (Object.prototype.toString.call(obj).slice(8, -1)) {
            case 'Array': return arrToSrc(obj);
            case 'Boolean':
            case 'Function':
            case 'RegExp': return obj.toString();
            case 'Date': return 'new Date(' + obj.getTime() + ')';
            case 'Math': return 'Math';
            case 'Number': return isFinite(obj) ? String(obj) : 'null';
            case 'Object': return objToSrc(obj);
            case 'String': return strToSrc(obj);
            default: return obj ? (obj.nodeType == 1 && obj.id ? 'document.getElementById(' + strToSrc(obj.id) + ')' : '{}') : 'null';
        }
    };

    var selWin = getSelWin(mainWin), win = selWin || mainWin, doc = win.document, loc = win.location;
    var ele, pEle, clone, reUrl = /(url\(\x22)(.+?)(\x22\))/g;

    if (selWin) {
        var rng = win.getSelection().getRangeAt(0);
        pEle = rng.commonAncestorContainer;
        ele = rng.cloneContents();
    } else {
        pEle = doc.documentElement;
        ele = (doc.body || doc.getElementsByTagName('body')[0]).cloneNode(true);
    };

    while (pEle) {
        if (pEle.nodeType == 1) {
            clone = pEle.cloneNode(false);
            clone.appendChild(ele);
            ele = clone;
        };
        pEle = pEle.parentNode
    };

    var sel = doc.createElement('div');
    sel.appendChild(ele);

    for (var el, all = sel.getElementsByTagName('*'), i = all.length; i--;) {
        el = all[i];
        if (el.style && el.style.backgroundImage) el.style.backgroundImage = el.style.backgroundImage.replace(reUrl, function (a, prev, url, next) {
            if (!/^[a-z]+:/.test(url)) url = resolveURL(url, loc.href);
            return prev + encodeImg(url) + next;
        });
        switch (el.nodeName.toLowerCase()) {
            case 'link':
            case 'style':
            case 'script': el.parentNode.removeChild(el); break;
            case 'a': 
            case 'area': if (el.hasAttribute('href') && el.getAttribute('href').charAt(0) != '#') el.href = el.href; break;
            case 'img':
            case 'input': if (el.hasAttribute('src')) el.src = encodeImg(el.src, el); break;
            case 'audio':
            case 'video':
            case 'embed':
            case 'frame':
            case 'iframe': if (el.hasAttribute('src')) el.src = el.src; break;
            case 'object': if (el.hasAttribute('data')) el.data = el.data; break;
            case 'form': if (el.hasAttribute('action')) el.action = el.action; break;
        }
    };

    var head = ele.insertBefore(doc.createElement('head'), ele.firstChild);
    var meta = doc.createElement('meta');
    meta.httpEquiv = 'content-type';
    meta.content = 'text/html; charset=utf-8';
    head.appendChild(meta);
    var title = doc.getElementsByTagName('title')[0];
    if (title) head.appendChild(title.cloneNode(true));

    head.copyScript = function (unsafeWin) {
        if ('$' in unsafeWin) return;
        var f = doc.createElement('iframe');
        f.src = 'about:blank';
        f.setAttribute('style', 'position:fixed;left:0;top:0;visibility:hidden;width:0;height:0;');
        doc.documentElement.appendChild(f);
        var str, script = doc.createElement('script');
        script.type = 'text/javascript';
        for (var name in unsafeWin) {
            if (name in f.contentWindow || !/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) continue;
            try {
                str = toSrc(unsafeWin[name]);
                if (!/\{\s*\[native code\]\s*\}/.test(str)) {
                    script.appendChild(doc.createTextNode('var ' + name + ' = ' + str.replace(/<\/(script>)/ig, '<\\/$1') + ';\n'));
                }
            } catch (e) {};
        };
        f.parentNode.removeChild(f);
        if (script.childNodes.length) this.nextSibling.appendChild(script);
    };
    head.copyScript(win.wrappedJSObject || win);

    head.copyStyle = function (s) {
        if (!s) return;
        var style = doc.createElement('style');
        style.type = 'text/css';
        if (s.media && s.media.mediaText) style.media = s.media.mediaText;
        try {
            for (var i = 0, rule; rule = s.cssRules[i]; i++) {
                if (rule.type != 3) {
                    if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) {
                        var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) {
                            if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href);
                            if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url);
                            return prev + url + next;
                        });
                        style.appendChild(doc.createTextNode(css + '\n'));
                    }
                } else {
                    this.copyStyle(rule.styleSheet);
                }
            }
        } catch(e) {
            if (s.ownerNode) style = s.ownerNode.cloneNode(false);
        };
        this.appendChild(style);
    };

    var sheets = doc.styleSheets;
    for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]);
    head.appendChild(doc.createTextNode('\n'));

    var doctype = '', dt = doc.doctype;
    if (dt && dt.name) {
        doctype += '<!DOCTYPE ' + dt.name;
        if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22';
        if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22';
        doctype += '>\n';
    };

    var fileName = selWin ? win.getSelection().toString() : (title && title.text ? title.text : loc.pathname.split('/').pop());
    fileName = fileName.replace(/[:\\\/<>?*|"]+/g, '').replace(/[\.]+/ig, ' ').replace(/[\,]+/ig, ' ').replace(/[\']+/ig, ' ').replace(/^\s+|\s+$/g, '').replace(/\s+/g, '_').slice(0, 100);
    fileName += (function () {
        var d = new Date(), z = function(n){return (n < 10 ? '0' : '') + n};
        return '_' + '[' + z(d.getFullYear()) + '_' + z(d.getMonth()+1) + '_' + z(d.getDate()) + '\u2014' + z(d.getHours()) + '_' + z(d.getMinutes()) + '_' + z(d.getSeconds()) + ']';
    })();

    if(!/\.html?$/.test(fileName))fileName += '.html';

    return [doctype + sel.innerHTML + '\n<!-- This document saved from ' + (loc.protocol != 'data:' ? loc.href : 'data:uri') + ' -->', fileName];
}


«The Truth Is Out There»

Отсутствует

 

№131221-03-2024 01:17:05

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

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

unter_officer на предыдущей странице SingleHTML.mjs сохраняет страницу или выделенное.

Отсутствует

 

№131321-03-2024 02:36:34

unter_officer
Участник
 
Группа: Members
Откуда: Санкт-Петербург
Зарегистрирован: 27-03-2011
Сообщений: 599
UA: Firefox 115.0

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

Dobrov пишет

unter_officer на предыдущей странице SingleHTML.mjs сохраняет страницу или выделенное.

Ваш код добавляет пункт меню "Всё или выбранное в единый HTML" в "гамбургер".
Я "гамбургером" не пользуюсь, он у меня скрыт. Поэтому мне это не подходит.


«The Truth Is Out There»

Отсутствует

 

№131421-03-2024 03:58:15

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

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

unter_officer - код универсальный, вы прочитали середину, но не увидели команду вызова в начале!
Добавить в любую кнопку: Cu.getGlobalForObject(Cu)[Symbol.for("SingleHTML")](true,window);


Кроме того, SingleHTML.mjs позволяет 1) сохранять страницу с выбором папки или автоматически.
2) сохранять в любые папки/подпапки, используя имя вкладки или домен. Пишем "Сайт||Фото|" в extensions.user_chrome_files.savedirs:
сохранение Html/Pics. [Загрузки]/"_Html/subdir|_Pics/subdir" «subdir: пусто | 0 имя страницы | 1 домен»
3) пути/имена страниц меняются на лету из кнопки настроек скрипта ucf_hookClicks.js или правкой extensions.user_chrome_files.savedirs.


Vitaliy V. может сможешь решить давнюю проблему скрипта SingleHTML.mjs ?


Этот код не сохраняет SVG-графику, но работает быстрее, чем дополнение SingleFile и сохраняет страницу более компактно.
https://meteo7.ru/forecast/59003

Отредактировано Dobrov (21-03-2024 04:31:28)

Отсутствует

 

№131521-03-2024 09:47:46

unter_officer
Участник
 
Группа: Members
Откуда: Санкт-Петербург
Зарегистрирован: 27-03-2011
Сообщений: 599
UA: Firefox 115.0

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

Dobrov
Извините, но мне нужна простая кнопка без всяких наворотов, в которой, в случае необходимости, я хоть что-то могу попытаться понять, а не такой комбайн.
И уж тем более без установки дополнительных скриптов в виде ucf_hookClicks.js или подобных.


«The Truth Is Out There»

Отсутствует

 

№131621-03-2024 11:09:50

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

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

_zt пишет

Вы как то делали переключалку доп панелей, так она теперь по ПКМ еще и меню вызывает, можете поправить?

Чтобы далеко не ходить, заменил image на "about:logo".
Сунул код в 126.0a1, жму ПКМ — верхний тулбар переключается.


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


unter_officer пишет

Извините, но мне нужна простая кнопка

Да, но сам принцип конвертации от этого же не меняется.


Всё тот же esModuleURI: Components.stack.filename вместо moduleURI: __URI__
Всё та же инструкция export перед class


И ChromeUtils.importESModule("resource:///modules/CustomizableUI.sys.mjs")
вместо ChromeUtils.import("resource:///modules/CustomizableUI.jsm")


EXPORTED_SYMBOLS тогда долой (не обязательно).
Ну, и picker(win.browsingContext вместо picker(win если 125+

Отсутствует

 

№131721-03-2024 11:40:03

unter_officer
Участник
 
Группа: Members
Откуда: Санкт-Петербург
Зарегистрирован: 27-03-2011
Сообщений: 599
UA: Firefox 115.0

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

Dumby пишет

Да, но сам принцип конвертации от этого же не меняется.

Dumby, большое спасибо. Всё получилось.



_zt пишет

Вы как то делали переключалку доп панелей, так она теперь по ПКМ еще и меню вызывает, можете поправить?

_zt, вы смогли понять, когда начинает появляться контекстное меню?
Дело в том, что я за последние три недели дважды сталкивался с таким поведением этого скрипта, но причину так и не понял.
То есть, всё нормально работает 5-7-10 дней и вдруг, ни с того ни с сего, появляется контекстное меню. Перезапустишь браузер и опять всё нормально работает.

Отредактировано unter_officer (21-03-2024 12:10:06)


«The Truth Is Out There»

Отсутствует

 

№131821-03-2024 18:54:14

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

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

Dumby
А вы потаскайте кнопку по панелям. UCF последний.
   
unter_officer
Нет не смог, сначала думал, что после перемещения кнопок.
Я вернулся на свой первоначальный вариант, он рабочий - 16-12-2021 02:14:46
   
Vitaliy V.
У меня есть одна проблема с вертикальной панелью нового UCF. На ней расположено два растягивающихся интервала - 1. сначала кнопки скриптов и расширений, 2. потом интервал, 3. потом кнопки ATB - вверх и вниз страницы через обычный пробел, 4. потом интервал и 5. еще пара кнопок. Так вот, две последние кнопки от расширений, из первого блока кнопок, постоянно сваливаются вниз, в позицию между кнопками ATB. Происходит это после скрытия/показа панели любым из скриптов выше.
Может сделаете переключалку панелей одной кнопкой, без подобных спецэффектов?

Отсутствует

 

№131921-03-2024 19:57:01

unter_officer
Участник
 
Группа: Members
Откуда: Санкт-Петербург
Зарегистрирован: 27-03-2011
Сообщений: 599
UA: Firefox 115.0

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

_zt
Я порылся в своих архивах и нашел вот такой вариант, только не помню где я его взял.
Он почти такой же как этот, за исключением пары строчек.

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

Выделить код

Код:

(async () => CustomizableUI.createWidget({
    id: "additional-toolbars-button",
    label: "Панели",
    tooltiptext: "ЛКМ: Переключить верт. панель\nПКМ: Переключить доп. панель",
    localized: false,
    // defaultArea: CustomizableUI.AREA_NAVBAR,
    onCreated(btn) {
        btn.setAttribute("context", false);
        btn.setAttribute("image", "data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' height='16' width='16' viewBox='0 0 16 16'><g><rect x='0' y='0' width='16' height='16' rx='1' ry='1' style='fill:rgb(0, 120, 173);'/><path style='fill:white;' d='M 2.5,1 C 1.7,1 1,1.7 1,2.5 V 13.5 C 1,14.3 1.7,15 2.5,15 H 13.5 C 14.3,15 15,14.3 15,13.5 V 2.5 C 15,1.7 14.3,1 13.5,1 Z M 3,2 H 13 C 13.7,2 14,2.3 14,3 V 13 C 14,13.7 13.7,14 13,14 H 3 C 2.3,14 2,13.7 2,13 V 3 C 2,2.3 2.3,2 3,2 Z M 7.3,3.03 C 7.11,3.03 6.95,3.2 6.95,3.4 V 4.09 C 6.6,4.18 6.28,4.34 5.96,4.5 L 5.45,3.99 C 5.39,3.93 5.3,3.9 5.23,3.9 5.14,3.9 5.04,3.93 4.95,3.99 L 3.99,4.98 C 3.84,5.1 3.85,5.33 3.99,5.49 L 4.5,5.96 C 4.31,6.28 4.18,6.6 4.09,6.95 H 3.37 C 3.17,6.95 3.01,7.11 3.01,7.3 V 8.67 C 3.01,8.89 3.17,9.05 3.37,9.05 H 4.09 C 4.18,9.4 4.31,9.72 4.5,10 L 3.99,10.5 C 3.85,10.7 3.84,10.9 3.99,11 L 4.95,12 C 5.1,12.1 5.33,12.1 5.45,12 L 5.96,11.5 C 6.28,11.7 6.6,11.8 6.95,11.9 V 12.6 C 6.95,12.8 7.11,13 7.3,13 H 8.7 C 8.89,13 9.05,12.8 9.05,12.6 V 11.9 C 9.4,11.8 9.72,11.7 10,11.5 L 10.5,12 C 10.7,12.1 10.9,12.1 11.1,12 L 12,11 C 12.2,10.9 12.2,10.7 12,10.5 L 11.5,10 C 11.7,9.72 11.8,9.4 11.9,9.05 H 12.6 C 12.8,9.05 13,8.89 13,8.67 V 7.3 C 13,7.11 12.8,6.95 12.6,6.95 H 11.9 C 11.8,6.6 11.7,6.28 11.5,5.96 L 12,5.49 C 12.2,5.33 12.2,5.1 12,4.98 L 11.1,3.99 C 10.9,3.86 10.7,3.86 10.5,3.99 L 10,4.5 C 9.72,4.34 9.4,4.18 9.05,4.09 V 3.4 C 9.05,3.2 8.89,3.03 8.7,3.03 Z M 8,6.5 C 8.8,6.5 9.5,7.2 9.5,8 9.5,8.8 8.8,9.5 8,9.5 7.2,9.5 6.5,8.8 6.5,8 6.5,7.2 7.2,6.5 8,6.5 Z'/></g></svg>");
    },
    0: "ucf-additional-vertical-bar",
    2: "ucf-additional-top-bar",
    onClick(e) {
        var id = this[e.button];
        id && CustomizableUI.setToolbarVisibility(id, e.target.ownerDocument.querySelector('#' + id).collapsed);
    }
}))();

Подключил этот скрипт для потестировать, вроде пока нормально. Может попробуете у себя?

Отредактировано unter_officer (21-03-2024 20:25:24)


«The Truth Is Out There»

Отсутствует

 

№132021-03-2024 20:53:50

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

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

_zt пишет

Я вернулся на свой первоначальный вариант, он рабочий

Насколько понимаю, для ЛКМ эти две строки не нужны. Они только для ПКМ, чтобы меню не появлялось.
e.preventDefault();
e.stopPropagation();

Превент может использоваться для предотвращения появления контекстного
меню при ПКМ (Windows)

Это сказано по ссылке в посте №1381 (выше).

Отсутствует

 

№132121-03-2024 22:35:27

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

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

_zt пишет

А вы потаскайте кнопку по панелям.

Потаскал. По этим четырём.
#toolbar-menubar, #TabsToolbar-customization-target,
#nav-bar-customization-target, #PersonalToolbar.


И после каждого такого потаскушества, честно жал ПКМ.
Но никакого контекстного меню увидеть так и не смог.


Тем не менее, любая осознанная модификация кода
всегда только приветствуется, будь то
btn.setAttribute("context", false) или btn.setAttribute("context", "")
или, даже пожёстче, btn.setAttribute("oncontextmenu", "return false");

Отсутствует

 

№132221-03-2024 23:16:24

unter_officer
Участник
 
Группа: Members
Откуда: Санкт-Петербург
Зарегистрирован: 27-03-2011
Сообщений: 599
UA: Firefox 115.0

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

Dumby пишет

И после каждого такого потаскушества, честно жал ПКМ.
Но никакого контекстного меню увидеть так и не смог.

Dumby, да тут и правда мистика какая-то.
Я этим скриптом пользуюсь где-то года два и никогда проблем не возникало, от слова совсем.
Первый раз я словил контекстное меню дней 20-25 назад. Причем я никаких кнопок не таскал, просто при очередном открытии доп.панели появилось меню.
Подумал, ну чего с FF не бывает, перезагрузил браузер и забыл про это. А позавчера вдруг опять словил этот глюк.
А тут оказывается и _zt описывает туже проблему, с тем же скриптом.
Странно как-то всё это. И в тоже время хочется понять, что это было.


P.S. В общем посмотрю как в дальнейшем будет работать скрипт, который я выложил чуть выше.


«The Truth Is Out There»

Отсутствует

 

№132322-03-2024 00:32:54

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

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

unter_officer пишет

Может попробуете у себя?

Не стал, так как вперед попробовал предложенное Dumby btn.setAttribute("oncontextmenu", "return false");
проблема исчезла. Значит дело именно в этой строке.
   
Еще б разобраться со скачками кнопок на вертикальной панели, после ее скрытия.

Отсутствует

 

№132422-03-2024 00:48:19

unter_officer
Участник
 
Группа: Members
Откуда: Санкт-Петербург
Зарегистрирован: 27-03-2011
Сообщений: 599
UA: Firefox 115.0

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

_zt пишет

Еще б разобраться со скачками кнопок на вертикальной панели, после ее скрытия.

Вот с этим у меня пока проблем нет.


«The Truth Is Out There»

Отсутствует

 

№132522-03-2024 05:04:43

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

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

Вопрос: чем заменить Services.wm.getMostRecentWindow("navigator:browser") на что-то попроще?
Хочу вызывать функцию globalThis[Symbol…… из другого js-кода без аргументов, но выдаёт ошибку win.gBrowser is undefined, если запускать так:
Cu.getGlobalForObject(Cu)[Symbol.for("SingleHTML")]();


пробовал разные варианты, пока в SingleHTML.mjs вписал такой второй аргумент по-умолчанию:
SingleHTML(to = false, win = this.ownerGlobal || Services.wm.getMostRecentWindow("navigator:browser")) {…

Отсутствует

 

Board footer

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