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

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

№12614-11-2021 02:19:52

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

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

Dumby - Спасибо! Ещё проблема: при возвращении из режима "Адаптивный дизайн" в обычный просмотр многие страницы остаются обрезанными, нужно F5 жать.
Как при возвращении в обычный просмотр ещё и обновить страницу? (но не обновлять её для Адаптивного дизайна)


Dumby - а как обновить подсказку для "Reader View" в панели адреса?
У меня только грубый вариант: зарегистрировать mouseenter и постоянно делать: ReaderView.tooltipText = подсказка……

Выделить код

Код:

var box = document.getElementById("page-action-buttons"); // кнопки панели адреса
var boxLst = e => {
	if (e.button == 1 && e.target.id == "pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_") // Reader View
		e.stopImmediatePropagation(),	document.getElementById("key_responsiveDesignMode").doCommand(); // Адаптивный дизайн
}
box.addEventListener("auxclick", boxLst, true);
addDestructor(() => box.removeEventListener("auxclick", boxLst, true));

Dumby - Вопрос: в custom_script.js функция loadscript не грузит одну .JSM-ку, для которой нужна отдельная строка запуска :
ChromeUtils.import(`${scripts}/UCFTitleChangedChild.jsm`, {}).registerUCFTitleChanged(); // исправление заголовка вкладки

Выделить код

Код:

