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

Хотите узнать больше о расширениях? Посмотрите ролики, рассказывающие о работе с расширениями Firefox.

№1552606-05-2021 18:22:10

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

Re: Custom Buttons

_zt пишет

не работает функция перезапуска

Да, BrowserUtils изрядно покромсали.
Ещё, смотрю, на 89, так сделанный alert/confirm
уходит в ихний новомодный внутриоконный вариант,
что не очень хорошо сочетается с незакрывающимся меню.
Вобщем, такая правка

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

Выделить код

Код:

/*
		maybeRestart(node, conf) {
			var msgRest = "Перезапустить браузер?", msgAbort = "Запрос на выход отменен.";
			if (pv >= 77) {
				var title = node.closest("toolbarbutton").label;
				var pp = domWin => Services.prompt.wrappedJSObject.pickPrompter({
					domWin, modalType: Ci.nsIPrompt.MODAL_TYPE_WINDOW
				});
				var confirm = win => pp(win).confirm(title, msgRest);
				var alert = win => pp(win).alert(title, msgAbort);
			} else {
				var confirm = win => win.confirm(msgRest);
				var alert = win => win.alert(msgAbort);
			}
			return (this.mayBeRestart = (node, conf) => {
				var win = node.ownerGlobal;
				if (conf && !confirm(win)) return;
				if (win.BrowserUtils.restartApplication() === false) alert(win);
				else return true;
			})(node, conf);
		},
*/
		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);
		},

Отсутствует

 

№1552707-05-2021 03:14:03

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

Re: Custom Buttons

Dumby просьба «косметически» доработать кнопку Quick Toggle about:config
я добавил скобки [] для строк меню, преф которых не существует (по-умолчанию).


Есть строки, требующие перезапуск браузера или обновление страницы. «Название меню» и «Значение» разделены тире —.
Нужно вместо тире — для строк, требующих refresh, подставлять например символ «»; а для restart символ «»
чтобы строка, запрашивающая например перезапуск (restart), выглядела так:  Провайдер DNS ↯ Cloudflare

Выделить код

Код:

// строка 400 кнопки https://forum.mozilla-russia.org/viewtopic.php?pid=789824#p789824
lab += ` — "${sfx}"`; // тире - обычный параметр, ⩫ требуется обновить страницу, ↯ нужен перезапуск браузера

Отсутствует

 

№1552807-05-2021 03:48:07

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

Re: Custom Buttons

Dumby
Перезапуск работает. Спасибо.
   
Действительно, индикация перезапуска не помешала бы.

Отредактировано _zt (07-05-2021 03:48:23)

Отсутствует

 

№1552907-05-2021 10:12:03

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

Re: Custom Buttons

Dobrov пишет

я добавил скобки [] для строк меню, преф которых не существует

Так и это, вроде как, не сложнее

Выделить код

Код:

lab += ` ${"restart" in pref ? "↯" : "refresh" in pref ? "⩫" : "—"} "${sfx}"`;

Отсутствует

 

№1553007-05-2021 11:44:14

Deriax
Участник
 
Группа: Members
Зарегистрирован: 27-03-2021
Сообщений: 20
UA: Chrome 90.0

Re: Custom Buttons

Dumby пишет
Deriax пишет

14f477a2ce81.png

Фу, в переводе это выглядит ещё более непонятно, чем в оригинале.
На самом деле, cookieStoreId — это всего лишь id'шник контейнера,
то есть, всего лишь уточняющий параметр для cookies.get() (и компании), не более того.


Типа — кука, именуемая так-то, с урлом каким-то эдаким, ограниченная контейнером (cookieStoreId) таким-то.
Еще раз: никакого «Хранилища файлов cookie вкладки» (так, как это звучит!) не существует.

