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

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

№1727616-03-2025 13:31:39

Andrey_Krropotkin
Участник
 
Группа: Members
Зарегистрирован: 11-11-2011
Сообщений: 491
UA: Firefox 136.0

Re: Custom Buttons

Dumby т.е. как я понял получается что они вырезали старые функции а новые еще не ввели, и пока про эту кнопку можно забыть

Отсутствует

 

№1727717-03-2025 01:51:19

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 44
UA: unknown 0.0

Re: Custom Buttons

Dumby
Код хорош, а нельзя и на открыть новую вкладку подобное ?

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

Выделить код

Код:

(flags => {
	
	var clear = Services.clearData.deleteData.bind(null, flags, () => {});

	var skip, check = () => {
		skip = null;
		for(var w of CustomizableUI.windows) for(var tab of gBrowser.tabs) try {
			if (tab.linkedBrowser.URI.host) return;
		} catch {}
		clear();
	}
	addEventListener("TabClose", e => skip ??= setTimeout(check, 400), false, gBrowser.tabContainer);
})(Ci.nsIClearDataService.CLEAR_DOM_STORAGES);

На форуме

 

№1727817-03-2025 10:10:01

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

Re: Custom Buttons

green25 пишет

и на открыть новую вкладку подобное

На «открыть новую вкладку» рассылается топик "browser-open-newtab-start",
так что можно попробовать добавить в код обсёрвер, как-то так:

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

Выделить код

Код:

(flags => {

	var clear = Services.clearData.deleteData.bind(null, flags, () => {});

	var skip, check = () => {
		skip = null;
		for(var w of CustomizableUI.windows) for(var tab of gBrowser.tabs) try {
			if (tab.linkedBrowser.URI.host) return;
		} catch {}
		clear();
	}
	addEventListener("TabClose", e => skip ??= setTimeout(check, 400), false, gBrowser.tabContainer);

	var topic = "browser-open-newtab-start";
	var obs = subj => Cu.getGlobalForObject(subj.wrappedJSObject) == window && clear();
	Services.obs.addObserver(obs, topic);
	addDestructor(() => Services.obs.removeObserver(obs, topic));

})(Ci.nsIClearDataService.CLEAR_DOM_STORAGES);

Отсутствует

 

№1727917-03-2025 10:40:33

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 44
UA: unknown 0.0

Re: Custom Buttons

Dumby
Класс!
Перестало работать в 115 SessionStore.jsm -это ? Менял не помогло

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

Выделить код

Код:

if(event.button == 2 && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey){
 

var cancel = true;
Services.obs.addObserver(function wfp(win, topic) {
	Services.obs.removeObserver(wfp, topic);
	var sd = win.gSanitizePromptDialog, {sanitize} = sd;
	sd.sanitize = e => cancel = sanitize.call(sd, e);
}, "widget-first-paint");

SidebarUI.hide();
Sanitizer.showUI(window);

var ssi = Cu.import("resource:///modules/sessionstore/SessionStore.jsm", {}).SessionStoreInternal;

if (cancel) return;


Извиняюс в "name": "Custom Buttons",
    "version": "0.0.7.0.0.35",      (Обзор...0) не работает ?

Отредактировано green25 (17-03-2025 18:41:55)

На форуме

 

№1728020-03-2025 22:05:10

Andrey_Krropotkin
Участник
 
Группа: Members
Зарегистрирован: 11-11-2011
Сообщений: 491
UA: Firefox 136.0

Re: Custom Buttons

Вот такой вопрос. Есть в настройках переключатель - показать новую боковую панель. Есть обычная старая боковая панель.  Нужна кнопка переключения между старой и новой. т.к в новой не отображаются пункты с других кнопок и дополнений. т.к. еще не перешли на новую боковую панель.  Из новых показывает только BrowserConsole от Dumby, которая сделана на USF

Добавлено 20-03-2025 22:12:22
Есть кнопка

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

Выделить код

Код:

// http://infocatcher.ucoz.net/js/cb/editCustomButtonInTab.js
// https://github.com/Infocatcher/Custom_Buttons/tree/master/Edit_Custom_Button_in_Tab

// Edit Custom Button in Tab button for Custom Buttons
// (code for "initialization" section)

// (c) Infocatcher 2012-2014
// version 0.1.8.3 - 2014-01-12

// Note:
// In Firefox 3.6 and older:
// - Force enables "Save size and position of editor windows separately for each custom button"
//   option for editor in tab (because doesn't work without this)
// - tab with editor can't be closed sometimes using OK/Cancel buttons

var editInTabLabel = (function() {
	var locale = (function() {
		if("Services" in window && "locale" in Services) {
			var locales = Services.locale.requestedLocales // Firefox 64+
				|| Services.locale.getRequestedLocales && Services.locale.getRequestedLocales();
			if(locales)
				return locales[0];
		}
		var prefs = "Services" in window && Services.prefs
			|| Components.classes["@mozilla.org/preferences-service;1"]
				.getService(Components.interfaces.nsIPrefBranch);
		function pref(name, type) {
			return prefs.getPrefType(name) != prefs.PREF_INVALID ? prefs["get" + type + "Pref"](name) : undefined;
		}
		if(!pref("intl.locale.matchOS", "Bool")) { // Also see https://bugzilla.mozilla.org/show_bug.cgi?id=1414390
			var locale = pref("general.useragent.locale", "Char");
			if(locale && locale.substr(0, 9) != "chrome://")
				return locale;
		}
		return Components.classes["@mozilla.org/chrome/chrome-registry;1"]
			.getService(Components.interfaces.nsIXULChromeRegistry)
			.getSelectedLocale("global");
	})().match(/^[a-z]*/)[0];
	if(locale == "ru")
		return "Редактировать во вкладке…";
	return "Edit button in tab…";
})();

const editorBaseUri = "chrome://custombuttons/content/editor.xul";
const cbIdTabAttr = "custombuttons-editInTab-id";

const editId = "custombuttons-contextpopup-edit";
const editInTabId = editId + "InTab";
var editInTab = document.getElementById(editInTabId);
if(editInTab)
	editInTab.parentNode.removeChild(editInTab);
var editItem = document.getElementById(editId);
editInTab = editItem.cloneNode(true);
editInTab.id = editInTabId;
editInTab.setAttribute("cb_id", editInTabId);
editInTab.setAttribute("label", editInTabLabel);
editInTab.setAttribute("oncommand", "editCustomButtonInTab();");
if(!Object.create) // Firefox 3.6 and older
	editInTab.removeAttribute("observes");
editInTab.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAitJREFUeNrEk0tIVVEUhr99zrnHc1+SkYQVFWo20G6SgkFRDorEILFJDoogkoLoXfOopEZCYIFlIITlRIUiC5UmFZVk1igwCAozfD9uat17z97tc5XK0pGDFiz289/rXz//FkopFhMGiwyr5GoHHgkpZUnCde9LqXwwHyuR3HVNIzZpGrubbLtjfHwYyzvywIYpHp0o386ajAAD3/R1MRfugZeFoGcgbm9pedo+7VVVCMvTwKt8tGwrfXGb5mfRJFj8VV0Ki7hpk9t5gW35lYx9GcSZGFOGSjJQvuXpYd4PTLPUYU6m+Q1SgzbBkEPey0tUHjlJfU8j0c8j+Aa/ahFn2x2cdknVgLBfpx5DyTQIBGx8+oHjras4vX8DtfWNFG0q4gmPyas9VqgZqEbNAEvPUnW1sCMI+QVBPXc02Ar5ONiURW55NsHus1TkjNDW2srHdYcormo/Z2kG+0p35BPTfaaHrVnBBAmt75QwKK3LYuPetdDbDxMTdHc2ELn4gfWj32l+MFQhdla1KVdKpCvxBPXAcWUSlQEaYgeIlK2GvmENHuHOmxVcW3mLoDuqn09gGjNiF8xnEPWw+DUFpTA0BS+uc/tdDodrnhf+445dV9p/LaQw+SH8nBfVRBMpKi0zm5LIEupq7lF541Vhy6lIV3XGTRw5qdWXM078bRSBK3zs6b3MWxEgplxSPnWS2e8kwXfPbO4SanIefy4cf7bWtdAl8d9/408BBgBVmNFVzOyEfgAAAABJRU5ErkJggg==");
editItem.parentNode.insertBefore(editInTab, editItem.nextSibling);

Array.prototype.filter.call( // Process already cloned menu items
	document.getElementsByAttribute("observes", editItem.getAttribute("observes")),
	function(mi) {
		var id = mi.id || "";
		return mi != editItem
			&& id.substr(0, editId.length) == editId
			&& id.substr(0, editInTabId.length) != editInTabId;
	}
).forEach(function(editItem, i) {
	var clone = editInTab.cloneNode(true);
	clone.id += "-cloned-" + i;
	editItem.parentNode.insertBefore(clone, editItem.nextSibling);
});

// Process #custombuttons-contextpopup-sub
const editIdSub = editId + "-sub";
var editItemSub = document.getElementById(editIdSub);
if(editItemSub) {
	var clone = editInTab.cloneNode(true);
	if(editItemSub.hasAttribute("observes"))
		clone.setAttribute("observes", editItemSub.getAttribute("observes"));
	else
		clone.removeAttribute("observes");
	clone.id += "-sub";
	editItemSub.parentNode.insertBefore(clone, editItemSub.nextSibling);
}

window.editCustomButtonInTab = function(btn, newTab) { // Should be global to work in cloned menus
	if(!btn)
		btn = custombuttons.popupNode;
	if(!btn)
		return;
	var btnId = btn.id;
	var link = custombuttons.makeButtonLink("edit", btnId);
	var cbService = "cbICustomButtonsService" in Components.interfaces
		? Components.classes["@xsms.nm.ru/custombuttons/cbservice;1"]
			.getService(Components.interfaces.cbICustomButtonsService)
		: Components.classes["@xsms.nm.ru/custombuttons/cbservice;1"] // Custom Buttons 0.0.5.9+
			.getService(Components.interfaces.nsISupports)
			.wrappedJSObject;
	var param = cbService.getButtonParameters(link);
	var editorUriFull = editorBaseUri
		+ "?window=" + cbService.getWindowId(document.documentURI)
		+ "&id=" + btnId;
	var editorUri = cbService.mode & 64 /*CB_MODE_SAVE_EDITOR_SIZE_SEPARATELY*/
		|| !Object.create // Firefox 3.6 and older
		? editorUriFull
		: editorBaseUri;

	// Search for already opened tab
	var rawParam = unwrap(param);
	var isSeaMonkey = "Services" in window && Services.appinfo.name == "SeaMonkey";
	var ws = Components.classes["@mozilla.org/appshell/window-mediator;1"]
		.getService(Components.interfaces.nsIWindowMediator)
		.getEnumerator(isSeaMonkey ? null : "navigator:browser");
	while(ws.hasMoreElements()) {
		let win = ws.getNext();
		if(isSeaMonkey && win.location.href != "chrome://navigator/content/navigator.xul")
			continue;
		let gBrowser = win.gBrowser;
		let tabs = gBrowser.tabs || gBrowser.tabContainer.childNodes;
		for(let i = 0, l = tabs.length; i < l; ++i) {
			let tab = tabs[i];
			if(tab == newTab)
				continue;
			let browser = tab.linkedBrowser;
			if(!browser)
				continue;
			let loc = browser.currentURI.spec;
			if(loc.substr(0, editorBaseUriLength) != editorBaseUri)
				continue;
			let isSameEditor = loc == editorUriFull
				|| tab.getAttribute(cbIdTabAttr) == btnId;
			let win = browser.contentWindow; // Will be null for unloaded tab
			if(!isSameEditor && win) {
				let rawWin = unwrap(win);
				let winParam = "arguments" in rawWin && rawWin.arguments.length
					? unwrap(rawWin.arguments[0])
					: rawWin.editor && rawWin.editor.param;
				isSameEditor = winParam && winParam.buttonLink == link;
			}
			if(isSameEditor) {
				gBrowser.selectedTab = tab;
				win && win.focus();
				newTab && setTimeout(function() {
					gBrowser.removeTab(newTab);
				}, 0);
				return;
			}
		}
	}

	// Or open new tab
	var tab = newTab;
	if(!tab) {
		tab = gBrowser.selectedTab = gBrowser.addTab(editorUri, {
			triggeringPrincipal: "Services" in window // Firefox 63+
				&& Services.scriptSecurityManager
				&& Services.scriptSecurityManager.getSystemPrincipal()
		});
		initSessionStore();
		tab.setAttribute(cbIdTabAttr, btn.id);
	}

	var browser = tab.linkedBrowser;
	browser.addEventListener("DOMContentLoaded", function load(e) {
		var doc = e.target;
		if(doc.location != editorUri)
			return;
		browser.removeEventListener(e.type, load, false);

		var win = doc.defaultView;
		win.arguments = [param];

		var iconLink = doc.createElementNS("http://www.w3.org/1999/xhtml", "link");
		iconLink.rel = "shortcut icon";
		//iconLink.href = "chrome://custombuttons-context/content/icons/default/custombuttonsEditor.ico";
		iconLink.href = getStdImage(rawParam.image);
		iconLink.style.display = "none";
		doc.documentElement.insertBefore(iconLink, doc.documentElement.firstChild);

		var alreadyAsked = false;
		function checkUnsaved(e) {
			if(alreadyAsked)
				return;
			var dlg = unwrap(doc).documentElement;
			if(
				"_fireButtonEvent" in dlg
					? !dlg._fireButtonEvent("cancel")
					: !dlg.cancelDialog()
			)
				e.preventDefault();
		}
		function onDialogCancel(e) {
			alreadyAsked = true;
			// win.setTimeout shouldn't fire while confirmation dialog from the same window are opened
			win.setTimeout(function() {
				alreadyAsked = false;
			}, 100);
		}
		function destroy(e) {
			win.removeEventListener("dialogcancel", onDialogCancel, false);
			win.removeEventListener("beforeunload", checkUnsaved, false);
			win.removeEventListener("unload", destroy, false);
		}
		win.addEventListener("dialogcancel", onDialogCancel, false);
		win.addEventListener("beforeunload", checkUnsaved, false);
		win.addEventListener("unload", destroy, false);
	}, false);
};
function unwrap(o) {
	return o.wrappedJSObject || o; // Firefox 3.6 and older
}
function getStdImage(iid) {
	if(/^custombuttons-stdicon-(\d)$/.test(iid)) switch(+RegExp.$1) {
		// chrome://custombuttons/skin/custombuttons.css
		// toolbarbutton[cb-stdicon="custombuttons-stdicon-*"] { ... }
		case 1: return "chrome://custombuttons/skin/button.png";
		case 2: return "chrome://custombuttons/skin/stdicons/rbutton.png";
		case 3: return "chrome://custombuttons/skin/stdicons/gbutton.png";
		case 4: return "chrome://custombuttons/skin/stdicons/bbutton.png";
	}
	return iid || "chrome://custombuttons/skin/button.png";
}

function initSessionStore() {
	initSessionStore = function() {};
	var ss = "nsISessionStore" in Components.interfaces
		? (
			Components.classes["@mozilla.org/browser/sessionstore;1"]
			|| Components.classes["@mozilla.org/suite/sessionstore;1"]
		).getService(Components.interfaces.nsISessionStore)
		: SessionStore; // Firefox 61+ https://bugzilla.mozilla.org/show_bug.cgi?id=1450559
	ss.persistTabAttribute(cbIdTabAttr);
}
function checkTab(tab) {
	var cbId = tab.getAttribute(cbIdTabAttr);
	if(!cbId)
		return;
	initSessionStore();
	let btn = document.getElementById(cbId);
	if(btn)
		editCustomButtonInTab(btn, tab);
}
const editorBaseUriLength = editorBaseUri.length;
// We can't use only SSTabRestoring: user can reload tab with editor
addEventListener("DOMContentLoaded", function(e) {
	var doc = e.target;
	if(doc.location.href.substr(0, editorBaseUriLength) != editorBaseUri)
		return;
	var tabs = gBrowser.tabs || gBrowser.tabContainer.childNodes;
	for(var i = 0, l = tabs.length; i < l; ++i) {
		let tab = tabs[i];
		let browser = tab.linkedBrowser;
		if(browser && browser.contentDocument == doc) {
			checkTab(tab);
			break;
		}
	}
}, true, document.getElementById("appcontent")); // Firefox 60+, gBrowser isn't a DOM node anymore 
checkTab(gBrowser.selectedTab);

function destructor(reason) {
	if(reason == "update" || reason == "delete") {
		Array.prototype.slice.call(document.getElementsByAttribute("cb_id", editInTabId)).forEach(function(btn) {
			btn.parentNode.removeChild(btn);
		});
		delete window.editCustomButtonInTab;
	}
}
if(
	typeof addDestructor == "function" // Custom Buttons 0.0.5.6pre4+
	&& addDestructor != ("addDestructor" in window && window.addDestructor)
)
	addDestructor(destructor, this);
else
	this.onDestroy = destructor;

вроде работает. но надо 2 раза повторить. чтобы открыть во вкладке, первый раз открывет пустое поле в /*Initialization Code*/
Есть ли возможность реананимировать спорную кнопку
скрытый текст

Выделить код

Код:

if(true) return; // Disabled by Disable Initialization button

// https://github.com/Infocatcher/Custom_Buttons/tree/master/CB_Source_Editor
// http://infocatcher.ucoz.net/js/cb/cbSourceEditor.js

// Source Editor (formerly Orion Editor) button for Custom Buttons
// (code for "initialization" section)

// (c) Infocatcher 2012-2019
// version 0.1.0a10 - 2019-12-25

var options = {
	cssInHelp: true,
	codeMirror: {
		lineNumbers: true,
		enableCodeFolding: true,
		showTrailingSpace: true,
		lineWrapping: true,
		autocomplete: true,
		fontSize: 12
	},
	orion: {
		lineNumbers: true
	}
};
// Also see devtools.editor.* preferences in about:config

const watcherId = "customButtonsSourceEditor_" + this.id;
var {Components} = window; // Prevent garbage collection in Firefox 3.6 and older
var storage = (function() {
	if(!("Services" in window)) // Firefox 3.6 and older
		return Application.storage;
	// Simple replacement for Application.storage
	// See https://bugzilla.mozilla.org/show_bug.cgi?id=1090880
	var global = Components.utils.getGlobalForObject(Components.utils);
	// Ensure, that we have global object (because window.Services may be overwritten)
	//var global = Components.utils.import("resource://gre/modules/Services.jsm", {});
	var ns = "_cbSourceEditorStorage";
	// Note: Firefox 57+ returns NonSyntacticVariablesObject w/o .Object property
	var storage = global[ns] || (global[ns] = Components.utils.getGlobalForObject(global).Object.create(null));
	return {
		get: function(key, defaultVal) {
			if(key in storage)
				return storage[key];
			return defaultVal;
		},
		set: function(key, val) {
			if(key === null)
				delete storage[key];
			else
				storage[key] = val;
		}
	};
})();
var watcher = storage.get(watcherId, null);
if(!watcher) {
	watcher = {
		REASON_STARTUP: 1,
		REASON_SHUTDOWN: 2,
		REASON_WINDOW_LOADED: 3,
		REASON_WINDOW_CLOSED: 4,

		get obs() {
			delete this.obs;
			return this.obs = Components.classes["@mozilla.org/observer-service;1"]
				.getService(Components.interfaces.nsIObserverService);
		},
		get ww() {
			delete this.ww;
			return this.ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
				.getService(Components.interfaces.nsIWindowWatcher);
		},
		get wm() {
			delete this.wm;
			return this.wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
				.getService(Components.interfaces.nsIWindowMediator);
		},
		get platformVersion() {
			delete this.platformVersion;
			return this.platformVersion = parseFloat(Services.appinfo.platformVersion);
		},
		get hasCodeMirror() {
			delete this.hasCodeMirror;
			return this.hasCodeMirror = Services.appinfo.name == "Pale Moon" //~ todo: test
				|| this.platformVersion >= 27;
		},
		init: function(reason) {
			if(!this.hasCodeMirror) {
				this.isBrowserWindow = function() {
					return false;
				};
			}
			this.obs.addObserver(this, "quit-application-granted", false);
			var ws = this.wm.getEnumerator(null);
			while(ws.hasMoreElements())
				this.initWindow(ws.getNext(), reason);
			this.ww.registerNotification(this);
		},
		destroy: function(reason) {
			this.obs.removeObserver(this, "quit-application-granted");
			var ws = this.wm.getEnumerator(null);
			while(ws.hasMoreElements())
				this.destroyWindow(ws.getNext(), reason);
			this.ww.unregisterNotification(this);
		},
		initWindow: function(window, reason, isFrame) {
			if(this.isBrowserWindow(window)) {
				this.initBrowserWindow(window, reason);
				return;
			}
			if(!this.isEditorWindow(window))
				return;
			_log("initWindow(): isFrame: " + isFrame);
			var document = window.document;
			if(isFrame)
				window.addEventListener("unload", this, false);

			Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
				.getService(Components.interfaces.mozIJSSubScriptLoader)
				.loadSubScript("chrome://global/content/globalOverlay.js", window);

			var isCodeMirror = false; 
			try { // See chrome://browser/content/devtools/scratchpad.js
				ChromeUtils.importESModule("resource://devtools/client/netmonitor/src/components/source-editor.jsm", window);
			}
			catch(e) {
				
				var g = ChromeUtils.importESModule("resource://devtools/shared/loader/Loader.sys.mjs")
				var require = (g.devtools || g).require;
				[
					"devtools/sourceeditor/editor",
					"devtools/client/sourceeditor/editor", // Firefox 44+
					"devtools/client/shared/sourceeditor/editor" // Firefox 68+
				].some(function(path) {
					try {
						return window.SourceEditor = require(path);
					}
					catch(e) {
					}
					return null;
				});
				isCodeMirror = true;
			}
			var SourceEditor = window.SourceEditor;

			if(this.platformVersion >= 73) {
				var psXUL = '<popupset id="sourceEditorPopupset">\
					<linkset>\
						<html:link rel="localization" href="toolkit/global/textActions.ftl" />\
					</linkset>\
					<menupopup id="sourceEditorContext"\
						onpopupshowing="popupHandler(event.target)"\
						oncommand="popupHandler(event.target)">\
\
						<menuitem id="menu_undo" data-l10n-id="text-action-undo" />\
						<menuitem id="menu_redo" data-l10n-id="text-action-redo" />\
						<menuseparator/>\
						<menuitem id="menu_cut" data-l10n-id="text-action-cut" />\
						<menuitem id="menu_copy" data-l10n-id="text-action-copy" />\
						<menuitem id="menu_paste" data-l10n-id="text-action-paste" />\
						<menuitem id="menu_delete" data-l10n-id="text-action-delete" />\
						<menuseparator/>\
						<menuitem id="menu_selectAll" data-l10n-id="text-action-select-all" />\
						<menuseparator/>\
						<menuitem id="menu_find" label="&findCmd.label;" accesskey="&findCmd.accesskey;" />\
						<menuitem id="menu_findAgain" label="&findAgainCmd.label;" accesskey="&findAgainCmd.accesskey;" />\
						<menuseparator/>\
						<menuitem id="se-menu-gotoLine" label="&gotoLineCmd.label;" accesskey="&gotoLineCmd.accesskey;" />\
					</menupopup>\
				</popupset>';
				var ps = window.MozXULElement.parseXULToFragment(psXUL, [
					"chrome://global/locale/editMenuOverlay.dtd",
					"chrome://devtools/locale/sourceeditor.dtd"
				]);
				if(!this.popupHandler) {
					var commands = {module: {}};
					ps.querySelectorAll("menuitem").forEach(function(menuitem) {
						commands[menuitem.id] = menuitem.id.replace(/^(se-)?menu./, "cmd_");
					});
					Services.scriptloader.loadSubScript(
						"resource://devtools/client/shared/sourceeditor/editor-commands-controller.js", commands
					);
					var createController = function(editor) {
						var res = editor.popupCmdController = commands.createController(editor);
						res.docShell = editor.container.contentWindow.docShell;
						return res;
					}
					var getObj = function(cmd, controller) {
						return controller.supportsCommand(cmd) ? controller: controller.docShell;
					}
					var setDisabled = function(menuitem) {
						var cmd = commands[menuitem.id];
						menuitem.disabled = !getObj(cmd, this).isCommandEnabled(cmd);
					}
					this.popupHandler = function(node) {
						var ed = node.ownerDocument.activeElement.contentWindow.editor;
						var controller = ed.popupCmdController || createController(ed);
						var cmd = commands[node.id];
						if(cmd) getObj(cmd, controller).doCommand(cmd);
						else node.menuitems.forEach(setDisabled, controller);
					}
				}
				var popup = ps.querySelector("menupopup");
				popup.menuitems = popup.querySelectorAll("menuitem");
				popup.popupHandler = this.popupHandler;

			} else {

				// See view-source:chrome://browser/content/devtools/scratchpad.xul
				// + view-source:chrome://browser/content/devtools/source-editor-overlay.xul
				var psXUL = (isCodeMirror
				? '<!DOCTYPE popupset [\
					<!ENTITY % editMenuStrings SYSTEM "chrome://global/locale/editMenuOverlay.dtd">\
					%editMenuStrings;\
					<!ENTITY % sourceEditorStrings SYSTEM "' + (
						Services.appinfo.name == "Pale Moon" || Services.appinfo.name == "Basilisk"
							? this.platformVersion >= 4.1
								? "chrome://devtools/locale/sourceeditor.dtd"
								: "chrome://global/locale/devtools/sourceeditor.dtd"
							: this.platformVersion >= 45
								? "chrome://devtools/locale/sourceeditor.dtd"
								: "chrome://browser/locale/devtools/sourceeditor.dtd"
					) + '">\
					%sourceEditorStrings;\
				]>\
				<popupset id="sourceEditorPopupset"\
					xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">\
					<menupopup id="sourceEditorContext"\
						onpopupshowing="goUpdateSourceEditorMenuItems()">\
						<menuitem id="menu_undo" label="&undoCmd.label;" accesskey="&undoCmd.accesskey;"\
							oncommand="goDoCommand(\'cmd_undo\')" />\
						<menuitem id="menu_redo" label="&redoCmd.label;" accesskey="&redoCmd.accesskey;"\
							oncommand="goDoCommand(\'cmd_redo\')" />\
						<menuseparator/>\
						<menuitem id="menu_cut" label="&cutCmd.label;" accesskey="&cutCmd.accesskey;"\
							oncommand="goDoCommand(\'cmd_cut\')" />\
						<menuitem id="menu_copy" label="&copyCmd.label;" accesskey="&copyCmd.accesskey;"\
							oncommand="goDoCommand(\'cmd_copy\')" />\
						<menuitem id="menu_paste" label="&pasteCmd.label;" accesskey="&pasteCmd.accesskey;"\
							oncommand="goDoCommand(\'cmd_paste\')" />\
						<menuitem id="menu_delete" label="&deleteCmd.label;" accesskey="&deleteCmd.accesskey;"\
							oncommand="goDoCommand(\'cmd_delete\')" />\
						<menuseparator/>\
						<menuitem id="menu_selectAll" label="&selectAllCmd.label;" accesskey="&selectAllCmd.accesskey;"\
							oncommand="goDoCommand(\'cmd_selectAll\')" />\
						<menuseparator/>\
						<menuitem id="menu_find" label="&findCmd.label;" accesskey="&findCmd.accesskey;" />\
						<menuitem id="menu_findAgain" label="&findAgainCmd.label;" accesskey="&findAgainCmd.accesskey;" />\
						<menuseparator/>\
						<menuitem id="se-menu-gotoLine"\
							label="&gotoLineCmd.label;"\
							accesskey="&gotoLineCmd.accesskey;"\
							key="key_gotoLine"\
							oncommand="goDoCommand(\'cmd_gotoLine\')"/>\
					</menupopup>\
				</popupset>'
				: '<popupset id="sourceEditorPopupset"\
					xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">\
					<menupopup id="sourceEditorContext"\
						onpopupshowing="goUpdateSourceEditorMenuItems()">\
						<menuitem id="se-menu-undo"/>\
						<menuitem id="se-menu-redo"/>\
						<menuseparator/>\
						<menuitem id="se-menu-cut"/>\
						<menuitem id="se-menu-copy"/>\
						<menuitem id="se-menu-paste"/>\
						<menuitem id="se-menu-delete"/>\
						<menuseparator/>\
						<menuitem id="se-menu-selectAll"/>\
						<menuseparator/>\
						<menuitem id="se-menu-find"/>\
						<menuitem id="se-menu-findAgain"/>\
						<menuseparator/>\
						<menuitem id="se-menu-gotoLine"/>\
					</menupopup>\
				</popupset>'
				).replace(/>\s+</g, "><");
	
				var ps = this.parseXULFromString(psXUL);
				// "Edit Custom Button in Tab" button, Firefox 71+
				if(isFrame && "parseFromSafeString" in window.DOMParser.prototype)
				ps = window.MozXULElement.parseXULToFragment(ps.outerHTML);
			}
			document.documentElement.appendChild(ps);

			window.setTimeout(function() {
				function appendNode(nodeName, id) {
					var node = document.createElementNS(xulns, nodeName);
					node.id = id;
					document.documentElement.appendChild(node);
				}
				appendNode("commandset", "editMenuCommands");
				appendNode("commandset", "sourceEditorCommands");
				appendNode("keyset", "sourceEditorKeys");
				appendNode("keyset", "editMenuKeys");

				this.loadOverlays(
					window,
					function done() {
						window.setTimeout(function() {
							var mp = document.getElementById("sourceEditorContext");
							if(mp.state == "closed")
								return;
							Array.prototype.forEach.call(
								mp.getElementsByAttribute("command", "*"),
								function(mi) {
									var cmd = mi.getAttribute("command");
									var controller = document.commandDispatcher
										.getControllerForCommand(cmd);
									if(controller && !controller.isCommandEnabled(cmd))
										mi.setAttribute("disabled", "true");
								}
							);
						}, 0);
						if(!isCodeMirror)
							return;
						// See view-source:chrome://browser/content/devtools/scratchpad.xul in Firefox 27.0a1
						window.goUpdateSourceEditorMenuItems = function() {
							goUpdateGlobalEditMenuItems();
							var commands = ["cmd_undo", "cmd_redo", "cmd_cut", "cmd_paste", "cmd_delete"];
							commands.forEach(goUpdateCommand);
						};
						var cmdsMap = {
							"se-menu-undo":   "cmd_undo",
							"se-menu-redo":   "cmd_redo",
							"se-menu-cut":    "cmd_cut",
							"se-menu-copy":   "cmd_copy",
							"se-menu-paste":  "cmd_paste",
							"se-menu-delete": "cmd_delete",
							__proto__: null
						};
						for(var id in cmdsMap) {
							var mi = document.getElementById(id);
							mi && mi.setAttribute("command", cmdsMap[id]);
						}
						// We can't use command="cmd_selectAll", menuitem will be wrongly disabled sometimes
						var enabledCmdsMap = {
							"se-menu-selectAll": "cmd_selectAll",
							"se-menu-findAgain": "cmd_findAgain",
							__proto__: null
						};
						for(var id in enabledCmdsMap) {
							var mi = document.getElementById(id);
							if(mi) {
								mi.removeAttribute("command");
								mi.removeAttribute("disabled");
								mi.setAttribute("oncommand", "goDoCommand('" + enabledCmdsMap[id] + "');");
							}
						}
						// Workaround: emulate keyboard shortcut
						var keyCmdsMap = {
							"menu_find":      { keyCode: KeyboardEvent.DOM_VK_F, charCode: "f".charCodeAt(0), ctrlKey: true },
							"menu_findAgain": { keyCode: KeyboardEvent.DOM_VK_G, charCode: "g".charCodeAt(0), ctrlKey: true },
							__proto__: null
						};
						var _key = function() {
							var e = this._keyData;
							var evt = document.createEvent("KeyboardEvent");
							evt.initKeyEvent(
								"keydown", true /*bubbles*/, true /*cancelable*/, window,
								e.ctrlKey || false, e.altKey || false, e.shiftKey || false, e.metaKey || false,
								e.keyCode || 0, e.charCode || 0
							);
							document.commandDispatcher.focusedElement.dispatchEvent(evt);
						};
						for(var id in keyCmdsMap) {
							var mi = document.getElementById(id);
							if(mi) {
								mi.removeAttribute("command");
								mi.removeAttribute("disabled");
								mi.setAttribute("oncommand", "this._key();");
								mi._keyData = keyCmdsMap[id];
								mi._key = _key;
							}
						}
						// Fix styles for autocomplete tooltip
						function css(uri) {
							document.insertBefore(document.createProcessingInstruction(
								"xml-stylesheet",
								'href="' + uri + '" type="text/css"'
							), document.documentElement);
						}
						css("resource://devtools/client/themes/variables.css");
						css("resource://devtools/client/themes/common.css");
						css("chrome://devtools/skin/tooltips.css");
						if(this.platformVersion >= 68) window.setTimeout(function fixSelection() {
							var sheets = document.styleSheets;
							for(var i = sheets.length - 1; i >= 0; --i) {
								var sheet = sheets[i];
								if(sheet.href != "resource://devtools/client/themes/common.css")
									continue;
								try {
									var rules = sheet.cssRules;
								}
								catch(e) {
									// InvalidAccessError:
									// A parameter or an operation is not supported by the underlying object
									return window.setTimeout(fixSelection, 10);
								}
								for(var j = 0, len = rules.length; j < len; ++j)
									if(rules[j].selectorText == "::selection")
										return !sheet.deleteRule(j);
								break;
							}
							return false;
						}, 10);
					}.bind(this),
					["chrome://global/content/editMenuOverlay.xul", function check(window) {
						return window.document.getElementById("editMenuCommands").hasChildNodes();
					}],
					["chrome://browser/content/devtools/source-editor-overlay.xul", function check(window) {
						return window.document.getElementById("sourceEditorCommands").hasChildNodes();
					}]
				);
			}.bind(this), 500); // We should wait to not break other extensions with document.loadOverlay()

			var tabs = document.getElementById("custombuttons-editbutton-tabbox");
			var selectedPanel = tabs.selectedPanel;
			Array.prototype.slice.call(document.getElementsByTagName("cbeditor")).forEach(function(cbEditor) {
				if("__sourceEditor" in cbEditor)
					return;
				var code = cbEditor.value;
				var isCSS = options.cssInHelp && cbEditor.id == "help";
				if(isCodeMirror) {
					var opts = {
						mode: isCSS
							? SourceEditor.modes.css
							: SourceEditor.modes.js,
						value: code,
						lineNumbers: true,
						enableCodeFolding: true,
						showTrailingSpace: true,
						autocomplete: true,
						contextMenu: "sourceEditorContext"
					};
					var optsOvr = options.codeMirror;
					for(var opt in optsOvr) if(optsOvr.hasOwnProperty(opt))
						opts[opt] = optsOvr[opt];
					var se = new SourceEditor(opts);
					if("codeMirror" in se) window.setTimeout(function() {
						if("insertCommandsController" in se)
							se.insertCommandsController(); // Pale Moon and Basilisk
						else
							this.insertCommandsController(se);
					}.bind(this), 200);
				}
				else {
					var se = new SourceEditor();
				}
				se.__isCodeMirror = isCodeMirror;
				var seElt = document.createElementNS(xulns, "hbox");
				if(cbEditor.id)
					seElt.id = "sourceEditor-" + cbEditor.id;
				seElt.className = "sourceEditor";
				seElt.setAttribute("flex", 1);
				seElt.__sourceEditor = se;
				cbEditor.parentNode.insertBefore(seElt, cbEditor);
				//cbEditor.setAttribute("hidden", "true");
				cbEditor.setAttribute("collapsed", "true");
				cbEditor.parentNode.appendChild(cbEditor);
				cbEditor.__sourceEditor = se;
				cbEditor.__sourceEditorElt = seElt;
				cbEditor.__defineGetter__("value", function() {
					if("__sourceEditor" in this) {
						var se = this.__sourceEditor;
						if(!se.__initialized)
							return se.__value;
						return se.getText().replace(/\r\n?|\n\r?/g, "\n");
					}
					return this.textbox.value;
				});
				cbEditor.__defineSetter__("value", function(v) {
					if("__sourceEditor" in this) {
						var se = this.__sourceEditor;
						if(!se.__initialized) {
							var _this = this;
							se.__onLoadCallbacks.push(function() {
								_this.value = v;
							});
							return se.__value = v;
						}
						return se.setText(v.replace(/\r\n?|\n\r?/g, "\n"));
					}
					return this.textbox.value = v;
				});
				cbEditor.selectLine = function(lineNumber) {
					if("__sourceEditor" in this) {
						var se = this.__sourceEditor;
						if(!se.__initialized) {
							var _this = this, args = arguments;
							se.__onLoadCallbacks.push(function() {
								_this.selectLine.apply(_this, args);
							});
							return undefined;
						}
						if(se.__isCodeMirror) {
							//se.focus();
							//se.setCursor({ line: lineNumber - 1, ch: 0 });
							//~ todo: optimize
							var val = this.value;
							var lines = val.split("\n");
							var line = Math.min(lineNumber - 1, lines.length);
							var ch = lines[line].length;
							se.focus();
							return se.setSelection({ line: line, ch: 0 }, { line: line, ch: ch });
						}
						else {
							var selStart = se.getLineStart(lineNumber - 1);
							var selEnd = se.getLineEnd(lineNumber - 1, false);
							se.focus();
							return se.setSelection(selStart, selEnd);
						}
					}
					return this.__proto__.selectLine.apply(this, arguments);
				};

				// For edit_button() from chrome://custombuttons/content/editExternal.js
				seElt.__cbEditor = cbEditor;
				seElt.__defineGetter__("localName", function() {
					return "cbeditor";
				});
				seElt.__defineGetter__("value", function() {
					return this.__cbEditor.value;
				});
				seElt.__defineSetter__("value", function(val) {
					this.__cbEditor.value = val;
				});

				se.__initialized = false;
				se.__onLoadCallbacks = [];
				se.__value = code;
				var onTextChanged = se.__onTextChanged = function() {
					window.editor.changed = true;
				};
				var isLoaded = reason == this.REASON_WINDOW_LOADED;
				function done() {
					se.__initialized = true;
					se.__onLoadCallbacks.forEach(function(fn) {
						try {
							fn();
						}
						catch(e) {
							Components.utils.reportError(e);
						}
					});
					delete se.__onLoadCallbacks;
					delete se.__value;
				}
				if(isCodeMirror) {
					se.appendTo(seElt).then(function() {
						try {
							se.setupAutoCompletion();
						}
						catch(e) {
							Components.utils.reportError(e);
						}
						if("setFontSize" in se) try {
							se.setFontSize(options.codeMirror.fontSize);
						}
						catch(e) {
							Components.utils.reportError(e);
						}
						window.setTimeout(function() {
							window.editor.changed = false; // Strange...
							window.setTimeout(function() { // Workaround for unexpected onTextChanged() calls
								if(window.editor.changed && cbEditor.value == code)
									window.editor.changed = false;
							}, 100);
							se.on("change", onTextChanged);
							if(isLoaded) {
								if("clearHistory" in se)
									se.clearHistory();
								else {
									var seGlobal = Components.utils.getGlobalForObject(SourceEditor.prototype);
									// Note: this is resource://app/modules/devtools/gDevTools.jsm scope in Firefox 34+
									var cm = seGlobal.editors.get(se);
									cm.clearHistory();
								}
							}
						}, isFrame ? 50 : 15); // Oh, magic delays...
						done();

						// See resource:///modules/devtools/sourceeditor/editor.js
						// doc.defaultView.controllers.insertControllerAt(0, controller(this, doc.defaultView));
						var controllers = window.controllers; // nsIControllers
						var controller = se.__cmdController = controllers.getControllerAt(0);
						if("__cmdControllers" in tabs)
							tabs.__cmdControllers.push(controller);
						else {
							tabs.__cmdControllers = [controller];
							var onSelect = tabs.__onSelect = function() {
								var seElt = tabs.selectedPanel;
								if(!seElt || !("__sourceEditor" in seElt))
									return;
								var se = seElt.__sourceEditor;
								var curController = se.__cmdController;
								tabs.__cmdControllers.forEach(function(controller) {
									try {
										if(controller == curController)
											controllers.insertControllerAt(0, controller);
										else
											controllers.removeController(controller);
									}
									catch(e) {
									}
								});
							};
							tabs.addEventListener("select", onSelect, false);
							window.setTimeout(onSelect, 0); // Activate controller from selected tab
						}
					});
				}
				else {
					var opts = {
						mode: isCSS
							? SourceEditor.MODES.CSS
							: SourceEditor.MODES.JAVASCRIPT,
						showLineNumbers: true,
						initialText: code,
						placeholderText: code, // For backward compatibility
						contextMenu: "sourceEditorContext"
					};
					var optsOvr = options.orion;
					for(var opt in optsOvr) if(optsOvr.hasOwnProperty(opt))
						opts[opt] = optsOvr[opt];
					se.init(seElt, opts, function callback() {
						done();
						isLoaded && se.resetUndo && se.resetUndo();
						se.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onTextChanged);

						// Hack to use selected editor
						var controller = se.ui._controller;
						controller.__defineGetter__("_editor", function() {
							var seElt = tabs.selectedPanel;
							var se = seElt && seElt.__sourceEditor
								|| document.getElementsByTagName("cbeditor")[0].__sourceEditor;
							return se;
						});
						controller.__defineSetter__("_editor", function() {});
					});
				}
			}, this);
			// Trick to select correct tab (especially if was selected "Button settings" tab)
			tabs.tabs.advanceSelectedTab(1, true);
			tabs.tabs.advanceSelectedTab(-1, true);

			var origExecCmd = window.editor.execute_oncommand_code;
			window.editor.execute_oncommand_code = function() {
				var cd = document.commandDispatcher;
				var cdFake = {
					__proto__: cd,
					get focusedElement() {
						var selectedTab = tabs.selectedTab;
						if(selectedTab && selectedTab.id == "code-tab")
							return document.getElementById("code").textbox.inputField;
						return cd.focusedElement;
					}
				};
				document.__defineGetter__("commandDispatcher", function() {
					return cdFake;
				});
				try {
					var ret = origExecCmd.apply(this, arguments);
				}
				catch(e) {
					Components.utils.reportError(e);
				}
				// document.hasOwnProperty("commandDispatcher") == false, so we cat just delete our fake property
				delete document.commandDispatcher;
				return ret;
			};

			window.addEventListener("load", function ensureObserversAdded() {
				window.removeEventListener("load", ensureObserversAdded, false);
				window.setTimeout(function() { window.editor.removeObservers(); }, 0);
				window.setTimeout(function() { window.editor.addObservers();    }, 0);
			}, false);
			// Fix for Ctrl+S hotkey (catched by CodeMirror)
			var hke = this.handleKeyEvent;
			window.addEventListener("keydown",  hke, true);
			window.addEventListener("keypress", hke, true);
			window.addEventListener("keyup",    hke, true);
		},
		insertCommandsController: function(se) {
			this.insertCommandsController = insertCommandsController;
			return insertCommandsController(se);
			// devtools/client/sourceeditor/editor-commands-controller in Pale Moon/Basilisk
			function createController(ed) {
				return {
					supportsCommand: function (cmd) {
						switch (cmd) {
							case "cmd_find":
							case "cmd_findAgain":
							case "cmd_gotoLine":
							case "cmd_undo":
							case "cmd_redo":
							case "cmd_delete":
							case "cmd_selectAll":
								return true;
						}

						return false;
					},

					isCommandEnabled: function (cmd) {
						let cm = ed.codeMirror;

						switch (cmd) {
							case "cmd_find":
							case "cmd_gotoLine":
							case "cmd_selectAll":
								return true;
							case "cmd_findAgain":
								return cm.state.search != null && cm.state.search.query != null;
							case "cmd_undo":
								return ed.canUndo();
							case "cmd_redo":
								return ed.canRedo();
							case "cmd_delete":
								return ed.somethingSelected();
						}

						return false;
					},

					doCommand: function (cmd) {
						let cm = ed.codeMirror;

						let map = {
							"cmd_selectAll": "selectAll",
							"cmd_find": "find",
							"cmd_undo": "undo",
							"cmd_redo": "redo",
							"cmd_delete": "delCharAfter",
							"cmd_findAgain": "findNext"
						};

						if (map[cmd]) {
							cm.execCommand(map[cmd]);
							return;
						}

						if (cmd == "cmd_gotoLine") {
							ed.jumpToLine();
						}
					},

					onEvent: function () {}
				};
			}
			function insertCommandsController(sourceEditor) {
				let input = sourceEditor.codeMirror.getInputField();
				let controller = createController(sourceEditor);
				input.controllers.insertControllerAt(0, controller);
			}
		},
		destroyWindow: function(window, reason, isFrame) {
			if(reason == this.REASON_WINDOW_CLOSED)
				window.removeEventListener(this.loadEvent, this, false); // Window can be closed before DOMContentLoaded
			if(this.isBrowserWindow(window)) {
				this.destroyBrowserWindow(window, reason);
				return;
			}
			if(!this.isEditorWindow(window) || !("SourceEditor" in window))
				return;
			_log("destroyWindow(): isFrame: " + isFrame);
			var document = window.document;
			if(isFrame)
				window.removeEventListener("unload", this, false);

			var tabs = document.getElementById("custombuttons-editbutton-tabbox");
			if("__onSelect" in tabs) {
				tabs.removeEventListener("select", tabs.__onSelect, false);
				delete tabs.__onSelect;
				delete tabs.__cmdControllers;
			}

			Array.prototype.slice.call(document.getElementsByTagName("cbeditor")).forEach(function(cbEditor) {
				if(!("__sourceEditor" in cbEditor))
					return;
				var se = cbEditor.__sourceEditor;
				var isCodeMirror = se.__isCodeMirror;
				if(isCodeMirror)
					se.off("change", se.__onTextChanged);
				else
					se.removeEventListener(window.SourceEditor.EVENTS.TEXT_CHANGED, se.__onTextChanged);
				delete se.__onTextChanged;
				if(reason == this.REASON_SHUTDOWN) {
					var val = cbEditor.value;
					delete cbEditor.value;
					delete cbEditor.selectLine;

					var seElt = cbEditor.__sourceEditorElt;
					seElt.parentNode.insertBefore(cbEditor, seElt);
					seElt.parentNode.removeChild(seElt);
					delete cbEditor.__sourceEditorElt;
					delete cbEditor.__sourceEditor;
					delete seElt.__sourceEditor;
					delete seElt.__cbEditor;

					cbEditor.value = val;
					window.setTimeout(function() {
						cbEditor.removeAttribute("collapsed");
					}, 0);
				}
				se.destroy();
				if("__cmdController" in se) {
					try {
						window.controllers.removeController(se.__cmdController);
					}
					catch(e) {
					}
					delete se.__cmdController;
				}
			}, this);

			if(reason == this.REASON_SHUTDOWN) {
				delete window.editor.execute_oncommand_code;
				[
					"sourceEditorPopupset",
					"editMenuCommands",
					"sourceEditorCommands",
					"sourceEditorKeys",
					"editMenuKeys"
				].forEach(function(id) {
					var node = document.getElementById(id);
					node && node.parentNode.removeChild(node);
				});
				[
					// chrome://global/content/globalOverlay.js
					"closeWindow", "canQuitApplication", "goQuitApplication", "goUpdateCommand", "goDoCommand",
					"goSetCommandEnabled", "goSetMenuValue", "goSetAccessKey", "goOnEvent", "visitLink",
					"setTooltipText", "NS_ASSERT",
					// chrome://global/content/editMenuOverlay.xul => view-source:chrome://global/content/editMenuOverlay.js
					"goUpdateGlobalEditMenuItems", "goUpdateUndoEditMenuItems", "goUpdatePasteMenuItems"
				].forEach(function(p) {
					delete window[p];
				});
				for(var child = document.documentElement; child = child.previousSibling; ) {
					if(
						child.nodeType == child.PROCESSING_INSTRUCTION_NODE
						&& child.data.indexOf("://devtools/") != -1
					) {
						setTimeout(function(child) {
							child.parentNode.removeChild(child);
						}, 0, child);
					}
				}
				delete window.SourceEditor;
			}
			var hke = this.handleKeyEvent;
			window.removeEventListener("keydown",  hke, true);
			window.removeEventListener("keypress", hke, true);
			window.removeEventListener("keyup",    hke, true);
			//~ todo: we have one not removed controller!
			//LOG("getControllerCount(): " + window.controllers.getControllerCount());
		},
		initBrowserWindow: function(window, reason) {
			_log("initBrowserWindow()");
			window.addEventListener("DOMContentLoaded", this, false);
			Array.prototype.forEach.call(window.frames, function(frame) {
				this.initWindow(frame, reason, true);
			}, this);
		},
		destroyBrowserWindow: function(window, reason) {
			_log("destroyBrowserWindow()");
			window.removeEventListener("DOMContentLoaded", this, false);
			Array.prototype.forEach.call(window.frames, function(frame) {
				this.destroyWindow(frame, reason, true);
			}, this);
		},
		isEditorWindow: function(window) {
			return window.location.href.substr(0, 41) == "chrome://custombuttons/content/editor.xul";
		},
		isBrowserWindow: function(window) {
			var loc = window.location.href;
			return loc == "chrome://browser/content/browser.xul"
				|| loc == "chrome://browser/content/browser.xhtml" // Firefox 69+
				|| loc == "chrome://navigator/content/navigator.xul";
		},
		get loadEvent() { // "DOMContentLoaded" -> initWindow() may hang editor window (and browser)
			delete this.loadEvent;
			return this.loadEvent = this.platformVersion >= 73 ? "load" : "DOMContentLoaded";
		},
		observe: function(subject, topic, data) {
			if(topic == "quit-application-granted")
				this.destroy();
			else if(topic == "domwindowopened")
				subject.addEventListener(this.loadEvent, this, false);
			else if(topic == "domwindowclosed")
				this.destroyWindow(subject, this.REASON_WINDOW_CLOSED);
		},
		handleEvent: function(e) {
			switch(e.type) {
				case "DOMContentLoaded":
				case "load":
					//var window = e.currentTarget;
					var window = e.target.defaultView || e.target;
					window.removeEventListener(e.type, this, false);
					var isFrame = window != e.currentTarget;
					this.initWindow(window, this.REASON_WINDOW_LOADED, isFrame);
				break;
				case "unload":
					//var window = e.currentTarget;
					var window = e.target.defaultView || e.target;
					window.removeEventListener(e.type, this, false);
					this.destroyWindow(window, this.REASON_WINDOW_CLOSED, true);
			}
		},
		handleKeyEvent: function(e) {
			if(
				(e.keyCode == e.DOM_VK_S || String.fromCharCode(e.charCode).toUpperCase() == "S")
				&& e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey
			) {
				e.preventDefault();
				e.stopPropagation();
				if(e.type == "keydown") {
					var window = e.currentTarget;
					window.editor.updateButton();
				}
			}
		},
		loadOverlays: function() {
			this.runGenerator(this.loadOverlaysGen, this, arguments);
		},

		get loadOverlaysGen() {
			var fn = this._loadOverlaysGen.toString()
				.replace(/__yield/g, "yield");
			try {
				new Function("function test() { yield 0; }");
			}
			catch(e) { // Firefox 58+: SyntaxError: yield expression is only valid in generators
				fn = fn.replace("function", "function*"); // Firefox 26+
			}
			delete this.loadOverlaysGen;
			return this.loadOverlaysGen = eval("(" + fn + ")");
		},
		_loadOverlaysGen: function loadOverlaysGen(window, callback/*, overlayData1, ...*/) {
			var gen = loadOverlaysGen.__generator;
			for(var i = 2, l = arguments.length; i < l; ++i) {
				var overlayData = arguments[i];
				this.loadOverlay(window, overlayData[0], overlayData[1], function() {
					gen.next();
				});
				__yield(0);
			}
			callback();
			__yield(0);
		},
		loadOverlay: function(window, uri, check, callback) {
			var document = window.document;
			var stopWait = Date.now() + 4500;
			window.setTimeout(function load() {
				_log("loadOverlay(): " + uri);
				var tryAgain = Date.now() + 800;
				try {
					document.loadOverlay(uri, null);
				}
				catch(e) {
					window.setTimeout(callback, 0);
					return;
				}
				window.setTimeout(function ensureLoaded() {
					if(check(window))
						window.setTimeout(callback, 0);
					else if(Date.now() > stopWait)
						return;
					else if(Date.now() > tryAgain)
						window.setTimeout(load, 0);
					else
						window.setTimeout(ensureLoaded, 50);
				}, 50);
			}, 0);
		},
		runGenerator: function(genFunc, context, args) {
			var gen = genFunc.apply(context, args);
			genFunc.__generator = gen;
			gen.next();
		},
		parseXULFromString: function(xul) {
			xul = xul.replace(/>\s+</g, "><");
			try {
				return new DOMParser().parseFromString(xul, "application/xml").documentElement;
			}
			catch(e) {
				// See http://custombuttons.sourceforge.net/forum/viewtopic.php?f=5&t=3720
				// + https://forum.mozilla-russia.org/viewtopic.php?pid=732243#p732243
				var dummy = document.createElement("dummy");
				dummy.innerHTML = xul.trimLeft();
				return dummy.firstChild;
			}
		}
	};
	storage.set(watcherId, watcher);
	setTimeout(function() {
		watcher.init(watcher.REASON_STARTUP);
	}, 50);
}
function destructor(reason) {
	if(reason == "update" || reason == "delete") {
		watcher.destroy(watcher.REASON_SHUTDOWN);
		storage.set(watcherId, null);
	}
}
if(
	typeof addDestructor == "function" // Custom Buttons 0.0.5.6pre4+
	&& addDestructor != ("addDestructor" in window && window.addDestructor)
)
	addDestructor(destructor, this);
