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

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

№1727616-03-2025 13:31:39

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

Re: Custom Buttons

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

Отсутствует

 

№1727717-03-2025 01:51:19

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 39
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
Сообщений: 2319
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
Сообщений: 39
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
Сообщений: 489
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)

Отсутствует

 

№17281Вчера 10:36:29

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2319
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);


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

Отсутствует

 

№17282Вчера 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 (Вчера 11:42:23)

Отсутствует

 

№17283Вчера 12:07:19

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

Re: Custom Buttons

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

Отсутствует

 

№17284Вчера 14:24:01

T0PMØ3iLLA
Участник
 
Группа: Members
Зарегистрирован: 18-09-2017
Сообщений: 27
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 (Вчера 18:04:46)

Отсутствует

 

№17285Вчера 15:54:30

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 39
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;

Отсутствует

 

№17286Вчера 16:45:09

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 39
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"

Отсутствует

 

№17287Вчера 17:28:51

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

Re: Custom Buttons

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

Отредактировано Garalf (Вчера 17:30:06)

Отсутствует

 

№17288Вчера 18:20:32

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2319
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 в коде ищи, или типа того.

Отсутствует

 

№17289Вчера 18:35:38

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

Re: Custom Buttons

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

Отсутствует

 

№17290Вчера 18:59:35

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

Re: Custom Buttons

Dumby пишет

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

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

Отсутствует

 

№17291Вчера 19:03:29

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 39
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);

Отсутствует

 

№17292Вчера 20:06:55

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

Re: Custom Buttons

green25

green25 пишет

Это ваше ?

У Dumby спроси.

Отсутствует

 

№17293Вчера 21:09:37

green25
Участник
 
Группа: Members
Зарегистрирован: 14-12-2024
Сообщений: 39
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 (Вчера 21:22:57)

Отсутствует

 

№17294Вчера 21:49:45

T0PMØ3iLLA
Участник
 
Группа: Members
Зарегистрирован: 18-09-2017
Сообщений: 27
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:05:53)

Отсутствует

 

Board footer

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