var EXPORTED_SYMBOLS = ["registerUCFTitleChanged", "UCFTitleChangedChild"];
function registerUCFTitleChanged() { // исправление заголовка вкладки …………

Попробуй исправить loadscript, чтобы он был более универсальный, а второй параметр мог быть именем выполняемой функции:
loadscript("UCFTitleChangedChild.jsm", registerUCFTitleChanged()); // так не работает!

Выделить код

Код:

const scripts = 'chrome://user_chrome_files/content/custom_scripts'; (async () => { // загрузка внешних js или jsm-скриптов
	var loadscript = (name, function_register) => {
		try { name.split('.').pop().split("?")[0].split("#")[0].toLowerCase() == "jsm"
			? ChromeUtils.import(`${scripts}/${name}`, {}).function_register
			: Services.scriptloader.loadSubScript(`${scripts}/${name}`,globalThis,"UTF-8");
			return true;
		} catch(e) {}
	};
	loadscript("ucf_eom-button.js"); // нижеследующая строка не работает:
	// loadscript("UCFTitleChangedChild.jsm", registerUCFTitleChanged()); 
})();

Отредактировано Dobrov (14-11-2021 04:37:50)

Отсутствует

 

№12714-11-2021 20:10:47

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

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

Dobrov пишет

но не обновлять её для Адаптивного дизайна

Можно проверять gBrowser.selectedBrowser.browsingContext.inRDMPane

как обновить подсказку для "Reader View" в панели адреса?

Если в смысле установить свою как для аддона, то вот вариант (в custom_script.js).

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

Выделить код

Код:

(async url => {
	var tooltip = "Test Tooltip";

	var m = "2495d258-41e7-4cd5-bc7d-ac15981f064e", id = `{${m}}`, aid = `_${m}_`;
	var manager = ChromeUtils.import(url).ExtensionParent.apiManager;
	var wait = (e, isAppShutdown) => isAppShutdown || manager.on("ready", onReady);
	var onReady = (e, addon) => {
		if (addon.id != id) return;
		manager.off("ready", onReady);
		addon.once("shutdown", wait);
		manager.global.PageActions.actionForID(aid).setTooltip(tooltip);
	}
	manager.on("ready", onReady);

})("resource://gre/modules/ExtensionParent.jsm");

исправить loadscript

Что-то мне не слишком понятны код и задача, может так сойдёт?

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

Выделить код

Код:

(async scripts => {
	var re = /\.jsm$/i;
	var loadscript = name => {
		try {
			var {href, pathname} = new URL(scripts + name);
			if (re.test(pathname))
				return ChromeUtils.import(href);
			Services.scriptloader.loadSubScript(href);
			return true;
		}
		catch(ex) {Cu.reportError(ex);}
	}

	loadscript("ucf_eom-button.js");
	loadscript("UCFTitleChangedChild.jsm")?.registerUCFTitleChanged?.();

})("chrome://user_chrome_files/content/custom_scripts/");


Добавлено: Хотя нет, сам вызов же может завершиться с ошибкой.
Тогда затащим внутрь, как написано, второй параметр — имя выполняемой функции.
скрытый текст

Выделить код

Код:

(async scripts => {
	var re = /\.jsm$/i;
	var loadscript = (name, funcName) => {
		try {
			var {href, pathname} = new URL(scripts + name);
			if (re.test(pathname)) {
				var obj = ChromeUtils.import(href);
				funcName && obj[funcName]();
			} else
				Services.scriptloader.loadSubScript(href);
			return true;
		}
		catch(ex) {Cu.reportError(ex);}
	}

	loadscript("ucf_eom-button.js");
	loadscript("UCFTitleChangedChild.jsm", "registerUCFTitleChanged");

})("chrome://user_chrome_files/content/custom_scripts/");

Отредактировано Dumby (14-11-2021 21:07:11)

Отсутствует

 

№12815-11-2021 00:13:02

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

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

Dumby - Спасибо! обновление подсказки кнопки также работает из custom_script_win.js.


Dumby - проверь мой новый загрузчик: (сократил, чтобы не повторять строки с loadscript)
Переделал через список массива  js-jsm скриптов. Путь к скриптам используется ещё для подключения [CB]-кодов, поэтому константа.

Выделить код

Код:

const scripts = 'chrome://user_chrome_files/content/custom_scripts/'; (async () => { // ваши скрипты
	[['ucf_QuickToggle.js'], ['UCFTitleChangedChild.jsm', 'registerUCFTitleChanged'], ['Test.jsm']]
	.forEach(function(name) { try { if (/\.jsm$/i.test(name[0])) { // [скрипт js или jsm, инициализация]
				var obj = ChromeUtils.import(scripts + name[0]);
				name[1] && obj[name[1]]();
			} else Services.scriptloader.loadSubScript(scripts + name[0]);
		} catch(ex) {Cu.reportError(ex);}
	});
})();

Отредактировано Dobrov (16-11-2021 02:10:34)

Отсутствует

 

№12915-11-2021 13:39:52

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

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

Dobrov пишет

проверь мой новый загрузчик: (сократил, чтобы не повторять строки с loadscript)

Ну, выглядит нормально.
Но, замысел целиком мне же неизвестен.
Вот зачем тогда функция что-то возвращает, раз это не используется.


Или, в исходнике, name.split('.').pop().split("?")[0].split("#")[0].toLowerCase()
наводило на мысль, что будут присутствовать имена типа "SomeModule.JsM?q=lol#bla",
но ничего подобного пока не видно, хотя, может потом добавятся, а если нет, то зря new URL() создаётся.
Короче — ничего серьёзного.

Отсутствует

 

№13016-11-2021 16:02:55

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

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

Dumby - вопрос по коду обновления ToolTip кнопки расширения.
Почему-то подсказка для Video DownloadHelper не обновляется! И как переделать код для замены Tooltip на нескольких кнопках расширений?

Выделить код

Код:

var view_id = "2495d258-41e7-4cd5-bc7d-ac15981f064e"; // Reader View
var vdh_id = "b9db16a4-6edc-47ec-a1f4-b86292ed211d"; // Video DownloadHelper
var manager = ChromeUtils.import("resource://gre/modules/ExtensionParent.jsm").ExtensionParent.apiManager,
wait = (e, isAppShutdown) => isAppShutdown || manager.on("ready", onReady),
onReady = (e, addon) => {
	// if (addon.id != `{${view_id}}`) return;
	if (addon.id == `{${view_id}}`) {
		manager.off("ready", onReady), addon.once("shutdown", wait);
		manager.global.PageActions.actionForID(`_${view_id}_`).setTooltip(`Reader View	${Services.appinfo.OS == "Darwin" ? "⌥⌘M" : "Ctrl+⇧+M"}\n\nКлик мыши	Режим для чтения\nКолёсико	Адаптивный дизайн`); // изменить подсказку
	}
	if (addon.id == `{${vdh_id}}`) {
		manager.off("ready", onReady), addon.once("shutdown", wait);
		manager.global.PageActions.actionForID(`_${vdh_id}_`).setTooltip(`Video DownloadHelper\nСкачивание проигрываемого видео`);
	}
};	manager.on("ready", onReady);

Отсутствует

 

№13117-11-2021 14:33:12

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

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

Dobrov пишет

Video DownloadHelper

Совсем разные вещи. У RV pageAction, а у VDH browserAction.

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

Выделить код

Код:

(async url => {
	// Reader View
	var rv = "2495d258-41e7-4cd5-bc7d-ac15981f064e";
	var rv_id = `{${rv}}`, rv_aid = `_${rv}_`;
	var rv_ttt = `Reader View	${Services.appinfo.OS == "Darwin" ? "⌥⌘M" : "Ctrl+⇧+M"}\n\nКлик мыши	Режим для чтения\nКолёсико	Адаптивный дизайн`;

	// Video DownloadHelper
	var vdh_id = "{b9db16a4-6edc-47ec-a1f4-b86292ed211d}";
	var vdh_ttt = "Video DownloadHelper\nСкачивание проигрываемого видео";

	var count = 0;
	var manager = ChromeUtils.import(url).ExtensionParent.apiManager;
	var wait = (e, isAppShutdown) => isAppShutdown || !--count || manager.on("ready", onReady);
	var onReady = (e, addon) => {
		if (addon.id == rv_id)
			manager.global.PageActions.actionForID(rv_aid).setTooltip(rv_ttt);
		else if (addon.id == vdh_id)
			setVDHTooltip(addon);
		else return;

		++count == 2 && manager.off("ready", onReady);
		addon.once("shutdown", wait);
	}
	manager.on("ready", onReady);

	var setVDHTooltip = addon => {
		var vdh_wid = `_${vdh_id.slice(1, -1)}_-browser-action`;
		var {gPalette} = Cu.import("resource:///modules/CustomizableUI.jsm", {});

		var upd = manager.global.browserAction.prototype.updateButton;
		var asgn = eval(`({${upd}})`.replace(/\n^.+"tooltiptext".+$/m, ""));

		(setVDHTooltip = addon => {
			var widget = gPalette.get(vdh_wid);
			widget.tooltiptext = vdh_ttt;

			var {action} = manager.global.browserActionFor(addon);
			Object.assign(action.buttonDelegate, asgn);
			for(var [, node] of widget.instances)
				node.setAttribute("tooltiptext", vdh_ttt);
		})(addon);
	}
})("resource://gre/modules/ExtensionParent.jsm");

Отсутствует

 

№13218-11-2021 18:33:26

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

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

Dumby - ты делал перехват кликов для кнопок в панели адреса в скрипте ucf_hookClicks.js.
Получилась обработка кликов двумя дублирующими способами: первый до ucf.unloadlisteners, затем для кнопок на панели адреса.
Второй способ перехватывает клики всех кнопок page-action-buttons, а при обработке проверяется id кнопки.


Возможно ли доработать код, чтобы сразу перехватывать клики кнопок "nav-bar-customization-target" основной панели и "page-action-buttons" панели адреса ?
Выгода этого способа в том, что проще в одном скрипте прописать дополнительные клики нужных кнопок, а не делать кучу скриптов, где каждая кнопка обрабатывается персонально. Также прошу по возможности добавить действие на долгое нажатие кнопки, так как у меня перестал обрабатываться долгий клик в скрипте ToggleAboutConfig, когда я добавил addEventListener("mouseenter" для nav-bar-customization-target в скрипт ucf_hookClicks.


Ещё хотелка - добавить перехват "wheel". Ожидаемый итог работы кода: перехват событий кнопок для двух панелей, разбор такой же, как в твоём коде перехвата кликов: 512: saveSelectionToTxt, // СКМ Click (сохранить .txt) цифра содержит сумму событий: id кнопки, клавиш мыши, мета-клавиш, тип кликов, скролл над кнопками тулбара…
Удобнее сделать изменение яркости скролом над панелью безопасности "identity-box", чем над Звёздочкой. А скролл над кнопками основной панели определять отдельно для каждой, то есть добавить флаги e.scroll+ и e.scroll- так же, как сделано для dbl (дубль-клик).

ucf_hookClicks.js - поменял подсчёт кнопок и клавиш - строка 136

Выделить код

Код:

(async (id, func) => { // для custom_script_win.js: дополнительные клики и подсказки кнопок
	await window.delayedStartupPromise; var
	box = document.getElementById("page-action-buttons"), // кнопки панели адреса
	nav = document.getElementById("nav-bar-customization-target"), // кнопки панели
	btn = document.getElementById("downloads-button"), // 0 Загрузки
	pui = document.getElementById("PanelUI-menu-button"), // 1 меню
	fav = document.getElementById("star-button"), // 2
	prn = document.getElementById("print-button"), // 3
	rv = "pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_", // 4 Reader View
	sgs = "_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action", // SingleSave button
	vdh = "_b9db16a4-6edc-47ec-a1f4-b86292ed211d_-browser-action"; /*Video DownloadHelper*/ if (!btn) return; btn_help =`

Двойной клик: ⬇︎ открыть [Загрузки]
…на картинке: ⧉ найти Похожие\n
Правый клик (Alt+S):  Сохранить
   в единый html всё / выделенное
…дважды  Картинки вкл/выкл\n
Ролик:	 Сохранить как файл .txt
Колёсико на рисунке: ➜ Сохранить`,	PanelUI_help =

`Клик мыши:	меню Firefox ${Services.appinfo.platformVersion}
…+ Shift		⚑ Краткая справка
…+ Alt		Персонализация
Клик дважды	⊠ закрыть браузер \n
Правый клик	⇲ Свернуть
…+ дважды	⤾ Вернуть вкладку
…+ Alt		Диспетчер задач
…+ Shift		Адаптивный дизайн\n
Колёсико:	Развернуть | окно
…+ Alt		Полный экран
…+ дважды	Обновить без кэша`, sgs_help = `\nAlt⇧S	 ⌨ нажатие SingleSave`, rv_help =

`Reader View	${Services.appinfo.OS == "Darwin" ? "⌥⌘M" : "Ctrl+⇧+M"}\n
Клик мыши	Режим для чтения
Колёсико	Адаптивный дизайн`; // vdh_help =`Video DownloadHelper\nСкачивание проигрываемого видео`;

	var addDestructor = nextDestructor => {
		var {destructor} = ucf[id];
		ucf[id].destructor = () => {
			try {destructor();} catch(ex) {Cu.reportError(ex);}
			nextDestructor();
		}
	},
	showInStatusPanel = (info, time = 5000) => {
		var win = Services.wm.getMostRecentWindow("navigator:browser"); StatusPanel = win.StatusPanel;
		if (StatusPanel.update.tid)
			clearTimeout(StatusPanel.update.tid)
		else {
			var {update} = StatusPanel;
			StatusPanel.update = () => {};
			StatusPanel.update.ret = () => {
				StatusPanel.update = update;
				StatusPanel.update();
			}
		}
		StatusPanel.update.tid = setTimeout(StatusPanel.update.ret, time);
		StatusPanel._label = info;
	},
	Title = (max, title) => { // получить заголовок. без обрезки: max не указан, домен: max <0, + дата: max=0
		if (!title) var title = document.title || gBrowser.selectedTab.label;
		if (max == undefined) return title; // заголовок как есть или ограничить длину, убрать служебные символы
		title = title.replace(/[\\\/?*\"'`]+/g,'').replace(/\s+/g,' ').replace(/[|<>]+/g,'_').replace(/:/g,'։').trim();
		if ( max > 0 ) return title.slice(0, max);
		if ( max == 0) return title.slice(0, 100) +"_"+ new Date().toLocaleDateString('ru', {day: 'numeric', month: 'numeric', year: '2-digit'}) +'-'+ new Date().toLocaleTimeString().replace(/:/g, "։");
		var host = decodeURIComponent(gURLBar.value); // max < 0
		if (!/^file:\/\//.test(host)) host = host.replace(/^.*url=|https?:\/\/|www\.|\/.*/g,'');
		return host.replace(/^ru\.|^m\.|forum\./,'').replace(/^club\.dns/,'dns');
	},
	saveSelectionToTxt = async () => { // сохранить страницу или выделенный текст как файл .txt
		var splice = saveURL.length == 10;
		var msgName = id + ":Save:GetSelection";
		var receiver = msg => {
			var title = Title(0);
			var args = [
				"data:text/plain," + encodeURIComponent(gBrowser.currentURI.spec + "\n\n" + msg.data),
				title + '.txt', null, false, true, null, window.document];
			splice && args.splice(5, 0, null);
			saveURL(...args) && showInStatusPanel("√ текст сохранён: " + title.slice(0, 60));
		}
		messageManager.addMessageListener(msgName, receiver);
		addDestructor(() => messageManager.removeMessageListener(msgName, receiver));
		var func = fm => {
			var res, fed, win = {}, 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))();
	},
	save = async () => { // SingleHtml by Лекс, правка: Dumby, Dobrov
		var msgName = id + "ucfDwnldsBtnSaveSnapshotToHTML";
		if (typeof IOUtils != "object") { // Firefox 78 ESR
			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))};
		}
		var write = IOUtils.writeUTF8 ? "writeUTF8" : "writeAtomicUTF8";
		var msgListener = async msg => {
			var [fileContent, fileName] = msg.data, dir; // fileName: выделенный текст или null
			try {dir = prefs.getComplexValue("browser.download.dir", Ci.nsIFile);} catch {dir = dirsvc.get("DfltDwnld", Ci.nsIFile);}
			var arr = prefs.getStringPref("ucf_save.dirs","_Web||_Images|0").split('|').slice(0,2); //subdir: title|host
			arr[1] = (arr[1] == "0") ? Title(100) : (arr[1] == "1") ? Title(-1) : ""; // имя вкладки или домен
			arr.forEach(dir.append); // ucf_save.dirs = "_Web||_Pics|1" HTML сохранится в папку [Загрузки]/_Web/label
			dir.exists() && dir.isDirectory() || dir.create(dir.DIRECTORY_TYPE, 0o777); // создать, если не существует…
			var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
			file.initWithPath(dir.path);
			if (!fileName) fileName = Title(100); // убрать служебные символы
			dir.append(Title(0, fileName) +'.html');
			await IOUtils[write](dir.path, fileContent) && showInStatusPanel("√ страница записана: " + fileName.slice(0, 60));
			var d = await Downloads.createDownload({ source: "about:blank", target: FileUtils.File(dir.path)}); // Fake download
			(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))();
	},
	tid, allowMousedown, listener = { // доп.события для 15 кнопок
		handleEvent(e) {
			if (e.detail > 2) return;
			var btn = e.target;
			var dbl = e.detail == 2;
			var num = e.button *512 + e.metaKey *256 + e.ctrlKey *128 + e.shiftKey *64 + e.altKey *32 + dbl *16 +
			(btn == document.getElementById(rv) && 4) +
			(btn == prn && 3) + (btn == fav && 2) + (btn == pui && 1);

			if (!this[num]) {
				if (e.button == 1) return;
				if (e.button) {
					num = "context";
					for(var p in this.a) this.a[p] = e[p];
				} else
					num = "mousedown";
			}
			if (dbl) tid &&= clearTimeout(tid), this[num](btn);
			else tid = setTimeout(this.exec, 300, num, btn, this);
		},
		exec(num, btn, self) {
			tid = null;
			self[num](btn);
		},
		mousedown(btn) {
			allowMousedown = true;
			btn.dispatchEvent(new MouseEvent("mousedown", {}));
			allowMousedown = false;
		},
		context(btn) {
			btn.removeAttribute("context");
			btn.dispatchEvent(new MouseEvent("contextmenu", this.a));
			btn.toggleAttribute("context");
		},
		switchToTab(but, url) { // открыть вкладку | закрыть, если открыта
			for(var tab of but.ownerGlobal.gBrowser.tabs)
				if ( tab.linkedBrowser.currentURI.spec == url ) {but.ownerGlobal.gBrowser.removeTab(tab); return;}; // вкладка найдена, закрыть
			but.ownerGlobal.switchToTabHavingURI(url, true, {relatedToCurrent: true, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()});
		},

		a: {__proto__: null, bubbles: true, screenX: 0, screenY: 0},

/*** ======= Downloads Clicks ======= ***/

		512: saveSelectionToTxt, // СКМ Click (сохранить .txt)
		16() { // Double Left Click - Обзор папки «Загрузки»
			Downloads.getSystemDownloadsDirectory().then(path => FileUtils.File(path).launch(), Cu.reportError) // Обзор папки «Загрузки»
		},
		1024: save, // ПКМ Click (Single HTML)
		1040(btn) { // Double Right Click
			var pref = "permissions.default.image";
			var one = prefs.getIntPref(pref) == 1;
			prefs.setIntPref(pref, one ? 2 : 1);
			btn.style.filter = one ? "hue-rotate(180deg) brightness(95%)" : "";
			BrowserReload();
		},

/*** ======= PanelUI-menu Clicks ======= 100*pui 32*e.button 8*e.ctrlKey 4*e.shiftKey 2*e.altKey dbl btn ***/

		33() { gCustomizeMode.enter(); // ЛКМ + Alt Персонализация
		},
		65() { // Shift + ЛКМ
			var help_ucf = ['chrome://user_chrome_files/content/help.html', 'http://forum.puppyrus.org/index.php?topic=22762'];
			var newURI = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry).convertChromeURL(Services.io.newURI(help_ucf[0])); // .spec = file:///
			(newURI.QueryInterface(Ci.nsIFileURL).file.exists()) ? this.switchToTab(pui, help_ucf[0]) : this.switchToTab(pui, help_ucf[1]);
		},
		545: BrowserFullScreen, // Alt + СКМ
		513() { // СКМ
			windowState != STATE_MAXIMIZED ? maximize() : restore();
		},
		529: BrowserReloadSkipCache,  // СКМ Double
		1025() { // ПКМ
			minimize();
		},
		1057(pui) { // Alt + ПКМ
			this.switchToTab(pui, 'about:performance');
		},
		1089(pui) { // Shift + ПКМ
			pui.ownerDocument.getElementById("key_responsiveDesignMode").doCommand(); // запуск пункта меню с HotKey
			if (gBrowser.selectedBrowser.browsingContext.inRDMPane) BrowserReload();
		},
		1153(pui) { // Shift + Alt + ПКМ
			var obj = ChromeUtils.import("resource://devtools/shared/Loader.jsm").require("devtools/client/menus").menuitems.find(menuitem => menuitem.id == "menu_devtools_remotedebugging");
			(this[138] = target => obj.oncommand({target}))(pui); // запуск пункта меню, у которого нет HotKey
		},
		17: BrowserTryToCloseWindow, // Double Left Click
		1041(pui) { // ПКМ Double Right Click
			pui.ownerGlobal.undoCloseTab();
		},
	}, // end Clicks

	keydown_win = e => { // нажатие клавиш
		if (e.keyCode == 83 && e.altKey) e.shiftKey // Alt+S [+Shift]
		? singlesave ? singlesave.click() : save() : save(); // имитировать клик по кнопке, используя её ID
		if (e.keyCode == 68 && e.altKey){ // Alt+D отладка - запуск внешнего JS
			// e.target.ownerDocument.getElementById("key_browserConsole").doCommand();
			eval(Cu.readUTF8URI(Services.io.newURI("chrome://user_chrome_files/content/custom_scripts/User.js")));
			console.log("END User.js " + Math.random());
		}
	},
	{prefs, dirsvc} = Services, linux = /macos|linux/.test(AppConstants.platform), singlesave;
	prefs.setBoolPref("browser.download.autohideButton", false); // не скрывать кнопку Загрузки

	var hint_upd = function(btn, text, find) { // обновить подсказку
		return;
	}
	var mouseenter = function(e) {
		this.parentNode.addEventListener("mousedown", stop, true);
		this.addEventListener("mouseleave", mouseleave, {once: true});

		var sgs_btn = document.getElementById(sgs), dw;
		try {dw = prefs.getComplexValue("browser.download.dir",Ci.nsIFile)}
			catch {dw = dirsvc.get("DfltDwnld", Ci.nsIFile)};
		var rv_btn = document.getElementById(rv); // Reader View
		if (e.target == rv_btn) {
			rv_btn.tooltipText = rv_help;
		}
		// var vdh_btn = document.getElementById(vdh); // Video DownloadHelper
		// if (e.target == vdh_btn) {
		// 	vdh_btn.tooltipText = vdh_help;
		// }
		if ((e.target == pui) && (!/справка/.test(pui.tooltipText)))
			pui.tooltipText = PanelUI_help; // обновить подсказки кнопок
		if (e.target == btn) {
		// if (!/Двойной/.test(btn.tooltipText))
			btn.tooltipText = GetDynamicShortcutTooltipText(btn.id) + btn_help; // обновлять подсказку при наведении мыши
		if (sgs_btn){
			if (!/SingleSave/.test(btn.tooltipText)) btn.tooltipText = btn.tooltipText + sgs_help;
		} else
			btn.tooltipText = btn.tooltipText.replace(sgs_help,'');
		if (!/выбранная/.test(btn.tooltipText))
			btn.tooltipText = btn.tooltipText + `${dw ? "\n\n[Загрузки] — выбранная папка:\n"+ dw.path.substring(0,33) + `${dw.path.length > 32 ? `…\n…${dw.path.substring(dw.path.length -31, dw.path.length)}`: ""}` : ""}`; // сократить/разбить длинную строку
		}
	}
	var mouseleave = function(e) {
		this.parentNode.removeEventListener("mousedown", stop, true);
	}
	var stop = e => {
		e.button || allowMousedown || e.stopImmediatePropagation();
	}
	var btns = [btn, pui];
	for(var b of btns) {
		b.toggleAttribute("context"),
		b.addEventListener("click", listener, true),
		b.addEventListener("mouseenter", mouseenter);
	}

	var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win;
	ucf[id] = {destructor() {
		for(var b of btns) {
			b.removeEventListener("click", listener, true);
			b.removeEventListener("mouseenter", mouseenter);
			if (b.matches(":hover"))
				b.removeEventListener("mouseleave", mouseleave),
				b.parentNode.removeEventListener("mousedown", stop, true);
		}
	}};
	ucf.unloadlisteners.push(id);

	var boxLst = e => {
		console.log('@: '+ e.button);
		if (e.button == 1 && e.target.id == `pageAction-urlbar-_${rv}_`) { // Reader View Button
			e.stopImmediatePropagation(),	document.getElementById("key_responsiveDesignMode").doCommand(); // Адаптивный дизайн
			if (gBrowser.selectedBrowser.browsingContext.inRDMPane)
				BrowserReload();
		}
	}
	box.addEventListener("auxclick", boxLst, true);
	box.addEventListener("mouseenter", mouseenter, true);
	window.addEventListener("keydown", keydown_win);
	addDestructor(() => {
		box.removeEventListener("auxclick", boxLst, true);
		box.removeEventListener("mouseenter", mouseenter, true);
		window.removeEventListener("keydown", keydown_win);
	});

})("downloads-button-click-listener", ({io, focus}) => { // SingleHTML не сохраняет svg графику

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

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

	head.copyStyle = function (s) {
		if (!s) return;
		var style = doc.createElement('style');
		style.type = 'text/css';
		if (s.media && s.media.mediaText) style.media = s.media.mediaText;
		try {
			for (var i = 0, rule; rule = s.cssRules[i]; i++) {
				if (rule.type != 3) {
					if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) {
						var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) {
							if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href);
							if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url);
							return prev + url + next;
						});
						style.appendChild(doc.createTextNode(css + '\n'));
					}
				} else {
					this.copyStyle(rule.styleSheet);
				}
			}
		} catch(e) {
			if (s.ownerNode) style = s.ownerNode.cloneNode(false);
		};
		this.appendChild(style);
	};
	for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]);
	head.appendChild(doc.createTextNode('\n'));
	var doctype = '', dt = doc.doctype;
	if (dt && dt.name) {
		doctype += '<!DOCTYPE ' + dt.name;
		if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22';
		if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22';
		doctype += '>\n';
	};
	var selText = selWin ? win.getSelection().toString().slice(0, 200) : undefined;
	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>', selText]); // выделенный текст

}); // END hookClicks