else
	this.onDestroy = destructor;

function ts() {
	var d = new Date();
	var ms = d.getMilliseconds();
	return d.toTimeString().replace(/^.*\d+:(\d+:\d+).*$/, "$1") + ":" + "000".substr(("" + ms).length) + ms + " ";
}
function _log(s) {
	Services.console.logStringMessage("[Custom Buttons :: Source Editor] " + ts() + s);
}

Отредактировано Andrey_Krropotkin (20-03-2025 22:31:24)

Отсутствует

 

№1728122-03-2025 10:36:29

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

Re: Custom Buttons

green25 пишет

Перестало работать в 115 SessionStore.jsm -это ? Менял не помогло

Я ничего не понял.
Что оно делало, при чём здесь SessionStore,
и почему jsm, что менял, и чему не помогло.


Вообще-то, топик "widget-first-paint" — он для top-level окон.
А в 115 это добро открывается во внутриоконном диаложке.
Так что, здесь больше подходит листенер.


И что там за cancel
Когда-то давно, метод sanitize() возвращал логическое значение,
true если случилась ошибка, не при самой очистке, а при исполнении именно этой функции.
А в 115 он ничего не возвращает.


Если нужно знать, не свалился ли код в блок catch {}
то можно попробовать проверять e.defaultPrevented

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