Пожалуйста, подскажите как получить id контейнера, вообще как это выглядит? Нашёл такое расширение,
https://chrome.google.com/webstore/detail/cookie-tab-viewer/fdlghnedhhdgjjfgdpgpaaiddipafhgk
функционал этого расширения даёт возможность это реализовать, значит это возможно, но как это сделать для firefox не знаю (

Отредактировано Deriax (07-05-2021 12:52:42)

Отсутствует

 

№1553107-05-2021 22:42:46

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

Re: Custom Buttons

Deriax пишет

вообще как это выглядит?

В реальности — это атрибут "usercontextid" <tab>'а и <browser>'а.
Выглядит как число.


А в WebExtensions представлении — ну, смотри сам.
Допустим, например:
Открываем какое-то количество вкладок, в разных контейнерах и не в контейнере.
Берём аддон с нужными permissions и переходим на любой его moz-extension://… адрес.
Открываем там веб-консоль (Ctrl+Shift+K), запускаем код типа такого и смотрим результат.

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

Выделить код

Код:

(await browser.tabs.query({}))
	.map(tab => tab.cookieStoreId.padEnd(30) + tab.title.slice(0, 100))
	.join("\n");

Deriax пишет

функционал этого расширения даёт возможность это реализовать, значит это возможно, но как это сделать для firefox не знаю (

Может официальный пример немного прояснит.

Отсутствует

 

№1553208-05-2021 14:17:44

Deriax
Участник
 
Группа: Members
Зарегистрирован: 27-03-2021
Сообщений: 20
UA: Chrome 90.0

Re: Custom Buttons

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

Dumby пишет
Deriax пишет

вообще как это выглядит?

В реальности — это атрибут "usercontextid" <tab>'а и <browser>'а.
Выглядит как число.


А в WebExtensions представлении — ну, смотри сам.
Допустим, например:
Открываем какое-то количество вкладок, в разных контейнерах и не в контейнере.
Берём аддон с нужными permissions и переходим на любой его moz-extension://… адрес.
Открываем там веб-консоль (Ctrl+Shift+K), запускаем код типа такого и смотрим результат.
[spoiler]

Выделить код

Код:

(await browser.tabs.query({}))
	.map(tab => tab.cookieStoreId.padEnd(30) + tab.title.slice(0, 100))
	.join("\n");

Deriax пишет

функционал этого расширения даёт возможность это реализовать, значит это возможно, но как это сделать для firefox не знаю (

Может официальный пример немного прояснит.

[/spoiler]

На будущее может пригодиться.

Отредактировано Deriax (11-05-2021 19:11:23)

Отсутствует

 

№1553309-05-2021 08:57:59

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

Re: Custom Buttons

Dumby - спасибо, кнопку переключения настроек обновил.
Почините скрипт Save HTML, он не работает в Firefox 78 ESR, ошибка консоли: IOUtils is not defined

Выделить код

Код:

(async (id, func) => { // дополнительные клики на downloads-button для custom_script_win.js
	await window.delayedStartupPromise;
	var btn = document.getElementById("downloads-button");
	if (!btn) return;
	btn.setAttribute("context", "event.stopPropagation()"); // откл контекстное меню
	btn.tooltipText = GetDynamicShortcutTooltipText(btn.id) +`

ПКМ:	Сохранить единый .html
…Shift	Обзор папки «Загрузки»
Ролик:	Сохранить как файл .txt
		всё | выделенный текст
…Shift	Сайт: графика Вкл/Выкл
Alt⇧S	нажать SingleSave`; // если такой кнопки нет, то выполнить save()

	var addDestructor = nextDestructor => {
		var {destructor} = ucf[id];
		ucf[id].destructor = () => {
			try {destructor();} catch(ex) {Cu.reportError(ex);}
			nextDestructor();
		}
	}
	var saveSelectionToTxt = async () => { // сохранить страницу или выделенный текст как файл .txt
		var splice = saveURL.length == 10;
		var msgName = id + ":Save:GetSelection";

		var receiver = msg => {
			var title = document.title || gBrowser.selectedTab.label;
			var args = [
				"data:text/plain," + encodeURIComponent(gBrowser.currentURI.spec + "\n\n" + msg.data),
				title.replace(/[:\\\/<>?*|"]+/g,'_').replace(/\s+/g,' ').slice(0, 100).trim() + '_' + new Date().toLocaleString('ru').replace(', ','-').replace(/:/g, '։') + '.txt',
				null, false, true, null, window.document
			];
			splice && args.splice(5, 0, null);
			saveURL(...args);
		}
		messageManager.addMessageListener(msgName, receiver);
		addDestructor(() => messageManager.removeMessageListener(msgName, receiver));

		var func = fm => {
			var res, fed, win = {};
			var fe = fm.getFocusedElementForWindow(content, true, win);
			var sel = (win = win.value).getSelection();
			if (sel.isCollapsed) {
				var ed = fe && fe.editor;
				if (ed && ed instanceof Ci.nsIEditor)
					sel = ed.selection, fed = fe;
			}
			if (sel.isCollapsed)
				fed && fed.blur(),
				docShell.doCommand("cmd_selectAll"),
				res = win.getSelection().toString(),
				docShell.doCommand("cmd_selectNone"),
				fed && fed.focus();

			res = res || sel.toString();
			/\S/.test(res) && sendAsyncMessage("saveSelectionToTxt", res);
		}
		var url = "data:;charset=utf-8," + encodeURIComponent(`(${func})`.replace("saveSelectionToTxt", msgName)) + '(Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager));';

		(saveSelectionToTxt = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))();
	} // end

	var save = async () => { // автор: Лекс, правка: Dumby, Dobrov
		var msgName = id + "ucfDwnldsBtnSaveSnapshotToHTML";
		var write = IOUtils.writeUTF8 ? "writeUTF8" : "writeAtomicUTF8";

		var Title = function (type) { // получить заголовок (без обрезки, если type не указан) или домен (type <0)
			var title = (document.title || gBrowser.selectedTab.label);
			if ( !type ) return title; // заголовок
			if ( type > 0 ) return title.replace(/[:\\\/<>?*|"]+/g,' ').replace(/\s+/g,' ').replace(/  /g,' ').substr(0, type).trim(); // ограничить длину имени
			var host = (/^file:\/\//.test(gURLBar.value)) ? '' : gURLBar.value.replace(/^.*url=/,'').replace(/^https?:\/\//,'').replace(/\/.*/,'');
			return host.replace(/^www\./,'').replace(/^ru\./,'').replace(/^m\./,'').replace(/^forum\./,'').replace(/^club\.dns/,'dns');
		};
		var msgListener = async msg => {
			var [fileContent, fileName] = msg.data;
			var savedir = PathUtils.join(await Downloads.getPreferredDownloadsDirectory(), "_Web", Title(-1)); // каталог Загрузки + домен
			var path = PathUtils.join(savedir, fileName);
			await IOUtils[write](path, fileContent);
			var d = await Downloads.createDownload({ source: "about:blank", target: FileUtils.File(path)});
			(await Downloads.getList(Downloads.ALL)).add(d);
			d.refresh(d.succeeded = true); // помигать кнопкой Загрузки
		}
		messageManager.addMessageListener(msgName, msgListener);
		addDestructor(() => messageManager.removeMessageListener(msgName, msgListener));

		var svc = 'globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services';
		var url = "data:;charset=utf8," + encodeURIComponent(`(${func})(${svc});`.replace("%MSG_NAME%", msgName));
		(save = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))();
	} // end save

	var listener = e => { // Clicks
		var trg = e.target, {prefs} = Services;
		if (e.button == 1) {
			if (e.shiftKey) { // СКМ + Shift
				if ( prefs.getIntPref("permissions.default.image", 1) == 1)
					prefs.setIntPref("permissions.default.image", 2), trg.style.filter = "hue-rotate(180deg) brightness(95%)"
				else
					prefs.setIntPref("permissions.default.image", 1), trg.style.filter = "";
				BrowserReload();
			} else	// СКМ Click
				saveSelectionToTxt(); // сохранить .txt
		} else if (e.button == 2) {
			if (e.shiftKey)
				Downloads.getSystemDownloadsDirectory().then(path => FileUtils.File(path).launch(), Cu.reportError) // Обзор папки «Загрузки»
			else	// ПКМ Click
				save(); // Single HTML
		}
	}
	var keydown_win = e => { // нажатие клавиш
		if (!(e.keyCode == 83 && e.shiftKey && e.altKey)) return;
		var singlesave = document.getElementById("_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action"); // SingleSave
		singlesave ? singlesave.click() : save(); // имитировать клик по кнопке, используя её ID
	}
	btn.addEventListener("click", listener);
   window.addEventListener("keydown", keydown_win);
	var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win;
	ucf[id] = {destructor() {
		btn.removeEventListener("click", listener);
		window.removeEventListener("keydown", keydown_win);
	}};
	ucf.unloadlisteners.push(id);

})("downloads-button-click-listener", ({io, focus}) => {

	var resolveURL = function (url, base) {
		try {
			return io.newURI(url, null, io.newURI(base)).spec;
		} 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 mainWin = {};
	focus.getFocusedElementForWindow(content, true, mainWin);
	mainWin = mainWin.value;

	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(/\s+/g, ' ').slice(0, 100).trim();
	fileName += "_" + new Date().toLocaleString("ru").replace(", ","-").replace(/:/g, "։");
	if (!/\.html?$/.test(fileName)) fileName += '.html';

	sendAsyncMessage("%MSG_NAME%", [doctype + sel.innerHTML +'\n<a href='+ (loc.protocol != 'data:' ? loc.href : 'data:uri') +'><small><blockquote>источник: '+ new Date().toLocaleString("ru") +'</blockquote></small></a>', fileName]);

}); // END hookClicks

Отсутствует

 

№1553409-05-2021 15:49:56

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

Re: Custom Buttons

Deriax пишет

куки нужной активной вкладки, как это реализовать через xpcom или модуль Services?

Без понятия что значит «куки вкладки», вообще кук не держу.
Возможно что-то типа такого

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

Выделить код

Код:

var {host, originAttributes} = gBrowser.contentPrincipal;
var cookies = Services.cookies.getCookiesFromHost(host, originAttributes);

var resultAsJSON = JSON.stringify(cookies, null, "\t");
gBrowser.selectedTab = gBrowser.addTrustedTab(
	"data:text/plain;charset=utf-8," + encodeURIComponent(resultAsJSON)
);

Dobrov пишет

Почините скрипт Save HTML, он не работает в Firefox 78 ESR

Что значит «почините»?
Он и не должен работать «в Firefox 78».
Можно попробовать добавить перед строкой с ошибкой

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

Выделить код

Код:

…
		if (typeof IOUtils != "object") {
			var {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
			var PathUtils = {join: (...args) => OS.Path.join(...args)};
			var IOUtils = {writeUTF8: (path, txt) => OS.File.writeAtomic(path, new TextEncoder().encode(txt))};
		}

Отсутствует

 

№1553509-05-2021 16:05:34

Cytrus
Участник
 
Группа: Members
Зарегистрирован: 30-04-2021
Сообщений: 10
UA: Firefox 78.0

Re: Custom Buttons

Подскажите, есть ли способ, чтобы определить в приватном ли режиме окно или в обычном режиме?

Отсутствует

 

№1553609-05-2021 16:39:00

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

Re: Custom Buttons

Cytrus
PrivateBrowsingUtils.isWindowPrivate(window);

Отсутствует

 

№1553709-05-2021 18:01:54

Cytrus
Участник
 
Группа: Members
Зарегистрирован: 30-04-2021
Сообщений: 10
UA: Firefox 78.0

Re: Custom Buttons

Понял, спасибо.

Отсутствует

 

№1553809-05-2021 19:17:13

Deriax
Участник
 
Группа: Members
Зарегистрирован: 27-03-2021
Сообщений: 20
UA: Chrome 90.0

Re: Custom Buttons

Dumby пишет
Deriax пишет

куки нужной активной вкладки, как это реализовать через xpcom или модуль Services?

Без понятия что значит «куки вкладки», вообще кук не держу.
Возможно что-то типа такого

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

Выделить код

Код:

var {host, originAttributes} = gBrowser.contentPrincipal;
var cookies = Services.cookies.getCookiesFromHost(host, originAttributes);

var resultAsJSON = JSON.stringify(cookies, null, "\t");
gBrowser.selectedTab = gBrowser.addTrustedTab(
	"data:text/plain;charset=utf-8," + encodeURIComponent(resultAsJSON)
);

Dobrov пишет

Почините скрипт Save HTML, он не работает в Firefox 78 ESR

Что значит «почините»?
Он и не должен работать «в Firefox 78».
Можно попробовать добавить перед строкой с ошибкой

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

Выделить код

Код:

…
		if (typeof IOUtils != "object") {
			var {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
			var PathUtils = {join: (...args) => OS.Path.join(...args)};
			var IOUtils = {writeUTF8: (path, txt) => OS.File.writeAtomic(path, new TextEncoder().encode(txt))};
		}

Как исправить эту ошибку?
gBrowser.addTrustedTab is not a function

Отсутствует

 

№1553909-05-2021 19:31:25

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

Re: Custom Buttons

Dumby - ваш код IOUtils как всегда идеален!


А есть варианты, как Сохранить картинку без запроса для user_chrome_files?
Лучше жестом или двойным кликом мыши или из контекстного меню (но это дольше).


Не работают: user-скрипт MouseGestures2_e10s.uc.js и CB Сохранить изображение без запроса…

Отсутствует

 

№1554009-05-2021 21:35:44

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

Re: Custom Buttons

Deriax пишет

Как исправить эту ошибку?
gBrowser.addTrustedTab is not a function

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


Dobrov пишет

Не работают: ... и CB Сохранить изображение без запроса…

На 90.0a1 работает.
Только, обычная (теперь уже), проблема с сепараторами, и настройку включить надо.
Для ucf? Например, вариант

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

Выделить код

Код:

(async sel => {
	var path = "E:\\Download";

	var menuitem = document.createXULElement("menuitem");
	document.querySelector(sel).before(menuitem);
	var {render} = menuitem.constructor.prototype;
	menuitem.render = () => {
		menuitem.className = "menuitem-iconic";
		menuitem.setAttribute("oncommand", "saveImg()");
		menuitem.setAttribute("label", "Сохранить изображение в папку: " + path);
		menuitem.setAttribute("image", "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAABAnAAAQJwAAAAAAAAAAAAAAAAEGAQECKAABATsAAAAoAAAAFAAAAAkAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIjRRXUVtk8U+Y4TGKUBYrRgmNpcOFR91BQgMWAECBD8AAQEqAAAAGAAAAAwAAAAGAAAAAQAAAAAAAAAAAAAAAEVrp7Nws9//fcr6/3W+9f5wten5ZKHQ7lWGsedDaI7QL0hjtR4sQKERGSaBBgkOXgAAACoAAAAEAAAAAAAAAABKdrK+aqjY/4XO7P+AyfL/fcXy/4HL+/97xPT/eMHy/3e+8f9trt77YpvI8Ux0m98TGymTAAAAJQAAAAAAAAAAVIS7yGWh0/8yTVv/UniH/0htff+L0e//WIab/0x2i/9XiKL/RGp+/zNRYv9dkrP+S26S2QQGClwAAAAGAAAAAGeYxtFxrtr/IDA7/01mbf8sPkP/SWZw/zlSWv88Vl//LkRL/3Wsv/83UVr/XYqe/3+51PQaJDCWAAAAGwAAAAB5qtHajMXk/yY1Pf9fa23/GB8g/2yGjP8mMDL/Sl9k/0RYXP9wmKL/dZ+r/4i6y/+n4PD+TmV5yQECA0UAAAACh7bX46zh8/9tjZj/gpen/4GMk//G4Oj/kJ6f/52clf+svbz/f5id/3yXnv+gx9L/wez1/5u0xuwPExt+AAAAEJTA3ey/7vr/ve35/7Hf8v+w0ub/ubvE/8a4uf/NwLv/083I/9Pl6//T7ff/0O32/9fw9v/a6vL8P0ZYtAAAAC+iy+P2zvX8/831/P/K6e3/y7Kg/+GNZf/vlWr/6Zx3/9qegv/Ino7/t8TQ/7HM4/+itc3yu8ja52BtirQAAAEkqs/l9dv8/f/b/P3/1dzU/9qXcf/slmb/+aFr//+td//+rXb/+aRu/9+1k/+/2uL/RldrtiIrPU0ZITEoAAAAA46017zX8Pf85/7+/+X8+//g7+3+yryw+O6odPz/wYj/9bJ7/+KpgP/nqn3/0tPJ/kRTY6QAAQEYAAAAAAAAAAA6V3Yuboyqj6C81My50ubgo7zR1I92bLbzt3/3/tGZ/8aTZttfY2+PbX2Sn3GFm7EiLDtNAAAABQAAAAAAAAAAAgMEAAUHCgYYJDETIS4+LjMwNU+3e029/NGZ/vHHlPRrSSx/BQUFEAMFBwcEBQcJAQECAgAAAAAAAAAAAAAAAAAAAAAAAAAAEQgAA1wvElSsaz3B9LZ8+fC7gu6WZ0COFg0GGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADcTAQrWbS+y7pdZ8eOVWMqUWy91IRIJFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP//AACf/wAAgH8AAIAfAACADwAAgA8AAIAHAACABwAAgA8AAIAPAADOHwAA/v8AAP//AAD//wAA//8AAA==");

		menuitem.saveImg = () => {
			var p = Services.prefs;
			var data = Object.assign(Object.create(null), {
				"browser.download.folderList": {type: "Int", set: 2},
				"browser.download.useDownloadDir": {type: "Bool", set: true},
				"browser.download.dir": {type: "String", set: path}
			});
			var save = eval(`(function ${gContextMenu.saveMedia})`.replace(
				"\n        false, // don't", "\n        true, //"
			));
			(menuitem.saveImg = () => {
				for(var pref in data) {
					var obj = data[pref], meth = `et${obj.type}Pref`;
					obj.val = p.prefHasUserValue(pref) ? p["g" + meth](pref) : null;
					p["s" + meth](pref, obj.set);
				}
				try {save.call(gContextMenu);} finally {
					for(var pref in data) data[pref].val === null
						? p.clearUserPref(pref)
						: p[`set${data[pref].type}Pref`](pref, data[pref].val);
				}
			})();
		}
		(menuitem.render = async () => {
			render.call(menuitem);
			var {context, browser} = nsContextMenu.contentData || {};
			menuitem.hidden = !context?.onImage ||
				browser.classList.contains("webextension-popup-browser");
		})();
	}
})("#context-viewimageinfo, #context-viewimagedesc");


А клики и жесты, ну ты же понимаешь, что изображение в другом процессе?

Отсутствует

 

№1554110-05-2021 02:37:17

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

Re: Custom Buttons

Dumby пишет

Только, обычная (теперь уже), проблема с сепараторами, и настройку включить надо

Какую настройку? Скрипт подключил в custom_script_win.js, работает нормально, но папку загрузок пришлось получать вот таким неправильным кодом:

Выделить код

Код:

// var path = Services.downloads.userDownloadsDirectory.path; // ошибка получения пути «Загрузки», так не работает
var {prefs} = Services;
var path = prefs.getStringPref("browser.download.lastDir", Services.dirsvc.get("Desk", Ci.nsIFile).path); // так не работает, если папка Загрузки не выбрана
Dumby пишет

Сохранить изображение без запроса…
клики и жесты, ну ты же понимаешь, что изображение в другом процессе?

В два действия из контекстного меню слишком долго! Кроме того, на картинках-ссылках появляется второй сепаратор.
А есть код: Сохранить картинку без запроса перетаскиванием вправо или двойным кликом? Желательно в папку <Загрузки>/_Images


Второй вопрос: сделал код Автоскрытие панели вкладок, панель переключается нормально, когда код в кнопке CustomButtons.
Но ничего не происходит при подключении этого кода в custom_script_win.js или custom_script.js (напрямую или через loadscript).

Выделить код

Код:

(url => { // автоскрытие панели вкладок. aris-t2/customcssforfx > TABS BELOW TITLEBAR (Fx56-like)
	var IdHeight = function (id_name, height) {
		document.getElementById(id_name).style.cssText = `min-height: ${height}px !important; max-height: ${height}px !important;`;
	}
	var TabCollapsed = function (tabs, nav_h, tab_h) { // пока только для панели вкладок в один ряд
		if (tabs == 1) bar.collapsed = true, IdHeight("navigator-toolbox", nav_h - tab_h);
		if (tabs == 2) bar.collapsed = false, IdHeight("navigator-toolbox", nav_h);
	}
	var num = gBrowser.tabs.length, bar = document.getElementById("TabsToolbar"), nav = document.getElementById("navigator-toolbox");
	this.hasAttribute("nav_h") ? null : this.setAttribute("nav_h", nav.clientHeight);
	this.hasAttribute("tab_h") ? null : this.setAttribute("tab_h", bar.clientHeight);
	var nav_h = this.getAttribute("nav_h"), tab_h = this.getAttribute("tab_h");

	addEventListener("TabOpen", () => {
		TabCollapsed(++num, nav_h, tab_h);
	}, false, gBrowser.tabContainer);

	addEventListener("TabClose", () => {
		TabCollapsed(--num, nav_h, tab_h);
	}, false, gBrowser.tabContainer);

	var type = windowUtils.USER_SHEET;
	windowUtils.loadSheetUsingURIString(url, type);
	TabCollapsed(num, nav_h, tab_h);

	addDestructor(() => {
		windowUtils.removeSheetUsingURIString(url, type);
		TabCollapsed(2, nav_h, tab_h);
	});
})("data:text/css;charset=utf-8,%23TabsToolbar[collapsed]:not([customizing]){visibility:collapse!important;}");

Отредактировано Dobrov (10-05-2021 11:40:26)

Отсутствует

 

№1554210-05-2021 23:48:04

kazarin
Участник
 
Группа: Members
Зарегистрирован: 23-11-2016
Сообщений: 24
UA: unknown 0.0

Re: Custom Buttons

Dobrov пишет

А есть код: Сохранить картинку без запроса перетаскиванием вправо или двойным кликом? Желательно в папку <Загрузки>/_Images

Извиняюсь, что лезу, но Вам принципиально, чтоб это было реализовано скриптом? А то в аддоне Image Picka, на который я раньше давал ссылку, настройка Show a download button on hover создаёт над изображением кнопку, с которой можно сохранять без запроса.

Отсутствует

 

№1554311-05-2021 01:00:43

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

Re: Custom Buttons

kazarin

расширения бесполезны на страницах moz-extension://… Если сайт скрывает картинки под div, сохранить их можно так:
Клик по кнопке Text Linky Tool покажет всю, даже скрытую графику, а расширение Pick Images таких картинок не найдёт.


Думаю, код user-chrome_files Сохранить картинку без запроса перетаскиванием или двойным кликом будет работать на странице найденных картинок moz-extension://…, открытой расширением Text Linky Tool.
Ведь скрипт Save HTML без проблем сохраняет страницы из режима просмотра about:reader, где расширение SingleFile и подобные не работают!

Отсутствует

 

№1554411-05-2021 07:02:35

kazarin
Участник
 
Группа: Members
Зарегистрирован: 23-11-2016
Сообщений: 24
UA: unknown 0.0

Re: Custom Buttons

Dobrov
Я бы на этой странице сделал так:
https://www.upload.ee/files/13132535/Video_2021-05-11_064226.wmv.html
Если правильно понимаю, это сайт из той же группы, что и предыдущий, дораматв? Там через Image Picka можно получить список урлов.
https://www.upload.ee/files/13132548/Video_2021-05-11_065220.wmv.html
Ну и расширение DownThemAll от xiaoxiaoflood на этой странице работает.
2021-05-11_065329.png
Если будет ещё и скрипт, хорошо, но, кмк, и одного расширения достаточно для этой работы:)

Отсутствует

 

№1554511-05-2021 07:54:29

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

Re: Custom Buttons

kazarin - у меня на обложке-ссылке фильма Гости из прошлого не появляется кнопка загрузки, только курсор в виде руки.

Отсутствует

 

№1554611-05-2021 10:21:38

Deriax
Участник
 
Группа: Members
Зарегистрирован: 27-03-2021
Сообщений: 20
UA: Chrome 90.0

Re: Custom Buttons

Попробую вникнуть...

Отредактировано Deriax (11-05-2021 17:26:55)

Отсутствует

 

№1554711-05-2021 10:34:11

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

Re: Custom Buttons

Dobrov пишет

Какую настройку?

Которая возвращает в строй пункт «Информация об изображении».
browser.menu.showViewImageInfo (Firefox 89+).

на картинках-ссылках появляется второй сепаратор

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

А есть код: Сохранить картинку без запроса перетаскиванием вправо

Ну, вообще-то, dataTransfer в родительском процессе есть.
И focused (content) browsingContext (Firefox 85+).
Можно попробовать прицепиться, но не уверен.

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

Выделить код

Код:

(async id => {
	var path = "E:\\Download";

	await delayedStartupPromise;
	var listener = {
		handleEvent(e) {
			this[e.type](e);
		},
		dragstart(e) {
			if (
				e.dataTransfer.mozItemCount
				&& gBrowser.selectedBrowser.matches(":hover")
				&& e.dataTransfer.getData("text/x-moz-url-data")
			)
				this.x = e.screenX,
				this.y = e.screenY,
				this.drag("add");
		},
		events: ["dragover", "drop", "dragend"],
		drag(meth = "remove") {
			meth += "EventListener";
			for(var type of this.events) window[meth](type, this, true);
		},
		drop() {
			this.drag();
		},
		dragover(e) {
			var {x, y} = this,
				cx = e.screenX, cy = e.screenY,
				dx = cx - x,
				ax = Math.abs(dx), ay = Math.abs(cy - y);

			if (ax < 10 && ay < 10) return;
			if (dx < 0 || ax < ay) return this.drag();
			this.x = cx; this.y = cy;
		},
		dragend(e) {
			var dt = e.dataTransfer;
			this.drag();
			if (dt.mozUserCancelled || e.screenX > mozInnerScreenX + innerWidth)
				return;
			var url, name = null;
			if (dt.types.contains("application/x-moz-nativeimage"))
				url = dt.getData("application/x-moz-file-promise-url"),
				name = dt.getData("application/x-moz-file-promise-dest-filename");				
			else {
				var html = dt.getData("text/html");
				if (html) url = new DOMParser().parseFromString(
					`<template>${html}</template>`, "text/html"
				).querySelector("template").content.querySelector("img")?.src;				
			}
			url && this.save(url, name);
		},
		save(url, name) {
			var p = Services.prefs;
			var data = Object.assign(Object.create(null), {
				"browser.download.folderList": {type: "Int", set: 2},
				"browser.download.useDownloadDir": {type: "Bool", set: true},
				"browser.download.dir": {type: "String", set: path}
			});
			var refp = "network.http.sendRefererHeader";
			var ReferrerInfo = Components.Constructor(
				"@mozilla.org/referrer-info;1", "nsIReferrerInfo", "init"
			);
			var {fetch} = Cu.getGlobalForObject(Cu);

			(this.save = async (url, name) => {
				var bc = Services.focus.focusedContentBrowsingContext;
				var http = url.startsWith("http");
				var referrerInfo = null;
				if (bc && http && Services.prefs.getIntPref(refp) != 0) {
					var ref = bc.currentURI;
					if (ref.spec.startsWith("http"))
						referrerInfo = new ReferrerInfo(Ci.nsIReferrerInfo.EMPTY, true, ref);
				}
				var contentType = this.getContentType(name && http ? "http://example.com/" + name : url);
				if (!contentType) {try {
					var arr = new Uint8Array(await (await fetch(url)).arrayBuffer());
					contentType = Cc["@mozilla.org/image/loader;1"]
						.createInstance(Ci.nsIContentSniffer)
						.getMIMETypeFromContent(null, arr, arr.length);
				} catch {}}
				for(var pref in data) {
					var obj = data[pref], meth = `et${obj.type}Pref`;
					obj.val = p.prefHasUserValue(pref) ? p["g" + meth](pref) : null;
					p["s" + meth](pref, obj.set);
				}
				try {internalSave(
					url,
					null, // document
					name, // file name
					null, // contentDisposition
					contentType,
					false, // do not bypass the cache
					null, // filepicker title key
					null, // chosen data
					referrerInfo,
					bc?.currentWindowGlobal?.cookieJarSettings,
					document, // initiating doc
					true, // skip prompt for where to save
					null, // cache key
					bc?.usePrivateBrowsing,
					document.nodePrincipal
				);}
				finally {
					for(var pref in data) data[pref].val === null
						? p.clearUserPref(pref)
						: p[`set${data[pref].type}Pref`](pref, data[pref].val);
				}
			})(url, name);
		},
		getContentType(url) {
			var re = /^data:(image\/[^;,]+)/;
			var ms = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
			return (this.getContentType = url => {
				if (re.test(url)) return RegExp.$1;
				try {return ms.getTypeFromURI(Services.io.newURI(url));} catch {}
				return null;
			})(url);
		}
	};
	gBrowser.tabpanels.addEventListener("dragstart", listener, true);
	var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win;
	ucf[id] = {destructor: () => gBrowser.tabpanels.removeEventListener("dragstart", listener, true)};
	ucf.unloadlisteners.push(id);
})("drag-image-saver");

Отсутствует

 

№1554811-05-2021 11:47:21

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

Re: Custom Buttons

Dumby - да, жестом картинка сохраняется, но не в папку Загрузки, а в корневую папку профиля.
А как сохранять в другую папку? Код изменения пути Загрузок не помог:

Выделить код

Код:

var {prefs} = Services;
var path = prefs.getStringPref("browser.download.lastDir", Services.dirsvc.get("Desk", Ci.nsIFile).path);
path = PathUtils.join(path, "_Images");

Отсутствует

 

№1554911-05-2021 12:35:44

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

Re: Custom Buttons

Dobrov
Я же без понятия что имеется в виду под «папка Загрузки», тем более на Мак.
Вариант: открой вкладку с адресом resource://gre/modules/DownloadIntegration.jsm
и поищи там getPreferredDownloadsDirectory и getSystemDownloadsDirectory
может найдётся подсказка к тому, что требуется.

Отсутствует

 

№1555011-05-2021 12:58:22

Cytrus
Участник
 
Группа: Members
Зарегистрирован: 30-04-2021
Сообщений: 10
UA: Firefox 78.0

Re: Custom Buttons

Подскажите, почему не получается сделать запись в локальное хранилище?
Выдаёт сообщение, типа недоступно.

Выделить код

Код:

localStorage.setItem('MyRecord', 1);
Выделить код

Код:

Exception { name: "NS_ERROR_NOT_AVAILABLE", message: "", result: 2147746065, filename: "chrome://custombuttons-context/content/button.js?windowId=Firefox&id=custombuttons-button21@code line 1 > Function", lineNumber: 3, columnNumber: 0, data: null, stack: "anonymous@chrome://custombuttons-context/content/button.js?windowId=Firefox&id=custombuttons-button21@code line 1 > Function:3:1\n@chrome://custombuttons-context/content/button.js?windowId=Firefox&id=custombuttons-button21@code:1:34\nbuttonCbExecuteCode@chrome://custombuttons/content/cbbutton.js:311:24\nbuttonCommand@chrome://custombuttons/content/cbbutton.js:338:10\ncommand@chrome://custombuttons/content/toolbarbutton/toolbarbutton.js:19:34\n", location: XPCWrappedNative_NoHelper }

Отредактировано Cytrus (11-05-2021 13:00:21)

Отсутствует

 

Board footer

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