ucf_BookmarkDir.js - только как пример: яркость прокруткой над ★

Выделить код

Код:

(async (id, sel) => { // Клики на Звёздочке, ToolTip: расположение закладки в Избранном, Недавняя папка
	var g = Cu.getGlobalForObject(Cu), stt = g[id]; // https://forum.mozilla-russia.org/viewtopic.php?pid=790890#p790890
	if (!stt) { var {obs, prefs} = Services, {bookmarks: bm, observers: pobs} = PlacesUtils;
		stt = g[id] = { bm, help_star: `

Правый клик:	⤾ Вернуть вкладку
…+ Alt 	Перевод выдел.текст | Сайт 
…+ Shift	Гугл Перевод или поиск\n
Колесико ±	Яркость страниц
…+ клик 	Полная яркость`,

			pref: `ucf.${id}Guid`,
			events: ["bookmark-added"],
			async init() {
				this.handleEvent = e => this[e.type](e);

				if ((this.pbm = typeof PlacesBookmarkMoved == "function"))
					this.events.push("bookmark-moved");
				else
					this.QueryInterface = g.ChromeUtils.generateQI([Ci.nsINavBookmarkObserver]),
					bm.addObserver(this);
				pobs.addListener(this.events, this.added = events => {
					for(var e of events) e.isTagging || this[e.constructor.name](e);
				});
				obs.addObserver(this, "quit-application-granted");
				this.args = [b => this.bguids.add(b.parentGuid), {concurrent: true}];
				var guid = prefs.getStringPref(this.pref, "");
				if (!guid) try {var [guid] = await PlacesUtils.metadata.get(
					PlacesUIUtils.LAST_USED_FOLDERS_META_KEY, []
				)} catch {}
				this.guids.push(guid || await PlacesUIUtils.defaultParentGuid || bm.unfiledGuid);

				var pref = "ucf.tabbrowser-tabpanels.opacity"; // яркость страницы
				var getPref = () => Services.prefs.getIntPref(pref, 100);
				var css = `@-moz-document url(chrome://browser/content/browser.xhtml) {
					:is(${sel})[rst] {filter: grayscale(1%) !important;}
					:root:not([chromehidden*=toolbar]) #tabbrowser-tabbox {background-color: black !important;}
					:root:not([chromehidden*=toolbar]) #tabbrowser-tabpanels {opacity:${getPref()/100} !important;}}`;
				var subst = "ucf-tabbrowser-tabpanels-opacity-style", url = `resource://${subst}/`;
				Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler)
					.setSubstitution(subst, Services.io.newURI("data:text/css," + encodeURIComponent(css)));
				var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
				sss.loadAndRegisterSheet(Services.io.newURI(url), sss.USER_SHEET);

				var st = InspectorUtils.getAllStyleSheets(document).find(s => s.href == url).cssRules[0].cssRules[2].style;

				this.setPref = (e, val = 100) => {
					Services.prefs.setIntPref(pref, val);
					e.target.toggleAttribute("rst");
				}
				this.wheel = e => {
					var val = getPref() + (e.deltaY < 0 ? 5 : -5); // шаг
					val < 25 || val > 100 || this.setPref(e, val);
				}
				var observer = () => st.setProperty("opacity", getPref() / 100, "important");
				Services.prefs.addObserver(pref, observer);
				this.removePrefObs = () => Services.prefs.removeObserver(pref, observer);
			},
			observe() {
				this.pbm || bm.removeObserver(this);
				pobs.removeListener(this.events, this.added);
				obs.removeObserver(this, "quit-application-granted");
				prefs.setStringPref(this.pref, this.guids[0]);
				this.removePrefObs();
			},
			bguids: new g.Set(), guids: new g.Array(),
			skipTags: true,
			tt(win) {
				var list = win.InspectorUtils
					.getChildrenForNode(win.document.documentElement, true);
				return list.item(list.length - 1);
			},
			PlacesBookmarkAddition(e) {
				if (e.itemType == bm.TYPE_BOOKMARK && e.source == bm.SOURCES.DEFAULT)
					this.guids[0] = e.parentGuid;
			},
			PlacesBookmarkMoved(e) {
				e.parentGuid != e.oldParentGuid && this.PlacesBookmarkAddition(e);
			},
			onItemMoved(a, b, c, d, e, itemType, f, oldParentGuid, parentGuid, source) {
				this.PlacesBookmarkMoved({itemType, source, oldParentGuid, parentGuid});
			},
			fetch(win) {
				this.bguids.clear();
				return bm.fetch({url: win.gBrowser.currentURI.spec}, ...this.args);
			},
			addTab: function(win, url, add, params = {relatedToCurrent: true}) { // открыть адрес [add: в новой вкладке]
				params.triggeringPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
				return (add) ? win.gBrowser.addTab(url, params) : win.gBrowser.loadURI(url, params);
			},
			translate(browserMM, win, e, go) { // Google-перевод сайта | выделенного текста (go) поиск выдел. текста в Яндекс
				browserMM.addMessageListener('getSelect', function listener(msg) {
					var url = (msg.data) ? (go)
						? "https://yandex.ru/search/?text="+ msg.data +"&src=suggest_Pers&lang=ru" // поиск текста в Яндекс
						: "https://translate.google.com/#view=home&op=translate&sl=auto&tl=ru&text="+ msg.data // Гугл перевод
						: "http://translate.google.com/translate?u="+ gURLBar.value +"&hl=ru&ie=UTF-8&sl=auto&tl=ru"; // Перевод сайта
					if (go && !msg.data) // Перевод сайти в Яндекс. ничего не выделено + go не пуст
						gBrowser.selectedTab = e.addTab(win, "https://translate.yandex.com/translate?url=" + gURLBar.value + "&dir=&ui=ru&lang=auto-ru", 1)
					else
						gBrowser.selectedTab = e.addTab(win, url, 1);
				browserMM.removeMessageListener('getSelect', listener, true);
				});
				browserMM.loadFrameScript('data:,sendAsyncMessage("getSelect", content.document.getSelection().toString())', false);
			},
			auxclick(e) {
				if (e.button == 2) {
					var win = e.view;
					if (e.altKey)
						this.translate(gBrowser.selectedBrowser.messageManager, win, this, 1);
					else if (e.shiftKey)
						this.translate(gBrowser.selectedBrowser.messageManager, win, this);
					else
						win.undoCloseTab();
				} else
					this.setPref(e);
			},
			find: obj => obj.name == "tooltiptext"
		};
		var ps = ["onBeginUpdateBatch", "onEndUpdateBatch", "onItemChanged", "onItemVisited"];
		var noop = () => {}; for(var p of ps) stt[p] = noop; stt.init();

		var func = id => this[id].mouseenter = async function(e) {
			var win = e.view, star = e.target, result = [], starred = star.hasAttribute("starred");
			starred && await this.fetch(win);
			this.help_star = this.help_star.replace(/Яркость страниц.*/, `Яркость страниц ${win.Services.prefs.getIntPref("ucf.tabbrowser-tabpanels.opacity", 100)}%`);

			for(var guid of (starred ? this.bguids : this.guids)) {
				var arr = [], num = 50;
				while(--num) {
					if (!star.matches(":hover")) return;
					var res = await this.bm.fetch(guid);
					if (!res) break;
					if ((guid = res.parentGuid) == this.bm.rootGuid) {
						arr.unshift(this.bm.getLocalizedTitle(res));
						break;
					}
					arr.unshift(res.title || "[Безымянная папка]");
				}
				arr.length && result.push(arr.join("\\"));
			}
			if (!star.matches(":hover")) return;

			var text = (await win.document.l10n.formatMessages([{ // стандартная подсказка
				id: star.getAttribute("data-l10n-id"),
				args: JSON.parse(star.getAttribute("data-l10n-args"))
			}]))[0].attributes.find(this.find).value, txt;

			if (result.length) {
				txt = result.join("\n");
				txt = starred ? `\n\n★ ${result.length > 1 ? "Данные закладки добавлены" : "Данная закладка добавлена"} в:\n${txt}` : "\n\n★ Недавно добавленная папка:\n" + txt;
			}
			win.document.tooltipNode == star ? this.tt(win).label = text + this.help_star + txt : star.tooltipText = text + this.help_star + txt;
		}
		var url = "data:;charset=utf-8," + encodeURIComponent(`(${func})("${id}")`);
		g.ChromeUtils.compileScript(url).then(ps => ps.executeInGlobal(g));
	}
	await delayedStartupPromise;

	var types = ["auxclick", "mouseenter", "wheel"];
	var stars = Array.from(document.querySelectorAll(sel));

	for(var star of stars) for(var type of types) star.addEventListener(type, stt);
	star.setAttribute("context", "event.stopPropagation()");

	var destructor = () => {
		for(var star of stars) for(var type of types) star.removeEventListener(type, stt);
	}
	var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win;
	if (ucf)
		ucf[id] = {destructor}, ucf.unloadlisteners.push(id);
	else
		window.addEventListener("unload", destructor, {once: true});
})("ucfBookmarksStarFTooltipHelper", "#star-button, #context-bookmarkpage");