Выделить код

Код:

document.getElementById("window-modal-dialog").addEventListener("dialogopen", e => {

	var win = e.target.querySelector("browser.dialogFrame").contentWindow;

	var sd = win.gSanitizePromptDialog, {sanitize} = sd;
	sd.sanitize = e => {

		sanitize.call(sd, e);
		alert(`Catch${e.defaultPrevented ? " not" : ""} happens.`);
	}

}, {once: true});

Sanitizer.showUI(window);

"version": "0.0.7.0.0.35",      (Обзор...0) не работает ?

Поставил 0.0.7.0.0.35 в 115.
У меня кнопка «Обзор… (O)» работает.


Andrey_Krropotkin пишет

Нужна кнопка переключения между старой и новой.

Берёшь любую кнопку, которая
переключает какую-нибудь логическую настройку,
и приспосабливаешь под настройку "sidebar.revamp"

надо 2 раза повторить. чтобы открыть во вкладке, первый раз открывет пустое поле в /*Initialization Code*/

Ну так всё, нет больше SessionStore.persistTabAttribute()
Можно попробовать переделать на SessionStore.{g, s}etCustomTabValue()

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

Выделить код

Код:

/*
				|| tab.getAttribute(cbIdTabAttr) == btnId;
*/
				|| SessionStore.getCustomTabValue(tab, cbIdTabAttr) == btnId;

