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

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

№1620107-01-2022 21:32:21

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

Re: Custom Buttons

Dumby
Переделайте пожалуйста кнопочку для UCF.

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

Выделить код

Код:

/*Initialization Code*/

// Simple Session Manager (https://forum.mozilla-russia.org/viewtopic.php?pid=744023#p744023) ..........

// Подсказки для кнопки .....
this.tooltipText = "Simple Session Manager";


// Настройка функций кликов мыши .....
this.onmousedown =e=> {

	this.onmouseup =e=> {
		if ( e.button ) return;
		self._handleClick =()=> menupopup.openPopup(this, "after_start");
	}
	if ( e.button == 2 ) {
		gShowPopup(this);
	}

}
self.onclick =e=> e.preventDefault();


var menupopup = self.appendChild(document.createXULElement("menupopup"));
menupopup.id = "ssm_menupopup";

var scs = document.createXULElement("menuitem");
scs.setAttribute("label", "Сохранить сессию");
scs.setAttribute("class", "menuitem-iconic");
scs.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKVSURBVHjajFNNTBNREJ6+7na73bLbQn8I0BKNCYWKGr0oYoiJPxeNh6oHozcOxgSVi4le1JNHQRPigRsewURNPKiJMQicSISUACelRVJ2tz/bdktpy9adBzT8xTjJ5L35ezNv5hsLHEAv7noEntguChx7EuV8oTydKRhfno8kCnt9LTuFZ7f87mAz/8rnl86GOoOBBq+LQX1S1ioLs0txWdEmsulS38Phlcy+BwZ6W0L+JsfolcjpsFDnBKNcgQ193bRUwSrwQFgr6Dkd3o9NzilqMdI/FF+sPYCZ245I4zdunw9DtQr6LxlK6bVdpdrcPAiHfGBYLDD69ltUXsmfw0oIGoPNjkHMjMHa3J9asDyRpoyEOrQR0+dq5MxR0c29Rj3Bhvn8YjeWjZmN9cpWcApSkzpkptYg8T1FdWjTfysg1Ang9YtdT+80OogTbJc7OlsD+OftzOqsBrMflqHe6QKXIEL00zLV0UpSBbM/G9DeEQy6OXKJsfPsCbdXYjb0Yu2/nmMS9LSGYGlYpXLPkxCwkq1mR98Gn8Q4XexxYhhgYKf3TPTfRDaPqklkvViaSSpaxSpw/x1v5e0UG8W10k+iW8qfF2ZiccIydFQ7ScsXKO8ep4NiYj4ai6k5+Eoev1F1Wcn8QJDgnAnHbGYRWTh800cZ77Ryzmr6eCGXzYGiZCcQ2vQ32XT5PiIMTJBI4Waw1ZtZzLu7XaSMd1s9b9paKJA+vpuKqols3y4ov7wXaPN67GPXIl1hnDOOansyVicHhGHMzHkzeDKqqPnr/UOJxX3LNNDb5BJd3KC3Uexu7wgEGxq3limRqcxH47FVWRtPreYePBpJagdu4zYhwjx1cMFus59CuVgqTmPDDlrnvwIMAGS8IFCLagHpAAAAAElFTkSuQmCC");
scs.addEventListener("command", saveCurrentSession, false);
menupopup.appendChild(scs);

var menusep = document.createXULElement("menuseparator"); // Сепаратор .....
menupopup.appendChild(menusep);


var savedSessions = loadFile(); // Сохраненный список .....
for (name in savedSessions) {
	makeitems(name);
}


// overwrite = 1 - Открыть сессию в текущем окне (все открытые вкладки будут закрыты) .....
// overwrite = 0 - Добавить вкладки в текущее окно (сессия будет добавлена к уже открытым вкладкам) .....
var overwrite = 1,
Cc = Components.classes,
Ci = Components.interfaces,
Cu = Components.utils,
SS = "nsISessionStore" in Components.interfaces ? ( Components.classes["@mozilla.org/browser/sessionstore;1"] || Components.classes["@mozilla.org/suite/sessionstore;1"] )
		.getService(Components.interfaces.nsISessionStore) : SessionStore;


if (!window.Services) { Cu.import("resource://gre/modules/Services.jsm"); }


// Функции работы с файлами .....
function saveFile(data) {
	var file = Services.dirsvc.get('UChrm', Ci.nsIFile);
	file.append("simple_session_manager.json");

	var suConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
	suConverter.charset = 'UTF-8';
	data = suConverter.ConvertFromUnicode(data);

	var foStream = Cc['@mozilla.org/network/file-output-stream;1'].createInstance(Ci.nsIFileOutputStream);
	foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0);
	foStream.write(data, data.length);
	foStream.close();
}

function loadFile() {
	var file = Services.dirsvc.get('UChrm', Ci.nsIFile);
	file.append("simple_session_manager.json");
	if (file.exists() === false) return false;
	var fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
	var sstream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
	fstream.init(file, -1, 0, 0);
	sstream.init(fstream);

	var data = sstream.read(sstream.available());
	try { data = decodeURIComponent(escape(data)); } catch(e) {}
	sstream.close();
	fstream.close();
	if (data === "undefined") return false;
	data = JSON.parse(data);
	return data;
}


// Получить текущее время .....
function getTime() {
var d = new Date();
	function addzero(t) {
		(t < 10) ? t = '0' + t : t;
		return t;
	}
	var t = addzero(d.getFullYear()) + '.' + addzero(d.getMonth()+1) + '.' + addzero(d.getDate()) + ' - ' + addzero(d.getHours()) + ':' + addzero(d.getMinutes()) + ':' + addzero(d.getSeconds());
	return t;
}


// Получить название вкладки .....
function getTabLabel() {
	var label = gBrowser.selectedTab.label;
	return label.substring(0, 70);
}


// Сохранение сессий .....
function saveSession(ssdata) {
	var countTabs_getTime = (gBrowser.tabs.length + "(B) " + "[" + getTime() + "]" );
	var saveName = prompt("Сохранить", getTabLabel() );
	var name = (saveName + ", " + countTabs_getTime );
	if (name != null) {
		if (loadFile() === false) { var data = {}; }
		else { var data = loadFile(); }
		if (data[name]) { alert('Сессия с тем же именем уже существует!'); return; }
		data[name] = JSON.parse(ssdata);
		saveFile(JSON.stringify(data));
		makeitems(name);
	}
}


// Сохранить текущую сессию .....
function saveCurrentSession() {
	var ssdata = SS.getBrowserState();
	saveSession(ssdata);
}


// Удалить сессию .....
function remove() {
	var node = this.parentNode.parentNode;
	var name = node.getAttribute("label");
	var cf = confirm('Вы уверены, что хотите удалить ' + name + ' ?');
	if (cf === true) {
		node.style.display = "none";
		var data = loadFile();
		delete data[name];
		saveFile(JSON.stringify(data));
	}
}


// Переименовать сессию .....
function rename() {
	var node = this.parentNode.parentNode;
	var name = node.getAttribute("label");
	var newname = prompt('Переименовать ' + '"' + name + '"' + ' в:', 'введите новое имя');
	if (!newname) return;
	this.parentNode.parentNode.setAttribute("label", newname);
	var data = loadFile();
	var value = data[name];
	data[newname] = value;
	delete data[name];
	saveFile(JSON.stringify(data));
}


// Восстановить сессию .....
function restoreSession(stateString) {
	if (typeof stateString === "string") {
		var state = stateString;
	}
	else {
		var name = this.parentNode.parentNode.getAttribute("label");
		var data = loadFile();
		var state = JSON.stringify(data[name]);
	}
	switch (overwrite) {
		case 0:
		SS.setWindowState(window, state, false);
		break;

		case 1:
		SS.setBrowserState(state);
		break;
	}
}


// Создаем меню .....
function makeitems(name) {
	var ss = document.createXULElement("menu");
	ss.setAttribute("label", name);
	ss.setAttribute("class", "savedSessions");
	ss.className = "menu-iconic";
	ss.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAEnQAABJ0BfDRroQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGxSURBVDiNnZE/T1NRGMZ/7zn3lmKLkIKpaUxZFINEJZ0YHXRwcnBxMQ6aOJi4+FH8Dm5OOjA4+AEYGCTRook1JlVIVUrbW/rnPg63UtReIr7bOXmf5/ye59jDlanHS3O+wn/Mu+/DF8HFeVe5f+vaPTdfPpF4UNvk6frmhwAvXOEsvrR0IoN47xM4CHCADmDQBkAHbdTrTBRZdgYLs6NTD/MiMC+gC8MO6ke8ffWsXv3S3JpksHouv7Z4/UEeM8z6IwKfEGjYRt0G1d3m1p3n0Y1JBi/vTtfKw1Yec2CHBDFmXYjboAgL4tTc5pXsmcNcDxIDUFQHuqgfYT69OAuE9qqAoX4jIcAL7b9H+0deOYYg3tkYXxx2EAo7dQYEBF/TEULD5oow7KHut18RhGVD3GwxMZ36YWn6IJd37vQCSMSNBpYQCMs43PQMAJXlwtr6k7CGfo9iznN1ebGY7Ak1NSJwYERYJgM+Q+nClVzp/OXc3wWMwdT+jAVKCMwLC2PUeoMrrEI4m94BQq0a6mxjoca/YKFgUCfeqR8jPhoHcIAHe3ST2+UFLv2T8o/5uMvrnx9Wn65p5nMEAAAAAElFTkSuQmCC");

	var ss_popup = document.createXULElement("menupopup");
	var rs = document.createXULElement("menuitem");
	rs.setAttribute("label", "Восстановить");
	rs.setAttribute("class", "menuitem-iconic");
	rs.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAACzElEQVQ4jX2QPWwbZRjHf+/5vfPdObZjO3Ga2pVpGtxCP4QIDKgqDCDUNQwgJCS2qFI3hBCRCvXSCcTAAu0GY0Fi4kuq+IjUCpWAgCTq4IpS3Di2G8c+x/bZ57t7mSJFMfBf/3p+z+95BPvy3pufxqKmcVY3ZFFKmQtFGIReuNnrDze6lv5TqfSyx4EIgA/e+fzkZML6MDmVnD80mz1kxW3DMAxQCs/z6Hb6g3q1Xt1ttdfa7dbFN668vrkHkADJhPntufNnc0LTDi7AjFkkUknzcGF2LvCDuZVvfiwCj+/1GoAmhL3x6x2cZhsVqjFIGIZs15ts/LJOJCLt/Z0EiE3Y9eLpR1ONaoMH9zbHAGiC9FSKkwunWF1Z3RoDABhRg/zRPPmj+XHA/0QDaLectFLj6gcT+AHdTm9mzMC27e766lrWtCwy2Qz2hIUeNVDAaDCku9ujWW/ij3wsO9oaMzCiunf66TMU5gt4wyGbf1Upr5W5u15mq1JDhYqZQo6HIuqtueLw4vLXzwC89NZXeQFw/ePv7zx5buHEf6nf3qgMVipOGE0ko6EKhoQi3NnZ+c51BwsaQLOxM9N1uv86vNtz+aHSDn0pH9S2tl6r/Pn3s/VG/WYunzs/NZ2OSID0dKpRrzZS98v3kYbEsi1004BQcbtc9Q07bdYb229/dvmFL5aWVvVts9mq1Wo/e54vJIAQqGOPzQHgj3zcvos39BAIBshRqJQYjYZ/AFy79tQIeHVx+ctiIDRTA+g43Xud9q4PIHVJPBknk82QzqY5VZg2UUrEYhOX9s5aXL5RnMykb8Rj9kcC4OrSVZ1Hpt+PJ5PPz+SzR5KpyYRpGgRKMei7fHLr7lBmZ1XHcX4LgsCxLPt4JBLRm82Hr4j9DyuVSprdO/ZELGafkXpkXtPA94OK03Vv/R4/csEw5XOGbuieN6y6bv/S9XdfvPkPTgcoDlpQJpwAAAAASUVORK5CYII=");
	rs.addEventListener("command", restoreSession, false);

	var rn = document.createXULElement("menuitem");
	rn.setAttribute("label", "Переименовать");
	rn.setAttribute("class", "menuitem-iconic");
	rn.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPFJREFUeNrEU0sOgkAMbc1IIHoQT+KeY7hkBW5ccwLdsOICxI2X8peIGhggI21gggpCwsImM01f+tpOO0WlFIwR0efgeR5nsG0boihizPd91A5UwZDjuq5qwycwUkQYhttSr4Y4l76fDdtBEAQqz3OVZdnPQ09o2sQhrpBSQgnAen/qzLxZzljHcawxy7KAuCJNUyiKAm53SS0FBGQNlUW3lFO2iVCLYRhAXJEkCQPn65NGAswpL/4fWAebt1ZGXB3geHlw9maXsKqjS94CHNxF7xRM0/wKgI7jDBojvbnZAz3Gv/9E7NvGvmXCsev8EmAAWocA9ofpaRIAAAAASUVORK5CYII=");
	rn.addEventListener("command", rename, false);

	var rm = document.createXULElement("menuitem");
	rm.setAttribute("label", "Удалить");
	rm.setAttribute("class", "menuitem-iconic");
	rm.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAABt0lEQVQ4ja2RT2sTURTFz8tk0nntFAQrVLBQxIUg/tkkMoLyIEVECHZhNrrxI+hOP5Mb6eBCcEipYIjZ2LpvhFasUtBSkwzOve+6mE6YSScuxLt67753fudyLvA/a7T+qCHmiTfrfWCMd3j9diPfq2SHX+uPnzJx71gP33w3bX9avBcE2j+SkK30Di7ffJ71VebMxD1hC2GGEEfH41prpftynIm92A0t2aYQQYgBThrndz/2KwCgf9Z2LNtImFOAtc356ijcCwJdJrZEUWzPfJpMAAAStPWR/h2Ktc10CoIQRUKEabFNvNbKfndcAKSjtrVfHW5YorWTzxDKYAxLtOWM+P7yt51hIYPpsDTNTyB/EwNAtWxdMuV8GCfbgxjxIviUYSV/SQOrbVjitbx4N8alBeXcdZR+3Tl3xS8FlIkt0dbnWH3xlbPgKgUo3HEq+tX7C4EuAAbGeOmqCuLIJt69s3PeQ1epKGfapCQJO6vGmwAWf/C1Wau6td8dV123BaAAUfHw6gSwtP3ugxA/y6X9INszAOQgbwFAIC/MQb9/Kv2vF2/UByejlVVn1Xiby/X6rPd/qj/1ak71UYKuwQAAAABJRU5ErkJggg==");
	rm.addEventListener("command", remove, false);

	ss_popup.appendChild(rs);
	ss_popup.appendChild(rn);
	ss_popup.appendChild(rm);
	ss.appendChild(ss_popup);
	menupopup.appendChild(ss);
}


