Объявление

В связи с наплывом спама и ботов на форуме, регистрация новых пользователей будет приостановлена. О восстановлении регистрации будет сообщено дополнительно

Administrator

№205121-05-2025 15:35:00

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

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

_zt пишет

Сложные скрипты все починили, вам же надо хотелку. Тоже самое, но с перламутровыми пуговицами.

Мне надо исправить то, что есть.
Но те, кто может исправить, это делать по каким-то своим внутренним убеждениям не хочет. Другие же предлагают альтернативу, которая по тем или иным причинам мне не подходит, или не работает.


Вот и остается, что дербанить Save, и вместо одного фала скрипта, получить два. Да, пока работает, но это извращение какое-то.


«The Truth Is Out There»

Отсутствует

 

№205221-05-2025 16:30:40

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

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

xrun1 пишет

Строка меню в гамбургере "Сохранить страницу | выбранное как HTML"

на замену

AppMenuTbbSaveHTMLChild.sys.mjs

Выделить код

Код:

// в custom_script.js (async url => ChromeUtils.importESModule(url))( "chrome://user_chrome_files/content/custom_scripts/Actors/AppMenuTbbSaveHTMLChild.mjs");
// или в scriptsbackground: [ // In the background [System Principal]
// { func: 'ChromeUtils.importESModule("chrome://user_chrome_files/content/custom_scripts/Actors/AppMenuTbbSaveHTMLChild.mjs");' },

var self, name = "AppMenuTbbSaveHTML";
var {io, focus, obs} = globalThis.Services;

export class AppMenuTbbSaveHTMLChild extends JSWindowActorChild {
	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);
	},
	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.className = "subviewbutton subviewbutton-iconic";
		btn.setAttribute("label", "Страница | выбранное в единый HTML");
		btn.setAttribute("image", "data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='context-fill' fill-opacity='context-fill-opacity'><path d='M12.225.01H2.656v5.993l.955-.125L3.569.677 11 .76l-.042 4.375h4.275l.041 10.125-12.575.042-.042.708h13.281V3.737L12.225.01zm-.272 1.613 2.384 2.394h-2.384V1.623zm2.93 10.318.062 1.333-2.992.063V8.003h1.328v4l1.601-.063zM4.647 8.002h-.664v1.334h.664v4h1.329v-4h.664V8.003H4.648zm5.313 0-.664 1.074-.664-1.074H7.305v5.334h1.328V10.53l.664 1.073.664-1.073v2.807h1.328V8.003H9.961zm-7.969 2h-.664v-2H0v5.334h1.328v-2h.664v2H3.32V8.003H1.992v2z'/></svg>");
		btn.saveHTML = this.saveHTML;
		popup.querySelector('toolbarbutton[id^="appMenu-print-button"]').before(btn);
		btn.addEventListener("command", (e) => {e.target.saveHTML();});
	},
	unload(e) {
		var win = e.target.ownerGlobal;
		win.removeEventListener("unload", this);
		win.document.getElementById("appMenu-popup").removeEventListener("popupshowing", this);
		win.document.getElementById("appMenu-popup").removeEventListener("command", (e) => {e.target.saveHTML();});
	},
	async saveHTML() {
		var win = this.ownerGlobal;
		var br = win.gBrowser.selectedBrowser;
		var bc = focus.focusedContentBrowsingContext;
		if (bc?.top.embedderElement != br) bc = br.browsingContext;

		var actor = bc?.currentWindowGlobal?.getActor(name);
		actor && self.save(win, ...await actor.sendQuery(""));
	},
	async save(win, fileContent, fileName) {
		var fp = Cc['@mozilla.org/filepicker;1'].createInstance(Ci.nsIFilePicker);
		fp.init(
			!("inIsolatedMozBrowser" in win.browsingContext.originAttributes)
			? win.browsingContext
			: win, "", fp.modeSave);
		fp.defaultString = fileName;
		fp.appendFilters(fp.filterHTML);
		fp.appendFilters(fp.filterAll);
		var res = await new Promise(fp.open);
		if (res == fp.returnOK || res == fp.returnReplace)
			this.write(fp.file.path, fileContent);
	},
	write(path, html) {
		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 => {

	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 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).replace(/^\s+|\s+$/g, '');
	fileName += (function () {
		var d = new Date(), z = function(n){return '_' + (n < 10 ? '0' : '') + n};
		return 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];
}


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

Отсутствует

 

№205321-05-2025 16:59:07

fuchsfan
Участник
 
Группа: Members
Зарегистрирован: 07-08-2023
Сообщений: 174
UA: Firefox 139.0

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

xrun1 пишет

contextviewpageinfo.js

Там, где другому пользователю  "с большим скрипом, но все же помогли исправить", этот скрипт есть в двух вариантах, на панель и в контекст, работает в 139.

Отсутствует

 

№205421-05-2025 18:54:51

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

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

unter_officer пишет

Виталий выложил новую версию UCF

Выделить код

Код:

styleschrome - CssChrome
stylesall - CssAllFrame
stylescontent - CssContent
scriptsbackground - JsBackground
scriptschrome - JsChrome
scriptsallchrome - JsAllChrome
scriptscontent - JsContent
	
domload - DOMContentLoaded
типа
JsChrome.DOMContentLoaded
JsAllChrome.DOMContentLoaded
	
ну и остальное
JsChrome.load
JsAllChrome.load
JsContent.DOMWindowCreated
JsContent.DOMContentLoaded
JsContent.pageshow

   
Чтобы перевести рег. выражения из CustomStylesScripts.mjs в строку для записи в prefs.json (новый файл настроек) - откройте консоль, введите RegExp и в конце .source
Например, вводим:

Выделить код

Код:

/^chrome:\/\/browser\/content\/places\/bookmarksSidebar\.xhtml/.source

получаем строку

Выделить код

Код:

"^chrome:\\/\\/browser\\/content\\/places\\/bookmarksSidebar\\.xhtml"

   
prefs.json вручную править не надо, все делается через страницу настроек.
   
Добавлено 21-05-2025 19:09:24
И самое главное забыл. Если в начале файла стиля/скрипта добавить строки, например

Выделить код

Код:

/**
@UCF @param {"prop":"JsAllChrome.load","ucfobj":false,"urlregxp":"^chrome:\\/\\/browser\\/content\\/(?:browser|places\\/(?:bookmarksSidebar|places))\\.xhtml"} @UCF
@UCF @param {"prop":"JsContent.pageshow","ucfobj":false,"urlregxp":"^chrome:\\/\\/browser\\/content\\/(?:browser|places\\/(?:bookmarksSidebar|places))\\.xhtml"} @UCF
*/

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

Отредактировано _zt (21-05-2025 19:10:39)

Отсутствует

 

№205521-05-2025 20:27:41

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

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

fuchsfan пишет

Там, где другому пользователю

Я там устал читать. Теряю изначальную мысль обсуждения к окончанию. :)
На предыдущей странице получил рабочий код.
unter_officer, Farby
Спасибо. :beer:

Отредактировано xrun1 (21-05-2025 20:31:26)

На форуме

 

№205621-05-2025 21:35:20

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

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

_zt пишет

выложил выше полностью рабочий вариант Save

Функции, вроде, работают (те, что проверил). А вот внешний вид не комильфо.
Системная тема. Слева мой вариант сейчас и то, что Вы выложили. https://imgsh.net/i/2c45617ddf
В тёмной теме значки видны. https://imgsh.net/i/95027066e7
Внешний вид, лично меня, пугает. Может, что-то сделал не так? У меня выглядит одинаково и на чистом профиле, и со стилями.

На форуме

 

№205721-05-2025 22:38:40

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

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

xrun1
При чем тут иконки, главное что скрипт рабочий, а иконки свои сделайте, я же сделал для себя когда меня те что были в оригинале не устроили.
Можете сравнением перенести измененные строки из моего варианта в старый и будут у вас привычные иконки. В скрипте ссылки на предыдущие версии есть.
А насчет блока с PNG - я хз почему так, может потому что скрипт на 138 не тестировался или потому что вы с лопуховатыми меню сидите. :) Можно из fulltheme взять menu_max138.css (в 139 menu.css). Все что после /* icons in menu --> */ можете удалить или оставить, но тогда и папка svg понадобится. У меня так выглядит: https://s1.directupload.eu/images/250521/3qgv8tge.png
   
ps^ все равно все ваши стили для меню в 139 отвалятся, так что можете уже сейчас начинать их выкидывать.
   
Добавлено 21-05-2025 22:56:02
ps2^ папка svg с пятью иконками понадобится даже если удалить блок начиная с /* icons in menu --> */ А именно: menu-right-icon.svg, checkbox-icon.svg, checkbox-icon-checked.svg, radio-icon.svg и radio-icon-checked.svg