.....

/*
		initSessionStore();
		tab.setAttribute(cbIdTabAttr, btn.id);
*/
		SessionStore.setCustomTabValue(tab, cbIdTabAttr, btn.id);

.....

/*
	var cbId = tab.getAttribute(cbIdTabAttr);
	if(!cbId)
		return;
	initSessionStore();
*/
	var cbId = SessionStore.getCustomTabValue(tab, cbIdTabAttr);
	if(!cbId)
		return;


И ещё некоторые вещи хорошо бы подлечить.
nsIFaviconService подпортили, и он ругается от добавления <link>'а.
Лучше заменить просто на вызов gBrowser.setIcon()
Машинерия табских превьюшек хочет, чтобы у документа было body,
а его здесь нет, надо что-то подсунуть.
И, при закрытии вкладки, BrowserElementParent засоряет консоль своей ошибкой,
причём, совершенно неуместной. Вобщем, как-то так
скрытый текст

Выделить код

Код:

/*
		var iconLink = doc.createElementNS("http://www.w3.org/1999/xhtml", "link");
		iconLink.rel = "shortcut icon";
		//iconLink.href = "chrome://custombuttons-context/content/icons/default/custombuttonsEditor.ico";
		iconLink.href = getStdImage(rawParam.image);
		iconLink.style.display = "none";
		doc.documentElement.insertBefore(iconLink, doc.documentElement.firstChild);
*/
		gBrowser.setIcon(tab, getStdImage(rawParam.image), null, document.nodePrincipal);
		Object.defineProperty(doc, "body", {configurable: true, enumerable: true, value: doc.documentElement});
		this.browsingContext.currentWindowGlobal.getActor("BrowserElement").receiveMessage = function() {};

Есть ли возможность реананимировать спорную кнопку

А сам-то как думаешь? Как по мне, так страшно даже приступить.
Для начала, нужно XUL <popupset>'а подсовременить.
Добавить ещё <link> локализации, и оставшиеся три менюитема перевести на data-l10n-id
То есть, примерно так

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

Выделить код

Код:

//
				var psXUL = '<popupset id="sourceEditorPopupset">\
					<linkset>\
						<html:link rel="localization" href="toolkit/global/textActions.ftl" />\
						<html:link rel="localization" href="devtools/client/styleeditor.ftl" />\
					</linkset>\
					<menupopup id="sourceEditorContext"\
						onpopupshowing="popupHandler(event.target)"\
						oncommand="popupHandler(event.target)">\
\
						<menuitem id="menu_undo" data-l10n-id="text-action-undo" />\
						<menuitem id="menu_redo" data-l10n-id="text-action-redo" />\
						<menuseparator/>\
						<menuitem id="menu_cut" data-l10n-id="text-action-cut" />\
						<menuitem id="menu_copy" data-l10n-id="text-action-copy" />\
						<menuitem id="menu_paste" data-l10n-id="text-action-paste" />\
						<menuitem id="menu_delete" data-l10n-id="text-action-delete" />\
						<menuseparator/>\
						<menuitem id="menu_selectAll" data-l10n-id="text-action-select-all" />\
						<menuseparator/>\
						<menuitem id="menu_find" data-l10n-id="styleeditor-find" />\
						<menuitem id="menu_findAgain" data-l10n-id="styleeditor-find-again" />\
						<menuseparator/>\
						<menuitem id="se-menu-gotoLine" data-l10n-id="styleeditor-go-to-line" />\
					</menupopup>\
				</popupset>';