// Восстановление выбранной сессии при открытии браузера .....
// Выбор сессии — двойной ЛКМ по соответствующему пункту .....
// Dumby: https://forum.mozilla-russia.org/viewtopic.php?pid=782655#p782655 .....
((g, id, pref, {obs, prefs, ww, dirsvc}, style) => {
	var popup = scs.parentNode;
	addEventListener("dblclick", g[id] || (g[id] = {
		get name() {
			return prefs.getStringPref(pref, null);
		},
		init() {
			obs.addObserver(this, "quit-application", false);
			prefs.addObserver(pref, this.upd = () => {
				var {name} = this;
				for(var win of ww.getWindowEnumerator("navigator:browser")) 
					win.toolbar.visible && this.updPopup(win, name);
				this.oldName = null;
			});
			var st = new Image().style;
			st.cssText = style;
			this.style = st.cssText;
			this.handleMuts = this.handleMuts.bind(this);
			return this;
		},
		destroy(reason) {
			delete g[id];
			obs.removeObserver(this, "quit-application");
			prefs.removeObserver(pref, this.upd);
			reason == "delete" && prefs.clearUserPref(pref);
		},
		observe(s, t, data) {
			this.destroy();
			if (data.includes("restart")) return;
			var {name} = this;
			if (name == null) return;
			var file = dirsvc.get("UChrm", Ci.nsIFile);
			file.append("simple_session_manager.json");
			var state;
			try {state = JSON.parse(Cu.readUTF8File(file))[name];} catch {}
			if (!state) return prefs.clearUserPref(pref);

			g.SessionStoreInternal.getCurrentState = () => state;
			prefs.setBoolPref("browser.sessionstore.resume_session_once", true);
		},
		handleEvent(e) {
			if (!e.button && e.target.nodeName == "menu")
				e.target.label == this.name
					? prefs.clearUserPref(pref)
					: prefs.setStringPref(pref, e.target.label);
		},
		oldName: null,
		updPopup(win, name = this.name) {
			var {style} = this, popup = win.document.getElementById("ssm_menupopup");
			if (popup) for(var menu of popup.getElementsByTagName("menu"))
				if (
					this.oldName != null && menu.label == this.oldName
					&& !void(menu.label = name) || menu.label == name
				)
					menu.style.cssText += style;
				else {
					var css = menu.style.cssText;
					if (css == style) menu.removeAttribute("style");
					else if (css.includes(style))
						menu.style.cssText = css.replace(style, "");
				}
		},
		opts: {
			attributes: true, attributeOldValue: true,
			attributeFilter: ["style", "label"], subtree: true
		},
		handleMuts(muts) {
			if(!muts[0].target.matches(":-moz-window-inactive")) for(var mut of muts)
				if (mut.attributeName == "label" && mut.oldValue == this.name)
					this.oldName = this.name,
					prefs.setStringPref(pref, mut.target.label);
				else if (mut.attributeName == "style" && mut.oldValue == this.style) {
					var css = mut.target.style.cssText;
					css && css != this.style && prefs.clearUserPref(pref);
				}
		}
	}).init(), false, popup || 1);
	g[id].updPopup(window);
	var mo = new MutationObserver(g[id].handleMuts);
	mo.observe(popup, g[id].opts);
	addDestructor(reason => mo.disconnect(reason[5] == "e" && g[id]?.destroy(reason)));
})(
	Cu.import("resource:///modules/sessionstore/SessionStore.jsm", {}),
	"CBSSMQuitApplicationObserver", "CB.SSM.sessionToRestore",  Services,
	"font-weight: bold !important; color: #AA0000 !important;"
);

Для FF91.


«The Truth Is Out There»

Отсутствует

 

№1620208-01-2022 01:32:36

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

Re: Custom Buttons

Dumby пишет

Шутить изволишь?

Нет, не нашёл простых примеров такого кода. Ещё просьба добавить универсальности:
чтобы проверка наличия файла работала с разными путями — файловой системы `C:\windows\explorer.exe` и `chrome://user_chrome_files/content/user_chrome.js`
но в Линукс имена могут содержать практически любые символы, поэтому String.raw может привести к проблемам


Прошу улучшить скрипт ucf_BookmarkDir (FF 90+), чтобы он работал хотя бы с версии Firefox 84.

Выделить код

Код:

(async (id, sel) => { // расположение закладки в Избранном, Недавняя папка (F90+)
	var g = Cu.getGlobalForObject(Cu), stt = g[id];
	if (!stt) {
		var {obs, prefs} = Services, pu = PlacesUtils, {bookmarks: bm, observers: pobs} = pu, stt = g[id] = {
			bm, // клики заданы в ucf_hookClicks.js
			help_star: "Правый клик	➜ Быстрая закладка\nЛев.клик+Alt	Библиотека закладок\n\nКлик дважды	Перевод сайта/выд.текста\n",
			pref: `ucf.${id}Guid`,

			async init() {
				var args = [
					["bookmark-added", "bookmark-moved"],
					events => {for(var e of events) e.isTagging || this[e.constructor.name](e);}
				];
				pobs.addListener(...args);
				pu.registerShutdownFunction(() => {
					pobs.removeListener(...args);
					prefs.setStringPref(this.pref, this.lastGuid);
				});
				this.args = [
					res => this.fetchRes.push(res),
					{concurrent: true, includePath: true}
				];
				var guid = prefs.getStringPref(this.pref, "");
				if (!guid) try {var [guid] = await PlacesUtils.metadata.get(
					PlacesUIUtils.LAST_USED_FOLDERS_META_KEY, [])} catch {}
				this.lastGuid = guid || await PlacesUIUtils.defaultParentGuid || bm.unfiledGuid;
			},
			PlacesBookmarkAddition(e) {
				if (e.itemType == bm.TYPE_BOOKMARK && e.source == bm.SOURCES.DEFAULT)
					this.lastGuid = e.parentGuid;
			},
			PlacesBookmarkMoved(e) {
				e.parentGuid != e.oldParentGuid && this.PlacesBookmarkAddition(e);
			},
			find: obj => obj.name == "tooltiptext",
			tt(win) {
				var list = win.InspectorUtils.getChildrenForNode(win.document.documentElement, true);
				return list.item(list.length - 1);
			},
			mapInfs(inf) {
				return inf.path.map(this.mapPaths).join("\\");
			},
			mapPaths: path => bm.getLocalizedTitle(path) || "[Безымянная папка]",
		};
		stt.init();

		var func = id => this[id].handleEvent = async function(e) {
			var win = e.view, star = e.target;
			var starred = win.BookmarkingUI._itemGuids.size;
			var arg = starred ? {url: win.gBrowser.currentURI.spec} : this.lastGuid;

			var arr = this.fetchRes = [];
			await this.bm.fetch(arg, ...this.args);
			if (!star.matches(":hover")) return;

			!starred && arr.length && arr[0].path.push(arr[0]);
			var paths = arr.length ? arr.map(this.mapInfs, this).join("\n") : "<Folder Not Found>";

			if (!star.matches(":hover")) return;
			var footer = `Колёсико	масштаб ${Math.round(win.ZoomManager.zoom*100)}% Текст | Всё\n\n★ ` + (
				starred
					? (arr.length > 1 ? "Данные закладки добавлены" : "Данная закладка добавлена") + " в"
					: "Недавно добавлялось в папку"
			) + ":\n" + paths;

			var header = (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;

			var text = header + '\n' + this.help_star + footer;
			var tt = star.linkedTooltip;
			star.contains(tt.triggerNode) ? tt.label = text : star.tooltipText = text;
		}
		var url = "data:;charset=utf-8," + encodeURIComponent(`(${func})("${id}")`);
		g.ChromeUtils.compileScript(url).then(ps => ps.executeInGlobal(g));
	}
	await delayedStartupPromise;

	var stars = Array.from(document.querySelectorAll(sel));
	for(var star of stars) {
		star.linkedTooltip = stt.tt(window);
		star.addEventListener("mouseenter", stt);
	}
	var destructor = () => {
		for(var star of stars)
			star.removeEventListener("mouseenter", 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, #star-button-box, #context-bookmarkpage");

Ещё вопрос - как создать ассоциативный массив и получить элемент массива по его имени: array.get("имя ключа")

Отредактировано Dobrov (09-01-2022 07:34:26)

Отсутствует

 

№1620311-01-2022 22:04:58

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 332
UA: Firefox 96.0

Re: Custom Buttons

Нет вопросов к 96...Норм.

Отсутствует

 

№1620413-01-2022 21:03:37

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

Re: Custom Buttons

unter_officer пишет

Переделайте пожалуйста кнопочку для UCF.

Вроде как-то давно пробовал возиться с ней, ещё под CB.
Всё что-то не так. Ладно, вот что есть.

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

Выделить код

Код:

(async pid => CustomizableUI.createWidget(({
	id: "797321",
	label: "Simple Session Manager",
	tooltiptext: "Simple Session Manager",
	localized: false,
	init() {
		this.handleEvent = e => this[e.type](e);
		this.onTimeout = () => this.saveSession() || this.save();
		Services.obs.addObserver(this, "quit-application");
		var {openMenu} = this;
		this.render = function() {
			this.openMenu = openMenu;
			this.constructor.prototype.render.call(this);
		}
		delete this.init;
		return this;
	},
	onCreated(btn) {
		btn.type = "menu";
		btn.phTimestamp = 0;
		btn.render = this.render;
		btn._handleClick = this.click;
		btn.setAttribute("image", "resource://usercontext-content/cart.svg");

		var popup = btn.ownerDocument.createXULElement("menupopup");
		popup.filler = this;
		popup.id = pid;
		popup.setAttribute("onpopupshowing", "event.defaultPrevented || filler.fill(event)");
		btn.prepend(popup);

		btn.addEventListener("mousedown", this);
		popup.addEventListener("command", this);
		btn.ownerGlobal.addEventListener("unload", () => {
			btn.removeEventListener("mousedown", this);
			popup.removeEventListener("command", this);
			if (popup.filler != this)
				popup.removeEventListener("dragstart", this),
				popup.removeEventListener("popuphidden", this);
		}, {once: true});
	},
	openMenu(arg) {
		var pos;
		if (this.matches(".widget-overflow-list > :scope"))
			pos = "after_start";
		else var win = this.ownerGlobal, {width, height, top, bottom, left, right} =
			this.closest("toolbar").getBoundingClientRect(), pos = width > height
				? `${win.innerHeight - bottom > top ? "after" : "before"}_start`
				: `${win.innerWidth - right > left ? "end" : "start"}_before`;
		this.firstChild.setAttribute("position", pos);
		delete this.openMenu;
		this.openMenu(arg);
	},

	mousedown(e) {
		if (e.button) return;
		var trg = e.target;
		if (trg.nodeName.startsWith("t")) {
			trg.mdTimestamp = Cu.now();
			trg.tid = e.view.setTimeout(this.onTimeout, 500);
			return e.preventDefault();
		}
		e.detail == 2 && trg.nodeName == "menu" && this.boot(trg);
	},
	boot(trg) {
		var popup = trg.parentNode;
		var old = popup.querySelector("[boot]");
		if (old != trg) old?.removeAttribute("boot");
		trg.toggleAttribute("boot");
		popup.dblMD = true;
	},
	click() {
		var win = this.ownerGlobal;
		if (win.event.target != this) return;
		win.clearTimeout(this.tid);
		if (this.mdTimestamp - this.phTimestamp > 50) this.open = true;
	},
	command(e) {
		var arg, trg = e.target, cmd = trg.value;
		if (cmd.startsWith("r")) {
			arg = trg.parentNode.parentNode.label;
			if (cmd.startsWith("res"))
				return this[cmd](arg, (e.button == 1 || e.ctrlKey) && e.view);
		}
		this[cmd](arg) || this.save();
	},

	dragstart(e) {
		var trg = e.target;
		if (trg.nodeName != "menu") return;

		var popup = trg.parentNode;
		this.dragData = {trg, mouse: true};
		trg.menupopup.hidePopup();

		var win = trg.ownerGlobal;
		win.setCursor("grabbing");
		var {width} = trg.getBoundingClientRect();
		trg.setAttribute("maxwidth", width);

		win.addEventListener("mouseup", this);
		popup.addEventListener("mousemove", this);
	},
	mousemove(e) {
		var trg = e.target, dtrg = this.dragData.trg;
		if (trg == dtrg || trg.nodeName != "menu") return;

		e.movementY > 0
			? trg.nextSibling != dtrg && trg.after(dtrg)
			: trg.previousSibling != dtrg && trg.before(dtrg);
	},
	mouseup(arg) {
		if (arg.constructor.isInstance?.(arg)) {
			arg.preventDefault();
			var {trg} = this.dragData;
			this.dragData.mouse = false;
		}
		else var trg = arg;

		trg.removeAttribute("maxwidth");
		trg.ownerGlobal.setCursor("auto");
		trg.ownerGlobal.removeEventListener("mouseup", this);
		trg.parentNode.removeEventListener("mousemove", this);
	},

	popuphidden(e) {
		if (!e.target.id) return;
		e.view.removeEventListener("keydown", this, true);
		var popup = e.target;
		popup.parentNode.phTimestamp = Cu.now();
		if (!this.dragData && !popup.dblMD) return;

		var save;
		if (this.dragData) {
			var {trg, mouse} = this.dragData;
			mouse && this.mouseup(trg);
	
			delete this.dragData;
			var order = Array.from(popup.getElementsByTagName("menu"), m => m.label);
			if (order.toString() != this.meta.order.toString()) {
				var hasBoot = this.meta.boot != null;
				if (hasBoot) var bootName = this.meta.order[this.meta.boot];
				this.meta.order = order;
				if (hasBoot) this.meta.boot = this.meta.order.indexOf(bootName);
				save = true;
			}
		}
		if (popup.dblMD) {
			delete popup.dblMD;
			var {boot} = this.meta;
			var bootNode = e.target.querySelector("[boot]");
			var ind = bootNode && this.meta.order.indexOf(bootNode.label);
			if (ind != boot)
				this.meta.boot = ind,
				save = true;
		}
		save && this.save(e.view);
	},

	sku: `#${pid} > menu[maxwidth]`,
	skd: `#${pid} > menu:is([maxwidth],[_moz-menuactive]):not([open])`,
	keydown(e) {
		if (e.repeat && e.key == "Shift" || !e.shiftKey) return;
		var func = this.keyHandlers[e.key];
		if (!func) return;

		var menu = e.view.windowRoot
			.ownerGlobal.document.querySelector(this.skd);
		if (menu)
			e.stopImmediatePropagation(),
			func.call(this, menu);
	},
	keyup(e) {
		if (e.key != "Shift") return;
		var win = e.view.windowRoot.ownerGlobal;
		win.removeEventListener("keyup", this, true);
		win.document.querySelector(this.skd)?.removeAttribute("maxwidth");
	},
	keyHandlers: {
		Enter(menu) {
			this.boot(menu);
		},
		ArrowDown(menu) {
			var ns = menu.nextSibling;
			if (ns) ns.after(menu), this.arrow(menu);
		},
		ArrowUp(menu) {
			var ps = menu.previousSibling;
			if (ps.nodeName == "menu") ps.before(menu), this.arrow(menu);
		}
	},
	arrow(menu) {
		if (menu.hasAttribute("maxwidth")) return;
		menu.setAttribute("maxwidth", menu.getBoundingClientRect().width);
		menu.ownerGlobal.addEventListener("keyup", this, true);
		this.dragData = {trg: menu};
	},

	fill(e) {
		var mxe = e.view.MozXULElement;

		var initFrag = mxe.parseXULToFragment(`
			<menuitem value="saveSession" class="menuitem-iconic" label="Сохранить сессию"/>
			<menuseparator/>
		`);
		this.menuFrag = mxe.parseXULToFragment(`<menu class="menu-iconic"><menupopup>
			<menuitem label="Восстановить"
				class="menuitem-iconic" value="restoreSession"/>
			<menuitem label="Переименовать"
				class="menuitem-iconic" value="renameSession"/>
			<menuitem label="Удалить"
				class="menuitem-iconic" value="removeSession"/>
		</menupopup></menu>`);

		this.regStyle();

		var filler = {fill: e => e.target.id
			? e.view.addEventListener("keydown", this, true)
				|| e.target.fillFlag || this.fillSessions(e.target)
			: this.dragData?.mouse && e.preventDefault()
		};

		(this.fill = e => {
			var trg = e.target;
			trg.setAttribute("context", "");
			trg.append(trg.ownerDocument.importNode(initFrag, true));
			(trg.filler = filler).fill(e);
			trg.addEventListener("dragstart", this);
			trg.addEventListener("popuphidden", this);
		})(e);
	},
	fillSessions(popup) {
		while(popup.lastChild.nodeName == "menu") popup.lastChild.remove();
		var ind = 0, {boot} = this.meta;
		for(var name of this.meta.order) {
			var df = popup.ownerDocument.importNode(this.menuFrag, true);
			df.firstChild.setAttribute("label", name);
			if (ind++ == boot) df.firstChild.toggleAttribute("boot");
			popup.append(df);
		}
		popup.fillFlag = true;
	},
	regStyle() {
		delete this.regStyle;
		var subst = "ucf-ssm-style-resurl";
		Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler).setSubstitution(
			subst, Services.io.newURI("data:text/css;charset=utf-8," + encodeURIComponent(`
			@-moz-document url-prefix(chrome://browser/content/browser.xhtml) {
				#${pid} > menu {
					list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAEnQAABJ0BfDRroQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGxSURBVDiNnZE/T1NRGMZ/7zn3lmKLkIKpaUxZFINEJZ0YHXRwcnBxMQ6aOJi4+FH8Dm5OOjA4+AEYGCTRook1JlVIVUrbW/rnPg63UtReIr7bOXmf5/ye59jDlanHS3O+wn/Mu+/DF8HFeVe5f+vaPTdfPpF4UNvk6frmhwAvXOEsvrR0IoN47xM4CHCADmDQBkAHbdTrTBRZdgYLs6NTD/MiMC+gC8MO6ke8ffWsXv3S3JpksHouv7Z4/UEeM8z6IwKfEGjYRt0G1d3m1p3n0Y1JBi/vTtfKw1Yec2CHBDFmXYjboAgL4tTc5pXsmcNcDxIDUFQHuqgfYT69OAuE9qqAoX4jIcAL7b9H+0deOYYg3tkYXxx2EAo7dQYEBF/TEULD5oow7KHut18RhGVD3GwxMZ36YWn6IJd37vQCSMSNBpYQCMs43PQMAJXlwtr6k7CGfo9iznN1ebGY7Ak1NSJwYERYJgM+Q+nClVzp/OXc3wWMwdT+jAVKCMwLC2PUeoMrrEI4m94BQq0a6mxjoca/YKFgUCfeqR8jPhoHcIAHe3ST2+UFLv2T8o/5uMvrnx9Wn65p5nMEAAAAAElFTkSuQmCC");
				}
				#${pid} > [value=saveSession] {
					list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKVSURBVHjajFNNTBNREJ6+7na73bLbQn8I0BKNCYWKGr0oYoiJPxeNh6oHozcOxgSVi4le1JNHQRPigRsewURNPKiJMQicSISUACelRVJ2tz/bdktpy9adBzT8xTjJ5L35ezNv5hsLHEAv7noEntguChx7EuV8oTydKRhfno8kCnt9LTuFZ7f87mAz/8rnl86GOoOBBq+LQX1S1ioLs0txWdEmsulS38Phlcy+BwZ6W0L+JsfolcjpsFDnBKNcgQ193bRUwSrwQFgr6Dkd3o9NzilqMdI/FF+sPYCZ245I4zdunw9DtQr6LxlK6bVdpdrcPAiHfGBYLDD69ltUXsmfw0oIGoPNjkHMjMHa3J9asDyRpoyEOrQR0+dq5MxR0c29Rj3Bhvn8YjeWjZmN9cpWcApSkzpkptYg8T1FdWjTfysg1Ang9YtdT+80OogTbJc7OlsD+OftzOqsBrMflqHe6QKXIEL00zLV0UpSBbM/G9DeEQy6OXKJsfPsCbdXYjb0Yu2/nmMS9LSGYGlYpXLPkxCwkq1mR98Gn8Q4XexxYhhgYKf3TPTfRDaPqklkvViaSSpaxSpw/x1v5e0UG8W10k+iW8qfF2ZiccIydFQ7ScsXKO8ep4NiYj4ai6k5+Eoev1F1Wcn8QJDgnAnHbGYRWTh800cZ77Ryzmr6eCGXzYGiZCcQ2vQ32XT5PiIMTJBI4Waw1ZtZzLu7XaSMd1s9b9paKJA+vpuKqols3y4ov7wXaPN67GPXIl1hnDOOansyVicHhGHMzHkzeDKqqPnr/UOJxX3LNNDb5BJd3KC3Uexu7wgEGxq3limRqcxH47FVWRtPreYePBpJagdu4zYhwjx1cMFus59CuVgqTmPDDlrnvwIMAGS8IFCLagHpAAAAAElFTkSuQmCC");
				}
				#${pid} [value=restoreSession] {
					list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAACzElEQVQ4jX2QPWwbZRjHf+/5vfPdObZjO3Ga2pVpGtxCP4QIDKgqDCDUNQwgJCS2qFI3hBCRCvXSCcTAAu0GY0Fi4kuq+IjUCpWAgCTq4IpS3Di2G8c+x/bZ57t7mSJFMfBf/3p+z+95BPvy3pufxqKmcVY3ZFFKmQtFGIReuNnrDze6lv5TqfSyx4EIgA/e+fzkZML6MDmVnD80mz1kxW3DMAxQCs/z6Hb6g3q1Xt1ttdfa7dbFN668vrkHkADJhPntufNnc0LTDi7AjFkkUknzcGF2LvCDuZVvfiwCj+/1GoAmhL3x6x2cZhsVqjFIGIZs15ts/LJOJCLt/Z0EiE3Y9eLpR1ONaoMH9zbHAGiC9FSKkwunWF1Z3RoDABhRg/zRPPmj+XHA/0QDaLectFLj6gcT+AHdTm9mzMC27e766lrWtCwy2Qz2hIUeNVDAaDCku9ujWW/ij3wsO9oaMzCiunf66TMU5gt4wyGbf1Upr5W5u15mq1JDhYqZQo6HIuqtueLw4vLXzwC89NZXeQFw/ePv7zx5buHEf6nf3qgMVipOGE0ko6EKhoQi3NnZ+c51BwsaQLOxM9N1uv86vNtz+aHSDn0pH9S2tl6r/Pn3s/VG/WYunzs/NZ2OSID0dKpRrzZS98v3kYbEsi1004BQcbtc9Q07bdYb229/dvmFL5aWVvVts9mq1Wo/e54vJIAQqGOPzQHgj3zcvos39BAIBshRqJQYjYZ/AFy79tQIeHVx+ctiIDRTA+g43Xud9q4PIHVJPBknk82QzqY5VZg2UUrEYhOX9s5aXL5RnMykb8Rj9kcC4OrSVZ1Hpt+PJ5PPz+SzR5KpyYRpGgRKMei7fHLr7lBmZ1XHcX4LgsCxLPt4JBLRm82Hr4j9DyuVSprdO/ZELGafkXpkXtPA94OK03Vv/R4/csEw5XOGbuieN6y6bv/S9XdfvPkPTgcoDlpQJpwAAAAASUVORK5CYII=");
				}
				#${pid} [value=renameSession] {
					list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPFJREFUeNrEU0sOgkAMbc1IIHoQT+KeY7hkBW5ccwLdsOICxI2X8peIGhggI21gggpCwsImM01f+tpOO0WlFIwR0efgeR5nsG0boihizPd91A5UwZDjuq5qwycwUkQYhttSr4Y4l76fDdtBEAQqz3OVZdnPQ09o2sQhrpBSQgnAen/qzLxZzljHcawxy7KAuCJNUyiKAm53SS0FBGQNlUW3lFO2iVCLYRhAXJEkCQPn65NGAswpL/4fWAebt1ZGXB3geHlw9maXsKqjS94CHNxF7xRM0/wKgI7jDBojvbnZAz3Gv/9E7NvGvmXCsev8EmAAWocA9ofpaRIAAAAASUVORK5CYII=");
				}
				#${pid} [value=removeSession] {
					list-style-image: url("data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAABt0lEQVQ4ja2RT2sTURTFz8tk0nntFAQrVLBQxIUg/tkkMoLyIEVECHZhNrrxI+hOP5Mb6eBCcEipYIjZ2LpvhFasUtBSkwzOve+6mE6YSScuxLt67753fudyLvA/a7T+qCHmiTfrfWCMd3j9diPfq2SHX+uPnzJx71gP33w3bX9avBcE2j+SkK30Di7ffJ71VebMxD1hC2GGEEfH41prpftynIm92A0t2aYQQYgBThrndz/2KwCgf9Z2LNtImFOAtc356ijcCwJdJrZEUWzPfJpMAAAStPWR/h2Ktc10CoIQRUKEabFNvNbKfndcAKSjtrVfHW5YorWTzxDKYAxLtOWM+P7yt51hIYPpsDTNTyB/EwNAtWxdMuV8GCfbgxjxIviUYSV/SQOrbVjitbx4N8alBeXcdZR+3Tl3xS8FlIkt0dbnWH3xlbPgKgUo3HEq+tX7C4EuAAbGeOmqCuLIJt69s3PeQ1epKGfapCQJO6vGmwAWf/C1Wau6td8dV123BaAAUfHw6gSwtP3ugxA/y6X9INszAOQgbwFAIC/MQb9/Kv2vF2/UByejlVVn1Xiby/X6rPd/qj/1ak71UYKuwQAAAABJRU5ErkJggg==");
				}
				#${pid} > menuseparator:last-child,
				#${pid} > menu[maxwidth] > .menu-right {
					display: none;
				}
				#${pid} > menu[boot] {
					color: red;
					font-weight: bold;
				}
				#${pid} > menu[maxwidth] {
					color: blue;
					font-weight: bold;
					outline-offset: -2px;
					outline: 2px solid orangered;
				}
			}
		`.replace(/;$/gm, " !important;"))));
		var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
		sss.loadAndRegisterSheet(Services.io.newURI("resource://" + subst), sss.USER_SHEET);
	},

	get gs() {
		delete this.gs;
		return this.gs = Cu.import("resource:///modules/sessionstore/SessionStore.jsm", {});
	},
	getState() {
		return JSON.parse(this.gs.SessionStore.getBrowserState());
	},
	splice(name, newName) {
		var ind = this.meta.order.indexOf(name);
		if (ind == -1) return;
		var args = [ind, 1];

		if (1 in arguments) args.push(newName);
		else {
			if (ind == this.meta.boot) this.meta.boot = null;
			else if (ind < this.meta.boot) this.meta.boot--;
		}
		this.meta.order.splice(...args);
	},
	get meta() {
		(this.dataFile = Services.dirsvc.get("UChrm", Ci.nsIFile))
			.append("simple_session_manager.json");
		
		try {this.data = JSON.parse(Cu.readUTF8File(this.dataFile));}
		catch {this.data = {};}

		var mp = "{07cae4f5-18b0-487b-80eb-973304af9528}";
		var meta = this.data[mp];
		if (!meta) {
			var order = Object.keys(this.data);
			meta = this.data[mp] = {order, boot: null};
		}
		delete this.meta;
		return this.meta = meta;
	},
	async save(excWin) {
		var {IOUtils} = Cu.getGlobalForObject(Cu);
		await IOUtils.makeDirectory(this.dataFile.parent.path);
		var {path} = this.dataFile;
		delete this.dataFile;
		(this.save = excWin => {
			IOUtils.writeJSON(path, this.data);
			for(var win of CustomizableUI.windows) {
				if (win == excWin) continue;
				var popup = win.document.getElementById(pid);
				if (popup) popup.fillFlag = false;
			}
		})(excWin);
	},

	get prompter() {
		var {prompt} = Services;
		var p = {}, args = [null, null, "UCF Simple Session Manager"];
		p.alert = prompt.alert.bind(...args);
		p.confirm = prompt.confirm.bind(...args);
		var pr = prompt.prompt.bind(...args);
		p.prompt = (msg, value) => {
			var res = {value};
			return pr(msg, res, null, {}) ? res.value : null;
		}
		delete this.prompter;
		return this.prompter = p;
	},
	observe(s, t, data) {
		Services.obs.removeObserver(this, "quit-application");
		if (data.includes("restart")) return;

		var {boot} = this.meta;
		if (boot == null) return;
		
		var state = this.data[this.meta.order[boot]];
		this.gs.SessionStoreInternal.getCurrentState = () => state;
		Services.prefs.setBoolPref("browser.sessionstore.resume_session_once", true);
	},

	get bwt() {
		delete this.bwt;
		var url = "resource:///modules/BrowserWindowTracker.jsm";
		return this.bwt = ChromeUtils.import(url).BrowserWindowTracker;
	},
	getName(state) {
		var wl = state.windows.length, tl = 0;
		for(var w of state.windows) tl += w.tabs.length;
		return `${
			this.bwt.getTopWindow().gBrowser.selectedTab.label.slice(0, 70)
		} ${wl}/${tl} [${
			new Date().toLocaleString("mn").replace(" ", "-")
		}]`;
	},
	exists(name) {
		this.meta;
		return (this.exists = name => name in this.data &&
			!this.prompter.alert("Сессия с тем же именем уже существует!"))(name);
	},
	saveSession(state = this.getState(), name = this.getName(state)) {
		var name = this.prompter.prompt("Сохранить:", name);
		if (name == null) return true;

		if (this.exists(name)) return this.saveSession(state, name);

		this.data[name] = state;

		this.meta.order.push(name);
		//this.meta.order.unshift(name);
		//if (this.meta.boot != null) this.meta.boot++;
	},
	restoreSession(name, win) {
		var ss = this.gs.SessionStore;
		var state = JSON.stringify(this.data[name]);
		win ? ss.setWindowState(win, state) : ss.setBrowserState(state);
	},
	renameSession(name, newName = name) {
		var newName = this.prompter.prompt(`Переименовать "${name}" в:`, newName);
		if (newName == null || newName == name) return true;

		if (this.exists(newName)) return this.renameSession(name, newName);

		var {data} = this;
		this.splice(name, newName);
		data[newName] = data[name];
		delete data[name];
	},
	removeSession(name) {
		if (!this.prompter.confirm(`Вы уверены, что хотите удалить ${name} ?`))
			return true;
		delete this.data[name];
		this.splice(name);
	}
}).init()))("ucf-ssm-menupopup");

Dobrov пишет

чтобы проверка наличия файла работала с разными путями — файловой системы `C:\windows\explorer.exe` и `chrome://user_chrome_files/content/user_chrome.js`

Ну, например, так.
Можно, наверно, запросом, как fetch или xhr, но это асинхрон.
Не, xhr можно и синхронный, но он что-то неуместное в консоль выдаёт,
к тому же можно и асинхронный, и не отправлять (уже будет xhr.channel.URI).

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

Выделить код

Код:

var path = "chrome://user_chrome_files/content/user_chrome.js";

if (path.startsWith("chrome://")) alert(

	Cc["@mozilla.org/chrome/chrome-registry;1"]
		.getService(Ci.nsIXULChromeRegistry)
		.convertChromeURL(Services.io.newURI(path))
		.QueryInterface(Ci.nsIFileURL).file.exists()
	/*
	Services.io.newChannelFromURIWithLoadInfo(
		Services.io.newURI(path),
		docShell.currentDocumentChannel.loadInfo
	).URI.QueryInterface(Ci.nsIFileURL).file.exists()
	*/
);

String.raw может привести к проблемам

Ну так не используй, раз «может».

Прошу улучшить скрипт ucf_BookmarkDir (FF 90+), чтобы он работал хотя бы с версии Firefox 84.

Вот уж нет. Рыться в этом, когда уже сделано как если бы это,
и плюшка вписана, уволь.

как создать ассоциативный массив и получить элемент массива по его имени: array.get("имя ключа")

Объект иногда называют «ассоциативным массивом»,
а если, зачем-то, нужен метод get(), то можно добавить.
Ну и Map подходит под описание, разумеется.

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

Выделить код

Код:

var something = {
	get(key) {
		return this[key];
	},
	"имя ключа": 2 * 22,
};
alert(
	something.get("имя ключа") // 44
);

//-------------------------------------

//var map = new Map([["имя ключа", 7 * 111]]);

var map = new Map();
map.set("имя ключа", 7 * 111);

alert(
	map.get("имя ключа") // 777
);

Отсутствует

 

№1620514-01-2022 03:02:57

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

Re: Custom Buttons

Dumby пишет

Вроде как-то давно пробовал возиться с ней, ещё под CB.
Всё что-то не так. Ладно, вот что есть.

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

Выделить код

Код:

(async pid => CustomizableUI.createWidget(({
	id: "797321",
	label: "Simple Session Manager",
	tooltiptext: "Simple Session Manager",
	localized: false,
	init() {
		this.handleEvent = e => this[e.type](e);
		this.onTimeout = () => this.saveSession() || this.save();
		Services.obs.addObserver(this, "quit-application");
		var {openMenu} = this;
		this.render = function() {
			this.openMenu = openMenu;
			this.constructor.prototype.render.call(this);
		}
		delete this.init;
		return this;
	},
	onCreated(btn) {
		btn.type = "menu";
		btn.phTimestamp = 0;
		btn.render = this.render;
		btn._handleClick = this.click;
		btn.setAttribute("image", "resource://usercontext-content/cart.svg");

		var popup = btn.ownerDocument.createXULElement("menupopup");
		popup.filler = this;
		popup.id = pid;
		popup.setAttribute("onpopupshowing", "event.defaultPrevented || filler.fill(event)");
		btn.prepend(popup);

		btn.addEventListener("mousedown", this);
		popup.addEventListener("command", this);
		btn.ownerGlobal.addEventListener("unload", () => {
			btn.removeEventListener("mousedown", this);
			popup.removeEventListener("command", this);
			if (popup.filler != this)
				popup.removeEventListener("dragstart", this),
				popup.removeEventListener("popuphidden", this);
		}, {once: true});
	},
	openMenu(arg) {
		var pos;
		if (this.matches(".widget-overflow-list > :scope"))
			pos = "after_start";
		else var win = this.ownerGlobal, {width, height, top, bottom, left, right} =
			this.closest("toolbar").getBoundingClientRect(), pos = width > height
				? `${win.innerHeight - bottom > top ? "after" : "before"}_start`
				: `${win.innerWidth - right > left ? "end" : "start"}_before`;
		this.firstChild.setAttribute("position", pos);
		delete this.openMenu;
		this.openMenu(arg);
	},

	mousedown(e) {
		if (e.button) return;
		var trg = e.target;
		if (trg.nodeName.startsWith("t")) {
			trg.mdTimestamp = Cu.now();
			trg.tid = e.view.setTimeout(this.onTimeout, 500);
			return e.preventDefault();
		}
		e.detail == 2 && trg.nodeName == "menu" && this.boot(trg);
	},
	boot(trg) {
		var popup = trg.parentNode;
		var old = popup.querySelector("[boot]");
		if (old != trg) old?.removeAttribute("boot");
		trg.toggleAttribute("boot");
		popup.dblMD = true;
	},
	click() {
		var win = this.ownerGlobal;
		if (win.event.target != this) return;
		win.clearTimeout(this.tid);
		if (this.mdTimestamp - this.phTimestamp > 50) this.open = true;
	},
	command(e) {
		var arg, trg = e.target, cmd = trg.value;
		if (cmd.startsWith("r")) {
			arg = trg.parentNode.parentNode.label;
			if (cmd.startsWith("res"))
				return this[cmd](arg, (e.button == 1 || e.ctrlKey) && e.view);
		}
		this[cmd](arg) || this.save();
	},

	dragstart(e) {
		var trg = e.target;
		if (trg.nodeName != "menu") return;

		var popup = trg.parentNode;
		this.dragData = {trg, mouse: true};
		trg.menupopup.hidePopup();

		var win = trg.ownerGlobal;
		win.setCursor("grabbing");
		var {width} = trg.getBoundingClientRect();
		trg.setAttribute("maxwidth", width);

		win.addEventListener("mouseup", this);
		popup.addEventListener("mousemove", this);
	},
	mousemove(e) {
		var trg = e.target, dtrg = this.dragData.trg;
		if (trg == dtrg || trg.nodeName != "menu") return;

		e.movementY > 0
			? trg.nextSibling != dtrg && trg.after(dtrg)
			: trg.previousSibling != dtrg && trg.before(dtrg);
	},
	mouseup(arg) {
		if (arg.constructor.isInstance?.(arg)) {
			arg.preventDefault();
			var {trg} = this.dragData;
			this.dragData.mouse = false;
		}
		else var trg = arg;

		trg.removeAttribute("maxwidth");
		trg.ownerGlobal.setCursor("auto");
		trg.ownerGlobal.removeEventListener("mouseup", this);
		trg.parentNode.removeEventListener("mousemove", this);
	},

	popuphidden(e) {
		if (!e.target.id) return;
		e.view.removeEventListener("keydown", this, true);
		var popup = e.target;
		popup.parentNode.phTimestamp = Cu.now();
		if (!this.dragData && !popup.dblMD) return;

		var save;
		if (this.dragData) {
			var {trg, mouse} = this.dragData;
			mouse && this.mouseup(trg);
	
			delete this.dragData;
			var order = Array.from(popup.getElementsByTagName("menu"), m => m.label);
			if (order.toString() != this.meta.order.toString()) {
				var hasBoot = this.meta.boot != null;
				if (hasBoot) var bootName = this.meta.order[this.meta.boot];
				this.meta.order = order;
				if (hasBoot) this.meta.boot = this.meta.order.indexOf(bootName);
				save = true;
			}
		}
		if (popup.dblMD) {
			delete popup.dblMD;
			var {boot} = this.meta;
			var bootNode = e.target.querySelector("[boot]");
			var ind = bootNode && this.meta.order.indexOf(bootNode.label);
			if (ind != boot)
				this.meta.boot = ind,
				save = true;
		}
		save && this.save(e.view);
	},

	sku: `#${pid} > menu[maxwidth]`,
	skd: `#${pid} > menu:is([maxwidth],[_moz-menuactive]):not([open])`,
	keydown(e) {
		if (e.repeat && e.key == "Shift" || !e.shiftKey) return;
		var func = this.keyHandlers[e.key];
		if (!func) return;

		var menu = e.view.windowRoot
			.ownerGlobal.document.querySelector(this.skd);
		if (menu)
			e.stopImmediatePropagation(),
			func.call(this, menu);
	},
	keyup(e) {
		if (e.key != "Shift") return;
		var win = e.view.windowRoot.ownerGlobal;
		win.removeEventListener("keyup", this, true);
		win.document.querySelector(this.skd)?.removeAttribute("maxwidth");
	},
	keyHandlers: {
		Enter(menu) {
			this.boot(menu);
		},
		ArrowDown(menu) {
			var ns = menu.nextSibling;
			if (ns) ns.after(menu), this.arrow(menu);
		},
		ArrowUp(menu) {
			var ps = menu.previousSibling;
			if (ps.nodeName == "menu") ps.before(menu), this.arrow(menu);
		}
	},
	arrow(menu) {
		if (menu.hasAttribute("maxwidth")) return;
		menu.setAttribute("maxwidth", menu.getBoundingClientRect().width);
		menu.ownerGlobal.addEventListener("keyup", this, true);
		this.dragData = {trg: menu};
	},

	fill(e) {
		var mxe = e.view.MozXULElement;

		var initFrag = mxe.parseXULToFragment(`
			<menuitem value="saveSession" class="menuitem-iconic" label="Сохранить сессию"/>
			<menuseparator/>
		`);
		this.menuFrag = mxe.parseXULToFragment(`<menu class="menu-iconic"><menupopup>
			<menuitem label="Восстановить"
				class="menuitem-iconic" value="restoreSession"/>
			<menuitem label="Переименовать"
				class="menuitem-iconic" value="renameSession"/>
			<menuitem label="Удалить"
				class="menuitem-iconic" value="removeSession"/>
		</menupopup></menu>`);

		this.regStyle();

		var filler = {fill: e => e.target.id
			? e.view.addEventListener("keydown", this, true)
				|| e.target.fillFlag || this.fillSessions(e.target)
			: this.dragData?.mouse && e.preventDefault()
		};

		(this.fill = e => {
			var trg = e.target;
			trg.setAttribute("context", "");
			trg.append(trg.ownerDocument.importNode(initFrag, true));
			(trg.filler = filler).fill(e);
			trg.addEventListener("dragstart", this);
			trg.addEventListener("popuphidden", this);
		})(e);
	},
	fillSessions(popup) {
		while(popup.lastChild.nodeName == "menu") popup.lastChild.remove();
		var ind = 0, {boot} = this.meta;
		for(var name of this.meta.order) {
			var df = popup.ownerDocument.importNode(this.menuFrag, true);
			df.firstChild.setAttribute("label", name);
			if (ind++ == boot) df.firstChild.toggleAttribute("boot");
			popup.append(df);
		}
		popup.fillFlag = true;
	},
	regStyle() {
		delete this.regStyle;
		var subst = "ucf-ssm-style-resurl";
		Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler).setSubstitution(
			subst, Services.io.newURI("data:text/css;charset=utf-8," + encodeURIComponent(`
			@-moz-document url-prefix(chrome://browser/content/browser.xhtml) {
				#${pid} > menu {
					list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAEnQAABJ0BfDRroQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGxSURBVDiNnZE/T1NRGMZ/7zn3lmKLkIKpaUxZFINEJZ0YHXRwcnBxMQ6aOJi4+FH8Dm5OOjA4+AEYGCTRook1JlVIVUrbW/rnPg63UtReIr7bOXmf5/ye59jDlanHS3O+wn/Mu+/DF8HFeVe5f+vaPTdfPpF4UNvk6frmhwAvXOEsvrR0IoN47xM4CHCADmDQBkAHbdTrTBRZdgYLs6NTD/MiMC+gC8MO6ke8ffWsXv3S3JpksHouv7Z4/UEeM8z6IwKfEGjYRt0G1d3m1p3n0Y1JBi/vTtfKw1Yec2CHBDFmXYjboAgL4tTc5pXsmcNcDxIDUFQHuqgfYT69OAuE9qqAoX4jIcAL7b9H+0deOYYg3tkYXxx2EAo7dQYEBF/TEULD5oow7KHut18RhGVD3GwxMZ36YWn6IJd37vQCSMSNBpYQCMs43PQMAJXlwtr6k7CGfo9iznN1ebGY7Ak1NSJwYERYJgM+Q+nClVzp/OXc3wWMwdT+jAVKCMwLC2PUeoMrrEI4m94BQq0a6mxjoca/YKFgUCfeqR8jPhoHcIAHe3ST2+UFLv2T8o/5uMvrnx9Wn65p5nMEAAAAAElFTkSuQmCC");
				}
				#${pid} > [value=saveSession] {
					list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKVSURBVHjajFNNTBNREJ6+7na73bLbQn8I0BKNCYWKGr0oYoiJPxeNh6oHozcOxgSVi4le1JNHQRPigRsewURNPKiJMQicSISUACelRVJ2tz/bdktpy9adBzT8xTjJ5L35ezNv5hsLHEAv7noEntguChx7EuV8oTydKRhfno8kCnt9LTuFZ7f87mAz/8rnl86GOoOBBq+LQX1S1ioLs0txWdEmsulS38Phlcy+BwZ6W0L+JsfolcjpsFDnBKNcgQ193bRUwSrwQFgr6Dkd3o9NzilqMdI/FF+sPYCZ245I4zdunw9DtQr6LxlK6bVdpdrcPAiHfGBYLDD69ltUXsmfw0oIGoPNjkHMjMHa3J9asDyRpoyEOrQR0+dq5MxR0c29Rj3Bhvn8YjeWjZmN9cpWcApSkzpkptYg8T1FdWjTfysg1Ang9YtdT+80OogTbJc7OlsD+OftzOqsBrMflqHe6QKXIEL00zLV0UpSBbM/G9DeEQy6OXKJsfPsCbdXYjb0Yu2/nmMS9LSGYGlYpXLPkxCwkq1mR98Gn8Q4XexxYhhgYKf3TPTfRDaPqklkvViaSSpaxSpw/x1v5e0UG8W10k+iW8qfF2ZiccIydFQ7ScsXKO8ep4NiYj4ai6k5+Eoev1F1Wcn8QJDgnAnHbGYRWTh800cZ77Ryzmr6eCGXzYGiZCcQ2vQ32XT5PiIMTJBI4Waw1ZtZzLu7XaSMd1s9b9paKJA+vpuKqols3y4ov7wXaPN67GPXIl1hnDOOansyVicHhGHMzHkzeDKqqPnr/UOJxX3LNNDb5BJd3KC3Uexu7wgEGxq3limRqcxH47FVWRtPreYePBpJagdu4zYhwjx1cMFus59CuVgqTmPDDlrnvwIMAGS8IFCLagHpAAAAAElFTkSuQmCC");
				}
				#${pid} [value=restoreSession] {
					list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAACzElEQVQ4jX2QPWwbZRjHf+/5vfPdObZjO3Ga2pVpGtxCP4QIDKgqDCDUNQwgJCS2qFI3hBCRCvXSCcTAAu0GY0Fi4kuq+IjUCpWAgCTq4IpS3Di2G8c+x/bZ57t7mSJFMfBf/3p+z+95BPvy3pufxqKmcVY3ZFFKmQtFGIReuNnrDze6lv5TqfSyx4EIgA/e+fzkZML6MDmVnD80mz1kxW3DMAxQCs/z6Hb6g3q1Xt1ttdfa7dbFN668vrkHkADJhPntufNnc0LTDi7AjFkkUknzcGF2LvCDuZVvfiwCj+/1GoAmhL3x6x2cZhsVqjFIGIZs15ts/LJOJCLt/Z0EiE3Y9eLpR1ONaoMH9zbHAGiC9FSKkwunWF1Z3RoDABhRg/zRPPmj+XHA/0QDaLectFLj6gcT+AHdTm9mzMC27e766lrWtCwy2Qz2hIUeNVDAaDCku9ujWW/ij3wsO9oaMzCiunf66TMU5gt4wyGbf1Upr5W5u15mq1JDhYqZQo6HIuqtueLw4vLXzwC89NZXeQFw/ePv7zx5buHEf6nf3qgMVipOGE0ko6EKhoQi3NnZ+c51BwsaQLOxM9N1uv86vNtz+aHSDn0pH9S2tl6r/Pn3s/VG/WYunzs/NZ2OSID0dKpRrzZS98v3kYbEsi1004BQcbtc9Q07bdYb229/dvmFL5aWVvVts9mq1Wo/e54vJIAQqGOPzQHgj3zcvos39BAIBshRqJQYjYZ/AFy79tQIeHVx+ctiIDRTA+g43Xud9q4PIHVJPBknk82QzqY5VZg2UUrEYhOX9s5aXL5RnMykb8Rj9kcC4OrSVZ1Hpt+PJ5PPz+SzR5KpyYRpGgRKMei7fHLr7lBmZ1XHcX4LgsCxLPt4JBLRm82Hr4j9DyuVSprdO/ZELGafkXpkXtPA94OK03Vv/R4/csEw5XOGbuieN6y6bv/S9XdfvPkPTgcoDlpQJpwAAAAASUVORK5CYII=");
				}
				#${pid} [value=renameSession] {
					list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPFJREFUeNrEU0sOgkAMbc1IIHoQT+KeY7hkBW5ccwLdsOICxI2X8peIGhggI21gggpCwsImM01f+tpOO0WlFIwR0efgeR5nsG0boihizPd91A5UwZDjuq5qwycwUkQYhttSr4Y4l76fDdtBEAQqz3OVZdnPQ09o2sQhrpBSQgnAen/qzLxZzljHcawxy7KAuCJNUyiKAm53SS0FBGQNlUW3lFO2iVCLYRhAXJEkCQPn65NGAswpL/4fWAebt1ZGXB3geHlw9maXsKqjS94CHNxF7xRM0/wKgI7jDBojvbnZAz3Gv/9E7NvGvmXCsev8EmAAWocA9ofpaRIAAAAASUVORK5CYII=");
				}
				#${pid} [value=removeSession] {
					list-style-image: url("data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAABt0lEQVQ4ja2RT2sTURTFz8tk0nntFAQrVLBQxIUg/tkkMoLyIEVECHZhNrrxI+hOP5Mb6eBCcEipYIjZ2LpvhFasUtBSkwzOve+6mE6YSScuxLt67753fudyLvA/a7T+qCHmiTfrfWCMd3j9diPfq2SHX+uPnzJx71gP33w3bX9avBcE2j+SkK30Di7ffJ71VebMxD1hC2GGEEfH41prpftynIm92A0t2aYQQYgBThrndz/2KwCgf9Z2LNtImFOAtc356ijcCwJdJrZEUWzPfJpMAAAStPWR/h2Ktc10CoIQRUKEabFNvNbKfndcAKSjtrVfHW5YorWTzxDKYAxLtOWM+P7yt51hIYPpsDTNTyB/EwNAtWxdMuV8GCfbgxjxIviUYSV/SQOrbVjitbx4N8alBeXcdZR+3Tl3xS8FlIkt0dbnWH3xlbPgKgUo3HEq+tX7C4EuAAbGeOmqCuLIJt69s3PeQ1epKGfapCQJO6vGmwAWf/C1Wau6td8dV123BaAAUfHw6gSwtP3ugxA/y6X9INszAOQgbwFAIC/MQb9/Kv2vF2/UByejlVVn1Xiby/X6rPd/qj/1ak71UYKuwQAAAABJRU5ErkJggg==");
				}
				#${pid} > menuseparator:last-child,
				#${pid} > menu[maxwidth] > .menu-right {
					display: none;
				}
				#${pid} > menu[boot] {
					color: red;
					font-weight: bold;
				}
				#${pid} > menu[maxwidth] {
					color: blue;
					font-weight: bold;
					outline-offset: -2px;
					outline: 2px solid orangered;
				}
			}
		`.replace(/;$/gm, " !important;"))));
		var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
		sss.loadAndRegisterSheet(Services.io.newURI("resource://" + subst), sss.USER_SHEET);
	},

	get gs() {
		delete this.gs;
		return this.gs = Cu.import("resource:///modules/sessionstore/SessionStore.jsm", {});
	},
	getState() {
		return JSON.parse(this.gs.SessionStore.getBrowserState());
	},
	splice(name, newName) {
		var ind = this.meta.order.indexOf(name);
		if (ind == -1) return;
		var args = [ind, 1];

		if (1 in arguments) args.push(newName);
		else {
			if (ind == this.meta.boot) this.meta.boot = null;
			else if (ind < this.meta.boot) this.meta.boot--;
		}
		this.meta.order.splice(...args);
	},
	get meta() {
		(this.dataFile = Services.dirsvc.get("UChrm", Ci.nsIFile))
			.append("simple_session_manager.json");
		
		try {this.data = JSON.parse(Cu.readUTF8File(this.dataFile));}
		catch {this.data = {};}

		var mp = "{07cae4f5-18b0-487b-80eb-973304af9528}";
		var meta = this.data[mp];
		if (!meta) {
			var order = Object.keys(this.data);
			meta = this.data[mp] = {order, boot: null};
		}
		delete this.meta;
		return this.meta = meta;
	},
	async save(excWin) {
		var {IOUtils} = Cu.getGlobalForObject(Cu);
		await IOUtils.makeDirectory(this.dataFile.parent.path);
		var {path} = this.dataFile;
		delete this.dataFile;
		(this.save = excWin => {
			IOUtils.writeJSON(path, this.data);
			for(var win of CustomizableUI.windows) {
				if (win == excWin) continue;
				var popup = win.document.getElementById(pid);
				if (popup) popup.fillFlag = false;
			}
		})(excWin);
	},

	get prompter() {
		var {prompt} = Services;
		var p = {}, args = [null, null, "UCF Simple Session Manager"];
		p.alert = prompt.alert.bind(...args);
		p.confirm = prompt.confirm.bind(...args);
		var pr = prompt.prompt.bind(...args);
		p.prompt = (msg, value) => {
			var res = {value};
			return pr(msg, res, null, {}) ? res.value : null;
		}
		delete this.prompter;
		return this.prompter = p;
	},
	observe(s, t, data) {
		Services.obs.removeObserver(this, "quit-application");
		if (data.includes("restart")) return;

		var {boot} = this.meta;
		if (boot == null) return;
		
		var state = this.data[this.meta.order[boot]];
		this.gs.SessionStoreInternal.getCurrentState = () => state;
		Services.prefs.setBoolPref("browser.sessionstore.resume_session_once", true);
	},

	get bwt() {
		delete this.bwt;
		var url = "resource:///modules/BrowserWindowTracker.jsm";
		return this.bwt = ChromeUtils.import(url).BrowserWindowTracker;
	},
	getName(state) {
		var wl = state.windows.length, tl = 0;
		for(var w of state.windows) tl += w.tabs.length;
		return `${
			this.bwt.getTopWindow().gBrowser.selectedTab.label.slice(0, 70)
		} ${wl}/${tl} [${
			new Date().toLocaleString("mn").replace(" ", "-")
		}]`;
	},
	exists(name) {
		this.meta;
		return (this.exists = name => name in this.data &&
			!this.prompter.alert("Сессия с тем же именем уже существует!"))(name);
	},
	saveSession(state = this.getState(), name = this.getName(state)) {
		var name = this.prompter.prompt("Сохранить:", name);
		if (name == null) return true;

		if (this.exists(name)) return this.saveSession(state, name);

		this.data[name] = state;

		this.meta.order.push(name);
		//this.meta.order.unshift(name);
		//if (this.meta.boot != null) this.meta.boot++;
	},
	restoreSession(name, win) {
		var ss = this.gs.SessionStore;
		var state = JSON.stringify(this.data[name]);
		win ? ss.setWindowState(win, state) : ss.setBrowserState(state);
	},
	renameSession(name, newName = name) {
		var newName = this.prompter.prompt(`Переименовать "${name}" в:`, newName);
		if (newName == null || newName == name) return true;

		if (this.exists(newName)) return this.renameSession(name, newName);

		var {data} = this;
		this.splice(name, newName);
		data[newName] = data[name];
		delete data[name];
	},
	removeSession(name) {
		if (!this.prompter.confirm(`Вы уверены, что хотите удалить ${name} ?`))
			return true;
		delete this.data[name];
		this.splice(name);
	}
}).init()))("ucf-ssm-menupopup");

Dumby, огромное спасибо.


«The Truth Is Out There»

Отсутствует

 

№1620614-01-2022 22:56:52

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 332
UA: Firefox 96.0

Re: Custom Buttons

Dumby

Dumby пишет

Simple Session Manager

Для последних FF подходит?  А, то чуть лочистил куки и историю и все...Ни черта не восстанавливает....(93-96)

Отсутствует

 

№1620715-01-2022 00:43:48

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

Re: Custom Buttons

ВВП пишет

Для последних FF подходит?

Ну, я поставил на 98.0a1, вроде работает.
Но всё, конечно, не тестировал, так, потыкал чуть-чуть.

Отсутствует

 

№1620815-01-2022 01:06:15

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

Re: Custom Buttons

ВВП пишет

Dumby

Dumby пишет

Simple Session Manager

Для последних FF подходит?  А, то чуть лочистил куки и историю и все...Ни черта не восстанавливает....(93-96)

Эта кнопка всегда была с придурью.
Например, если в настройках [firefox] поставить "При закрытии Firefox должен автоматически удалять: Журнал посещений и загрузок", то сессию можно буде восстановить только вручную. Автоматическое восстановление не сработает.
Есть и другие косяки.
Я держу эту кнопку только из-за того, что она при восстановлении сессии также восстанавливает положение прокрутки страниц. А для меня это важно.
Все современные дополнения этого делать не умеют. Иначе я бы уже давно поставил что-нибудь типа "Tab Session Manager" и не мучил Dumby правкой этой кнопки.


«The Truth Is Out There»

Отсутствует

 

№1620915-01-2022 09:33:13

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

Re: Custom Buttons

unter_officer пишет

Например, если в настройках [firefox] поставить "При закрытии Firefox должен автоматически удалять: Журнал посещений и загрузок", то сессию можно буде восстановить только вручную. Автоматическое восстановление не сработает.

О! Я вижу это. Вот такая правка вроде помогает

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

Выделить код

Код:

…
		//this.gs.SessionStoreInternal.getCurrentState = () => state;
		var ssi = this.gs.SessionStoreInternal;
		ssi.getCurrentState = () => state;
		Services.obs.removeObserver(ssi, "browser:purge-session-history");

Есть и другие косяки.

Заинтригован, вдруг там что-то простое.

Отсутствует

 

№1621015-01-2022 09:56:55

shadow_user
Участник
 
Группа: Members
Зарегистрирован: 14-02-2007
Сообщений: 244
UA: Firefox 91.0

Re: Custom Buttons

Dumby
Пожалуйста, поправьте код кнопки для вставки символов https://forum.mozilla-russia.org/viewto … 86#p776486 , чтобы в темной теме браузера символы были читаемыми. Сейчас выглядит так, слева в светлой теме, справа в темной. Спасибо!
char.png

Отсутствует

 

№1621115-01-2022 12:46:27

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

Re: Custom Buttons

shadow_user пишет

чтобы в темной теме браузера символы были читаемыми

Можно чёрный color в css вписать и будут читаемыми, типа так

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

Выделить код

Код:

/**/
        #${_id} menuitem:not(:hover) > .menu-text {
            color: black;
        }


А можно закомментировать/удалить этот кусок, он был добавлен,
чтобы закрасить вертикальный отделитель места для иконок в меню,
который здесь неуместен, но в Win10, как я вижу, такового просто нет.
Тогда в темной теме менюшка будет тёмной.
скрытый текст

Выделить код

Код:

/*
        #${_id} menugroup,
        #${_id} > menupopup > arrowscrollbox {
            background-color: menu;
        }
*/

Отсутствует

 

№1621215-01-2022 13:19:33

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 332
UA: Firefox 96.0

Re: Custom Buttons

Dumby

ВВП пишет

Simple Session Manager

Можно кнопкой это и если есть косячки, то и исправить ? Буксует на ютубе из-за авторизации.

Отсутствует

 

№1621315-01-2022 13:37:06

shadow_user
Участник
 
Группа: Members
Зарегистрирован: 14-02-2007
Сообщений: 244
UA: Firefox 91.0

Re: Custom Buttons

Dumby пишет

Можно чёрный color в css вписать и будут читаемыми, типа так

Dumby пишет

А можно закомментировать/удалить этот кусок, он был добавлен,

Просто супер, спасибо! :beer:

Отсутствует

 

№1621415-01-2022 17:09:47

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

Re: Custom Buttons

Dumby пишет
unter_officer пишет

Есть и другие косяки.

Заинтригован, вдруг там что-то простое.

Это связано с восстановлением позиции прокрутки страницы.
И боюсь, что описание получится длинновато.


Например, есть очень большая статья, в которой меня заинтересовали несколько абзацев, но в данный момент времени нет времени с этим разбираться.
В FF52 я пользовался менеджером сессий, который встроен в дополнение Tab Mix Plus. Я делал так.


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


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


В этой кнопке с клонированием (дублированием) вкладок такое не получается. Первая вкладка восстанавливает позицию прокрутки, а остальные (клонированные) нет.
В общем не нравится этой кнопке клонирование (дублирование) вкладок.

Надеюсь, не очень путанно описал проблему.


«The Truth Is Out There»

Отсутствует

 

№1621515-01-2022 20:57:41

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

Re: Custom Buttons

unter_officer пишет

И боюсь, что описание получится длинновато.
Надеюсь, не очень путанно описал проблему.

Замечательно. Чётко, подробно, доходчиво.


Попробовал воспроизвести, но не получилось.
Вернее, получилось частично. В первых четырёх вкладках позиция прокрутки
сохранилась актуальная, а в пятой (последней) осталась как в четвёртой (предпоследней).


Подумал, может нужно время, чтобы устоялось, и точно, так и есть.
Проделал то же самое, но не сразу полез сохранять, а подождал сколько-то [десятков секунд(?)].
Затем сохранил, восстановил, и у каждой из пяти восстановилась своя позиция прокрутки.


В любом случае, со стороны кода здесь вряд ли что-то можно сделать,
он же не сам собирает сессионные данные, а просто запрашивает у лисы SessionStore.getBrowserState().
Если бы точно знать где затык, то можно было бы попробовать подумать как пнуть, но разве найдёшь.


ВВП пишет

Можно кнопкой это

Из кнопки это жутко неудобно.
В чём проблема, закинул в UCF custom_script.js и все дела.

Отсутствует

 

№1621615-01-2022 22:38:53

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

Re: Custom Buttons

DEL

Отредактировано unter_officer (16-01-2022 03:30:17)


«The Truth Is Out There»

Отсутствует

 

№1621716-01-2022 01:33:44

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

Re: Custom Buttons

Dumby
unter_officer
browser.sessionstore.interval

Отсутствует

 

№1621816-01-2022 03:22:38

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

Re: Custom Buttons

_zt пишет

Dumby
unter_officer
browser.sessionstore.interval

_zt, спасибо за наводку.
У меня этот параметр был изменён с 15000 (по умолчанию) на 300000.
Вернул значение по умолчанию и вроде всё стало нормально сохраняться.
Для полной уверенности потестирую ещё и понаблюдаю, но думаю, что проблема была именно в этом.


«The Truth Is Out There»

Отсутствует

 

№1621916-01-2022 04:10:16

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 332
UA: Firefox 96.0

Re: Custom Buttons

Dumby
Почему сразу ::-moz-selection ?
2ss7y6pq.jpg

Отсутствует

 

№1622016-01-2022 09:04:04

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

Re: Custom Buttons

ВВП пишет

Почему сразу ::-moz-selection ?

Потому, что у них так сделано.
resource://gre/modules/CommonDialog.jsm

скриншот

Выделить код

Код:

data:image/png;base64,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


А почему у них так сделано я не знаю.
Наверно считается, что это удобно.

Отсутствует

 

№1622116-01-2022 11:52:18

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 332
UA: Firefox 96.0

Re: Custom Buttons

Dumby

Dumby пишет

Наверно считается, что это удобно.

Так, а шо делать ? Рихтую,рихтую и никак...Вру, сделал...Похожая шняга с editBMPanel_namePicker , от тут не знаю.
Да нет, нашел в editBookmark.js ,короче, меняю на focused

Отредактировано ВВП (16-01-2022 12:41:45)

Отсутствует

 

№1622216-01-2022 21:29:06

Азат55555
Участник
 
Группа: Members
Зарегистрирован: 01-11-2018
Сообщений: 28
UA: Yandex 22

Re: Custom Buttons

Простите что отвлекаю. Как заархивировать папку? Есть папка по пути C:\\Папка нужно через CB превратить в Папка.rar

Отсутствует

 

№1622317-01-2022 21:11:54

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

Re: Custom Buttons

Азат55555 пишет

Как заархивировать папку? Есть папка по пути C:\\Папка нужно через CB превратить в Папка.rar

Запустить программу-архиватор с аргументами, очевидно же.

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

Выделить код

Код:

var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
process.startHidden = true;

process.init(FileUtils.File("C:\\Program Files (x86)\\WinRAR\\rar.exe"));

var args = ["a", "-ep1", "-r", "Y:\\Папка.rar", "C:\\Папка\\*"];

process.runw(false, args, args.length);

Отсутствует

 

№1622419-01-2022 15:31:28

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

Re: Custom Buttons

Dumby
Переделайте пожалуйста кнопочку для UCF.

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

Выделить код

Код:

/*Initialization Code*/

// Сохранить как PNG ..........
((main, parts) => this._handleClick = () => {
    var df = MozXULElement.parseXULToFragment(`
        <menupopup>
            <menuitem class="menuitem-iconic"
                image="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAOwSURBVHjaYmBiYuJvamo+xiIsLLL3uaazMUAAMTY3txxjAAFubq7/ZiYm/wECACIA3f8AGhobzGhoaP8QFRr/6enp/wT5+fgBLS0tAOLi4gCnp6cAAoixtrbuFBsb6x+QNnZ2jo0MXz9/+Qdk/wfhO3fu/Gc5cuwoA4NqHEOoszjDrVu3GFiAogxJtiwMagrCQHMeMgAEoHhsdRCG4Tj463+rxGFIqN2CYI7wBpiaWhzPheF5SMhIKliCYiQtyTC4hvSLcu7cHYQQl5SSDyFGa23UWkfvfXTORWNMpiIYH2NV1xXN5gvq9kfqNjtSStF7mkAhBPTXHm3TYL1qsV2+8LyfIaXEbRjAyuzpUOCcI+cMYgzp31hCnft+fgII6Cm95oiICOd///4CFTAwAOWBgBFIM7Lw8vLZM5w7d+7/t2/fwA4DOfDp02d/QQ4GWv1z6tSpU5g+ffrI8OnTJyagFUx2Tu5MsnIyTDk52UyfPn5k/vXr9x+mjx8+MsTFxTGERMUzVK09yCAsn8AwY+ZMhlevX0Pc9PTZM4a3b94wXHjwmaEsu5th87GpQIcyMdy+fZvh79+/DEwfP35giIuPZ3hzbTeDCtcjhngnEwZVVRWGz58/g+ON5dOnz6BYYKioqGY4eOggg5SuBYORkRHDixcvQL5hZNTR0flnY2PD+O8fKAwYgGHwHyTMwMzMwrBt2zZHgAA9Uz1Lw1AUPWlKE1vFlEIFHRoKQgcRtDSLIAiCgoJuiovYP6DopnR1EdRYHO3W6tbg5K5LwclmVQviRwutpSaQtI3P+yIK7/Eu94t77jkPiqIcGUaZ5vlmlvXFbNui12LEBSPo/uU29/EYrYQ1m01WqVRYPn++FQiHI3Mj8RG4jst7wHFcFAoFaFoGsixBliRoGc338dg3AQuKojc2OoZ+vzcZ4JRwQNQAxVIJsVgMuVwO8/OL2D29xPjSHvpCHAf7+36M57iuSzUdnzISg4d3AvxgVqHrJ5BCIcxu7KCdWoLx3MFLaBjOxDJSC1lIsowzXUfVNFEnJflrJi2i1WrBtm1MpzNgAoN5U8TtySE61Sccb6/jIjuF3uMduo5DOWk/l9fwxQr0o+6J+rSqqlxjQq1WQ9kw8PH2CoF5cLtd8gaRSCSwsrqKZDJJu3A8WZbFer2hB2nLAc5ZNBplHFskEsEmSUcURV8q+GXTH5ffBo1OUzNFGUa7/cm4eGcEIbA2MBBW6df8VnC1s3/zv8mfScchaq+GhgavfwBr4dP0kYqtcwAAAABJRU5ErkJggg=="
                label="Сохранить всю страницу как PNG"
                value="all"/>

            <menuitem class="menuitem-iconic"
                image="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAOwSURBVHjaYmBiYuJvamo+xiIsLLL3uaazMUAAMTY3txxjAAFubq7/ZiYm/wECACIA3f8AGhobzGhoaP8QFRr/6enp/wT5+fgBLS0tAOLi4gCnp6cAAoixtrbuFBsb6x+QNnZ2jo0MXz9/+Qdk/wfhO3fu/Gc5cuwoA4NqHEOoszjDrVu3GFiAogxJtiwMagrCQHMeMgAEoHhsdRCG4Tj463+rxGFIqN2CYI7wBpiaWhzPheF5SMhIKliCYiQtyTC4hvSLcu7cHYQQl5SSDyFGa23UWkfvfXTORWNMpiIYH2NV1xXN5gvq9kfqNjtSStF7mkAhBPTXHm3TYL1qsV2+8LyfIaXEbRjAyuzpUOCcI+cMYgzp31hCnft+fgII6Cm95oiICOd///4CFTAwAOWBgBFIM7Lw8vLZM5w7d+7/t2/fwA4DOfDp02d/QQ4GWv1z6tSpU5g+ffrI8OnTJyagFUx2Tu5MsnIyTDk52UyfPn5k/vXr9x+mjx8+MsTFxTGERMUzVK09yCAsn8AwY+ZMhlevX0Pc9PTZM4a3b94wXHjwmaEsu5th87GpQIcyMdy+fZvh79+/DEwfP35giIuPZ3hzbTeDCtcjhngnEwZVVRWGz58/g+ON5dOnz6BYYKioqGY4eOggg5SuBYORkRHDixcvQL5hZNTR0flnY2PD+O8fKAwYgGHwHyTMwMzMwrBt2zZHgAA9Uz1Lw1AUPWlKE1vFlEIFHRoKQgcRtDSLIAiCgoJuiovYP6DopnR1EdRYHO3W6tbg5K5LwclmVQviRwutpSaQtI3P+yIK7/Eu94t77jkPiqIcGUaZ5vlmlvXFbNui12LEBSPo/uU29/EYrYQ1m01WqVRYPn++FQiHI3Mj8RG4jst7wHFcFAoFaFoGsixBliRoGc338dg3AQuKojc2OoZ+vzcZ4JRwQNQAxVIJsVgMuVwO8/OL2D29xPjSHvpCHAf7+36M57iuSzUdnzISg4d3AvxgVqHrJ5BCIcxu7KCdWoLx3MFLaBjOxDJSC1lIsowzXUfVNFEnJflrJi2i1WrBtm1MpzNgAoN5U8TtySE61Sccb6/jIjuF3uMduo5DOWk/l9fwxQr0o+6J+rSqqlxjQq1WQ9kw8PH2CoF5cLtd8gaRSCSwsrqKZDJJu3A8WZbFer2hB2nLAc5ZNBplHFskEsEmSUcURV8q+GXTH5ffBo1OUzNFGUa7/cm4eGcEIbA2MBBW6df8VnC1s3/zv8mfScchaq+GhgavfwBr4dP0kYqtcwAAAABJRU5ErkJggg=="
                label="Сохранить видимую часть страницы как PNG"
                value="page"/>

            <menuitem class="menuitem-iconic"
                image="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKaSURBVHjaYpx94sPD44//CDG9+/SDp8bsBw9AADEmrX7zmQEIGF+//fD/w8dPDAABxNix6/nbcA0GIQYoYGJiZGSQFBdmOHnqLAMrKwsDQAAxJq958/n/f4jsm2//GBifP3v+/8cfiMDDj/8ZmHi5ORl4gPjPn18M///9ZWDh5uVm4GJkYfj56zcD9z9GBoAAYmwH2aL8UwimDRk8+fyfgYWRgZFBgI+b4TsWBR+BtoNcxcDDwwW2R1iQn2HvgcMMX799Y/j6/TvDzz+/GVj+/fvPvO0BC8N/oGpGhv8ML3m0GS59EwWbcP/9XwaAAGSRwQ3CMAxFfxq3TgrqiSMswARMwSJMxZEdGAXBAEiQquICJMFuekDqwTlY38/Wi9kf78OqNTO8kndretBh+1puuvl+R8Dpwm9iruG8xPP/tIGzhULc1OB6voJJXxGjQpumGpsKCc8wEqISwGJfA1P1IYCEmCegkTmqLIELT/8KC+/x+cbxBpEPOl8zbn0q5voWXdcipQQrgZiC/QlQORmzNBAEUfjt7N4ichBUDIKCWNsJhiBiZ2mZf5XC0v/gT7C10lqwNMVBkBC9kKAmt7e+uQtJxBS6cNwy7L2b981bTrz/fnmIxnHTYN081i1F8PQacddDzm0M+UfAYPw/gfyTlqMNVfOJVxIGpfxNgMcZRwoYpkVpe1ezLn/jplc7B2wWb+1gwwfuvxg31lwi7MAimOU4E+IevuXoXt+gILTE1aQ1VBJnwNYR9ltXFKCweM9RWFpYCnjWiukU7dYJLs7PUMyKuglNAZt6GVncZ7SgIU2ZJ8M/bLqVQEFYN9hJPQ5201pgvhztjnk2ZhOYh+esd/vY39ZPZYWBXlURqZ4Qwg8uZXU3gM7p3vAbsXveewxHZWUAAAAASUVORK5CYII="
                label="Сохранить выбранный элемент страницы как PNG"
                value="click"/>

            <menuitem class="menuitem-iconic"
                image="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAL/SURBVHjaYijccvd25ZHvv5n4RSUVQs2vswAEECOIxwACy+8v/3/30Zv/AAHE0Hb6y+//UPDv4///LD/+MjJ8+PqF4cvnnww/vgkxAAQQY8Xhb78YgQCsj5mFgQGm/P+v///fvvj/n+n/fwaGe//vMexg2Mrw7BsDA8vXHwwMPN/5GdQ/mzG8BbIBAoiRfdqvX8xf/rBCDAEaAWL8ByOgmZwMLBXGvxnrzLgYVj9cyfCL+TfDj9+/Gd7//sAQw5vK8PEXAwMTRBsD0Li3DNKikgwC4twM3NIMDF9/fGf4CVTA8u0fM+ODjwwM7qJZDH8/MTBI/GFgUAba/QYo+fEnAwNAADKoXQVhIAjOJYfgsxIR/AwRi/yBlY3gz9j7FUI+wt7CwkbEzs7CNIo2Yl53t3duElDBhYXZZXaWGbHYKW0M4b+cex7WG9FaxmxGfNcfYNH3T+pr/LcSzu1h3Wx11EU2eOkYYRSi7jVgrQeb1TDtzFHkLgu13GQIBgGkJ6GFxva8h6XqX0kgRlF+AfkEw4S7ujEGbKnAzDa6GNEYLvOh2N6wOUGaVXHKayqQsHeiHgyfqKJ51sbxjvAWoG1qWWkYiKJnZhKTpgapK1tEslRw50+4camIGz/ObfcuBP0HBREEn12I+MBUadPM5HomqbWgi8kJydzHOfdctXmU29Vhbhqq8leNfxQyLP6lWgjjdxds9Yxs95ZRVAo+h8yFqEau2fHEKjpKqgojRDg+H0iw1gb212NY2oC/MCxz5DxGaYgPsKrGsnRYUEusnvKb4MNqnBlN5aZD8q54Hb2gP+gj62bohOyKdVxgobTBk3vE7cMzDhYPkVA0NW0xaBrlk6BZtRN20I16SMIWPt0CJlLQowqJStE2YwqnQRbE2ZwazrYURDquL5zcnCINU4xdiYo7QXXo4TesSMaIGGRTJ6jnqBxvkJNwfhFa2Ovu1jlrwXjD2gZ9wITeKVhImEFXgXcIgrvri/udqySztpDZemJurTzK70h/3h1xY3xpvwGLI42vrCwxmAAAAABJRU5ErkJggg=="
                label="Сохранить выбранную область страницы как PNG"
                value="clipping"/>
        </menupopup>
    `);
    var popup = df.firstChild;
    popup.setAttribute("context", "");
    popup.setAttribute("oncommand", "handleCommand(event);");
    popup.handleCommand = e => {
        var name = _id + ":DataURLReady";
        main = main.replace("%MESSAGE_NAME%", name);

        var urls = {}, configurable = true, enumerable = true;
        Object.entries(parts).forEach(([key, part]) => Object.defineProperty(urls, key, {
            configurable, enumerable, get() {
                var value = `data:;charset=utf-8,({${
                    encodeURIComponent(main + part)
                }%0A}).init("${key}")`;
                Object.defineProperty(urls, key, {configurable, enumerable, value});
                return value;
        }}));

        // Получить название вкладки без не сохраняемых символов и лишних пробелов .....
        var getTabLabel = () => {
            var label = gBrowser.selectedTab.label;
            var label = label.replace(/[:+.\\\/<>?*|"]+/g, " ").replace(/\s\s+/g, " ");
            return label.substring(0, 50);
        }

        var listener = msg => {
            var fp = makeFilePicker();
            fp.init(window, "Сохранить как…", fp.modeSave);
            fp.appendFilter("", "*.png");

            var fileName = getTabLabel();
            fileName = fileName.replace(/[:\\\/<>?*|"]+/g, '').replace(/\s+/g, '_').slice(0, 100).replace(/^\s+|\s+$/g, '');
            var fileDate = (function () {
              var d = new Date(), z = function(n){return (n < 10 ? '0' : '') + n};
              return '[' + z(d.getFullYear()) + '_' + z(d.getMonth()+1) + '_' + z(d.getDate()) + '\u00F7' + z(d.getHours()) + '_' + z(d.getMinutes()) + '_' + z(d.getSeconds()) + ']';
            })();

            fp.defaultString = fileName + "_" + fileDate + ".png";
            fp.open(res => res == fp.returnCancel || !fp.file || makeWebBrowserPersist().saveURI(
                Services.io.newURI(msg.data), document.nodePrincipal,
                null, null, null, null, null, fp.file, null, null
            ));
        }
        messageManager.addMessageListener(name, listener);
        addDestructor(() => messageManager.removeMessageListener(name, listener));

        (popup.handleCommand = e => gBrowser.selectedBrowser.messageManager
            .loadFrameScript(urls[e.target.value], false)
        )(e);
    }
    this.append(df);
    (this._handleClick = () => popup.openPopup(this, "after_start"))();
})(`
    init(cmd) {
        cmd.startsWith("c")
            ? this[cmd].init(this[cmd].parent = this)
            : this[cmd]();
    },
    capture(win, x, y, width, height) {
        var canvas = win.document.createElementNS("${xhtmlns}", "canvas");
        canvas.width = width;
        canvas.height = height;
        var ctx = canvas.getContext("2d");
        var tryDraw = ind => {
            try {ctx.drawWindow(win, x, y, canvas.width, canvas.height, "white")}
            catch(ex) {canvas.height = ind * canvas.width; tryDraw(--ind);}
        }
        tryDraw(17);
        sendAsyncMessage("%MESSAGE_NAME%", canvas.toDataURL("image/png"));
    },
    `, {

    all: `all() {
        var win = content;
        this.capture(win, 0, 0, win.innerWidth + win.scrollMaxX, win.innerHeight + win.scrollMaxY);
    }`,
    page: `page() {
        var win = content, doc = win.document, body = doc.body, html = doc.documentElement;
        var scrX = (body.scrollLeft || html.scrollLeft) - html.clientLeft;
        var scrY = (body.scrollTop || html.scrollTop) - html.clientTop;
        this.capture(win, scrX, scrY, win.innerWidth, win.innerHeight);
    }`,
    clipping: `clipping: {
        handleEvent(e) {
            if (e.button) return false;
            e.preventDefault();
            e.stopPropagation();
            switch(e.type) {
                case "mousedown":
                    this.downX = e.pageX;
                    this.downY = e.pageY;
                    this.bs.left = this.downX + "px";
                    this.bs.top = this.downY + "px";
                    this.body.appendChild(this.box);
                    this.flag = true;
                    break;
                case "mousemove":
                    if (!this.flag) return;
                    this.moveX = e.pageX;
                    this.moveY = e.pageY;
                    if (this.downX > this.moveX) this.bs.left = this.moveX + "px";
                    if (this.downY > this.moveY) this.bs.top  = this.moveY + "px";
                    this.bs.width = Math.abs(this.moveX - this.downX) + "px";
                    this.bs.height = Math.abs(this.moveY - this.downY) + "px";
                    break;
                case "mouseup":
                    this.uninit();
                    break;
            }
        },
        init() {
            var win = {};
            Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager)
                .getFocusedElementForWindow(content, true, win);
            this.win = win.value;

            this.doc = this.win.document;
            this.body = this.doc.body;
            if (!HTMLBodyElement.isInstance(this.body)) {
                Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService)
                    .showAlertNotification("${self.image}", ${JSON.stringify(self.label)}, "Не удается захватить!");
                return false;
            }
            this.flag = null;
            this.box = this.doc.createElement("div");
            this.bs = this.box.style;
            this.bs.border = "#0f0 dashed 1px";
            this.bs.position = "absolute";
            this.bs.zIndex = "2147483647";
            this.defaultCursor = this.win.getComputedStyle(this.body, "").cursor;
            this.body.style.cursor = "crosshair";
            ["click", "mouseup", "mousemove", "mousedown"].forEach(type=> this.doc.addEventListener(type, this, true));
        },
        uninit() {
            var pos = [this.win, parseInt(this.bs.left), parseInt(this.bs.top), parseInt(this.bs.width), parseInt(this.bs.height)];
            this.body.style.cursor = this.defaultCursor;
            this.body.removeChild(this.box);
            this.parent.capture.apply(this, pos);
            ["click", "mouseup", "mousemove", "mousedown"].forEach(type=> this.doc.removeEventListener(type, this, true));
        }
    }`,
    click: `click: {
        getPosition() {
            var html = this.doc.documentElement;
            var body = this.doc.body;
            var rect = this.target.getBoundingClientRect();
            return [
                this.win,
                Math.round(rect.left) + (body.scrollLeft || html.scrollLeft) - html.clientLeft,
                Math.round(rect.top) + (body.scrollTop || html.scrollTop) - html.clientTop,
                parseInt(rect.width),
                parseInt(rect.height)
            ];
        },
        highlight() {
            this.orgStyle = this.target.hasAttribute("style") ? this.target.style.cssText : false;
            this.target.style.cssText += "outline: red 1px solid; outline-offset: 1px; -moz-outline-radius: 2px;";
        },
        lowlight() {
            if (this.orgStyle) this.target.style.cssText = this.orgStyle;
            else this.target.removeAttribute("style");
        },
        handleEvent(e) {
            switch(e.type){
                case "click":
                    if (e.button) return;
                    e.preventDefault();
                    e.stopPropagation();
                    this.lowlight();
                    this.parent.capture.apply(this, this.getPosition());
                    this.uninit();
                    break;
                case "mouseover":
                    if (this.target) this.lowlight();
                    this.target = e.target;
                    this.highlight();
                    break;
            }
        },
        init() {
            this.win = content;
            this.doc = content.document;
            ["click", "mouseover"].forEach(type=> this.doc.addEventListener(type, this, true));
        },
        uninit() {
            this.target = false;
            ["click", "mouseover"].forEach(type=> this.doc.removeEventListener(type, this, true));
        }
    }`
});


«The Truth Is Out There»

Отсутствует

 

№1622520-01-2022 17:05:29

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

Re: Custom Buttons

unter_officer пишет

Переделайте пожалуйста кнопочку для UCF.

Нехочу. Можешь просто сам обернуть, типа

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

Выделить код

Код:

(async func => CustomizableUI.createWidget({
	id: "797743",
	label: "Сохранить как PNG",
	tooltiptext: "Сохранить как PNG",
	localized: false,
	onCreated(btn) {
		var win = btn.ownerGlobal;
		new win.Function("_id, xhtmlns, addDestructor", func.toString().slice(7, -1)).call(
			btn, this.id, "http://www.w3.org/1999/xhtml",
			destructor => win.addEventListener("unload", destructor, {once: true})
		);
		btn.setAttribute("image", "resource://usercontext-content/pet.svg");
	}
}))(() => {

// Здесь код

});


Bug 1743099 - Remove unused AddonType bits (Firefox 98+)
Кнопки с about:addons тю-тю. Соберу сейчас, на всякий случай.


Custom Buttons 0.0.7.0.0.23, paxmod и bootstrap в zip-папке.

Отсутствует

 

Board footer

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