ucf_QuickToggle.js - здесь код LongPress

Отредактировано Dobrov (20-11-2021 01:29:28)

Отсутствует

 

№13322-11-2021 21:25:38

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

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

Dobrov пишет

доработать код, чтобы сразу перехватывать клики кнопок "nav-bar-customization-target" основной панели и "page-action-buttons"

Так PanelUI-menu-button же торчит в коде,
nav-bar-customization-target ей не родитель. Общим будет nav-bar.

identity-box

Раз предполагаются элементы с видимыми для мыши
дочерними элементами, придётся использовать перебор и closest().
Кстати, с FF90+ таковы pageAction's (в hbox иконки завернули).

добавить действие на долгое нажатие кнопки
добавить перехват "wheel"

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

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

Выделить код

Код:

(() => {
	var c = msg => Services.console.logStringMessage("[HC] " + msg);
	var data = {
		"#downloads-button": {
			mousedownTarget: true,

			128() { // СКМ Click 
				c("Downloads Button Middle Click");
			},
			4() { // Double Left Click
				c("Downloads Button Double Left Click");
			},
			256() { // ПКМ Click
				c("Downloads Button Right Click");
			},
			260(btn) { // Double Right Click
				c("Downloads Button Double Right Click");
			},

			1() { // Left Long Press
				c("Downloads Button Left Long Press");
			},
		},
		"#PanelUI-menu-button": {
			mousedownTarget: true,

			8() { // ЛКМ + Alt
				c("PUI Button Alt + Left Click");
			},
			16(btn) { // Shift + ЛКМ
				c("PUI Button Shift + Left Click");
			},
			136(btn) { // Alt + СКМ
				c("PUI Button Alt + Middle Click");
			},
			128() { // СКМ
				c("PUI Button Middle Click");
			},
			132() { // СКМ Double
				c("PUI Button Double Middle Click");
			},
			256() { // ПКМ
				c("PUI Button Right Click");
			},
			264(btn) { // Alt + ПКМ
				c("PUI Button Alt + Right Click");
			},
			272() { // Shift + ПКМ
				c("PUI Button Shift + Right Click");
			},
			280(btn) { // Shift + Alt + ПКМ
				c("PUI Button Shift + Alt + Right Click");
			},
			4() { // Double Left Click
				c("PUI Button Double Left Click");
			},
			260() { // ПКМ Double Right Click
				c("PUI Button Double Right Click");
			},

			145() { // Shift + Middle Long Press
				c("PUI Button Shift + Middle Long Press");
			},
		},
		"#pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_": { // Reader View Button
			128() { // Middle Click
				c("Reader View Middle Click");
			},

			289() { // Ctrl + Right Long Press
				c("Reader View Ctrl + Right Long Press");
			},
			2(trg, forward) { // wheel
				c("Reader View Wheel " + (forward ? "forward" : "backward"));
			},
		},
		"#star-button-box": {
			1() { // Left Long Press
				c("Star Left Long Press");
			},
			4() { // Double Left Click
				c("Star Double Left Click");
			},
			129() { // Middle Long Press
				c("Star Middle Long Press");
			},
		},

		"#identity-permission-box": {
			2(trg, forward) { // wheel
				c("Identity Permisson Box Wheel " + (forward ? "forward" : "backward"));
			}
		},
		"#identity-box": {
			2(trg, forward) { // wheel
				c("Identity Box Wheel " + (forward ? "forward" : "backward"));
			},
			34(trg, forward) { // Ctrl + wheel
				c("Identity Box Ctrl + Wheel " + (forward ? "forward" : "backward"));
			},
		},
		"#identity-icon-box": {
			16() { // Shift + Left Click
				c("Identity Icon Box Shift + Left Click");
			},
		},
	};

	var listener = {
		filter(sel) {
			return this.closest(sel);
		},
		find(sel) {
			return data[sel][this] || data[sel][this + 1];
		},
		handleEvent(e) {
			if (this.skip || e.detail > 2) return;

			var trg = e.target;
			var sels = this.selectors.filter(this.filter, trg);
			var {length} = sels;
			if (!length) return;

			var dbl = e.detail == 2;
			var wh = e.type.startsWith("w");

			var num = e.metaKey *64 + e.ctrlKey *32 + e.shiftKey *16 + e.altKey *8
				+ (wh ? 2 : e.button *128 + dbl *4);

			var obj = data[
				length > 1 && sels.find(this.find, num) || sels[0]
			];

			// wheel
			if (wh) return obj[num]?.(trg, e.deltaY < 0);

			// mousedown
			if (e.type.startsWith("m")) {
				obj.mousedownTarget && this.stop(e);
				if (dbl) return;

				this.longPress = false;
				if (++num in obj)
					this.mousedownTID = setTimeout(this.onLongPress, 640, trg, obj, num);
				if (e.button == 2)
					this.ctx = trg.getAttribute("context"),
					trg.setAttribute("context", "");
				return;
			}

			// click
			obj.mousedownTarget || this.stop(e);
			if (this.longPress) return this.longPress = false;
			dbl
				? this.clickTID &&= clearTimeout(this.clickTID)
				: this.mousedownTID &&= clearTimeout(this.mousedownTID);

			if (!obj[num]) {
				if (e.button == 1) return;
				if (e.button) {
					num = "context";
					for(var p in this.a) this.a[p] = e[p];
				} else
					num = "dispatch",
					this.mdt = obj.mousedownTarget;
				obj = this;
			}
			dbl
				? obj[num](trg)
				: this.clickTID = setTimeout(this.exec, 300, trg, obj, num);
		},
		get selectors() {
			this.exec = (trg, obj, num) => {
				this.clickTID = null;
				obj[num](trg);
			}
			this.onLongPress = (trg, obj, num) => {
				this.mousedownTID = null;
				this.longPress = true;
				obj[num](trg);
			}
			delete this.selectors;
			return this.selectors = Object.keys(data);
		},
		get mdEvent() {
			delete this.mdEvent;
			return this.mdEvent = new MouseEvent("mousedown", {bubbles: true});
		},
		context(trg) {
			this.ctx
				? trg.setAttribute("context", this.ctx)
				: trg.removeAttribute("context");
			trg.dispatchEvent(new MouseEvent("contextmenu", this.a));
		},
		dispatch(trg) {
			this.skip = true;
			this.mdt ? trg.dispatchEvent(this.mdEvent) : trg.click();
			this.skip = false;
		},
		stop: e => {
			e.preventDefault();
			e.stopImmediatePropagation();
		},
		a: {__proto__: null, bubbles: true, screenX: 0, screenY: 0}
	};

	var root = document.getElementById("nav-bar");
	var events = ["click", "mousedown", "wheel"];
	for(var type of events) root.addEventListener(type, listener, true);
	var id = "test-hookClicks";
	ucf_custom_script_win.unloadlisteners.push(id);
	ucf_custom_script_win[id] = {destructor() {
		for(var type of events) root.removeEventListener(type, listener, true);
	}};
})();

Отсутствует

 

№13423-11-2021 02:02:40

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

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

Dumby спасибо за отличный код дополнительных кликов. :)
Подключил оба кода в custom_script_win.js, попробую вернуть функции Save HTML и прочие…


Только не понял, как в код обновления tooltips добавить removeEventListener и нужен ли он.

Выделить код

Код:

(() => { // update Tooltips
	………
	addDestructor(() => {
		………
	});
})();

Ещё не обновляются подсказки для 1) tracking-protection-icon-container "На этой странице не обнаружено ни одного известного Firefox трекера" и 2) identity-icon-box "Подтверждено: Let's Encrypt".
Я подключил на них яркость страниц, код работает. А как к этим кнопкам с динамической подсказкой добавить свой текст?
`Колесико ±    Яркость страниц\n…+ клик     Полная яркость
Яркость страниц ${win.Services.prefs.getIntPref("ucf.tabbrowser-tabpanels.opacity", 100)}%`
?

Отредактировано Dobrov (23-11-2021 10:45:15)

Отсутствует

 

№13523-11-2021 22:34:40

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

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

Dobrov пишет

как в код обновления tooltips добавить removeEventListener и нужен ли он

Да так же как и в коде для кликов.
А вот нужен ли он — это я и сам хотел бы знать.
Необходимость вызывает сомнение, но так принято (было),
поэтому, по возможности, оно так и продолжается.


Допустим, тултипский код рядом, сразу после var listener = {.....};
и добавление обработчиков и деструктора в самом конце.

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

Выделить код

Код:

.......
	var str_cut = s => s;

	var dsym = Symbol();
	var j = (...args) => args.join("\n");
	var tooltips = {
		get "PanelUI-menu-button"() {
			delete this["PanelUI-menu-button"];
			return j(
				`Клик мыши:	меню Firefox ${Services.appinfo.platformVersion}`,
				"…+ Shift		⚑ Краткая справка",
				"…+ Alt		Персонализация",
				"Клик дважды	⊠ закрыть браузер\n",

				"Правый клик	⇲ Свернуть",
				"…+ дважды	⤾ Вернуть вкладку",
				"…+ Alt		Диспетчер задач",
				"…+ Shift		Адаптивный дизайн\n",

				"Колёсико:	Развернуть | окно",
				"…+ Alt		Полный экран",
				"…+ дважды	Обновить без кэша"
			);
		},

		"pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_": j(
			`Reader View	${Services.appinfo.OS == "Darwin" ? "⌥⌘M" : "Ctrl+⇧+M"}\n`,

			"Клик мыши	Режим для чтения",
			"Колёсико	Адаптивный дизайн"
		),

		"_b9db16a4-6edc-47ec-a1f4-b86292ed211d_-browser-action": j(
			"Video DownloadHelper",
			"Скачивание проигрываемого видео"
		),

		[dsym]: j(
			GetDynamicShortcutTooltipText("downloads-button"),

			"\nДвойной клик: ⬇︎ открыть [Загрузки]",
			"…на картинке: ⧉ найти Похожие\n",

			"Правый клик (Alt+S):  Сохранить",
			"   в единый html всё / выделенное",
			"…дважды  Картинки вкл/выкл\n",

			"Ролик:	 Сохранить как файл .txt",
			"Колёсико на рисунке: ➜ Сохранить"
		),
		get "downloads-button"() {
			var hint = this[dsym];
			if (document.getElementById("_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action"))
				hint += "\nAlt⇧S	 ⌨ нажатие SingleSave";
			try {var dw = Services.prefs.getComplexValue("browser.download.dir", Ci.nsIFile);}
			catch {dw = Services.dirsvc.get("DfltDwnld", Ci.nsIFile);}
			if (dw) hint += "\n\n[Загрузки] — выбранная папка:\n" + str_cut(dw.path, 33);
			return hint;
		},

		get "identity-icon-box"() {
			var ttt = "";
			var trg = window.event.target;
			if (!trg.id.endsWith("x")) {
				if (trg.hasAttribute("tooltiptext"))
					ttt = trg.ttt = trg.tooltipText;
				else
					ttt = trg.ttt;
				if (ttt) ttt += "\n\n";
				trg.removeAttribute("tooltiptext");
			}
			return ttt + "Свой текст";
		},

		get "tracking-protection-icon-container"() {
			var trg = window.event?.target;
			return trg.id.endsWith("r") &&
				trg.textContent + "\n\nСвой текст";
		}
	};

	document.getElementById("tracking-protection-icon-container")
		.removeAttribute("tooltip");

	var onMouseenter = e => {
		var trg = e.target;
		var hint = tooltips[trg.id] || tooltips[(trg = trg.parentNode).id];
		if (hint) trg.tooltipText = hint;
	}
	var root = document.getElementById("nav-bar");
	var events = ["click", "mousedown", "wheel"];

	root.addEventListener("mouseenter", onMouseenter, true);
	for(var type of events) root.addEventListener(type, listener, true);

	var id = "hookClicks-and-tooltips";
	ucf_custom_script_win.unloadlisteners.push(id);
	ucf_custom_script_win[id] = {destructor() {
		root.removeEventListener("mouseenter", onMouseenter, true);
		for(var type of events) root.removeEventListener(type, listener, true);
	}};
})();

Отсутствует

 

№13630-11-2021 07:08:17

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

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

Dumby - спасибо! Скрипт hookClicks пригодится многим, он позволит прописывать обработку кликов в одном скрипте и позволит «разгрузить» другие кнопки, не добавлять в них код обработки кликов.
Этот код, расширяющий возможности нескольких кнопок, значительно устарел. Рекомендуется ucf_hookClicks.js

hookClicks дополнительные клики и подсказки кнопок

Выделить код

Код:

(async (id, func) => { // для custom_script_win.js: дополнительные клики и подсказки кнопок © Dumby, mod Dobrov
	var dsym = Symbol(), j = (...args) => args.join("\n"),
	br_val = () => { return ` ${Services.prefs.getIntPref("ucf.tabbrowser-tabpanels.opacity",100)}%`;}, br_txt =

		`Клик ролика	сброс яркости\nКрутить ±	Яркость страниц`, tooltips = {
	get "PanelUI-menu-button"() {	/* delete this["PanelUI-menu-button"]; */ return j(
		`Клик мыши:	меню Firefox ${Services.appinfo.platformVersion}`,
		`… держать	⚑ Краткая справка`,
		`…+ Alt		Персонализация`,
		`Клик дважды	⊠ закрыть браузер\n`,
		`Правый клик	⇲ Свернуть`,
		`…+ дважды	⤾ Вернуть вкладку`,
		`…+ Alt		Диспетчер задач\n`,
		`Колёсико:	Развернуть | окно`,
		`…+ Alt		Полный экран`,
		`…+ дважды	Обновить без кэша`
	);},
	[dsym]: j(GetDynamicShortcutTooltipText("downloads-button"),
		`\nДвойной клик: ⬇︎ открыть [Загрузки]`,
		`…на картинке: ⧉ найти Похожие\n`,
		`Правый клик (Alt+S):  Сохранить`,
		`   в единый html всё / выделенное`,
		`…дважды  Картинки вкл/выкл\n`,
		`Ролик:	 Сохранить как файл .txt`,
		`Колёсико на рисунке: ➜ Сохранить`
	),
	get "titlebar-button titlebar-close"() { return j(
		`Закрыть Firefox ${AppConstants.MOZ_APP_VERSION.replace(/-.*/,'')}\n`,
		`◉ колёсико	вернуть вкладку`,
		`◧ держать	краткая Справка`,
		`◨ пр. клик	⇲ Свернуть`);
	},
	get "pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_"() { return j(
		`Reader View	${Services.appinfo.OS == "Darwin" ? "⌥⌘M" : "Ctrl+⇧+M"}\n`,
		`Клик мыши	Режим для чтения`, `Колёсико	Адаптивный дизайн\nКолесико ±	Яркость сайта` + br_val());
	},
	"_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action":
		`Сохранить страницу с помощью SingleFile (Alt+S)`
	,
	"_b9db16a4-6edc-47ec-a1f4-b86292ed211d_-browser-action":
		`Video DownloadHelper\nСкачивание проигрываемого видео`
	,
	get "downloads-button"() {
		var hint = this[dsym];
		if (document.getElementById("_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action"))
			hint += "\nAlt⇧S	 ⌨ нажатие SingleSave";  //убрать/добавить
		try {var dw = Services.prefs.getComplexValue("browser.download.dir", Ci.nsIFile);}
			catch {dw = Services.dirsvc.get("DfltDwnld", Ci.nsIFile);} //отличается от ⇧
		if (dw) hint += "\n\n[Загрузки] — выбранная папка:\n" + str_cut(dw.path, 33);
		return hint;
	},
	get "identity-icon-box"() {
		var trg = window.event.target, ttt = "";
		if (!trg.id.endsWith("x")) {
			if (trg.hasAttribute("tooltiptext"))
				ttt = trg.ttt = trg.tooltipText;
			else
				ttt = trg.ttt;
			if (ttt) ttt += "\n\n";
			trg.removeAttribute("tooltiptext");
		}
		return ttt +`Правый клик	Копировать адрес в буфер\n`+ br_txt + br_val();
	},
	get "tracking-protection-icon-container"() {
		var trg = window.event?.target;
		return trg.id.endsWith("r") && trg.textContent + "\n\n" + br_txt + br_val();
	}
	}; /* end tooltips */ document.getElementById("tracking-protection-icon-container").removeAttribute("tooltip");

	var listener = { // дополнительные клики кнопок и перехват существующих
		filter(sel) {
			return this.closest(sel);
		},
		find(sel) {
			return data[sel][this] || data[sel][this + 1];
		},
		handleEvent(e) {
			if (this.skip || e.detail > 2) return;

			var trg = e.target;
			var sels = this.selectors.filter(this.filter, trg);
			var {length} = sels;
			if (!length) return;

			var dbl = e.detail == 2;
			var wh = e.type.startsWith("w");

			var num = e.metaKey *64 + e.ctrlKey *32 + e.shiftKey *16 + e.altKey *8 + (wh ? 2 : e.button *128 + dbl *4);

			var obj = data[
				length > 1 && sels.find(this.find, num) || sels[0]
			];
// wheel
			if (wh) return obj[num]?.(trg, e.deltaY < 0);
// mousedown
			if (e.type.startsWith("m")) {
				obj.mousedownTarget && this.stop(e);
				if (dbl) return;

				this.longPress = false;
				if (++num in obj)
					this.mousedownTID = setTimeout(this.onLongPress, 640, trg, obj, num);
				if (e.button == 2)
					this.ctx = trg.getAttribute("context"),
					trg.setAttribute("context", "");
				return;
			}
// click
			obj.mousedownTarget || this.stop(e);
			if (this.longPress) return this.longPress = false;
			dbl
				? this.clickTID &&= clearTimeout(this.clickTID)
				: this.mousedownTID &&= clearTimeout(this.mousedownTID);

			if (!obj[num]) {
				if (e.button == 1) return;
				if (e.button) {
					num = "context";
					for(var p in this.a) this.a[p] = e[p];
				} else
					num = "dispatch",
					this.mdt = obj.mousedownTarget;
				obj = this;
			}
			dbl
				? obj[num](trg)
				: this.clickTID = setTimeout(this.exec, 300, trg, obj, num);
		},
		get selectors() {
			this.exec = (trg, obj, num) => {
				this.clickTID = null;
				obj[num](trg);
			}
			this.onLongPress = (trg, obj, num) => {
				this.mousedownTID = null;
				this.longPress = true;
				obj[num](trg);
			}
			delete this.selectors;
			return this.selectors = Object.keys(data);
		},
		get mdEvent() {
			delete this.mdEvent;
			return this.mdEvent = new MouseEvent("mousedown", {bubbles: true});
		},
		context(trg) {
			this.ctx
				? trg.setAttribute("context", this.ctx)
				: trg.removeAttribute("context");
			trg.dispatchEvent(new MouseEvent("contextmenu", this.a));
		},
		dispatch(trg) {
			this.skip = true;
			this.mdt ? trg.dispatchEvent(this.mdEvent) : trg.click();
			this.skip = false;
		},
		stop: e => {
			e.preventDefault();
			e.stopImmediatePropagation();
		},
		a: {__proto__: null, bubbles: true, screenX: 0, screenY: 0}
	};
	var onMouseenter = e => {
		var trg = e.target, id = trg.id || trg.className;
		console.log('id= «'+ id + '» '+ Math.random());
		var hint = tooltips[id] || tooltips[(trg = trg.parentNode).id];
		if (hint) trg.tooltipText = hint;
	}
	var keydown_win = e => { // нажатие клавиш
		if (e.keyCode == 83 && e.altKey) { // Alt+S [+Shift]
			var singlesave = document.getElementById('_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action');
			e.shiftKey ? singlesave ? singlesave.click() : save() : save(); // имитировать клик по кнопке, используя её ID
		}
		if (e.keyCode == 88 && e.altKey){ // Alt+X отладка внешнего JS-кода
			// e.target.ownerDocument.getElementById("key_browserConsole").doCommand();
			eval(Cu.readUTF8URI(Services.io.newURI("chrome://user_chrome_files/content/custom_scripts/User.js")));
			console.log("[END] User.js " + Math.random());
		}
	}
	var root = document.getElementById("navigator-toolbox");
	var events = ["click", "mousedown", "wheel"];
	root.addEventListener("mouseenter", onMouseenter, true);
	for(var type of events) root.addEventListener(type, listener, true);
	window.addEventListener("keydown", keydown_win);
	ucf_custom_script_win.unloadlisteners.push(id);

	ucf_custom_script_win[id] = {destructor() {
		root.removeEventListener("mouseenter", onMouseenter, true);
		for(var type of events) root.removeEventListener(type, listener, true);
		window.removeEventListener("keydown", keydown_win);
	}};
	addDestructor = nextDestructor => {
		var {destructor} = ucf_custom_script_win[id];
		ucf_custom_script_win[id].destructor = () => {
			try {destructor();} catch(ex) {Cu.reportError(ex);}
			nextDestructor();
		}
	}; // end Hooks

	var {prefs, dirsvc} = Services, getIntPref = (p) => prefs.getIntPref(p, 100),
	c = msg => Services.console.logStringMessage("[HC] "+ msg), // отладка
	sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
	my_br = "ucf.tabbrowser-tabpanels.opacity", // яркость страниц
	css = `@-moz-document url(chrome://browser/content/browser.xhtml) {
		:is(${id})[rst] {filter: grayscale(1%) !important;}
		:root:not([chromehidden*=toolbar]) #tabbrowser-tabbox {background-color: black !important;}
		:root:not([chromehidden*=toolbar]) #tabbrowser-tabpanels {opacity:${getIntPref(my_br)/100} !important;}}`,
	subst = "ucf-tabbrowser-tabpanels-opacity-style", url = `resource://${subst}/`;
	Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler)
		.setSubstitution(subst, Services.io.newURI("data:text/css," + encodeURIComponent(css)));
	sss.loadAndRegisterSheet(Services.io.newURI(url), sss.USER_SHEET);
	var st = InspectorUtils.getAllStyleSheets(document).find(s => s.href == url).cssRules[0].cssRules[2].style;
	var observer = () => st.setProperty("opacity", getIntPref(my_br)/100, "important");
	prefs.addObserver(my_br, observer);
	this.removePrefObs = () => prefs.removeObserver(my_br, observer); // end яркость

	if (typeof IOUtils != "object") { // Firefox 78 ESR
		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))};
	};
	prefs.setBoolPref("browser.download.autohideButton", false); // не скрывать кнопку Загрузки

	str_cut = (s, cut = 33) => { // сократить/разбить строку
		return s.substring(0,cut) + `${s.length > cut - 1 ? `…\n…${s.substring(s.length -cut + 2, s.length)}`: ''}`;
	},
	url_color = (color = "rgba(240,176,0,0.5)", ms = 300) => { // строка адреса мигает
		var u_alert = document.getElementById("urlbar-input-container");
		u_alert.style.background = color; setTimeout(() => u_alert.style.background = "", ms);
	},
	gClipboard = {
		get ch() { delete this.ch;
			return this.ch = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
		},
		write(str) { this.ch.copyStringToClipboard(str, Services.clipboard.kGlobalClipboard);}
	},
	switchToTab = (url, but = window) => { // открыть вкладку | закрыть, если открыта
		for(var tab of but.ownerGlobal.gBrowser.tabs)
			if (tab.linkedBrowser.currentURI.spec == url) {but.ownerGlobal.gBrowser.removeTab(tab); return;}; // закрыть
		but.ownerGlobal.switchToTabHavingURI(url, true, {relatedToCurrent: true, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()});
	},
	showInStatusPanel = (info, time = 5000) => {
		StatusPanel = window.StatusPanel;
		if (StatusPanel.update.tid)
			clearTimeout(StatusPanel.update.tid)
		else {
			var {update} = StatusPanel;
			StatusPanel.update = () => {};
			StatusPanel.update.ret = () => {
				StatusPanel.update = update;
				StatusPanel.update();
			}
		}
		StatusPanel.update.tid = setTimeout(StatusPanel.update.ret, time);
		StatusPanel._label = info;
	},
	Title = (max, title) => { // получить заголовок. без обрезки: max не указан, домен: max <0, + дата: max=0
		if (!title) var title = document.title || gBrowser.selectedTab.label;
		if (max == undefined) return title; // заголовок как есть или ограничить длину, убрать служебные символы
		title = title.replace(/[\\\/?*\"'`]+/g,'').replace(/\s+/g,' ').replace(/[|<>]+/g,'_').replace(/:/g,'։').trim();
		if ( max > 0 ) return title.slice(0, max);
		if ( max == 0) return title.slice(0, 100) +"_"+ new Date().toLocaleDateString('ru', {day: 'numeric', month: 'numeric', year: '2-digit'}) +'-'+ new Date().toLocaleTimeString().replace(/:/g, "։");
		var host = decodeURIComponent(gURLBar.value); // max < 0
		if (!/^file:\/\//.test(host)) host = host.replace(/^.*url=|https?:\/\/|www\.|\/.*/g,'');
		return host.replace(/^ru\.|^m\.|forum\./,'').replace(/^club\.dns/,'dns');
	},
	saveSelectionToTxt = async () => { // сохранить выделенный/весь текст страницы как .txt
		var msgName = id + ":Save:GetSelection", splice = saveURL.length == 10;
		var receiver = msg => {
			var args = ["data:text/plain," + encodeURIComponent(gBrowser.currentURI.spec + "\n\n" + msg.data),
				Title(0) + '.txt', null, false, true, null, window.document];
			splice && args.splice(5, 0, null);
			saveURL(...args); showInStatusPanel("√ текст сохранён: "+ Title(0).slice(0, 60));
		}
		messageManager.addMessageListener(msgName, receiver);
		addDestructor(() => messageManager.removeMessageListener(msgName, receiver));
		var func = fm => {
			var res, fed, win = {}, 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))();
	},
	save = async () => { // SingleHtml by Лекс, правка: Dumby, Dobrov
		var msgName = id + "ucfDwnldsBtnSaveSnapshotToHTML";
		var write = IOUtils.writeUTF8 ? "writeUTF8" : "writeAtomicUTF8";
		var msgListener = async msg => {
			var [fileContent, fileName] = msg.data, dir; // fileName: выделенный текст или null
			try {dir = prefs.getComplexValue("browser.download.dir", Ci.nsIFile);} catch {dir = dirsvc.get("DfltDwnld", Ci.nsIFile);}
			var arr = prefs.getStringPref("ucf_save.dirs","_Web||_Images|0").split('|').slice(0,2); //subdir: title|host
			arr[1] = (arr[1] == "0") ? Title(100) : (arr[1] == "1") ? Title(-1) : ""; // имя вкладки или домен
			arr.forEach(dir.append); // ucf_save.dirs = "_Web||_Pics|1" HTML сохранится в папку [Загрузки]/_Web/label
			dir.exists() && dir.isDirectory() || dir.create(dir.DIRECTORY_TYPE, 0o777); // создать, если не существует…
			var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
			file.initWithPath(dir.path);
			if (!fileName) fileName = Title(100); // убрать служебные символы
			dir.append(Title(0, fileName) +'.html');
			await IOUtils[write](dir.path, fileContent) && showInStatusPanel("√ страница записана: " + fileName.slice(0, 60));
			var d = await Downloads.createDownload({ source: "about:blank", target: FileUtils.File(dir.path)}); // Fake download
			(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))();
	},
	bright = (trg, forward, val) => { // wheel
		if (!val) var val = getIntPref(my_br) + (forward ? 5 : -5);
		val = val > 100 ? 100 : val < 20 ? 20 : val;
		prefs.setIntPref(my_br, val), trg.toggleAttribute("rst"), showInStatusPanel("☀ Яркость страниц: "+ val +"%");
	},
	help = (btn) => { // встроенная справка
		var help_ucf = ['chrome://user_chrome_files/content/help.html', 'http://forum.puppyrus.org/index.php?topic=22762'];
		var newURI = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry).convertChromeURL(Services.io.newURI(help_ucf[0])); // .spec = file:///
		(newURI.QueryInterface(Ci.nsIFileURL).file.exists()) ? switchToTab(help_ucf[0]) : switchToTab(help_ucf[1]);
	},
	GetSelection = (mM = gBrowser.selectedBrowser.messageManager) => {
		mM.addMessageListener('getSelect', function sel_listener(msg) {
			window.seltxt = msg.data;
			mM.removeMessageListener('getSelect', sel_listener, true);
		});
		mM.loadFrameScript('data:,sendAsyncMessage("getSelect",content.document.getSelection().toString())',false);
	},
	data = {
		"#downloads-button": { mousedownTarget: true,

			4() { // Double Left Click - Обзор папки «Загрузки»
				c("DW Double Left Click");
				Downloads.getSystemDownloadsDirectory().then(path => FileUtils.File(path).launch(), Cu.reportError);
			},
			128() { saveSelectionToTxt();}, // СКМ Click (сохранить .txt)
			256() { save();}, // ПКМ Click (Single HTML)
			260(btn) { // Double ПКМ Click
				var pref = "permissions.default.image";
				var one = prefs.getIntPref(pref) == 1;
				prefs.setIntPref(pref, one ? 2 : 1);
				btn.style.filter = one ? "hue-rotate(180deg) brightness(95%)" : "";
				BrowserReload();
			},
		},
		"#PanelUI-menu-button": { mousedownTarget: true,

			1(btn) { help(btn);}, // Long Press
			8() { gCustomizeMode.enter();}, //ЛКМ + Alt Персонализация
			16(btn) { help(btn);}, // Shift + ЛКМ
			4() { goQuitApplication();}, // Double Left Click
			128() { windowState != STATE_MAXIMIZED ? maximize() : restore();}, // СКМ
			136(btn) { BrowserFullScreen();}, // Alt + СКМ
			132() { BrowserReloadSkipCache();}, // СКМ Double
			256() { minimize();}, // ПКМ
			260(btn) { btn.ownerGlobal.undoCloseTab();}, // ПКМ Double Right Click
			264(btn) { switchToTab('about:performance');}, // Alt + ПКМ
			280(btn) { // Shift + Alt + ПКМ
				var obj = ChromeUtils.import("resource://devtools/shared/Loader.jsm").require("devtools/client/menus").menuitems.find(menuitem => menuitem.id == "menu_devtools_remotedebugging");
				(this[280] = target => obj.oncommand({target}))(btn); // запуск пункта меню, у которого нет HotKey
			},
		},
		"#pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_": { // Reader View Button
			128(btn) { // СКМ
				btn.ownerDocument.getElementById("key_responsiveDesignMode").doCommand(); // запуск пункта меню с HotKey
				if (gBrowser.selectedBrowser.browsingContext.inRDMPane) BrowserReload();
			},
			2(trg, forward) { bright(trg, forward);}, // яркость по wheel ±
			264(btn) { // Alt + ПКМ
				translate(gBrowser.selectedBrowser.messageManager, 1);
			},
			1(btn) { // Shift + ПКМ
				translate(gBrowser.selectedBrowser.messageManager);
			},
		},
		"#star-button-box": {
			1() { // Left Long Press
				c("Star Left Long Press");
			},
			2(trg, forward) { bright(trg, forward);}, // яркость по wheel ±
			// 128(btn) { // СКМ
			// 	switchToTab('about:config');
			// },
			256() { // ПКМ
				window.undoCloseTab();
			},
		},
		"#identity-box": { // Замок
			2(trg, forward) { bright(trg, forward);}, // яркость по wheel ±
			128(trg, forward) { bright(trg, forward, 100);}, // СКМ
			256(btn) { // ПКМ
				gClipboard.write(gURLBar.value);
				url_color(), showInStatusPanel("в буфере: "+ gURLBar.value.slice(0, 80));
			},
		},
		"#tracking-protection-icon-container": { // Защита
			2(trg, forward) { bright(trg, forward);}, // яркость по wheel ±
			128(trg, forward) { bright(trg, forward, 100);}, // СКМ
		},
		"#identity-permission-box": {
			2(trg, forward) { // wheel
				c("Identity Permisson Box Wheel " + (forward ? "forward" : "backward"));
			}
		},
		"#identity-icon-box": {
			16() { // Shift + Left Click
				c("Identity Icon Box Shift + Left Click");
			},
		},
	}; // end Clicks, HotKeys ==================================================


})("hookClicks-and-tooltips", ({io, focus}) => { // SingleHTML не сохраняет svg графику

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

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

	head.copyStyle = function (s) {
		if (!s) return;
		var style = doc.createElement('style');
		style.type = 'text/css';
		if (s.media && s.media.mediaText) style.media = s.media.mediaText;
		try {
			for (var i = 0, rule; rule = s.cssRules[i]; i++) {
				if (rule.type != 3) {
					if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) {
						var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) {
							if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href);
							if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url);
							return prev + url + next;
						});
						style.appendChild(doc.createTextNode(css + '\n'));
					}
				} else {
					this.copyStyle(rule.styleSheet);
				}
			}
		} catch(e) {
			if (s.ownerNode) style = s.ownerNode.cloneNode(false);
		};
		this.appendChild(style);
	};
	for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]);
	head.appendChild(doc.createTextNode('\n'));
	var doctype = '', dt = doc.doctype;
	if (dt && dt.name) {
		doctype += '<!DOCTYPE ' + dt.name;
		if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22';
		if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22';
		doctype += '>\n';
	};
	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>', selWin ? win.getSelection().toString().slice(0, 200) : undefined]); // выделенный текст
}); // END hookClicks