Ну, и дальше, где parseXULToFragment() можно убрать второй аргумент (массив .dtd'шек).


И, чуть CSS'а подсадить, а то, как минимум, <iframe> сам занимать всё место не хочет.
Где-то в методе initWindow(), например, после var document = window.document;

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

Выделить код

Код:

//
			var sheet = new window.CSSStyleSheet();
			sheet.replaceSync("iframe{flex-grow:1!important;border:none!important}.tab-middle{outline:none!important}");
			document.adoptedStyleSheets.push(sheet);


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

Отсутствует

 

№1728222-03-2025 11:19:18

manuk
Участник
 
Группа: Members
Зарегистрирован: 17-10-2010
Сообщений: 309
UA: Firefox 135.0

Re: Custom Buttons

Dumby, приветствую. Заметил, что кнопка:

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

Выделить код

Код:

(popup => {
	var id = "cswem-menugroup";
	var mid = "_5dd73bb9-e728-4d1e-990b-c77d8e03670f_-menuitem-_root_menu";
	var css = `
		#${id} {
			padding-left: 30px;

			display: grid;
			grid-template-columns: repeat(auto-fill, 32px);
			grid-auto-rows: 26px;
		}
		#${id} > menuitem {
			-moz-box-pack: center;
		}
		#${mid},
		#${id}:empty,
		#context-searchselect,
		#context-keywordfield,
		#${id} > menuitem > :not(.menu-iconic-left) {
			display: none;
		}
		/*
		#${id} > menuitem > .menu-iconic-left > .menu-iconic-icon {
			margin-inline: 2px -3px;
		}
		*/

	`.replace(/;$/gm, " !important;");
	var url = "data:text/css," + encodeURIComponent(css), type = windowUtils.USER_SHEET;
	windowUtils.loadSheetUsingURIString(url, type);

	var menugroup = document.createXULElement("menugroup");
	menugroup.id = id;
	menugroup.hidden = true;

	var find = info => info.type == "command";
	menugroup.setAttribute("oncommand", "handleCommand(event);");
	menugroup.handleCommand = e => {
		var target = e.target.linkedMenuitem;
		var {button, ctrlKey, shiftKey, altKey, metaKey} = e;
		Services.els.getListenerInfoFor(target).find(find).listenerObject({
			button, target, currentTarget: target,
			ctrlKey, shiftKey, altKey, metaKey
		});
	}
	document.getElementById("context-searchselect").after(menugroup);

	var kwf = document.getElementById("context-keywordfield");
	Object.defineProperty(kwf, "hidden", {
		configurable: true, enumerable: true, get: () => true, set() {}
	});
	addEventListener("popuphidden", e => {
		if (menugroup.firstChild && e.target == popup) menugroup.textContent = "";
	}, false, popup);

	var fillMenugroup = menu => {
		var p = menu.querySelector(":scope > menupopup");
		for(var menuitem of menu.getElementsByTagName("menuitem")) {

			var m = document.createXULElement("menuitem");
			m.className = "menuitem-iconic";
			m.setAttribute("image", menuitem.getAttribute("image"));

			var tt = menuitem.getAttribute("label");
			if (menuitem.closest("menupopup") != p)
				tt = menuitem.closest("menu").getAttribute("label") + "\n" + tt;
			m.setAttribute("tooltiptext", tt);

			m.linkedMenuitem = menuitem;
			menugroup.append(m);
		}
		var lc = menugroup.lastChild;
		menugroup.style.setProperty(
			"height", (lc.screenY + lc.scrollHeight - menugroup.screenY) + "px", "important"
		);
	}
	var mo = new MutationObserver(muts => {
		for(var mut of muts) for(var node of mut.addedNodes) 
			if (node.id == mid) return fillMenugroup(node);
	});
	mo.observe(popup, {childList: true});
	addDestructor(() => {
		mo.disconnect();
		delete kwf.hidden;
		menugroup.remove();
		windowUtils.removeSheetUsingURIString(url, type);
	});
})(document.getElementById("contentAreaContextMenu"));


начала странно себя вести. Или так всегда было? Первый раз при выделении отображает нормально. Если кликнуть и перейти, а потом вернуться, выделить другой текст, то без перезагрузки страницы только иконка гугла. Некритично, но всё-таки. FF135.
35006081.jpg

Отредактировано manuk (22-03-2025 11:42:23)

Отсутствует

 

№1728322-03-2025 12:07:19

Andrey_Krropotkin
Участник
 
Группа: Members
Зарегистрирован: 11-11-2011
Сообщений: 491
UA: Firefox 136.0

Re: Custom Buttons

Dumby спасибо, все работает

Отсутствует

 

№1728422-03-2025 14:24:01

T0PMØ3iLLA
Участник
 
Группа: Members
Зарегистрирован: 18-09-2017
Сообщений: 28
UA: Firefox 91.0

Re: Custom Buttons

Так-с… версия 0.0.7.0.0.11 перестала работать (истекли сертификаты?)… накатываю из другого профиля версию 0.0.7.0.0.16 — заработало (надолго ли?), но кнопка быстрого переключения about:config параметров слетела/съехала и перестала фурычить (c 2020 года не было нужды обновлять её).
Проверяю 0.0.7.0.0.31 — ну, обновило, кнопка так и остались "поехавшей"… И уже тот код кнопки, что был давно адаптирован под 0.0.7.0.0.16 уже не работает…
Но забавно то, что само расширение CustomButtons работает. Проблема осталась только в кнопках (которые теперь больше не работают)…
Вопрос, будет ли он ещё поддерживаться старыми версиями [firefox] от 60-ых до 91esr (чтобы знать, стоит ли возиться с Quick toggle about:config preferences)?

Отредактировано T0PMØ3iLLA (22-03-2025 18:04:46)

Отсутствует

 

№1728522-03-2025 15:54:30

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 44
UA: unknown 0.0

Re: Custom Buttons

Dumby
Не фига не понял...
Что здесь исправить ?

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

Выделить код

Код:

if(event.button == 2 && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey){
 

var cancel = true;
Services.obs.addObserver(function wfp(win, topic) {
	Services.obs.removeObserver(wfp, topic);
	var sd = win.gSanitizePromptDialog, {sanitize} = sd;
	sd.sanitize = e => cancel = sanitize.call(sd, e);
}, "widget-first-paint");


Sanitizer.showUI(window);



if (cancel) return;

На форуме

 

№1728622-03-2025 16:45:09

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 44
UA: unknown 0.0

Re: Custom Buttons

Andrey_Krropotkin
Это ваше ?Как аввтопопуп убрать ? Рарку с закладками открываю и при наваждении мыши и это открывается..

Выделить код

Код:

// http://infocatcher.ucoz.net/js/cb/toggleRestartlessAddons.js
// https://forum.mozilla-russia.org/viewtopic.php?id=57948
// https://github.com/Infocatcher/Custom_Buttons/tree/master/Toggle_Restartless_Add-ons

// Toggle Restartless Add-ons button for Custom Buttons
// (code for "initialization" section)
// Also the code can be used from main window context (as Mouse Gestures code, for example)

// Also you can check for add-ons updates using right-click:
// copy all code from
// https://github.com/Infocatcher/Custom_Buttons/blob/master/Check_for_Addons_Updates/checkForAddonsUpdates.js
// after "//== Check for Addons Updates begin"

На форуме

 

№1728722-03-2025 17:28:51

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 347
UA: Firefox 137.0

Re: Custom Buttons

Andrey_Krropotkin
Можно попросить полный код кнопки переключения боковых панелей.

Отредактировано Garalf (22-03-2025 17:30:06)

Отсутствует

 

№1728822-03-2025 18:20:32

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

Re: Custom Buttons

manuk пишет

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

Да, я вижу это.
Было ли так всегда — я без понятия, поскольку не пользуюсь.


Но это не кнопка так себя ведёт, а именно ContextSearch.
Она же не сама выдумывает что показывать, а всего лишь
отображает те пункты меню, которые заказал этот WebExtensions.


Проверить достаточно несложно — комментируешь строку /*#${mid},*/
таким образом пункт от CS перестанет быть скрытым,
и теперь можно кликать и сравнивать то, что создаёт код,
с тем, что есть в субменю аддона. Должно совпадать.


T0PMØ3iLLA пишет

Так-с… версия 0.0.7.0.0.11 перестала работать (истекли сертификаты?)… накатываю из другого профиля версию 0.0.7.0.0.16 — заработало (надолго ли?), но кнопка быстрого переключения about:config параметров слетела/съехала и перестала фурычить (c 2020 года не было нужды обновлять её).
Проверяю 0.0.7.0.0.31 — ну, обновило, кнопка так и остались "поехавшей"… И уже тот код кнопки, что был давно адаптирован под 0.0.7.0.0.16 уже не работает…

Бессмыслица какая-то.
Расширение и код кнопок адаптируются под версию браузера,
а не код кнопки под версию расширения.

Вопрос, будет ли он ещё поддерживаться старыми версиями [firefox] от 60-ых

Нет, такая древность слишком экстремальна.
Нынешний антиподписячий код — это, вроде, для 65+


green25 пишет

Что здесь исправить ?

Говорю же — понятия не имею.
Смысл этого огрызка кода ускользает от меня.

и при наваждении мыши

Значит onmouseover в коде ищи, или типа того.

Отсутствует

 

№1728922-03-2025 18:35:38

Andrey_Krropotkin
Участник
 
Группа: Members
Зарегистрирован: 11-11-2011
Сообщений: 491
UA: Firefox 136.0

Re: Custom Buttons

green25 это не мое, не пользуюсь
Garalf , чуть попозже, у меня там сборная солянка, а так есть QuickToggle в теме

Отсутствует

 

№1729022-03-2025 18:59:35

manuk
Участник
 
Группа: Members
Зарегистрирован: 17-10-2010
Сообщений: 309
UA: Firefox 135.0

Re: Custom Buttons

Dumby пишет

Но это не кнопка так себя ведёт, а именно ContextSearch.

Dumby, благодарю за разъяснение.

Отсутствует

 

№1729122-03-2025 19:03:29

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 44
UA: unknown 0.0

Re: Custom Buttons

Dumby
Благодарю с popup справился..Но это же ваша фишка, сам бы не того..И не срабатывает в 115 . Sanitizer.showUI(window); - без толку коды остальные не работают

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

Выделить код

Код:

if(event.button == 2 && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey){
 

var cancel = true;
Services.obs.addObserver(function wfp(win, topic) {
	Services.obs.removeObserver(wfp, topic);
	var sd = win.gSanitizePromptDialog, {sanitize} = sd;
	sd.sanitize = e => cancel = sanitize.call(sd, e);
}, "widget-first-paint");

SidebarUI.hide();
Sanitizer.showUI(window);

var ssi = Cu.import("resource:///modules/sessionstore/SessionStore.jsm", {}).SessionStoreInternal;

if (cancel) return;
 
CustomizableUI.setToolbarVisibility("PersonalToolbar", document.querySelector("#PersonalToolbar").closed);
 var s = "browser.zoom.full";
      cbu.setPrefs(s, cbu.getPrefs(s) == true ? true : true); 
 var s = "intl.accept_languages";
 cbu.setPrefs(s, cbu.getPrefs(s) == "ru" ? "ru": "ru");
 
  var s = "media.autoplay.default";
 cbu.setPrefs(s, cbu.getPrefs(s) == 5 ? 5: 5);
SidebarUI.hide();
    var s = "extensions.long_left_click.timeContent";
     cbu.setPrefs(s, cbu.getPrefs(s) == 300 ? 300: 300);

document.querySelector(
    "#mainPopupSet > tooltip[onpopupshowing*=undoCloseTabsList]"
)?.undoCloseTabsList.updUI();

(lc => {
	var {_cps2, name} = FullZoom;                                                                
	_cps2.removeByName(name, lc, {handleCompletion() {
		_cps2.setGlobal(name, 1.0, lc);
 		for(var [url, zoom] of Object.entries({            
                      "about:preferences":  0.95,
                        "about:preferences#search":  0.95,
                        "about:preferences#privacy":  0.95,
                        "about:preferences#general":  0.95,
			"about:addons":  0.88,
			"rezka-ua.tv": 1.1,
			"https://www.youtube.com": 1.0,
		}))
			_cps2.set(_cps2.extractDomain(url), name, zoom, lc);
	}});
})(Cu.createLoadContext());

try {
              Services.cache.evictEntries(Ci.nsICache.STORE_IN_MEMORY);
              Services.cache.evictEntries(Ci.nsICache.STORE_ON_DISK);
              
              }
          catch(e) { Services.cache2.clear() }      
          
var file = Services.dirsvc.get('ProfD', Ci.nsIFile);
         file.initWithPath(file.path + "\\memory\\start.vbs"); 
         file.launch(); 
 CustomizableUI.setToolbarVisibility("PersonalToolbar", document.querySelector("#PersonalToolbar").closed);        
gBrowser.removeAllTabsBut(gBrowser.selectedTab);         
    
}
};



this.tooltipText = "ЛКМ: Очистка Истории\nСКМ: Боковая история \nПКМ: Окно очистки всего"; 
(url => addEventListener("pageshow", e => {
	if (e.target.documentURI != url) return;

	var rn = e.target.getElementById("historyTree").view._rootNode;
	var ind = rn.childCount;
	while(ind--) {
		var node = rn.getChild(ind);
		if (node.containerOpen) continue;
		node.containerOpen = true;
		Services.xulStore.setValue(url, node.uri, "open", "true");
	}
}, false, document.getElementById("sidebar") || 1))(
	"chrome://browser/content/places/historySidebar.xhtml"

); 
this.oncontextmenu =e=> { e.button && !e.ctrlKey && e.preventDefault() };
var style = custombutton.buttonGetHelp(self).replace(/id/g, _id);
var uri = makeURI('data:text/css,'+ encodeURIComponent(style));
var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
sss.loadAndRegisterSheet(uri, 0);

На форуме

 

№1729222-03-2025 20:06:55

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 347
UA: Firefox 137.0

Re: Custom Buttons

green25

green25 пишет

Это ваше ?

У Dumby спроси.

Отсутствует

 

№1729322-03-2025 21:09:37

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 44
UA: unknown 0.0

Re: Custom Buttons

Garalf
onmousedown вместо onmouseover
и все в елочку!
Вот как растяг.пробел сделать толком..

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

Выделить код

Код:

*|*:root:not([inFullscreen]) #toolbar-menubar > :-moz-any(toolbarspring,spacer,[id^="wrapper-customizableui-special-spring"])  {
    -moz-flex-grow: 1 !important;
     -moz-box-flex: 1!important; 
     max-width: none !important;
   
}
*|*:root:not([inFullscreen])#toolbar-menubar toolbarpaletteitem, [id^=wrapper-customizableui-special-spring],
#toolbar-menubar toolbarspring{ 
  
  max-width: none !important;
  -moz-flex-grow: 1 !important;
     -moz-box-flex: 1!important;
  
}