Отредактировано _zt (21-05-2025 22:57:54)

Отсутствует

 

№2058Вчера 00:08:19

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

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

_zt
Всё нормально. Это был чистый скрипт. Кривенько вышла группа PNG, но это я забыл о стилях. Приношу извинения. Со стилями всё выровнялось, иконки заменяются (на скрине заменил 2 первые). Чек и радио buttons не потребовались.
https://imgsh.net/i/a1b6791b71

все равно все ваши стили для меню в 139 отвалятся, так что можете уже сейчас начинать их выкидывать

Чёй-то отвалятся? А хоть и отвалятся - починю, первый раз что ли?:D

На форуме

 

№2059Вчера 02:57:53

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

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

Чек и радио buttons нужны для меню панелей и др. :/
https://s1.directupload.eu/images/250522/jrdqbq4a.png
Ну а menu-right-icon.svg это стрелка в конце пункта menu

Отредактировано _zt (Вчера 03:02:11)

Отсутствует

 

№2060Вчера 07:05:45

fuchsfan
Участник
 
Группа: Members
Зарегистрирован: 07-08-2023
Сообщений: 174
UA: Firefox 139.0

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

xrun1 пишет

На предыдущей странице получил рабочий код.

Который в консоли выдает ошибку
err.png
Упомянутые мною, которые там, не ошибаются.

Отсутствует

 

№2061Вчера 09:29:21

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

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

Отсутствует

 

№2062Вчера 09:35:15

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

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

fuchsfan
У меня в консоли такого нет. [firefox] 138.0.3 и UCF 2025.05.02 23:38:18
_zt
Чек и радио buttons прописаны в каком-то стиле, т.е. картинки как-бы есть. Поэтому в скрипте квадратик с галочкой или без есть. :)
Поправили мне поиск по картинкам. В custom_script_win.js

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

Выделить код

Код:

// Добавить подменю "Поиск изображения в" в контекстном меню изображений
(this.searchimagecontextmenu = {
    handleEvent(evt) {
        if (evt.target != this.contextMenu || !gContextMenu?.imageInfo?.currentSrc) return;
        var array = [
            ['Яндекс', 'chrome://activity-stream/content/data/content/tippytop/favicons/yandex-ru.png', 'https://yandex.ru/images/search?rpt=imageview&url='],
            ['Bing', 'chrome://activity-stream/content/data/content/tippytop/favicons/bing-com.ico', 'https://www.bing.com/images/search?view=detailv2&iss=sbi&form=SBIHMP&sbisrc=UrlPaste&q=imgurl:'],
            ['Tineye', 'https://tineye.com/favicon.ico', 'https://tineye.com/search?pluginver=bookmark_1.0&url='],
// нерабочий            ['Google', 'https://www.google.lv/favicon.ico', 'https://www.google.com/searchbyimage?&image_url='],
            ['Google1', 'chrome://activity-stream/content/data/content/tippytop/favicons/google-com.ico', 'https://lens.google.com/v3/upload?url='],
            ['Google2', 'chrome://activity-stream/content/data/content/tippytop/favicons/google-com.ico', 'https://www.google.com/searchbyimage?sbisrc=cr_1_5_2&image_url='],
        ];
        var menu = document.createXULElement("menu");
        menu.setAttribute("label", "Поиск изображения в ...");
        menu.setAttribute("class", "menu-iconic");
        menu.setAttribute("image", array[0][1]);
//        menu.setAttribute("onclick", "_searcclick(event);");
//        menu._searcclick = function(e) {
        menu.onclick = function(e) {
            if (e.target != this) return;
//            gBrowser.selectedTab = gBrowser.addTrustedTab(this._searcharg[2] + encodeURIComponent(gContextMenu.imageInfo.currentSrc), { index: gBrowser.selectedTab._tPos + 1 } );
        gBrowser.selectedTab = gBrowser.addTrustedTab(array[0][2] + encodeURIComponent(gContextMenu.imageInfo.currentSrc), { index: gBrowser.selectedTab._tPos + 1 } );
            this.parentNode.hidePopup();
        }
//        menu._searcharg = array[0];
        var menuPopup = document.createXULElement("menupopup");
        menu.append(menuPopup);
        array.forEach(m=> {
            var mItem = document.createXULElement("menuitem");
            mItem.setAttribute("label", m[0]);
            mItem.setAttribute("image", m[1]);
            mItem.setAttribute("class", "menuitem-iconic");
//            mItem.setAttribute("oncommand", "gBrowser.selectedTab = gBrowser.addTrustedTab(_searcharg[2] + encodeURIComponent(gContextMenu.imageInfo.currentSrc), { index: gBrowser.selectedTab._tPos + 1 } );");
//            mItem._searcharg = m;
            mItem._searchimg = e => gBrowser.selectedTab = gBrowser.addTrustedTab(m[2] + encodeURIComponent(gContextMenu.imageInfo.currentSrc), { index: gBrowser.selectedTab._tPos + 1 } );
            mItem.addEventListener("command", mItem._searchimg);
            menuPopup.append(mItem);
        });
        var mItem = document.createXULElement("menuitem");
        mItem.setAttribute("label", 'Искать во всех поисковиках');
//        mItem.setAttribute("oncommand", "_searcharg.forEach(m => { gBrowser.selectedTab = gBrowser.addTrustedTab(m[2] + encodeURIComponent(gContextMenu.imageInfo.currentSrc), { index: gBrowser.selectedTab._tPos + 1 } );});");
//        mItem._searcharg = array;
        mItem._searchimg = e => array.forEach(m => { gBrowser.selectedTab = gBrowser.addTrustedTab(m[2] + encodeURIComponent(gContextMenu.imageInfo.currentSrc), { index: gBrowser.selectedTab._tPos + 1 } );});
        mItem.addEventListener("command", mItem._searchimg);
        menuPopup.append(mItem);
        this.contextMenu.querySelector("#context-copyimage-contents")?.before(menu);
        this.popupshowing = e => {
            if (e.target != this.contextMenu) return;
            menu.hidden = !gContextMenu?.imageInfo?.currentSrc;
        };
        this.popuphiding = e => {
            if (e.target != this.contextMenu) return;
            menu.hidden = true;
        };
        this.contextMenu.addEventListener("popuphiding", this);
        this.handleEvent = e => {
            this[e.type](e);
        };
    },
    init(that) {
        var contextMenu = this.contextMenu = document.querySelector("#contentAreaContextMenu");
        if (!contextMenu) return;
        contextMenu.addEventListener("popupshowing", this);
//        that.unloadlisteners.push("searchimagecontextmenu");
        setUnloadMap(Symbol("searchimagecontextmenu"), this.destructor, this);
    },
    destructor() {
        this.contextMenu.removeEventListener("popupshowing", this);
        this.contextMenu.removeEventListener("popuphiding", this);
    },
}).init(this);

Отредактировано xrun1 (Вчера 22:30:42)

На форуме

 

№2063Вчера 09:55:07

egorsemenov06
Участник
 
Группа: Members
Зарегистрирован: 23-07-2024
Сообщений: 33
UA: Firefox 138.0

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

для [firefox] 138-139+ может кому надо

OpenPageInOtherBrowser

Выделить код

Код:

(async id => CustomizableUI.createWidget({
	label: "Открыть страницу в другом браузере",
	get image() {
		var img = `${this.id.toLowerCase()}-img`;
		Services.io.getProtocolHandler("resource")
			.QueryInterface(Ci.nsIResProtocolHandler)
			.setSubstitution(img, Services.io.newURI(
				"data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'><path style='fill:context-fill rgb(142, 142, 152);fill-opacity:context-fill-opacity' d='M7.94.062h.085a7.42 7.42 0 0 1 3.868 1.082l-.035-.02a7.77 7.77 0 0 1 3.033 3.25l.02.043-6.44-.344a4.18 4.18 0 0 0-2.57.672l.016-.01a3.826 3.826 0 0 0-1.6 2.006l-.008.026L1.913 3.01A7.657 7.657 0 0 1 4.569.856l.046-.02A7.54 7.54 0 0 1 7.938.06h.002zM1.455 3.649l2.926 5.875a4.317 4.317 0 0 0 1.81 1.91l.022.012a3.669 3.669 0 0 0 1.81.471c.26 0 .512-.026.756-.077l-.024.004-1.997 3.995a7.788 7.788 0 0 1-5.686-4.153l-.02-.043a7.818 7.818 0 0 1-.864-3.6v-.048.003-.046c0-1.603.474-3.092 1.285-4.332l-.017.029zm13.769 1.497c.32.815.51 1.76.518 2.75v.002l.001.114c0 .93-.154 1.823-.439 2.654l.017-.057a7.898 7.898 0 0 1-1.339 2.423l.01-.013a7.845 7.845 0 0 1-2.098 1.834l-.036.02a7.46 7.46 0 0 1-4.345 1.053l.022.002 3.516-5.519a4.262 4.262 0 0 0 .716-2.582v.01a3.902 3.902 0 0 0-.929-2.464l.004.005 4.382-.232zm-7.256.178c1.447 0 2.62 1.198 2.622 2.675-.001 1.477-1.175 2.675-2.622 2.675-1.448 0-2.621-1.198-2.622-2.675 0-1.477 1.174-2.675 2.622-2.675z'/></svg>"
			));
		delete this.image;
		return this.image = `resource://${img}`;
	},
	tooltiptext: [
		"С: Добавить в меню новый браузер",
		"\nФункции кликов мыши для меню:",
		"\tЛ: Открыть страницу",
		"\tС: Добавить разделитель",
		"\tП: Удалить пункт меню или разделитель",
		"\tCtrl+П: Изменить название пункта меню",
		"Перетаскиванием можно передвигать пункты меню или разделители"
	].join("\n"),
	id,
	localized: false,
	onCreated(btn) {
		btn.owner = this;
		btn.type = "menu";
		btn.setAttribute("image", this.image);
		btn.openPopup = btn.openMenu;
		btn.openMenu = this.openMenu;
		const popup = btn.appendChild(btn.ownerDocument.createXULElement("menupopup"));
		popup.setAttribute("context", "");
		popup.shouldRebuild = true;
		popup.addEventListener("command", event => this.command(event));
		popup.addEventListener("popupshowing", () => {
			if (popup.shouldRebuild) this.rebuild(popup);
		});
		popup.addEventListener("dragstart", this.dragstart.bind(btn));
		btn.onauxclick = this.auxclick;
		const { openDelay, closeDelay } = this;
		this.autoOpenCloseFeature(btn.ownerGlobal, btn, openDelay, closeDelay);
	},
	file: Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile),
	openMenu(...args) {
		if (this.parentNode != this.domParent) {
			this.domParent = this.parentNode;
			this.owner.setPopupPosition(this);
		}
		this.openPopup(...args);
	},
	setPopupPosition(node) {
		if (node.matches(".widget-overflow-list > :scope"))
			var pos = "after_start";
		else {
			var win = node.ownerGlobal,
				{ width, height, top, bottom, left, right } =
					node.closest("toolbar").getBoundingClientRect();
			pos = width > height
				? `${win.innerHeight - bottom > top ? "after" : "before"}_start`
				: `${win.innerWidth - right > left ? "end" : "start"}_before`;
		}
		node.firstChild.setAttribute("position", pos);
	},
	autoOpenCloseFeature(win, btn, openDelay = 200, closeDelay = 350) {
		var _openTimer = 0;
		var _closeTimer = 0;
		btn.onmouseover = function (e) {
			win.clearTimeout(_closeTimer);
			if (e.target == btn && closeOtherMenus()) {
				btn.open = true;
				return;
			}
			_openTimer = win.setTimeout(() => btn.open = true, openDelay);
		};
		btn.onmouseout = function (e) {
			win.clearTimeout(_openTimer);
			_closeTimer = win.setTimeout(() => btn.open = false, closeDelay);
		};
		function closeOtherMenus() {
			return win.Array.prototype.some.call(
				btn.parentNode.getElementsByTagName("*"),
				function (node) {
					if (
						node != btn &&
						win.XULElement.isInstance(node) &&
						"open" in node &&
						node.open &&
						node.getElementsByTagName("menupopup").length
					) {
						node.open = false;
						return true;
					}
					return false;
				}
			);
		}
	},
	get markup() {
		try {
			var data = Cu.readUTF8URI(Services.io.newURI(
				`chrome://user_chrome_files/content/custom_scripts/${id}-data.txt`
			)).split("\n").filter(line => /\S/.test(line));
		}
		catch {
			var data = [];
		}
		delete this.markup;
		return this.markup = this.dataToMarkup(data);
	},
	setMarkup(popup) {
		this.markup = popup.innerHTML;
		for (var { node } of CustomizableUI.getWidget(id).instances)
			if (node.firstChild != popup) node.firstChild.shouldRebuild = true;
		this.write(Array.from(popup.children, node =>
			node.hasAttribute("value")
				? node.tooltipText + (node.value == "true" ? ">" + node.label : "")
				: "separator"
		).join("\n"));
	},
	dataToMarkup(data) {
		var markup = "";
		for (var str of data) markup += str == "separator"
			? "<menuseparator/>" : this.strToMenuitem(str);
		return markup;
	},
	repl: [/^./, c => c.toUpperCase()],
	strToMenuitem(str, ind = str.lastIndexOf(">")) {
		var name, val, path = str;
		if ((val = ind != -1))
			path = str.slice(0, ind),
				name = str.slice(ind + 1);
		else
			this.file.initWithPath(path),
				name = this.file.leafName.split(".")
					.shift().replace(...this.repl);
		return `<menuitem label="${name}" tooltiptext="${path}" value="${val}"
			class="menuitem-iconic" image="moz-icon://file://${path}"/>`;
	},
	append(popup, xul = this.markup) {
		popup.append(popup.ownerGlobal.MozXULElement.parseXULToFragment(xul));
	},
	rebuild(popup) {
		popup.textContent = "";
		this.append(popup);
		delete popup.shouldRebuild;
	},
	auxclick(e) {
		var trg = e.target, popup = this.firstChild;
		if (trg == this && e.button == 1)
			return this.owner.addMenuitem(popup);
		else if (trg.parentNode != popup) return;
		if (e.button == 1) {
			var up = e.screenY < trg.screenY + trg.clientHeight / 2;
			up = up ? trg.previousSibling : !trg.nextSibling;
			trg[up ? "before" : "after"](
				trg.ownerDocument.createXULElement("menuseparator")
			);
		} else {
			if (e.ctrlKey) {
				if (trg.nodeName.endsWith("r")) return;
				var name = this.owner.prompt(
					"Введите другое название пункта",
					trg.label, trg.ownerGlobal
				);
				if (name && name != trg.label)
					trg.label = name,
						trg.value = true;
			}
			else trg.remove();
		}
		this.owner.changeMarkup(popup);
	},
	prompt(msg, value, domWin) {
		var res = { value };
		return Services.prompt.wrappedJSObject.pickPrompter({
			domWin, modalType: Ci.nsIPrompt.MODAL_TYPE_WINDOW
		}).nsIPrompt_prompt(this.label, msg, res, null, {})
			? res.value : null;
	},
	addMenuitem(popup) {
		var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
		fp.appendFilters(fp.filterApps);
		fp.init(popup.ownerGlobal.browsingContext, "Укажите путь к программе", fp.modeOpen);
		fp.open(res => {
			if (res == fp.returnOK)
				this.append(popup, this.strToMenuitem(fp.file.path, -1)),
					this.setMarkup(popup);
		});
	},
	changeMarkup(popup) {
		popup.state == "open"
			? popup.addEventListener("popuphidden", this, { once: true })
			: this.setMarkup(popup);
	},
	handleEvent(e) {
		this[e.type](e);
	},
	popuphidden(e) {
		this.setMarkup(e.target);
	},
	dragstart(e) {
		var trg = e.target;
		if (trg.parentNode.nodeName != "menupopup") return;
var owner = (this && this.owner) || (this.parentNode && this.parentNode.owner);
if (!owner) return;
		var pn = trg.flattenedTreeParentNode;
		owner.dragData = { trg, pn, ns: trg.nextSibling };
		trg.style.cssText = "font-weight: bold; color: red;"
			+ "outline: 2px solid red; outline-offset: -2px;"
				.replace(/;/g, " !important;");
		var win = trg.ownerGlobal;
		win.setCursor("grabbing");
		pn.addEventListener("mousemove", owner);
		win.addEventListener("mouseup", owner, { once: true });
	},
	mousemove(e) {
		var trg = e.target, dtrg = this.dragData.trg;
		if (trg == dtrg) return;
		e.movementY > 0
			? trg.nextSibling != dtrg && trg.after(dtrg)
			: trg.previousSibling != dtrg && trg.before(dtrg);
	},
	mouseup(e) {
		e.preventDefault();
		var { trg, pn, ns } = this.dragData;
		delete this.dragData;
		trg.removeAttribute("style");
		trg.ownerGlobal.setCursor("auto");
		pn.removeEventListener("mousemove", this);
		trg.nextSibling != ns && this.changeMarkup(trg.parentNode);
	},
	command(e) {
		this.file.initWithPath(e.target.tooltipText);
		if (this.file.exists()) {
			var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
			process.init(this.file);
			return process.run(false, [e.view.gBrowser.currentURI.spec], 1);
		}
		Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService)
			.showAlertNotification(this.image, this.label, "Файл не существует");
	},
	write(txt) {
		var file = Services.dirsvc.get("UChrm", Ci.nsIFile), CC = Components.Constructor;
		["user_chrome_files", "custom_scripts", id + "-data.txt"].forEach(file.append);
		var te = new (Cu.getGlobalForObject(Cu).TextEncoder)();
		var fos = CC("@mozilla.org/network/file-output-stream;1", "nsIFileOutputStream", "init")
			.bind(null, file, 0x02 | 0x08 | 0x20, 0o644, 0);
		var bos = CC("@mozilla.org/binaryoutputstream;1", "nsIBinaryOutputStream", "setOutputStream");
		(this.write = txt => {
			var stream = new fos();
			try {
				new bos(stream).writeByteArray(te.encode(txt));
			}
			catch (ex) {
				Cu.reportError(ex);
			}
			finally {
				stream.close();
			}
		})(txt);
	}
}))("ucf-cbbtn-OpenPageInOtherBrowser");