Отредактировано Dobrov (15-06-2024 07:27:54)

Отсутствует

 

№13706-12-2021 18:57:00

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

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

egorsemenov06 пишет

JSON.parse

/*JSON.parse*/

Отсутствует

 

№13808-12-2021 20:37:15

sachka
Участник
 
Группа: Members
Зарегистрирован: 11-04-2018
Сообщений: 23
UA: Firefox 95.0

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

воможно ли с помощью скрипта https://forum.mozilla-russia.org/viewto … 54#p782454 открывать ссылки и страницы в tor browser? после последнего обновления тор открывается через скрипт, но соединения нет

Отсутствует

 

№13914-12-2021 21:47:29

sandro79
Участник
 
Группа: Members
Зарегистрирован: 15-11-2017
Сообщений: 1750
UA: Firefox 91.0

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

Dumby
Хочу на базе этого скрипта сделать ещё один, но чтоб он закрывал текущую вкладку, заменить им хочу расширение.
Подскажите пожалуйста, может где подправить можно по мелочи?
Сейчас мой код закрытия "других вкладок" стал немного другим, иконку ещё более подходящую нашёл

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

Выделить код

Код:

CustomizableUI.createWidget({
	id: "Close-Tabs-button",
	label: "Закрыть другие вкладки",
	tooltiptext: "Закрыть другие вкладки",
	defaultArea: CustomizableUI.AREA_NAVBAR,
	localized: false,
	onCreated(btn) {
		btn.render = this.render;
		btn._handleClick = this.close;
		btn.setAttribute("image", "chrome://devtools/skin/images/close.svg");
	},
	render() {
		delete this.render;
		this.render();
		this.icon.style.setProperty("padding", "3px", "important");
	},
	close() {
		var gb = this.ownerGlobal.gBrowser;
		gb.removeAllTabsBut(gb.selectedTab);
	}
});

По-моему, строку gb.removeAllTabsBut(gb.selectedTab); нужно изменить, но вот как...

Отсутствует

 

№14014-12-2021 23:11:31

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

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

sandro79 пишет

По-моему, строку gb.removeAllTabsBut(gb.selectedTab); нужно изменить, но вот как...

Верно, эту строку. Как? Ну, обычно,
следует просто посмотреть как это делает сам браузер, и срисовать себе.
Если как пункт контекстного меню вкладок «Закрыть (N) вклад(ку|ки|ок)»,
то получится что-то типа

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

Выделить код

Код:

...
		//gb.removeAllTabsBut(gb.selectedTab);
		var tab = gb.selectedTab;
		tab.multiselected
			? gb.removeMultiSelectedTabs()
			: gb.removeTab(tab, {animate: true});


Но там учитывается вариант несколько-выделенных вкладок.
Если нужно это игнорировать, то есть понимать вопрос
строго буквально «чтоб он закрывал текущую вкладку» и никак иначе,
то, в простейшем случае, можно заменить на
gb.removeTab(gb.selectedTab, {animate: true});

Отсутствует

 

№14114-12-2021 23:42:17

sandro79
Участник
 
Группа: Members
Зарегистрирован: 15-11-2017
Сообщений: 1750
UA: Firefox 91.0

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

Dumby пишет

следует просто посмотреть как это делает сам браузер, и срисовать себе

С этим я пока не разобрался, хотя не помешало бы такую мелочь самому вычислить.

строго буквально «чтоб он закрывал текущую вкладку» и никак иначе

Да, как раз так и хотел, пункт "Выбрать все вкладки" не использую, и он у меня скрыт стилем. Скрипт собрал, всё работает

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

Выделить код

Код:

CustomizableUI.createWidget({
	id: "Close-Tab",
	label: "Закрыть вкладку",
	tooltiptext: "Закрыть вкладку",
	defaultArea: CustomizableUI.AREA_NAVBAR,
	localized: false,
	onCreated(btn) {
		btn.render = this.render;
		btn._handleClick = this.close;
		btn.setAttribute("image", "chrome://devtools/skin/images/close.svg");
	},
	render() {
		delete this.render;
		this.render();
		this.icon.style.setProperty("padding", "3px", "important");
	},
	close() {
		var gb = this.ownerGlobal.gBrowser;
		gb.removeTab(gb.selectedTab, {animate: true});
	}
});

Благодарю за помощь! :beer:

Отсутствует

 

№14215-12-2021 18:09:11

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3231
UA: Firefox 95.0

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

Dumby
Кнопку  "Закрыть другие вкладки" №82 куда лучше подключить, а то она у меня на [firefox] 95 никак не хочет работать?

Отсутствует

 

№14315-12-2021 19:47:29

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

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

У меня кнопка "Закрыть вкладки..." такая, может кому пригодится. Кто-то помогал сделать, закреплённые вкладки, когда удаление слева или другие не удаляет. Я бы сам так не осилил. Работает, ucf у меня старый.

custom_script.js

Выделить код

Код:

// Этот скрипт можно использовать для создания кнопок с помощью CustomizableUI.createWidget
(() => {
    var loadscript = name => {
        try {
            Services.scriptloader.loadSubScript(`chrome://user_chrome_files/content/custom_scripts/${name}`, globalThis, "UTF-8");
        } catch(e) {}
    };
    loadscript("my_buttons.js");
})();


my_buttons.js

Выделить код

Код:

var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
var {console} = Cu.import("resource://gre/modules/Console.jsm", {});
try {
    CustomizableUI.createWidget({
        id: "add-select-close-tabs-app",
        type: "custom",
        tooltiptext: [
            "ЛКМ: Закрыть все вкладки",
            "Shift+ЛКМ: Закрыть другие вкладки",
            "Ctrl+ЛКМ: Закрыть слева",
            "Alt+ЛКМ: Закрыть справа",
        ].join("\n"),
        onBuild: function(document) {
            var toolbarbutton_0 = document.createXULElement("toolbarbutton");
            toolbarbutton_0.id = this.id;
            toolbarbutton_0.tooltipText = this.tooltiptext;
            toolbarbutton_0.label = "Закрыть все вкладки";
            toolbarbutton_0.setAttribute("context", false);
            toolbarbutton_0.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFLSURBVDhPYxg8wD5wy1y7gK1/7AO3/ncI2nq7uOnk3cq20//BuOP07b1Hnt09eurl/6OnXvwB0rOh2hAAphmGU0uOQDRD8ZrN94CaQQZADIFqQwBkzSAcnLTnVkLewWMgnFZy6Ep9z9kr3dMuHoNhqDYEQDeAEIZqQ4Dd937/JwVDtSEANkX4MFQbAmBThA9DtSEANkXIeM/t7/8vz1v9/1590//rE2f8/+pkIQ3VCgHYNMEwSPOLtOT/X1ws/n9xNvv/xRVIO5l9+OxsoQvVjt+AS/PXgDX/vXnt/4/q4v9/b1z9/y0tGmiY6S6odvwGgJwNshmk+f+fP/9/790JcQnQFVDt+A0A+RnsAqDNIM3/Prz//y0lEmTAZah2/OCrvZkM0LnvvqXFgG3+lgzUDAoHZ9N4qBLC4LOriQ7Qxt0gZwMNuQLRzMAAAAEG9BCOlZEaAAAAAElFTkSuQmCC");
            toolbarbutton_0.addEventListener("click", function(event) {
                var win = event.target.ownerDocument.defaultView;
                if (event.button == 0) {
                    if (event.shiftKey) {
                        win.gBrowser.removeAllTabsBut(win.gBrowser.selectedTab);
                    } else if (event.ctrlKey) {
                        var ctab = win.gBrowser.selectedTab, tabs;
                        if (ctab.multiselected)
                            tabs = win.gBrowser.visibleTabs.filter(tab => !tab.multiselected && !tab.pinned);
                        else
                            tabs = win.gBrowser.visibleTabs.filter(tab => !tab.pinned);
                        var index = tabs.indexOf(ctab);
                        tabs = tabs.slice(0, (index != -1) ? index : tabs.length);
                        tabs.forEach((tab) => {
                            win.gBrowser.removeTab(tab);
                        });
                    } else if (event.altKey) {
                        var ctab = win.gBrowser.selectedTab, tabs;
                        if (ctab.multiselected)
                            tabs = win.gBrowser.visibleTabs.filter(tab => !tab.multiselected && !tab.pinned);
                        else
                            tabs = win.gBrowser.visibleTabs.filter(tab => !tab.pinned);
                        var index = tabs.indexOf(ctab);
                        tabs = tabs.slice((index != -1) ? (index + 1) : 0, tabs.length);
                        tabs.forEach((tab) => {
                            win.gBrowser.removeTab(tab);
                        });
                    }
                else {
                    win.gBrowser.selectAllTabs();
                    win.gBrowser.removeMultiSelectedTabs();
                    }
                }
            }, false);
            toolbarbutton_0.classList.add("toolbarbutton-1");
            toolbarbutton_0.classList.add("chromeclass-toolbar-additional");
            return toolbarbutton_0;
        }
    });
} catch(e) {}


И ещё мне 2 кнопки сделал Vitaliy V. здесь.

Отредактировано xrun1 (15-12-2021 19:49:44)

Отсутствует

 

№14415-12-2021 19:48:55

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

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

voqabuhe пишет

куда лучше подключить

Что значит лучше?
Либо добавить в custom_script.js или подобный, либо отдельным файлом.
Придумываешь название, создаёшь, и прописываешь в CustomStylesScripts.jsm
(это если использовать встроенный загрузчик)

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