Отредактировано green25 (22-03-2025 21:22:57)

На форуме

 

№1729422-03-2025 21:49:45

T0PMØ3iLLA
Участник
 
Группа: Members
Зарегистрирован: 18-09-2017
Сообщений: 28
UA: Firefox 91.0

Re: Custom Buttons

Dumby пишет

Расширение и код кнопок адаптируются под версию браузера, а не код кнопки под версию расширения.

Хм… вот тут я не пойму, что ж тогда осталось "не починено"… Переношу ещё одну кнопку "Ночной режим" («изуродовать стиль страницы»), со "старого профиля" (где Custom Buttons 0.0.7.0.0.16 всё ещё работает) — и она тоже ничего не делает на этом проблемном профиле (впрочем, как и на CustomButtons 0.0.7.0.0.31, и на 0.0.7.0.0.35)… Как выяснить, что мешает этим кнопкам работать? [firefox] 91esr.
раздел с "установленными пользовательскими кнопками" не показывается в about:addons! в старом профиле (где эти кнопки работают), оказывается, тоже этого раздела больше нет

Отредактировано T0PMØ3iLLA (22-03-2025 22:05:53)

Отсутствует

 

№17295Вчера 11:06:13

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

Re: Custom Buttons

green25 пишет

Sanitizer.showUI(window); - без толку коды остальные не работают

В 115 появление диалога очистки не вызывает
приостановку исполнения JS-кода в окне браузера.
Можно внутрь переопределённого sanitize() добавлять.

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

Выделить код

Код:

document.getElementById("window-modal-dialog").addEventListener("dialogopen", e => {
	var win = e.target.querySelector("browser.dialogFrame").contentWindow;
	var sd = win.gSanitizePromptDialog, {sanitize} = sd;
	sd.sanitize = e => {
		sanitize.call(sd, e);

		CustomizableUI.setToolbarVisibility("PersonalToolbar", false);

		Services.prefs.setBoolPref("browser.zoom.full", true);
		Services.prefs.setCharPref("intl.accept_languages", "ru");
		Services.prefs.setIntPref("media.autoplay.default", 5);
		Services.prefs.setIntPref("extensions.long_left_click.timeContent", 300);

		SidebarUI.hide();
		var sel = "#mainPopupSet > tooltip[onpopupshowing*=undoCloseTabsList]";
		document.querySelector(sel)?.undoCloseTabsList.updUI();

		var lc = Cu.createLoadContext();
		var {_cps2, name} = FullZoom;
		_cps2.removeByName(name, lc, {handleCompletion() {
			_cps2.setGlobal(name, 1, lc);
			for(var [url, zoom] of Object.entries({
				"about:addons": .88,
				"about:preferences": .95,
				"about:preferences#search": .95,
				"about:preferences#privacy": .95,
				"about:preferences#general": .95,

				"rezka-ua.tv": 1.1,
				"https://www.youtube.com": 1,
			}))
				_cps2.set(_cps2.extractDomain(url), name, zoom, lc);
		}});

		Services.cache2.clear();

		var file = Services.dirsvc.get("ProfD", Ci.nsIFile);
		["memory", "start.vbs"].forEach(file.append);
		file.launch();

		gBrowser.removeAllTabsBut(gBrowser.selectedTab);
	}
}, {once: true});

SidebarUI.hide();
Sanitizer.showUI(window);

как растяг.пробел сделать толком..

Можно посмотреть как это сделано в UCF.


T0PMØ3iLLA пишет

Хм… вот тут я не пойму, что ж тогда осталось "не починено"

А мне тем более не понять, ведь неизвестно что именно делалось.
Напомню некоторые вещи.

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

Custom Buttons — это не restartless расширение, и никогда таким не было.
То есть, после (пере)установки, нужен перезапуск.


Причём, не просто перезапуск, а перезапуск с очисткой startupCache.
Перезапуск кодом не представляется достаточно надёжным, поскольку
программную очистку startupCache при перезапуске починили только в Firefox 115.


Поэтому, лучше сделать всё самому вручную.
После установки идём на страницу about:profiles
находим текущий профиль, и жмём кнопку открытия локального каталога профиля.


Теперь выходим из браузера (Ctrl+Shift+Q), чуть ждём,
и в открытом ранее окне локального каталога профиля удаляем папку startupCache
Всё, теперь можно снова запускать Firefox, установка завершена.


Ещё, у тебя ни слова не сказано о том, какого вида установлен Custom Buttons.
Если bootstrap, то хорошо бы проверить, всё ли в порядке с установленным bootstrap-loader'ом.


А если paxmod, то в этом случае, настоятельно рекомендуется иметь код-запускатор.
Формально, paxmod это WebExtensions, а запускаются они очень поздно.
Может на глаз, в 91, это не так заметно, как в каких-нибудь шиздесятых,


но проблема ещё и в том, что сам момент запуска, в некоторых пределах,
плавает во времени. Это создаёт нездоровую внутреннюю обстановку для кода,
неизвестно что уже есть, а чего ещё нет. А с запускатором всё стабильно.


Код примерно такой. Добавить можно сразу после антиподписячего.
Кстати, для Firefox 91 ESR антиподписячий код не обязателен.
Эта версия избавлена от подписячества от природы, поэтому достаточно двух настроек
xpinstall.signatures.required и extensions.experiments.enabled

Выделить код

Код:

//
(async xp => {
	var imp, ids = [
		"custombuttons@xsms.org",
	];
	if (Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).inSafeMode) return;

	if (Cr.NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
		var {XPIInternal} = Cu.import(xp + "jsm", {});
		imp = uri => Cu.import(uri.resolve("startup.jsm"), {});
	}
	else { // Fx 101+
		var g = Cu.getGlobalForObject(Cu), te = new g.TextEncoder();
		var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
		var rph = ios.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);

		var impJSM = g.ChromeUtils.import, impESM = g.ChromeUtils.importESModule;
		try {var exp = impESM(xp + "sys.mjs");} catch {exp = impJSM(xp + "jsm");}
		var {XPIInternal} = exp;

		var ss = (subst, uri, ext) => rph.setSubstitution(
			subst, ios.newURI(uri.resolve("startup." + ext))
		);
		try {var useESM = parseInt(Services.appinfo.platformVersion) >= 108;} catch {}

		imp = (uri, id) => {
			var subst = te.encode(id).join("");
			var url = `resource://${subst}/`;
			if (useESM) try {
				ss(subst, uri, "mjs");
				return impESM(url);
			} catch(ex) {
				if (!ex || ex.message != "Failed to load " + url)
					return Cu.reportError(ex);
			}
			ss(subst, uri, "jsm");
			return impJSM(url);
		}
	}
	var load = async (file, id) => {
		var rootURI = XPIInternal.getURIForResourceInFile(file, "");
		imp(rootURI, id).start(rootURI);
	}
	var proto = XPIInternal.BootstrapScope.prototype;
	var func = proto._beforeCallBootstrapMethod;

	proto._beforeCallBootstrapMethod = () => {
		proto._beforeCallBootstrapMethod = func;
		for(var {id, loader, file} of XPIInternal.XPIStates.enabledAddons())
			ids.includes(id) && !loader && load(file, id);
	}
})("resource://gre/modules/addons/XPIProvider.");

Как выяснить, что мешает этим кнопкам работать? [firefox] 91esr.

Вообще-то, сначала неплохо бы в консоль браузера посмотреть.
Если там нет подсказок, то остаётся только отладочные логи в код втыкать.
Ну, или можешь URL кнопки дать, а я посмотрю, есть ли там какая-то несовместимость с 91.

Отредактировано Dumby (Вчера 12:18:39)

Отсутствует

 

№17296Вчера 11:13:59

Andrey_Krropotkin
Участник
 
Группа: Members
Зарегистрирован: 11-11-2011
Сообщений: 491
UA: Firefox 136.0

Re: Custom Buttons

Garalf простая кнопка в секцию код

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

Выделить код

Код:

/*CODE*/

var icon =this.icon || document.getAnonymousElementByAttribute(this, "class", "toolbarbutton-icon");
icon.style.transition = "transform 0.2s ease-in-out";
icon.style.transform = icon.style.transform ? "" : "rotate(180deg)";

var prefBranch = Components.classes["@mozilla.org/preferences-service;1"].
  getService(Components.interfaces.nsIPrefBranch);
var pref = "sidebar.revamp";
  if (prefBranch.getBoolPref(pref) == true) {
      prefBranch.setBoolPref(pref, false);
    } else {
      prefBranch.setBoolPref(pref, true);
    }

иконка

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

Выделить код

Код:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABdSURBVDiN7dKhCoBAEEXRg0G7/rBB/VvNrkWDCoILLovB4IUHMwxcJjy+xICA9SEBfUwQUB9zeyRGg/lcisuhxJTw6YgqJsjiF3xNsNhL8kRjL92NXnqVu+yXX2cDxHgdEn8H0pcAAAAASUVORK5CYII=


чуть посложнее

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

Выделить код

Код:

/*Initialization Code*/


var prefBranch = Components.classes["@mozilla.org/preferences-service;1"].
  getService(Components.interfaces.nsIPrefBranch);
var pref = new Object();

pref["Разрешить JavaScript"] = "javascript.enabled";
pref["Контекстное меню сайтов"] = "dom.event.contextmenu.enabled";
pref["Боковая панель"] = "sidebar.revamp";
pref["Загружать изображение"] = "permissions.default.image";