loads-favicons

Выделить код

Код:

(async widget => widget = CustomizableUI.createWidget({

  maxtimeout: 30,  // Длительность до прерывания запроса в секундах
  maxrequests: 50, // Максимальное количество параллельных запросов
  alertnotification: true, // Уведомление о завершении поиска фавиконок для закладок
  image: "data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'><path style='fill:none;stroke:context-fill rgb(142, 142, 152);stroke-opacity:context-fill-opacity;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;' d='M3.6.6v14.8L8 11l4.4 4.4V.6z'/></svg>",

  id: "ucf-loads-favicons",
  label: "Восстановить фавиконки",
  tooltiptext: "Восстановить фавиконки закладок",

  defaultArea: CustomizableUI.AREA_NAVBAR,
  localized: false,
  onCreated(btn) {
    this.setFill(btn);
    btn.style.setProperty("list-style-image", this.lsi, "important");
    btn._handleClick = this.favSearchStart;
  },
  get lsi() {
    this.favSearchStart = this.favSearchStart.bind(this);
    ChromeUtils.defineESModuleGetters(this, {
      NetUtil: "resource://gre/modules/NetUtil.sys.mjs"
    });
    var subst = this.id + "-img";
    Services.io.getProtocolHandler("resource")
      .QueryInterface(Ci.nsIResProtocolHandler)
      .setSubstitution(subst, Services.io.newURI(this.image));
    delete this.lsi;
    return this.lsi = `url(\"${this.image = "resource://" + subst}\")`;
  },
  setFill(btn) {
    this.favrunning
      ? btn.style.setProperty("fill", "color-mix(in srgb, currentColor 20%, #e31b5d)")
      : btn.style.removeProperty("fill");
  },
  setBtnsFill() {
    for (var win of CustomizableUI.windows) {
      var btn = widget.forWindow(win).node;
      btn && this.setFill(btn);
    }
  },
  get showAlert() {
    delete this.showAlert;
    return this.showAlert = Cc["@mozilla.org/alerts-service;1"]
      .getService(Ci.nsIAlertsService).showAlertNotification.bind(null, this.image);
  },
  favSearchStart() {
    if (this.favrunning) return;
    this.favrunning = true;
    this.setBtnsFill();
    console.log("favSearchStart: Получаем дерево закладок...");
    PlacesUtils.promiseBookmarksTree(PlacesUtils.bookmarks.rootGuid).then(root => {
      console.log("favSearchStart: дерево закладок получено: ", root);
      var urlsList = [];
      var convert = (node, url) => {
        if (node.children)
          node.children.map(convert);
        else if ((url = node.uri) && /^(?:https?|ftp|file):/.test(url))
          urlsList.push(url);
      };
      convert(root);
      console.log("favSearchStart: найдено URL для проверки фавиконок:", urlsList.length, urlsList);
      
var favForPage = async (siteURL) => {
  let siteURI;
  try {
    siteURI = Services.io.newURI(siteURL);
  } catch {
    console.warn("\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 URI:", siteURL);
    return null;
  }

  try {
    let faviconURI = await PlacesUtils.promiseFaviconLinkForPage(siteURI);
    console.log("Favicon \u043d\u0430\u0439\u0434\u0435\u043d:", siteURL, faviconURI?.spec);
    return faviconURI ? null : siteURI;
  } catch (e) {
    console.log("\u041e\u0448\u0438\u0431\u043aа \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0444\u0430\u0432\u0438\u043a\u043e\u043d\u043a\u0438:", siteURL, e);
    return siteURI;
  }
};

      
      Promise.all(urlsList.map(favForPage)).then(results => {
        console.log("\u0412\u0441\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b favForPage:", results);
        this.favSearchResults(results.filter(url => url !== null));
      });
    });
  },
  favComplete(favsuccesslength, favmaxlength) {
    this.favrunning = false;
    this.setBtnsFill();
    this.alertnotification && this.showAlert(
      "Поиск фавиконок",
      `Успешно обработано - ${favsuccesslength}, не удалось обработать - ${favmaxlength - favsuccesslength}`
    );
  },
  favSearchResults(results) {
    console.log("favSearchResults: обработка результатов", results);
    var favmaxlength = _favmaxlength = results.length;
    var favsuccesslength = 0;
    if (!favmaxlength) {
      this.favComplete(0, 0);
      return;
    }
    var { maxrequests } = this;
    var favmaxtimeout = this.maxtimeout * 1000;

    var setFaviconForPage = "setAndFetchFaviconForPage" in PlacesUtils.favicons

      ? async (siteURI, favURI) => {
        var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
        var request = PlacesUtils.favicons.setAndFetchFaviconForPage(siteURI, favURI, false, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, {
          onComplete() {
            ++favsuccesslength;
            timer.cancel();
            timer = request = null;
          },
        }, Services.scriptSecurityManager.getSystemPrincipal());
        if (!request) {
          timer = null;
          return;
        }
        timer.initWithCallback(() => {
          try {
            request.cancel();
          } catch { }
          timer = request = null;
        }, favmaxtimeout, timer.TYPE_ONE_SHOT);
      }

      : async (siteURI, uri, type) => {
        var resolver = Promise.withResolvers();
        if (uri.schemeIs("data"))
          resolver.resolve(uri);
        else {
          let { NetUtil } = this;
          let channel = NetUtil.newChannel({
            uri,
            loadingPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
            securityFlags:
              Ci.nsILoadInfo.SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT |
              Ci.nsILoadInfo.SEC_COOKIES_INCLUDE |
              Ci.nsILoadInfo.SEC_ALLOW_CHROME |
              Ci.nsILoadInfo.SEC_DISALLOW_SCRIPT,
            contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE_FAVICON,
          });
          NetUtil.asyncFetch(channel, async (input, status, request) => {
            if (!Components.isSuccessCode(status)) {
              resolver.reject(status);
              return;
            }
            try {
              let data = NetUtil.readInputStream(input, input.available());
              let { contentType } = request.QueryInterface(Ci.nsIChannel);
              input.close();
              let buffer = new Uint8ClampedArray(data);
              let blob = new Blob([buffer], { type: type || contentType });
              let dataURL = await new Promise((resolve, reject) => {
                let reader = new FileReader();
                reader.onload = () => resolve(reader.result);
                reader.onerror = e => reject(e);
                reader.readAsDataURL(blob);
              });
              resolver.resolve(Services.io.newURI(dataURL));
            } catch (e) {
              resolver.reject(e);
            }
          });
        }
        try {
          PlacesUtils.favicons.setFaviconForPage(siteURI, uri, await resolver.promise);
          ++favsuccesslength;
        } catch { }
      };

    var favSearchPage = siteURI => {
      new Promise(resolve => {
        let req = new XMLHttpRequest({ mozAnon: false });
        req.mozBackgroundRequest = true;
        req.open("GET", siteURI.spec, true);
        req.responseType = "document";
        req.overrideMimeType("text/html");
        req.timeout = favmaxtimeout;
        req.onload = async () => {
          try {
            let doc = req.responseXML, favURI, favType;
            if (doc) {
              let lastlink, is16, is32, isany;
              for (let link of doc.head.querySelectorAll("link[href][rel~='icon']")) {
                if (link.sizes.length === 1) {
                  let size = link.sizes[0];
                  if (/any/i.test(size))
                    isany = link;
                  else if (/32x32/i.test(size))
                    is32 = link;
                  else if (/16x16/i.test(size))
                    is16 = link;
                }
                lastlink = link;
              }
              let icon = (isany || is32 || is16 || lastlink);
              favURI = icon?.href;
              favType = icon?.type;
            }
            if (!favURI) {
              favURI = `${req.responseURL ? Services.io.newURI(req.responseURL).prePath : siteURI.prePath}/favicon.ico`;
              favType = "image/x-icon";
            }
            setFaviconForPage(siteURI, Services.io.newURI(favURI), favType);
          } catch { }
          resolve();
        };
        req.onabort = () => resolve();
        req.onerror = req.ontimeout = () => {
          resolve();
          req.abort();
        };
        req.send(null);
      }).then(() => {
        if (!(--_favmaxlength)) {
          this.favComplete(favsuccesslength, favmaxlength);
          return;
        }
        if (results.length)
          favSearchPage(results.shift());
      });
    };
    results.splice(0, maxrequests).map(favSearchPage);
  }
}))();