Выделить код

Код:

var UcfStylesScripts = {
    /** ************************▼ Настройки ▼************************ */

    .......

    scriptsbackground: [ // В фоне [System Principal]
        .......

        { path: "closeOtherTabs.js" },
    ],
    /** ************************▲ Настройки ▲************************ */
};

никак не хочет работать

Что значит не хочет работать?
Открывает вкладки вместо того, чтобы закрывать?


id'шник проверь, чтоб уникальный был.
Иконки, кстати, такой как там у тебя может не быть, пропиши свою.
Кэш ещё может залипнуть, закрой браузер и удали папку startupCache руками.

Отсутствует

 

№14515-12-2021 21:18:30

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

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

xrun1 пишет

my_buttons.js

Выделить код

Код:

var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
var {console} = Cu.import("resource://gre/modules/Console.jsm", {});
try {
    CustomizableUI.createWidget({
        id: "add-select-close-tabs-app",
        type: "custom",
        tooltiptext: [
            "ЛКМ: Закрыть все вкладки",
            "Shift+ЛКМ: Закрыть другие вкладки",
            "Ctrl+ЛКМ: Закрыть слева",
            "Alt+ЛКМ: Закрыть справа",
        ].join("\n"),
        onBuild: function(document) {
            var toolbarbutton_0 = document.createXULElement("toolbarbutton");
            toolbarbutton_0.id = this.id;
            toolbarbutton_0.tooltipText = this.tooltiptext;
            toolbarbutton_0.label = "Закрыть все вкладки";
            toolbarbutton_0.setAttribute("context", false);
            toolbarbutton_0.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFLSURBVDhPYxg8wD5wy1y7gK1/7AO3/ncI2nq7uOnk3cq20//BuOP07b1Hnt09eurl/6OnXvwB0rOh2hAAphmGU0uOQDRD8ZrN94CaQQZADIFqQwBkzSAcnLTnVkLewWMgnFZy6Ep9z9kr3dMuHoNhqDYEQDeAEIZqQ4Dd937/JwVDtSEANkX4MFQbAmBThA9DtSEANkXIeM/t7/8vz1v9/1590//rE2f8/+pkIQ3VCgHYNMEwSPOLtOT/X1ws/n9xNvv/xRVIO5l9+OxsoQvVjt+AS/PXgDX/vXnt/4/q4v9/b1z9/y0tGmiY6S6odvwGgJwNshmk+f+fP/9/790JcQnQFVDt+A0A+RnsAqDNIM3/Prz//y0lEmTAZah2/OCrvZkM0LnvvqXFgG3+lgzUDAoHZ9N4qBLC4LOriQ7Qxt0gZwMNuQLRzMAAAAEG9BCOlZEaAAAAAElFTkSuQmCC");
            toolbarbutton_0.addEventListener("click", function(event) {
                var win = event.target.ownerDocument.defaultView;
                if (event.button == 0) {
                    if (event.shiftKey) {
                        win.gBrowser.removeAllTabsBut(win.gBrowser.selectedTab);
                    } else if (event.ctrlKey) {
                        var ctab = win.gBrowser.selectedTab, tabs;
                        if (ctab.multiselected)
                            tabs = win.gBrowser.visibleTabs.filter(tab => !tab.multiselected && !tab.pinned);
                        else
                            tabs = win.gBrowser.visibleTabs.filter(tab => !tab.pinned);
                        var index = tabs.indexOf(ctab);
                        tabs = tabs.slice(0, (index != -1) ? index : tabs.length);
                        tabs.forEach((tab) => {
                            win.gBrowser.removeTab(tab);
                        });
                    } else if (event.altKey) {
                        var ctab = win.gBrowser.selectedTab, tabs;
                        if (ctab.multiselected)
                            tabs = win.gBrowser.visibleTabs.filter(tab => !tab.multiselected && !tab.pinned);
                        else
                            tabs = win.gBrowser.visibleTabs.filter(tab => !tab.pinned);
                        var index = tabs.indexOf(ctab);
                        tabs = tabs.slice((index != -1) ? (index + 1) : 0, tabs.length);
                        tabs.forEach((tab) => {
                            win.gBrowser.removeTab(tab);
                        });
                    }
                else {
                    win.gBrowser.selectAllTabs();
                    win.gBrowser.removeMultiSelectedTabs();
                    }
                }
            }, false);
            toolbarbutton_0.classList.add("toolbarbutton-1");
            toolbarbutton_0.classList.add("chromeclass-toolbar-additional");
            return toolbarbutton_0;
        }
    });
} catch(e) {}

Интересная кнопочка.
Только немешало бы в неё добавить "защиту от дурака" на все действия - подтверждение на закрытие вкладок.


Что-то типа такого:

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

untitled-4.png
untitled-2.png
untitled-3.png

Отредактировано unter_officer (15-12-2021 21:20:15)


«The Truth Is Out There»

Отсутствует

 

№14616-12-2021 00:05:28

kokoss
Участник
 
Группа: Members
Зарегистрирован: 15-02-2018
Сообщений: 1739
UA: Firefox 95.0

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


Win7

Отсутствует

 

№14716-12-2021 02:14:46

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

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

Dumby
Посмотрите пожалуйста, я правильно отредактировал?

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

Выделить код

Код:

try {
    CustomizableUI.createWidget({
        id: "additional-toolbars-button",
        type: "custom",
        label: "Доп. панели",
        tooltiptext: [
            "ЛКМ: Переключить верт. панель",
            "ПКМ: Переключить доп. панель"
        ].join("\n"),
        localized: false,
        onBuild(doc) {
            var trbn = doc.createXULElement("toolbarbutton");
            trbn.id = this.id;
            trbn.tooltipText = this.tooltiptext;
            trbn.label = this.label;
            trbn.className = "toolbarbutton-1 chromeclass-toolbar-additional";
            trbn.setAttribute("context", false);
            trbn.setAttribute("image", "chrome://user_chrome_files/content/custom_styles/svg/layer-visible-off.svg");
            trbn.addEventListener("click", function(e) {
                var pref = "browser.add.toolbars.visibility";
                if (e.button == 0) {
                    e.preventDefault();
                    e.stopPropagation();
                    CustomizableUI.setToolbarVisibility("ucf-additional-vertical-bar", doc.querySelector("#ucf-additional-vertical-bar").collapsed);
                } else if (e.button == 2) {
                    e.preventDefault();
                    e.stopPropagation();
                    CustomizableUI.setToolbarVisibility("ucf-additional-top-bar", doc.querySelector("#ucf-additional-top-bar").collapsed);
                }
            }, false);
            return trbn;
        },
    });
} catch(e) {}

Отсутствует

 

№14816-12-2021 05:01:45

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

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

unter_officer
Для меня такое сделать нереально. :) Не представляю, как в кнопку прикрутить confirm()... Да и не нужно. Кнопка "Восстановить" из расширения ATB Vitaliy V. восстанавливает все закрытые вкладки моей кнопкой. Если сразу озаботиться, конечно.
kokoss
Я ещё для боковой панели менял кнопку "Закладки" для экономии места, вдруг пригодится.

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

Заменить в user_chrome.js кнопку с id: "add-view-bookmarks-sidebar-button". Ещё раз повторюсь, ucf у меня старый.

Выделить код

Код:

try {
                CustomizableUI.createWidget({
                    id: "add-view-bookmarks-sidebar-button",
                    type: "custom",
                    label: "Закладки Библиотека История",
                    tooltiptext: "ЛКМ: Показать / Скрыть Закладки\nСКМ: Открыть Библиотеки в табе\nПКМ: Показать / Скрыть Историю",
                    localized: false,
                    onBuild: function(doc) {
                        var win = doc.defaultView;
                        var trbn_0 = doc.createElementNS(ns_xul, "toolbarbutton");
                        trbn_0.id = "add-view-bookmarks-sidebar-button";
                        trbn_0.className = "toolbarbutton-1 chromeclass-toolbar-additional";
                        trbn_0.setAttribute("label", "Закладки Библиотека История");
                        trbn_0.setAttribute("context", "false");
                        trbn_0.setAttribute("tooltiptext", "ЛКМ: Показать / Скрыть Закладки\nСКМ: Открыть Библиотеки в табе\nПКМ: Показать / Скрыть Историю");
                        trbn_0.addEventListener("click", function(e) {
                            if (e.button == 0) {
                                if ("SidebarUI" in win)
                                    win.SidebarUI.toggle("viewBookmarksSidebar");
                                else if ("toggleSidebar" in win)
                                    win.toggleSidebar("viewBookmarksSidebar");
                            }
                            else if (e.button == 1) {
                                var url="chrome://browser/content/places/places.xhtml";
                                win.SidebarUI.hide();
                                /* Для CB, открывает "История" в окне "Библиотека"
                                PlacesCommandHook.showPlacesOrganizer('History'); */
                                win.gBrowser.selectedTab = win.gBrowser.addTrustedTab(url);
                            }
                            else if (e.button == 2) {
                                if ("SidebarUI" in win)
                                    win.SidebarUI.toggle("viewHistorySidebar");
                                else if ("toggleSidebar" in win)
                                    win.toggleSidebar("viewHistorySidebar");
                            }
                        });
                        return trbn_0;
                    }
                });
            } catch(e) {}

Отсутствует

 

№14916-12-2021 12:20:30

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

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

_zt пишет

Посмотрите пожалуйста, я правильно отредактировал?

Не люблю я вопросы про «правильно», откуда мне знать что есть правильно.
Если работает, и страшных косяков нет (а их нет) — значит правильно.

скрытый текст
И, потом, не всегда понятен замысел, вот смотришь и думаешь,
что здесь имелось в виду? Если судить по себе, то далеко не всё пишется
с каким-то смыслом, иногда просто от балды, первое что в голову придёт.


Вот, например, в коде определяется переменная pref, но нигде не используется.
Или зачем e.preventDefault(); e.stopPropagation(); я же не знаю.
Превент может использоваться для предотвращения появления контекстного
меню при ПКМ (Windows), но там уже решено, что этого контекстного меню
не будет совсем никогда, поскольку установлен атрибут "context".


Или tooltiptext массивом. Когда там целая батарея подсказочных строк, то имеет смысл.
А парочку вполне можно и одной строкой записать. Это не вопрос правильности,
а вопрос предпочтения. Вот там widget создаётся как type: "custom", не знаю,
может это как-то внутренне оптимальнее, но чего не сделаешь, чтоб записать попроще, типа

Выделить код

Код:

(async () => CustomizableUI.createWidget({
	label: "Доп. панели",
	tooltiptext: "ЛКМ: Переключить верт. панель\nПКМ: Переключить доп. панель",

	id: "additional-toolbars-button",
	localized: false,
	onCreated(btn) {
		btn.toggleAttribute("context");
		btn.setAttribute("image", "chrome://user_chrome_files/content/custom_styles/svg/layer-visible-off.svg");
	},
	0: "ucf-additional-vertical-bar",
	2: "ucf-additional-top-bar",
	onClick(e) {
		var id = this[e.button];
		id && CustomizableUI.setToolbarVisibility(id, e.view.document.getElementById(id).collapsed);
	}
}))();

Отсутствует

 

№15016-12-2021 15:06:02

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

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

Dumby
По мне судить не надо, судите по Vitaliy V., это его код.
Я в скриптах разбираюсь на уровне  - что нибудь добавить/удалить по доступному примеру. (Сколько раз это повторить надо?) Поэтому и спросил. Спасибо за готовый код, это то что в итоге мне нужно было.

Отсутствует

 

Board footer

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