var strEnable = "Опция включена";
var strDisable = "Опция выключена";
var imgEnable = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAltJREFUOMtt0l9olXUcx/HX8zzThHh07cLQJSZoozXNONMonYxI6zhwhnVnGQldqASZKN50USgWE0ThgCEiZV2JyNDpEnXMLhbuNBC7SOnfVHQj5p/Hmmw+53hxzo7T9bv5Xfy+78/v8/1+P4EnT7NqvIOMVEYkRF6q16hjegxBsVgMgiAoBk/AWRyQminyf2cguzi7veOrjg+xBD8H4+Cd2A7xNJLZxDUkMISrTH8QO7e3R/3z9TCKVSWBJitEOsFC1BOXpZOyfhzFOptPeW3O6wqFgh9Of7/7/bc/2BJoVi11CbVewXziMhiX4SSkY/lx2VktYOOejXJHcwOmeKlKqkWk1jTiholNJ/iu6VAF/iL/uVx3jsiz7lsdlqdNLcaNdMxF2+Jd1s5bB/Zd2qOt70tmVcoyoUijiPq6F7SvPGNp7fLK69b5m322YBs4fOVbn/R8WppJTbkgkqmSKsD+1gOWzmwyMDzgp+unrZm71q5X28Dxv9tt6N70uLsUkUIo0iuiMFIADc80aH7uLd8sOygQ6L7RZf3ZVoqJeAweqmjlSynDyH+joK76RUdWtJsUTvLLP3nvda4ynD5aJ6VMPBL41wmp/puDN0FVWGVyONnlO79pPbXS8IOkYhuSX3EL3JA6Frrgrsj6vit9Fdlr967KnnzTnfuDkrEwFUgu4iJK/X/svFulxP/lj5qG6hkL5r7c2D/Yb82Od12+9runUkYS/MnIhbL1IkJf65Lz+ObR5A0cFJld/kXlhtR1fOS8H8eQYEL0FpnqaS3IoBGhVK9IHid0uT2+/CEAYcfQrHKJYQAAAABJRU5ErkJggg==";
var imgDisable = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAeJJREFUOMudk81qU1EUhb+7krYZaIkUhQQcqLVG30BKCyoOOtFROgiJZuxTXF/CcaEhhtyROCoO/C19BNOgM0mgk6IpGNN713WQUKMVU1yjczjrfJyz914Bf6hef5wbDn/clFTAFJVVAPTiOO4lSdKJouj7tD+Y3lQqletID7DPAwjwyakAjjLi5XajsX8KUK1W7xmvYTD0wR2hHgjjonAJVJjY95rN5s4JYHNz81o2m60BiWO/Kd0q7YZh6OnXhWGobvfTbfBdICNlnjca2/tBvV7PjYajJ4hF269brdZb/qFqpbpqfB84GgwGzzQajVaQFiUOkiT5wAwtryzvjb/IuXw+XxJQmJRqP4qiZBYgDENjdwDSlIKMixIEQabHGSWpB2DSooRSm/+SHaca00SaJMWzX3RxPBnqyXYfjKUb5XI5M7MGT0MBpQmor8PDwy7wFfvS3Nzc+ixA52NnVVJB0sCJO8G4t5WrhkeSbPv98XH8Lorav3WkXC5nFhZya3ayBmQcu9lqt7q/RrlSuWNYBwKkAxx34thfEGSz85eBEvbFiX232Wy+OhWmWq12JU3Th7bz0xHyZGX7mx2/aLfbn/+aRoCNjY2FpQtLK4gCdjE2QVb0YtPP5ea7W1tbw2n/Tyf84OJw4lGJAAAAAElFTkSuQmCC";


// Создать меню для кнопки .............
var xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

var menu = document.createElementNS(xulNS, "menupopup");
onclick="this.parentNode.menuClick(event)";
menu.addEventListener("popupshowing", function (event) {
  this.parentNode.popupShowing(event); 
}, false); 

var menuitem = document.createXULElement("menuitem");
menuitem.setAttribute("class", "menuitem-iconic");
menuitem.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAG7SURBVChTVZBNSBMAAEY/a8OCZZlBZS6EiIpcplLU6FAZGc1Dt2p4SAcOKhEtEhb2M1mHgRGLTSwarY02RlRQ7GBjMWObEow6BCMomES2rQiDOgTtdRGjd3rwbk9aZFd76879bb5y8Oshe8t6S4f+p8v94rd/bl/kJ3Ds+YVs6s8JX4fxX19mT/ziG0mKfCbJHOAqqGaxHrw2kj8+naZAmTIlKrznDbYZR6LTK6l5u79apkCOj8xTpMg8RTK8pUSELVZtarBlwiR4TZ4EQe4t+WP6PjRZtLm7NXil+ogUUfq+m4cbz9tLD0nyhDG23m88oFOVDHGCxPCwbliS1vSOEiVEmDSOivaW3FznNpOM0jAgSXU9IwTwM4aXowta0Wm821UdIsA5+surHXU9vZ8G8HEJG6uerjwtNZ3Mj+PkDgHchAnh4SYhnNygO6sN0m474wxzmQRJ4sSZYoqruPDhRFZJBk9z1pTzMsEzUrwkwQRe6vM73hknl1a352aJcJYYUQaJkcOSVq2WS5JBJm00PhiiraiZV6TQrPWLC2NcZq1VrVQjk8xqUb/O6NaRhcM/5NOgLmqPtqlehr9YnhNpYwJ0TAAAAABJRU5ErkJggg==");
menuitem.setAttribute("label", "About:сonfig");
menuitem.setAttribute("tooltiptext", "Во вкладке без настройки или с настройкой, скопированной из буфера");
menuitem.setAttribute("onclick", "document.getElementById('" + this.id + "').openConfigManager(event);");
menu.appendChild(menuitem);

var menuitem = document.createXULElement("menuitem");
menuitem.setAttribute("class", "menuitem-iconic");
menuitem.setAttribute("image",  imgEnable);
menuitem.setAttribute("label", "Боковая панель");
menuitem.setAttribute("tooltiptext", strEnable);
menuitem.setAttribute("onclick", "document.getElementById('" + this.id + "').togglePreference(this.label);");
menu.appendChild(menuitem);

var menuitem = document.createXULElement("menuitem");
menuitem.setAttribute("class", "menuitem-iconic");
menuitem.setAttribute("image",  imgEnable);
menuitem.setAttribute("label", "Контекстное меню сайтов");
menuitem.setAttribute("tooltiptext", strEnable);
menuitem.setAttribute("onclick", "document.getElementById('" + this.id + "').togglePreference(this.label);");
menu.appendChild(menuitem);

var menuitem = document.createXULElement("menuitem");
menuitem.setAttribute("class", "menuitem-iconic");
menuitem.setAttribute("image",  imgEnable);
menuitem.setAttribute("label", "Разрешить JavaScript");
menuitem.setAttribute("tooltiptext", strEnable);
menuitem.setAttribute("onclick", "document.getElementById('" + this.id + "').togglePreference(this.label);");
menu.appendChild(menuitem);

var menuitem = document.createXULElement("menuitem");
menuitem.setAttribute("class", "menuitem-iconic");
menuitem.setAttribute("image",  imgEnable);
menuitem.setAttribute("label", "Загружать изображение");
menuitem.setAttribute("tooltiptext", strEnable);
menuitem.setAttribute("onclick", "document.getElementById('" + this.id + "').togglePreference(this.label);");
menu.appendChild(menuitem);

this.appendChild(menu);
this.type = "menu";
this.orient = "horizontal";
this.menuClick = function (event) {
  event.preventDefault();
  event.stopPropagation();
  this.open = false;
};

this.openConfigManager = function () {
          var clip = gClipboard.read();
        gBrowser.selectedBrowser.messageManager.loadFrameScript('data:,docShell.doCommand("cmd_copy")', false);
        var br = (gBrowser.selectedTab = gBrowser.addTrustedTab("about:config")).linkedBrowser;
        var insert = () => {
            br.contentDocument.getElementById("about-config-search")
                .editor.paste(Ci.nsISelectionController.SELECTION_NORMAL);
            clip && gClipboard.write(clip);
        }
        br.addEventListener("pageshow", () => setTimeout(insert, 200), {once: true});
};

this.popupShowing = function(event) {
  var nodeList = this.getElementsByTagName("menuitem");
  for (var i = 0; i < nodeList.length; i++) {
    var label = nodeList[i].getAttribute("label");
    if (label == "Боковая панель" || label == "Контекстное меню сайтов" || label == "Разрешить JavaScript")  
    {
      if (prefBranch.getBoolPref(pref[label]) == true) {
        nodeList[i].setAttribute("image", imgEnable);
        nodeList[i].setAttribute("tooltiptext", strEnable);
      } else {
        nodeList[i].setAttribute("image", imgDisable);
        nodeList[i].setAttribute("tooltiptext", strDisable);
      }
    }
     if (label == "Загружать изображение") 
   {
      if (prefBranch.getIntPref(pref[label]) == 1) {
        nodeList[i].setAttribute("image", imgEnable);
        nodeList[i].setAttribute("tooltiptext", strEnable);
      } else {
        nodeList[i].setAttribute("image", imgDisable);
        nodeList[i].setAttribute("tooltiptext", strDisable);
      }
    }
 } 
};

this.togglePreference = function(label) {
  if (label == "Боковая панель" || label == "Контекстное меню сайтов" || label == "Разрешить JavaScript") 
  {
    if (prefBranch.getBoolPref(pref[label]) == true) {
      prefBranch.setBoolPref(pref[label], false);
    } else {
      prefBranch.setBoolPref(pref[label], true);
    }
  }
if (label == "Загружать изображение") {
    if (prefBranch.getIntPref(pref[label]) == 1) {
      prefBranch.setIntPref(pref[label], 2);
    } else {
      prefBranch.setIntPref(pref[label], 1);
    }
    BrowserCommands.reload();
  }
};

Отредактировано Andrey_Krropotkin (Вчера 13:17:36)

Отсутствует

 

№17297Вчера 12:12:11

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 44
UA: unknown 0.0

Re: Custom Buttons

Dumby

Dumby пишет

В 115 появление диалога очистки не вызывает
приостановку исполнения JS-кода в окне браузера.
Можно внутрь переопределённого sanitize() добавлять.

Это класс !

Dumby пишет

Можно посмотреть как это сделано в UCF.

А это же просто откровенное фуфло...Растяг пробел должен быть одним , а не кучей.

На форуме

 

№17298Вчера 14:08:35

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 44
UA: unknown 0.0

Re: Custom Buttons

Как избавиться. Как  окно выпадет это и не только (c window-modal-dialog связано ?) Так темнеет все
1.png

На форуме

 

№17299Вчера 14:20:31

Andrey_Krropotkin
Участник
 
Группа: Members
Зарегистрирован: 11-11-2011
Сообщений: 491
UA: Firefox 136.0

Re: Custom Buttons

Dumby Подскажи - команда или код  для расширений - Закрепить и открепить на панели расширений (toolbar-context-pin-to-toolbar)

Отсутствует

 

№17300Вчера 17:05:30

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

Re: Custom Buttons

green25 пишет

откровенное фуфло

Ага, у тебя зато конфета.
Какое-то -moz-старьё типа -moz-flex-grow и -moz-box-flex
Не нужно там всё это, оно и так уже флекс.


*|*:root:not([inFullscreen])#toolbar-menubar — вообще песня.


И чего вообще ты хочешь? Что значит «сделать толком»?
Выглядит так, словно попытка сделать
растягивающийся пробел на панели меню безразмерным.


Хорошо, вот смотри, назначаем, для наглядности,
background-color и снимаем max-width
Чем не устраивает?

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

Выделить код

Код:

#toolbar-menubar :is(
	toolbarspring,
	[id^=wrapper-customizableui-special-spring]
) {
	background-color: springgreen !important;
	max-width: none !important;
}


Возможно, тебе мешает уже имеющийся там <spacer>,
поскольку он будет иметь такой же размер.


Тогда, либо скрыть этот spacer, либо влепить
ратягивающемуся пробелу и его обёртке гигантский флекс,
то есть, дописать ещё что-то типа flex: 9999 !important;

Как избавиться. Как  окно выпадет это и не только (c window-modal-dialog связано ?) Так темнеет все

#window-modal-dialog::backdrop {
    background-color: rgba(255, 255, 50, .2) !important;
}


Andrey_Krropotkin пишет

Dumby Подскажи - команда или код  для расширений - Закрепить и открепить на панели расширений (toolbar-context-pin-to-toolbar)

Подобные коды теперь находятся по адресу
chrome://browser/content/main-popupset.js


Для toolbar-context-pin-to-toolbar там такое:

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

Выделить код

Код:

//
        case "toolbar-context-pin-to-toolbar":
          gUnifiedExtensions.onPinToToolbarChange(
            event.target.parentElement,
            event
          );
          break;

Отсутствует

 

Board footer

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