LnkCreator

Выделить код

Код:

(async () => CustomizableUI.createWidget(({
	label: "Вкладки в контейнере",
	get image() {
        var img = `${this.id.toLowerCase()}-img`;
        Services.io.getProtocolHandler("resource")
        .QueryInterface(Ci.nsIResProtocolHandler)
        .setSubstitution(img, Services.io.newURI("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'><g style='fill:context-fill rgb(142, 142, 152);fill-opacity:context-fill-opacity'><rect width='6' height='6' x='1' y='1' rx='1'/><path d='M14.75 3H13V1.25a.25.25 0 0 0-.25-.25h-1.5a.25.25 0 0 0-.25.25V3H9.25a.25.25 0 0 0-.25.25v1.5a.25.25 0 0 0 .25.25H11v1.75a.25.25 0 0 0 .25.25h1.5a.25.25 0 0 0 .25-.25V5h1.75a.25.25 0 0 0 .25-.25v-1.5a.25.25 0 0 0-.25-.25'/><rect width='6' height='6' x='1' y='9' rx='1'/><rect width='6' height='6' x='9' y='9' rx='1'/></g></svg>"));
        delete this.image;
        return this.image = `resource://${img}`;
    },
	get defaultFavicon() {
        var img = `${this.id.toLowerCase()}-default-favicon-img`;
        Services.io.getProtocolHandler("resource")
        .QueryInterface(Ci.nsIResProtocolHandler)
        .setSubstitution(img, Services.io.newURI("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'><path style='fill:context-fill rgb(142, 142, 152);fill-opacity:context-fill-opacity;' d='M13.384 3.408c.535.276 1.22 1.152 1.556 1.963a8 8 0 0 1 .503 3.897l-.009.077-.026.224A7.758 7.758 0 0 1 .006 8.257v-.04q.025-.545.114-1.082c.01-.074.075-.42.09-.489l.01-.051a6.6 6.6 0 0 1 1.041-2.35q.327-.465.725-.87.35-.358.758-.65a1.5 1.5 0 0 1 .26-.137c-.018.268-.04 1.553.268 1.943h.003a5.7 5.7 0 0 1 1.868-1.443 3.6 3.6 0 0 0 .021 1.896q.105.07.2.152c.107.09.226.207.454.433l.068.066.009.009a2 2 0 0 0 .213.18c.383.287.943.563 1.306.741.201.1.342.168.359.193l.004.008c-.012.193-.695.858-.933.858-2.206 0-2.564 1.335-2.564 1.335.087.997.714 1.839 1.517 2.357a4 4 0 0 0 .439.241q.114.05.228.094c.325.115.665.18 1.01.194 3.043.143 4.155-2.804 3.129-4.745v-.001a3 3 0 0 0-.731-.9 3 3 0 0 0-.571-.37l-.003-.002a2.68 2.68 0 0 1 1.87.454 3.92 3.92 0 0 0-3.396-1.983q-.116.001-.23.01l-.042.003V4.31h-.002a4 4 0 0 0-.8.14 7 7 0 0 0-.333-.314 2 2 0 0 0-.2-.152 4 4 0 0 1-.088-.383 5 5 0 0 1 1.352-.289l.05-.003c.052-.004.125-.01.205-.012C7.996 2.212 8.733.843 10.17.002l-.003.005.003-.001.002-.002h.002l.002-.002h.015a.02.02 0 0 1 .012.007 2.4 2.4 0 0 0 .206.48q.09.153.183.297c.49.774 1.023 1.379 1.543 1.968.771.874 1.512 1.715 2.036 3.02l-.001-.013a8 8 0 0 0-.786-2.353'/> </svg>"));
        delete this.defaultFavicon;
        return this.defaultFavicon = `resource://${img}`;
    },
	id: "ucf-cbbtn-LnkCreator",
	localized: false,
	onCreated(btn) {
	    btn.owner = this;
	    btn.tooltipText = this.label;
	    btn.setAttribute("image", this.image);
	    btn.addEventListener("command", event => this.createLnk(event.target));
    },

	init() {
		this.widget.parent = this;
		this.widget.contextmenu.destroy = id => {
			CustomizableUI.destroyWidget(id);
			delete this.data[id.slice(8)];
			this.save();
		}
		try {this.data = JSON.parse(Cu.readUTF8URI(Services.io.newURI(
			`chrome://user_chrome_files/content/custom_scripts/${this.id}-data.json`
		)))}
		catch {this.data = {}; return this;}
		for (var [id, inf] of Object.entries(this.data))
			this.createWidget(id, inf.url, inf.name);
		return this;
	},

	createLnk(btn) {
		var id = Date.now();
		var gb = btn.ownerGlobal.gBrowser;
		var uri = gb.currentURI;
		var label = gb.contentTitle.slice(0, 75);

		var widget = this.createWidget(id, uri, label);
		var { area, position } = CustomizableUI.getPlacementOfWidget(this.id);
		CustomizableUI.addWidgetToArea(widget.id, area, position + 1);

		this.data[id] = { name: label, url: uri.spec };
		this.save();
	},

	createWidget(id, url, label) {
		var obj = {
			uri: url.spec ? url : Services.io.newURI(url),
			id: "ucf-lnk-" + id,
			label,
			...this.widget
		};
		var widget = obj.widget = CustomizableUI.createWidget(obj);

		// Попробовать получить favicon
		let faviconUrl = obj.uri.prePath + "/favicon.ico";
		fetch(faviconUrl).then(res => {
			if (!res.ok) throw new Error("Favicon not found");
			return res.blob();
		}).then(blob => {
			let reader = new FileReader();
			reader.onloadend = () => {
				obj.image = reader.result;
				for (let { node } of widget.instances || [])
					node.setAttribute("image", obj.image);
			};
			reader.readAsDataURL(blob);
		}).catch(() => {
			obj.image = this.defaultFavicon;
			for (let { node } of widget.instances || [])
				node.setAttribute("image", obj.image);
		});

		return widget;
	},

	tip: "\nShift+ПКМ - Удалить кнопку",

	widget: {
		localized: false,
		onCreated(btn) {
			btn.uri = this.uri;
			btn.addTab = this.addTab;
			btn.oncontextmenu = this.contextmenu;
			btn.addEventListener("command", event => this.addTab(event.target));
			btn.tooltipText = this.label + this.parent.tip;
			this.image && btn.setAttribute("image", this.image);
		},
		addTab(btn) {
			var gb = btn.ownerGlobal.gBrowser;
			gb.selectedTab = gb.addTrustedTab(btn.uri.spec, { userContextId: 1 });
		},
		contextmenu: function checkShift(e) {
			if (e.shiftKey)
				e.preventDefault(),
				checkShift.destroy(e.target.id);
		}
	},

	save() {
		var file = Services.dirsvc.get("UChrm", Ci.nsIFile);
		var CC = Components.Constructor;
		["user_chrome_files", "custom_scripts", this.id + "-data.json"].forEach(file.append);
		var te = new (Cu.getGlobalForObject(Cu).TextEncoder)();
		var fos = CC("@mozilla.org/network/file-output-stream;1", "nsIFileOutputStream", "init")
			.bind(null, file, 0x02 | 0x08 | 0x20, 0o644, 0);
		var bos = CC("@mozilla.org/binaryoutputstream;1", "nsIBinaryOutputStream", "setOutputStream");

		(this.save = () => {
			var stream = new fos();
			try {
				new bos(stream).writeByteArray(te.encode(JSON.stringify(this.data)));
			} catch (ex) {
				Cu.reportError(ex);
			} finally {
				stream.close();
			}
		})();
	}
}).init()))();

ToggleRestartlessAddons

Выделить код

Код:

//Кнопка дополнения.......
(async () => {
  const id = "ucf-toggle-restartless-addons";
  const label = "Дополнения";
  const tooltiptext =
    "СКМ – открыть страницу дополнений\n" +
    "ПКМ – проверить обновления\n" +
    "В меню:\n" +
    "ЛКМ – включить/выключить дополнение без закрытия меню\n" +
    "СКМ – Удалить\n" +
    "ПКМ – открыть настройки дополнения (если есть)";
  const show_hidden = false;
  const show_version = true;

  const { AddonManager, ExtensionParent, Services, Ci } = globalThis;

  const imgData =
    `<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'>` +
    `<path style='fill:none;stroke:context-fill rgb(142, 142, 152);stroke-opacity:context-fill-opacity;` +
    `stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;' ` +
    `d='M12.9 15.3H3.2c-.88 0-1.6-.6-1.6-1.4v-2.7c0-.4.33-.6.74-.6h1.72c.7 0 1.25-.64 1.25-1.2 0-.64-.55-1.15-1.25-1.15H2.34c-.41 0-.74-.32-.74-.68V5.84c0-.81.72-1.48 1.6-1.48h2.36V3.13c0-1.21.93-2.297 2.21-2.419C9.23.57 10.5 1.62 10.5 2.98v1.38h2.4c.9 0 1.5.67 1.5 1.48v8.06c0 .8-.6 1.4-1.5 1.4z'/>` +
    `</svg>`;
  const dataURI = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(imgData);
  Services.io
    .getProtocolHandler("resource")
    .QueryInterface(Ci.nsIResProtocolHandler)
    .setSubstitution("ucf-button", Services.io.newURI(dataURI));
  const img = "resource://ucf-button/";

  function openAddonOptions(addon, win) {
    if (addon.optionsType === 5) {
      const viewID = `addons://detail/${encodeURIComponent(addon.id)}/preferences`;
      if (win.BrowserAddonUI?.openAddonsMgr) {
        win.BrowserAddonUI.openAddonsMgr(viewID);
      } else {
        win.BrowserOpenAddonsMgr(viewID);
      }
    } else if (addon.optionsURL) {
      win.switchToTabHavingURI(addon.optionsURL, true);
    }
  }

  function handleItemAction(addon, win, button, ctrlKey) {
    if (button === 0) {
      addon[addon.userDisabled ? "enable" : "disable"]();
    } else if (button === 1) {
      if (!addon.isSystem && !addon.isBuiltin) {
        if (Services.prompt.confirm(win, null, `Удалить ${addon.name}?`)) {
          addon.uninstall();
        }
      }
    } else if (button === 2) {
      openAddonOptions(addon, win);
    }
  }
  // =======================================
  // Блок: checkForAddonsUpdates для Firefox
  // =======================================
  async function checkForAddonsUpdates(btn) {
    if (btn._cb_disabled) return;
    btn._cb_disabled = true;

    const win = Services.wm.getMostRecentWindow("navigator:browser");
    const icon = new ProgressIcon(btn);
    const manager = new TabManager(win);
    const prevTab = win.gBrowser.selectedTab;
    const { tab, wasExisting } = manager.findOrCreateTab();
    const browser = tab.linkedBrowser;
    const proc = new UpdateProcessor(btn, tab, browser, icon, prevTab, wasExisting);

    function waitForLoad(browser, callback) {
      if (browser.webProgress.isLoadingDocument) {
        browser.addEventListener("load", function onLoad() {
          browser.removeEventListener("load", onLoad, true);
          callback();
        }, true);
      } else {
        callback();
      }
    }

    waitForLoad(browser, () => proc.start());
  }

class ProgressIcon {
  constructor(btn) {
    this.btn = btn;
    this.icon = btn.icon;
    this.origIcon = this.icon.src;

    this.box = btn.ownerDocument.createXULElement("hbox");
    this.box.toggleAttribute("busy");
    this.box.toggleAttribute("fadein");
    this.box.className = "tab-throbber";

    const s = btn.style;
    const r = btn.getBoundingClientRect();
    s.setProperty("min-width", `${r.width}px`, "important");
    s.setProperty("min-height", `${r.height}px`, "important");
    Object.defineProperty(btn, "open", { configurable: true });

    this.icon.replaceWith(this.box);

    setTimeout(() => {
      this.box.replaceWith(this.icon);
      this.icon.src = "chrome://global/skin/icons/loading.svg";
    }, 300);
  }

  loading() {
    setTimeout(() => {
      this.icon.src = this.origIcon;
      const s = this.btn.style;
      s.removeProperty("min-width");
      s.removeProperty("min-height");
      delete this.btn.open;
    }, 700);
  }

  restore() {
    this.icon.src = this.origIcon;
    delete this.btn.open;
  }
}

  class TabManager {
    constructor(win) {
      this.win = win;
      this.gBrowser = win.gBrowser;
    }

    findOrCreateTab() {
      for (let tab of this.gBrowser.tabs) {
        if (!tab.closing && tab.linkedBrowser.currentURI.spec === "about:addons") {
          this.gBrowser.selectedTab = tab;
          return { tab, wasExisting: true };
        }
      }

      const insertBefore = this.gBrowser.selectedTab;
      const tab = this.gBrowser.addTab("about:addons", {
        triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()
      });

      const index = Array.prototype.indexOf.call(this.gBrowser.tabs, insertBefore);
      this.gBrowser.moveTabTo(tab, index);
      tab.setAttribute("hidden", "true");

      return { tab, wasExisting: false };
    }
  }

  class UpdateProcessor {
    constructor(btn, tab, browser, icon, prevTab, wasExisting) {
      this.btn = btn;
      this.tab = tab;
      this.browser = browser;
      this.icon = icon;
      this.prevTab = prevTab;
      this.wasExisting = wasExisting;
      this.origTip = btn.getAttribute("tooltiptext");
    }

    start() {
      this.btn.setAttribute("tooltiptext", `Processing about:addons…`);
      this.icon.loading();
      const doc = this.browser.contentDocument;
      const origIcon = doc.querySelector('link[rel="shortcut icon"]')?.href || this.tab.image;
      this.tab.setAttribute("_cb_origIcon", origIcon);
      this.tab.image = this.btn.getAttribute("image");
      (doc.getElementById("cmd_findAllUpdates") || doc.querySelector('[action="check-for-updates"]'))?.click();
      this._watch(doc);
    }

    _watch(doc) {
      this.timer = setInterval(async () => {
        const msg = doc.getElementById("updates-message");
        if (!msg) return;
        const state = msg.getAttribute("state");
        if (state !== "updating") {
          clearInterval(this.timer);
          await this._finish(doc, state);
        }
      }, 50);
    }

    async _finish(doc, state) {
      this.icon.restore();
      this.btn.setAttribute("tooltiptext", this.origTip);
      this.tab.image = this.tab.getAttribute("_cb_origIcon");
      this.tab.removeAttribute("_cb_origIcon");
      delete this.btn._cb_disabled;

      const keyMap = {
        "none-found": "addon-updates-none-found",
        "installed": "addon-updates-installed"
      };
      const msgKey = keyMap[state] || `addon-updates-${state}`;
      const message = doc.l10n ? await doc.l10n.formatValue(msgKey) : msgKey;

      Components.classes["@mozilla.org/alerts-service;1"]
        .getService(Ci.nsIAlertsService)
        .showAlertNotification(
          "chrome://mozapps/skin/extensions/extensionGeneric.svg",
          this.btn.label,
          message,
          false, "", null
        );

      const gBrowser = this.browser.ownerGlobal.gBrowser;

      if (state === "none-found") {
        if (!this.wasExisting) {
          gBrowser.removeTab(this.tab, { animate: false });
          if (this.prevTab && !this.prevTab.closing && gBrowser.tabs.includes(this.prevTab)) {
            gBrowser.selectedTab = this.prevTab;
          }
        }
      } else {
        this.tab.removeAttribute("hidden");
        this.tab.setAttribute("closable", "true");
        gBrowser.selectedTab = this.tab;
      }
    }
  }
  // =======================================
  CustomizableUI.createWidget({
    id,
    type: "custom",
    label,
    tooltiptext,
    defaultArea: CustomizableUI.AREA_NAVBAR,
    onBuild(doc) {
      const win = doc.defaultView;
      const btn = doc.createXULElement("toolbarbutton");
      btn.setAttribute("id", id);
      btn.setAttribute("label", label);
      btn.setAttribute("type", "menu");
      btn.setAttribute("tooltiptext", tooltiptext);
      btn.setAttribute("image", img);
      btn.setAttribute("class", "toolbarbutton-1 chromeclass-toolbar-additional toolbarbutton-iconic");
      const popup = doc.createXULElement("menupopup");
      popup.id = id + "-popup";
      btn.appendChild(popup);
      popup.addEventListener("popupshown", () => {
        const rect = btn.getBoundingClientRect();
        const x = rect.left + rect.width / 2;
        const y = rect.top + rect.height / 2;
        const evt = new win.MouseEvent("mousemove", {
          bubbles: true,
          cancelable: true,
          view: win,
          clientX: x,
          clientY: y,
          screenX: win.mozInnerScreenX + x,
          screenY: win.mozInnerScreenY + y,
        });
        btn.dispatchEvent(evt);
      });

      btn.addEventListener("mousedown", e => {
        if (e.button === 1) {
          e.preventDefault();
          const g = win.gBrowser;
          let t = [...g.tabs].find(t => t.linkedBrowser.currentURI.spec === "about:addons");
          if (t) {
            g.selectedTab = t;
            t.linkedBrowser.reload();
          } else {
            g.selectedTab = g.addTab("about:addons", { triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal() });
          }
        }
      });

      btn.addEventListener("click", async e => {
        if (e.button !== 0) return;
        popup.textContent = "";

        try {
          const all = await AddonManager.getAddonsByTypes(["extension", "theme", "plugin", "locale"]);
          const visible = show_hidden ? all : all.filter(a => !a.hidden);
          const { extensionMap } = ExtensionParent.GlobalManager;

          const sortGroup = type => [
            ...visible.filter(a => a.type === type && a.isActive),
            ...visible.filter(a => a.type === type && !a.isActive)
          ];

          function createAddonItems(groupType, defaultIcon) {
            for (let addon of sortGroup(groupType)) {
              const item = doc.createXULElement("menuitem");
              item.className = "menuitem-iconic";
              const label = show_version && addon.version
                ? `${addon.name} (${addon.version})`
                : addon.name;
              item.setAttribute("label", label);
              item.setAttribute("tooltiptext", addon.description || "");
              const icon = extensionMap.get(addon.id)?.iconURL || addon.iconURL || defaultIcon;
              item.setAttribute("image", icon);
              if (!addon.isActive) item.style.opacity = 0.5;
              item.setAttribute("type", "checkbox");
              item.setAttribute("checked", addon.isActive);
              item.addEventListener("mousedown", async ev => {
                const win = doc.defaultView;
                ev.preventDefault();
                ev.stopPropagation();

                if (ev.button === 0) {
                  item.setAttribute("closemenu", "none");
                  if (addon.userDisabled) {
                    await addon.enable();
                  } else {
                    await addon.disable();
                  }
                  item.setAttribute("checked", addon.isActive);
                  item.style.opacity = addon.isActive ? "1" : "0.5";
                } else {
                  item.removeAttribute("closemenu");
                  handleItemAction(addon, win, ev.button, ev.ctrlKey);
                  popup.hidePopup();
                }
              });

              popup.appendChild(item);
            }
          }

          createAddonItems("extension", "chrome://mozapps/skin/extensions/extension.svg");
          if (visible.some(a => a.type === "theme")) {
            popup.appendChild(doc.createXULElement("menuseparator"));
            createAddonItems("theme", "chrome://mozapps/skin/extensions/theme.svg");
          }
          if (visible.some(a => a.type === "plugin")) {
            popup.appendChild(doc.createXULElement("menuseparator"));
            createAddonItems("plugin", "chrome://global/skin/icons/plugin.svg");
          }
		  if (visible.some(a => a.type === "locale")) {
            popup.appendChild(doc.createXULElement("menuseparator"));
            createAddonItems("locale", "chrome://mozapps/skin/extensions/category-languages.svg");
          }
          const toolbar = btn.closest("toolbar");
          const rect = toolbar.getBoundingClientRect();
          const pos = (rect.width > rect.height)
            ? (win.innerHeight - rect.bottom > rect.top ? "after_start" : "before_start")
            : (win.innerWidth - rect.right > rect.left ? "end_before" : "start_before");

          popup.setAttribute("position", pos);
          if (popup.state !== "open") popup.openPopup(btn);

        } catch (err) {
          console.error("Ошибка при построении меню дополнений:", err);
        }
      });

      btn.addEventListener("contextmenu", e => {
        if (e.target !== btn) return;
        e.preventDefault();
        checkForAddonsUpdates(btn);
      });

      return btn;
    }
  });
})();

код запуска attributesInspector от Dumby
скрытый текст

Выделить код

Код:

// Атрибут инспектор
(async () => {
  CustomizableUI.createWidget({
    id: "AttributesInspector",
    label: "Attributes Inspector",
    get image() {
      const img = `${this.id.toLowerCase()}-img`;
      Services.io.getProtocolHandler("resource")
        .QueryInterface(Ci.nsIResProtocolHandler)
        .setSubstitution(
          img,
          Services.io.newURI(
            "data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'><path style='fill:context-fill rgb(142, 142, 152);fill-opacity:context-fill-opacity;' d='M 3.5 0 C 2.67157 0 2 0.67157 2 1.5 L 2 5.4160156 C 2.3175 5.2772956 2.6522 5.1702094 3 5.0996094 L 3 1.5 C 3 1.22386 3.22386 1 3.5 1 L 8 1 L 8 4.5 C 8 5.32843 8.6716 6 9.5 6 L 13 6 L 13 14.5 C 13 14.7761 12.910861 15 12.634766 15 L 11.076172 15 C 11.139982 15.380805 11.123616 15.698627 11.103516 16 L 12.5 16 C 13.3284 16 14 15.3284 14 14.5 L 14 5.4140625 C 14 5.0162425 13.841847 4.6348256 13.560547 4.3535156 L 9.6464844 0.43945312 C 9.3651844 0.15815313 8.9837375 0 8.5859375 0 L 3.5 0 z M 9 1.2070312 L 12.792969 5 L 9.5 5 C 9.2239 5 9 4.77614 9 4.5 L 9 1.2070312 z M 4 6 C 1.79086 6 0 7.79086 0 10 C 0 12.2091 1.79086 14 4 14 C 4.92432 14 5.775795 13.686656 6.453125 13.160156 L 9.1445312 15.851562 C 9.3398312 16.046863 9.6562625 16.046862 9.8515625 15.851562 C 10.046862 15.656363 10.046862 15.339831 9.8515625 15.144531 L 7.1601562 12.453125 C 7.6867262 11.775725 8 10.9244 8 10 C 8 7.79086 6.20914 6 4 6 z M 4 7 C 5.65685 7 7 8.3431 7 10 C 7 11.6569 5.65685 13 4 13 C 2.34315 13 1 11.6569 1 10 C 1 8.3431 2.34315 7 4 7 z'/></svg>"
          )
        );
      delete this.image;
      return (this.image = `resource://${img}`);
    },
    localized: false,
    onCreated(btn) {
      btn.setAttribute("image", this.image);
      btn.setAttribute("tooltiptext", this.label);
      btn.onmouseenter = btn.onmouseleave = this.onmouse;
      btn.addEventListener("command", this.handleCommand);
    },
    get handleCommand() {
      delete this.handleCommand;
      return (this.handleCommand = async function () {
        this.focusedWindow?.focus();
        Services.scriptloader.loadSubScript(
          "chrome://user_chrome_files/content/custom_scripts/custom_script/ucf-attributesInspector.js",
          this,
          "UTF-8"
         );
      });
    },
    onmouse: (e) =>
      (e.target.focusedWindow = e.type.endsWith("r")
        ? Services.wm.getMostRecentWindow(null)
        : null),
  });
})();

Отредактировано egorsemenov06 (Вчера 11:30:13)

Отсутствует

 

№2064Вчера 11:25:27

fuchsfan
Участник
 
Группа: Members
Зарегистрирован: 07-08-2023
Сообщений: 174
UA: Firefox 128.0

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

xrun1 пишет

У меня в консоли такого нет. [firefox] 138.0.3 и UCF 2025.05.02 23:38:18

В 139, которая через 4 дня зарелизится. Запуск в консоли не привязан к способу активации, или я неправ?

Отсутствует

 

№2065Вчера 11:49:34

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

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

fuchsfan пишет

Который в консоли выдает ошибку Упомянутые мною, которые там, не ошибаются.

У меня в 139 версии никаких ошибок в консоли нет. Что я делаю не так?


«The Truth Is Out There»

Отсутствует

 

№2066Вчера 12:24:10

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

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

xrun1
А какой поиск нужен, этот?

скрытый текст
https://lens.google.com/v3/upload?url=

У вас там вообще нерабочий вариант, можно так еще
скрытый текст
https://www.google.com/searchbyimage?sbisrc=cr_1_5_2&image_url=
тогда будет искать точно совпадающие, вплоть до формата и предлагать другие размеры, если найдет.

Отредактировано _zt (Вчера 12:34:46)

Отсутствует

 

№2067Вчера 15:00:00

fuchsfan
Участник
 
Группа: Members
Зарегистрирован: 07-08-2023
Сообщений: 174
UA: Firefox 139.0

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

unter_officer пишет

У меня в 139 версии никаких ошибок в консоли нет. Что я делаю не так?

139, 138, деактивирую все скрипты оптом (переименовал папку), все равно ошибка
err.png
CSP и то, что возле него, не влияет.

Отсутствует

 

№2068Вчера 16:27:47

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

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

_zt
Спасибо, забрал оба урла.
egorsemenov06
attributesInspector забрал.

Отредактировано xrun1 (Вчера 16:47:27)

На форуме

 

№2069Вчера 17:41:47

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

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

fuchsfan
Вам же дали ссылку, как правильно подключать скрипты с setUnloadMap. Вы сделали так, как там написано? И повторюсь, у меня в 139 ошибок нет.


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

Отредактировано unter_officer (Вчера 17:59:08)


«The Truth Is Out There»

Отсутствует

 

№2070Вчера 22:50:33

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

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

Сохранять изображение без запроса в указанную папку, из контекстного меню

Выделить код

Код:

/**
@UCF @param {"prop":"JsChrome.load","ucfobj":true} @UCF
*/
// Сохранять изображение без запроса в указанную папку, из контекстного меню
(async (
    id = "ucf_contextsaveimg",
    path = "E:\\Download",
    label = `Сохранить без подтверждения`, // в ${path}`, с путем папки сохранения в меню
    beforeSelector = "#context-sendimage",
) => ({
    init() {
        var popup = this.popup = document.querySelector("#contentAreaContextMenu");
        if (!popup) return;
        setUnloadMap(Symbol(id), this.destructor, this);
        popup.addEventListener("popupshowing", this);
    },
    handleEvent(e) {
        this[e.type](e);
    },
    get data() {
        delete this.data;
        return this.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 }
        });
    },
    command(e) {
        var {prefs} = Services, {data} = this;
        for (let pref in data) {
            let obj = data[pref], meth = `et${obj.type}Pref`;
            obj.val = prefs.prefHasUserValue(pref) ? prefs["g" + meth](pref) : null;
            prefs["s" + meth](pref, obj.set);
        }
        try {
            let {window: win, browser, mediaURL, principal, contentData: {referrerInfo, cookieJarSettings, contentDisposition, contentType}} = gContextMenu;
            win.urlSecurityCheck(mediaURL, principal);
            win.internalSave(
              mediaURL,
              null, // originalURL
              null, // document
              null, // file name; we'll take it from the URL
              contentDisposition,
              contentType,
              false, // do not bypass the cache
              "SaveImageTitle",
              null, // chosen data
              referrerInfo,
              cookieJarSettings,
              null, // initiating doc
              true, // skip prompt for where to save
              null, // cache key
              PrivateBrowsingUtils.isBrowserPrivate(browser),
              principal
            );
        } catch {}
        for (let pref in data)
            data[pref].val === null ? prefs.clearUserPref(pref) : prefs[`set${data[pref].type}Pref`](pref, data[pref].val);
    },
    popupshowing(e) {
        if (!gContextMenu.onImage || gContextMenu.webExtBrowserType === "popup") return;
        this.popupshowing = this.showing;
        var mitem = this.mitem = document.createXULElement("menuitem");
        mitem.id = id;
        mitem.setAttribute("label", label);
        mitem.addEventListener("command", this);
        (this.popup.querySelector(beforeSelector) || this.popup.lastElementChild).after(mitem);
        this.popup.addEventListener("popuphiding", this);
    },
    showing({target}) {
        if (target != this.popup || !gContextMenu.onImage || gContextMenu.webExtBrowserType === "popup") return;
        this.mitem.hidden = false;
    },
    popuphiding({target}) {
        if (target != this.popup) return;
        this.mitem.hidden = true;
    },
    destructor() {
        this.popup.removeEventListener("popupshowing", this);
        this.popup.removeEventListener("popuphiding", this);
    },
}).init())();

Отсутствует

 

№2071Вчера 23:50:23

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

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

contextviewpageinfo без setUnloadMap для FF139+

Выделить код

Код:

/**
@UCF @param {"prop":"JsChrome.load","ucfobj":false} @UCF
*/
// Пункт контекстного меню "Информация о странице" .....
//
location == "chrome://browser/content/browser.xhtml" && (async (id, id2, img) => {
    var menuitem = document.createXULElement("menuitem");
    document.getElementById(id2).after(menuitem);

    var hidden = (d = nsContextMenu.contentData, {context: c, browser: b} = d) =>
        c.onImage || c.onLink || b.className.startsWith("webext");

    menuitem.render = () => {
        if (menuitem.hidden = hidden()) return;

        menuitem.id = id;
        menuitem.label = "Информация о странице";
        menuitem.className = "menuitem-iconic";
        menuitem.onclick = e => {
            var win = event.target.ownerDocument.defaultView;
            win.BrowserCommands.pageInfo(null, "generalTab");
        }

        delete menuitem.render;
        menuitem.render();

        menuitem.firstChild.src = img;
 
        menuitem.render = () => menuitem.hidden = hidden();
    }
})(
"context-viewpageinfo",
"context-viewsource",
"data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAACXBIWXMAAAAAAAAAAAHqZRakAAACIUlEQVQ4y4WSsU9TURTGf7d9TiqDg0kHRRdCAjG+IhEVI0waIwuGpMHNGGyUaHApC2GAKDiITkJijJNBTRgcFKIBS0MTwNZ/QAguzgrYvr533z0Or320JdGznJtzvvvd893vWCICgAVg27ZYYSWd3ZDW041UKmLbNl29qQD7IbMJwIP710NEGNbE9LwMJ68wNDbL1EhCWU7RYXHlO+c7zgSIX793cIzCq1wRESZnFiR1+3LIMzQ2S3tzA/19V5UF4BSL5L5t4WrhzkAvI0/m6O44vifBcVwKJY3rBwye1rimSuPOn23efUwD0NkzSGY5zZf0Es/HB/brqA+rnGtQo1PvSSbaicViyqpu2LbN6nqO7d0Cj1+kmRpJhAx8zW8B8Cn7gwudZ1leXKx5gl3HLyvwMSaCQWoBERUUjBA0xdQx6AgAWhRawK/+h3ujLwHhYs8gy+klBCEaje55ATA5syAAnqcBcCvZDXLJ9bjW1US89SSvj/xUd6WldgSAakNFhHg8DsDqeo7Uo7ccO9HM01efaXoTEWhRNQSOU6pxQClFPp/HL+sZT/Xhej43+y/xbHqOG3VOhb9SkSQCbW3BBNm1HAJEolEONxzC0/4+q0OtK6sbCKDN3jQLmc1g0yKK7nONSNVmhASFohNI0cHimKrt8YwEhKLQRhDzD4JTdmPYnM+sIWU5RkAbYdc1+GL2E8xM3FIARw8e4H8x/TAZnv8CSRYQGWupptQAAAAASUVORK5CYII="
);


«The Truth Is Out There»

Отсутствует

 

№2072Сегодня 01:44:24

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

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

unter_officer
Работает в 138.0.3, уже говорил выше об этом.
И кто может объяснить разницу, между "ucfobj":true и "ucfobj":false? Например, скрипт выше работает и так и сяк. У меня есть ещё похожие скрипты. В том числе такие, где поменял
//that.unloadlisteners.push("xxxxxxxxxxxxxx");
на
setUnloadMap(Symbol("xxxxxxxxxxxxxx"), this.destructor, this);
а false на true забыл. Скрипты работают. Так для чего этот параметр?

На форуме

 

№2073Сегодня 02:27:20

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1182
UA: Seamonkey 2.49

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

xrun1 пишет

И кто может объяснить разницу, между "ucfobj":true и "ucfobj":false?

В исходниках UCF написано:

Выделить код

Код:

* @param {Boolean} ucfobj: (optional)
*    if true, load the script into a specially created object, not for scripts in the background [System Principal].

Отсутствует

 

№2074Сегодня 02:35:43

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

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

xrun1 пишет

Работает в 138.0.3, уже говорил выше об этом.

Вы какой вариант скрипта имеете ввиду?
Если крайний, без setUnloadMap, то вроде не должен в 138 версии работать.
Однако, я не проверял. У меня 138 нет, а скачивать ради проверки одного скрипта лень. Но, если работает, то хорошо.


«The Truth Is Out There»

Отсутствует

 

№2075Сегодня 12:21:31

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

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

unter_officer
Работает у меня. [firefox] 138.0.3
Вы здесь выложили два одинаковых. На этой странице с "шапкой" для будущего UCF, и на странице 82 №2049 без неё.:) Я проверил оба.))

На форуме

 

Board footer

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