скрытый текст
А чего это там код
два раза два раза
повторяется?
Исправь, если у тебя так.
А правка, может такую попробуй
/* mp.setAttribute("onpopupshowing", "this.updateMenu();"); mp.setAttribute("oncommand", "if(!event.button) this.handleEvent(event);"); // Ignore middle-click in Firefox 89+ mp.setAttribute("onmousedown", "if(event.button == 0) this.handleEvent(event);"); mp.setAttribute("onclick", "if(event.button > 0) this.handleEvent(event);"); mp.setAttribute("oncontextmenu", "return false;"); mp.setAttribute("onpopuphidden", "this.destroyMenu();"); */ addEventListener("popupshowing", () => mp.updateMenu(), false, mp); addEventListener("command", mp.onmousedown = mp.onclick = e => { if (!e.button || e.type.endsWith("k")) mp.handleEvent(e); }, false, mp); mp.toggleAttribute("context"); addEventListener("popuphidden", () => mp.destroyMenu(), false, mp);
Отсутствует
Dumby
Спасибо! Кнопка заработала.
Огромная просьба. Посмотри еще раз код
Дополнительные пункты в контекстном меню кнопки из моего
предыдущего поста. Очень полезная кнопка. Твоя правка к сожалению не сработала.
Ни один пункт меню не работает.
Отредактировано Garalf (08-02-2025 23:31:32)
Отсутствует
Огромная просьба. Посмотри еще раз код
Дополнительные пункты в контекстном меню кнопки
Посмотрел.
На сей раз на 137.0a1 (2025-02-09).
Создал кнопку с предоставленным кодом инициализации.
Сделал предложенные правки. Рестарт.
Пункты «Показать Id кнопки» и «Переместить кнопку...» точно работают.
Остальные не проверял, поскольку, таким образом, утверждение
«Ни один пункт меню не работает» уже не подтвердилось.
Отсутствует
Проверь пожалуйста пункт меню Редактирование кнопки.
Это не представляется возможным,
поскольку меня такого пункта вообще нет.
Есть пункт «Редактировать…».
#custombuttons-contextpopup-edit,
ну тот, который самый первый сверху.
Но этот пункт не из добавляемых кодом, а пункт самого расширения.
Если имееется в виду именно он, и если не работает именно он,
то, может, обновление встало криво,
или startupCache при этом, после рестарта не очистился,
или, даже не знаю что ещё.
Отсутствует
Dumby
Раз теме тишина попрошу полечить еще одну кнопку.
UserCSSLoader
(obj => { this.onclick = obj.click.bind(obj); this.oncontextmenu = obj.contextmenu.bind(obj); this.tooltipText = "L: Reload userChrome.css\nM: CB Menu\nR: Reload userContent.css"; })({ async click(e) { if (e.button == 1) return gShowPopup(self); if (e.button || !this.chromeSheet) return; await this.reload(this.chromeSheet); this.restyle(0); }, async contextmenu(e) { if (e.ctrlKey || e.shiftKey || e.detail != 1 || !this.contentSheetURL) return; e.preventDefault(); var count = Services.ppmm.childCount, one = count == 1; var data = await this.reloadTab("chrome://extensions/content/dummy.xul", one ? false : {}); if (one) this.reloadTab(); else if (data) { var url = "data:," + encodeURIComponent( self.Help + this.contentSheetURL + '", ' + JSON.stringify(data) + ");" ); var types = ["web", "file", "extension"]; for(var ind = 0; ind < count; ind++) { var child = Services.ppmm.getChildAt(ind); types.includes(child.remoteType) && child.loadProcessScript(url, false); } } this.restyle(250); }, async reload(sheet, obj) { try {var style = await (await fetch(sheet.href)).text();} catch (ex) {return obj;} InspectorUtils.parseStyleSheet(sheet, style); if (obj) obj[sheet.href] = style; for(var ind = 0, len = sheet.cssRules.length; ind < len; ind++) { var rule = sheet.cssRules.item(ind); rule.type == rule.IMPORT_RULE && rule.styleSheet.href.startsWith("file:///") && await this.reload(rule.styleSheet, obj); } return obj; }, reloadTab(url, obj) { var tab = gBrowser.addTab(url, {skipAnimation: true}); tab.style.setProperty("display", "none", "important"); return new Promise(resolve => { var result, stop, destroy = () => { if (!stop) resolve(result), gBrowser.removeTab(tab), stop = true; } setTimeout(destroy, 500); try { tab.linkedBrowser.addEventListener("DOMContentLoaded", async e => { var sheet = this.getSheet(e.target, this.contentSheetURL); if (sheet) result = await this.reload(sheet, obj); destroy(); }, {once: true}); } catch(ex) { destroy(); } }); }, getSheet(doc, href) { var sheets = InspectorUtils.getAllStyleSheets(doc); return sheets.find(sheet => sheet.href == href); }, get contentSheetURL() { var file = Services.dirsvc.get("UChrm", Ci.nsIFile); file.append("userContent.css"); if (!file.exists()) return null; delete this.contentSheetURL; return this.contentSheetURL = Services.io.newFileURI(file).spec; }, get restyle() { var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); var uri = Services.io.newURI("data:text/css,:root{}"), type = sss.USER_SHEET; delete this.restyle; return this.restyle = delay => setTimeout(() => { sss.loadAndRegisterSheet(uri, type); sss.unregisterSheet(uri, type); }, delay); }, get chromeSheet() { var file = Services.dirsvc.get("UChrm", Ci.nsIFile); file.append("userChrome.css"); if (!file.exists()) return null; var href = Services.io.newFileURI(file).spec; var sheet = this.getSheet(document, href); if (!sheet) return null; delete this.chromeSheet; return this.chromeSheet = sheet; } });
Напомню - это 136.b3 Кстати, пункт меню Edit в контекстном меню кнопки
неожиданно заработал.
Отредактировано Garalf (11-02-2025 10:19:25)
Отсутствует
Dumby
Справка
((href, data) => { var en = Services.ww.getWindowEnumerator(null); if (!en.hasMoreElements()) return; var doc = en.getNext().document; var du = Components.classes["@mozilla.org/inspector/dom-utils;1"] .getService(Components.interfaces.inIDOMUtils); var reload = sheet => { var style = data[sheet.href]; if (!style) return; du.parseStyleSheet(sheet, style); for(var ind = 0, len = sheet.cssRules.length; ind < len; ind++) { var rule = sheet.cssRules.item(ind); rule.type == rule.IMPORT_RULE && rule.styleSheet.href.startsWith("file:///") && reload(rule.styleSheet); } } var sheet = du.getAllStyleSheets(doc).find(sheet => sheet.href == href); if (sheet) reload(sheet); })("
Отсутствует
Справка
Другое дело.
Напомню - это 136.b3
Что-то я не вижу в кнопке
ни использования «on…» атрибутов, ни импорта модулей.
Но многовато чего-то совсем древнего,
поэтому попробую чуть переделать.
Код со Справки перенёс в Инициализацию.
(code => { this._handleClick = () => { var href = getHref("hrome"); if (!href) return; var sheet = getSheet(document, href); sheet && (this._handleClick = () => reload(sheet).then(restyle))(); } this.onauxclick = e => e.button > 1 || gShowPopup(this); this.oncontextmenu = e => { if (e.ctrlKey || e.shiftKey || e.detail != 1) return; e.preventDefault(); reloadContentSheet(); } this.tooltipText = "L: Reload userChrome.css\nM: CB Menu\nR: Reload userContent.css"; var getHref = str => { var file = Services.dirsvc.get("UChrm", Ci.nsIFile); file.append(`userC${str}.css`); if (file.exists()) return Services.io.newFileURI(file).spec; } var getSheet = (doc, href) => InspectorUtils.getAllStyleSheets(doc).find(sheet => sheet.href == href); var reload = async (sheet, obj) => { try {var style = await (await fetch(sheet.href)).text();} catch {return obj;} InspectorUtils.parseStyleSheet(sheet, style); if (obj) obj[sheet.href] = style; for(var ind = 0, len = sheet.cssRules.length; ind < len; ind++) { var rule = sheet.cssRules.item(ind); rule.type == rule.IMPORT_RULE && rule.styleSheet.href.startsWith("file:///") && await reload(rule.styleSheet, obj); } return obj; } var restyle = delay => { var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); var uri = Services.io.newURI("data:text/css,:root{}"), type = sss.USER_SHEET; var regUnreg = () => { sss.loadAndRegisterSheet(uri, type); sss.unregisterSheet(uri, type); }; (restyle = delay => setTimeout(regUnreg, delay))(delay); } var reloadContentSheet = async () => { var href = getHref("ontent"); if (!href) return; var {br} = this; if (!br) { br = this.br = document.createXULElement("browser"); br.setAttribute("type", "content"); this.append(br); await new Promise(resolve => br.addEventListener("pageshow", resolve, {once: true})); } var sheet = getSheet(br.contentDocument, href); if (!sheet) return; br.remove(); delete this.br; var {ppmm} = Services; var re = /^(?:web|file|extension|privileged)/; var prfx = "data:," + encodeURIComponent(code.trim() + sheet.href + '", '); (reloadContentSheet = async () => { var data = await reload(sheet, Object.create(null)); var url = prfx + encodeURIComponent(JSON.stringify(data)) + ");" for(var ind = 0, count = ppmm.childCount; ind < count; ind++) { var child = ppmm.getChildAt(ind); re.test(child.remoteType) && child.loadProcessScript(url, false); } restyle(350); })(); } })(` ((href, data) => { var en = Services.ww.getWindowEnumerator(null); if (!en.hasMoreElements()) return; var doc = en.getNext().document; var reload = sheet => { var style = data[sheet.href]; if (!style) return; InspectorUtils.parseStyleSheet(sheet, style); for(var ind = 0, len = sheet.cssRules.length; ind < len; ind++) { var rule = sheet.cssRules.item(ind); rule.type == rule.IMPORT_RULE && rule.styleSheet.href.startsWith("file:///") && reload(rule.styleSheet); } } var sheet = InspectorUtils.getAllStyleSheets(doc).find(sheet => sheet.href == href); sheet && reload(sheet); })(" `);
Отсутствует
Dumby
Нашел еще две удобные неработающие кнопки
1. "Два в одном"
//Настройка функций кликов мыши для кнопки .................... this.onclick =e=> {if(e.button==0)BrowserOpenAddonsMgr();//ЛКМ if(e.button==1)gShowPopup(this); //СКМ if(e.button==2 && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){//ПКМ setTimeout(function(){document.getElementById("custombuttons-contextpopup").hidePopup();},0);openPreferences();}}; this.tooltipText="Л: Addons\nС: CBMenu\nП: Preferences"; //data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAABuwAAAbsBOuzj4gAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAMJSURBVDiNdVPNa1N5FD2/30uMeX1IPjFmE3BKERdhRKqgwyBqibsuZqGYRRf2H3Ax0J28je22XcRCwwhNKh0ki24GSn20iE3TNMKjONKkHyYUokmbMR++F/Oa966baUkVL9zNvfdc7jmHy4gIP4uFhcUFABgejgz/dIiITjKZTF3JZtXKzEziPgC+tbV3tLW1dwSAz8wk7mezaiWZTF3pxZxaEI2O3mk2NSoWy918/kO73e5Qu92hQuFDu1gsd5tNjaLR0Tu9GEZEiMdf/Orz+Ry6rndu3rz21u/3ciLCp08VAEAgcB6MMRwc1KzV1exVURQdh4eHndHRhyoDwBYXX38Mhy+f17S26fW6hHR6HUtLKzBNEwAgCAKGhm7hxo3rqNXqZl+fU9jcfF+JRH6/wImIEolZeX+/bElSn5DLqUins0TUKXBuRDk3okSdQjqdpVxOhST1Cfv7ZSuRmJXpRAiAK0pGL5UqNDUVt2T5ab6XJxFBlp/mp6biVqlUIUVZ0wFwIgKfnIwnl5fXW8FgwKlpOiRJZB6PW/7eLY/HLUuSyDRNRzB4wbm8vN6anIwnbaq6yTWtaw+FfoHLJcHn8+PsWdsPdnu9XkiSG3t7H1Gvf0GptGvf3n7PTyiMj0+35uaWqFAoWoqy8gMFRVnJFwpFa35eofHx6dYxBRsAxGKz94jsgig6oOsGGxi41K+qm3nLIhkAOGdPBgYu9TcaGjt3ToTH4xZisdl7AP7hjDFWLldjLpfHqesNq15v4etXg4dCF/sDgeBcIBCcC4Uu9h8ddXmzqUHXm5bf73dWq7UYY4zZiIgikeEHq6uvXA6Hvf748Z9vOh2XcHBQ46LoAGMMnz/XuWmaMIwv5vPnz34zDMNltzvqRESs95mmp/+6Ojh4faPR+K9rWQaFw+EzjDG8e/evYbefYW63z5bJpAcfPRp5e4zhvUpnMmlbLpepplJ/jwwN3XXu7u5oOzvb2u3bt5wvX86PbGysVTOZtVMWnboAABhjjP4vTkxMpABgbGzsj+97x/ENhTvQG3f/6bsAAAAASUVORK5CYII= //forum.mozilla-russia.org/viewtopic.php?pid=704725#p704725 //openWebPanel("Downloads","about:downloads");
2. Поиск по изображению
/*Initialization Code*/ // Добавить подменю "Поиск изображения в" в контекстном меню изображений, от 31.05.2019. ............. (()=> { var copyimage = document.getElementById("context-copyimage-contents"); var contextMenu = copyimage.parentNode; var array = [ ['Google', 'https://www.google.lv/favicon.ico', 'http://www.google.com/searchbyimage?image_url='], ['Яндекс', 'http://yastatic.net/morda-logo/i/favicon_islands.ico', 'https://yandex.com/images/search?rpt=imageview&img_url='], ['Bing', 'https://www.bing.com/s/a/bing_p.ico', 'https://www.bing.com/images/searchbyimage?FORM=IRSBIQ&cbir=sbi&imgurl='], ['Tineye', 'http://tineye.com/favicon.ico', 'http://tineye.com/search?pluginver=bookmark_1.0&url='], ['SauceNao', 'https://saucenao.com/favicon.ico', 'https://saucenao.com/search.php?url='], ['IQDB', 'https://iqdb.org/favicon.ico', 'https://iqdb.org/?url='], ]; var menu = contextMenu.insertBefore(document.createXULElement("menu"), copyimage); menu.setAttribute("label", "Поиск изображения в ..."); menu.setAttribute("class", "menu-iconic"); menu.onclick =e=> { e.target.nodeName == 'menu' && search(array[0][2]); setTimeout(()=> contextMenu.hidePopup(), 20) }; addEventListener("popupshowing", ()=> menu.hidden = copyimage.hidden, true, contextMenu); addDestructor(() => menu.remove()); var menuPopup = menu.appendChild(document.createXULElement("menupopup")); array.forEach(m=> { var mItem = menuPopup.appendChild(document.createXULElement("menuitem")); mItem.setAttribute("label", m[0]); mItem.setAttribute("image", m[1]); mItem.setAttribute("class", "menuitem-iconic"); mItem.onclick =()=> search(m[2]); }); function search(finder) { gBrowser.selectedTab = gBrowser.addTrustedTab(finder + encodeURIComponent(gContextMenu.imageURL)) }; var mItem = menuPopup.appendChild(document.createXULElement("menuitem")); mItem.setAttribute("label", 'Искать во всех поисковиках'); mItem.setAttribute("class","menuitem-iconic"); mItem.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADZElEQVR42oXSe0xbVRwH8N8597a35e7SAmUFukGhY66AMiNzw4GvTCQLCssc4pQsmTOa+ERMlrktW1zigpnEuWn8x2eMmiVGMBDCFjS+cJHEDIk8RoSNV1+3tLWX3t72nnO8sETJFrfvP7/k5Pw+Ob9fDoLrYi8ow9GFUbq+5aRLrGraqQcX6hlF2wkFEWn6EDIJAyQy9+3VT58cWb6PrmvmjGZS/FSHlxbXtbtLobGqJlPKMhNepWb0V8hKpi8FNd/gzCCogbdmvtg/8C9gz9+Eor5x5nn2tDOZ98Dx2i3C/uYai9mOGCxiDQIIg1/PgUCEhyvDMox9PXYBkPzaaoAzAFL0yle7ShtqO/eWJ9w1vJ1oGsVzYhTNATMQG4Q1G40ldDw6PB339fs7VgMmA0jnHfioo6F9Z3tDYYJzKSZKMYcDvAILiICfZUNYEYFixMKpKBk8MfTTasBsACnngU/6Wg4+VL/VFSOmBHAYY1BAhzAvgmyMEIkh0EUOBD1Eu49eStwA5D3z4TcPv9TYdHvxEhXSGgaEIMkJkKAS+ONmSKYolOVqMBlRSd8bv8v/AQXlJoiHUE5rZ1tFa/Nhj1uVrCaNMoQxYSaIqDxAGqAuQ2XZ1iS8HUTpkZMXe1eATOdtiCcJblGe1a3PnWp0uEvfv3tbeX5RhSet/q3wxh6xgAncZUmw2hxEryQx9/LHE7I2RV5HNudGFAtcZsuQd919u/kiz56JOwobcjd6xerqKnB4HIB4RvMzCM1DGj8X0GD64pL2Xdf850z+4djKC8wl24XUpj1P75sdfe/+sSHoq3uQnSuwa+s2Vy5uubd2jQWUTAYchJK8HpyIzvv7p/rMkV/OzPeeGEWi+x6LufiR573h8VO7Zr4n9fEZNeiqXHOofFvPsKPkS1fKsX5JU6uNZQh8Wh/hRcuvOC3/fLXrcGj52yOo7zzU9udvbzbN9uglggK2MhsnvfiE0tY9tfed7vM98D+x53tx1DdG0Z2b97Ejf3SRSiGGCysyENvdoipZa4+/8NmPp8+N+Ei2ZEVpQhG71rdcqFFozD+xcoQugFUvlDS8wWsl8Uebk5C79ujjHwyc6R/309ysDBRauEzhJkG9ErAdG0xEe6yVkwqcr+549/zZgcmQ7pAEkH2TDG6RfwCoJI0uEWJP5QAAAABJRU5ErkJggg=="); mItem.onclick =()=> { array.forEach(m=> { gBrowser.selectedTab = gBrowser.addTrustedTab(m[2] + encodeURIComponent(gContextMenu.imageURL)) }) }; })(); 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);
Отредактировано Garalf (20-02-2025 18:45:49)
Отсутствует
Dumby
В 136 пререлизе у меня не устанавливаются CB и ATB
Появляется сообщение: Дополнение не может быть установлено,
так как оно не было проверено.
Может, что то в config.js не так?
// try {(jsval => { var dbg, gref, genv = func => { var sandbox = new Cu.Sandbox(g, {freshCompartment: true}); Cc["@mozilla.org/jsdebugger;1"].createInstance(Ci.IJSDebugger).addClass(sandbox); (dbg = new sandbox.Debugger()).addDebuggee(g); gref = dbg.makeGlobalObjectReference(g); return (genv = func => func && gref.makeDebuggeeValue(func).environment)(func); } var g = Cu.getGlobalForObject(jsval), o = g.Object, {freeze} = o, disleg; var AC = "AppConstants", uac = `resource://gre/modules/${AC}.`; var lexp = () => lockPref("extensions.experiments.enabled", true); if (o.isFrozen(o)) { // Fx 102.0b7+ lexp(); disleg = true; var env, def = g.ChromeUtils.defineModuleGetter; g.ChromeUtils.defineModuleGetter = (...args) => { try { genv(); dbg.addDebuggee(globalThis); var e = dbg.getNewestFrame().older.environment; var obj = e.parent.type == "object" && e.parent.object; if (obj && obj.class.startsWith("N")) // JSM, NSVO obj.unsafeDereference().Object = { freeze: ac => (ac.MOZ_REQUIRE_SIGNING = false) || freeze(ac) }; else env = e; // ESM, Lexy "var"(?) } catch(ex) {Cu.reportError(ex);} (g.ChromeUtils.defineModuleGetter = def)(...args); } ChromeUtils.import(uac + "jsm"); // (?) env && env.setVariable(AC, gref.makeDebuggeeValue(freeze(o.assign( new o(), env.getVariable(AC).unsafeDereference(), {MOZ_REQUIRE_SIGNING: false} )))); } else o.freeze = obj => { if (!Components.stack.caller.filename.startsWith(uac)) return freeze(obj); obj.MOZ_REQUIRE_SIGNING = false; if ((disleg = "MOZ_ALLOW_ADDON_SIDELOAD" in obj)) lexp(); else obj.MOZ_ALLOW_LEGACY_EXTENSIONS = true, lockPref("extensions.legacy.enabled", true); return (o.freeze = freeze)(obj); } lockPref("extensions.experiments.enabled", true); lockPref("xpinstall.signatures.required", false); lockPref("extensions.langpacks.signatures.required", false); var useDbg = true, xpii = "resource://gre/modules/addons/XPIInstall.jsm"; if (Ci.nsINativeFileWatcherService) { // Fx < 100 jsval = Cu.import(xpii, {}); var shouldVerify = jsval.shouldVerifySignedState; if (shouldVerify.length == 1) useDbg = false, jsval.shouldVerifySignedState = addon => !addon.id && shouldVerify(addon); } if (useDbg) { jsval = g.ChromeUtils.import(xpii); var env = genv(jsval.XPIInstall.installTemporaryAddon); var ref = name => {try {return env.find(name).getVariable(name).unsafeDereference();} catch {}} jsval.XPIDatabase = (ref("lazy") || {}).XPIDatabase || ref("XPIDatabase"); var proto = ref("Package").prototype; var verify = proto.verifySignedState; proto.verifySignedState = function(id) { return id ? {cert: null, signedState: undefined} : verify.apply(this, arguments); } dbg.removeAllDebuggees(); } if (disleg) jsval.XPIDatabase.isDisabledLegacy = () => false; })( "permitCPOWsInScope" in Cu ? Cu.import("resource://gre/modules/WebRequestCommon.jsm", {}) : Cu );} catch(ex) {Cu.reportError(ex);} // // (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} = (imp = url => Cu.import(url, {}))(xp + "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."); // // version, date year-month-day: 2024-6-12 (async () => { var file = Services.dirsvc.get("UChrm", Ci.nsIFile), iname; file.append("user_chrome_files"); file.append("user_chrome.manifest"); if (!file.exists() || !file.isFile()) return; switch (Services.appinfo.name) { case "Firefox": iname = "user_chrome.js"; break; case "Thunderbird": iname = "user_chrome_tb.js"; break; default: return; } Components.manager.QueryInterface(Ci.nsIComponentRegistrar) .autoRegister(file); var sandbox = Cu.Sandbox(Services.scriptSecurityManager.getSystemPrincipal(), { wantComponents: true, sandboxName: "UserChromeFiles", wantGlobalProperties: ["ChromeUtils"], }); Services.scriptloader.loadSubScript(`chrome://user_chrome_files/content/user_chrome/${iname}`, sandbox, "UTF-8"); })();
policies.json
{ "policies": { "BlockAboutAddons": false, "BlockAboutConfig": false, "BlockAboutProfiles": false, "BlockAboutSupport": false, "DisableSetDesktopBackground": true, "DisableMasterPasswordCreation": true, "DisableFeedbackCommands": true, "DisableFirefoxStudies": true, "DisableProfileRefresh": true, "DisableTelemetry": true, "NoDefaultBookmarks": false, "OverrideFirstRunPage": "", "OverridePostUpdatePage": "", "SearchEngines": { "Add": [ { "Name": "Google RU", "URLTemplate": "https://www.google.com/search?q={searchTerms}®ion=ru-RU", "Method": "GET", "Description": "metager", "IconURL": "https://www.google.com/favicon.ico" }, { "Name": "Metager", "URLTemplate": "https://metager.de/meta/meta.ger3?eingabe={searchTerms}", "Description": "metager", "IconURL": "https://metager.de/favicon.ico" } ], "Default": "Google RU" }, "Preferences": { "browser.search.update": false, "browser.search.newSearchConfig.enabled": false, "browser.warnOnQuitShortcut": false, "datareporting.policy.dataSubmissionPolicyBypassNotification": true, "extensions.blocklist.enabled": false, "extensions.getAddons.showPane": false, "extensions.experiments.enabled": true, "xpinstall.signatures.required": false, "extensions.legacy.enabled": true, "extensions.htmlaboutaddons.recommendations.enabled": false, "intl.accept_languages": "ru-RU,ru,en-US,en", "print.more-settings.open": true, "security.ssl.errorReporting.enabled": false, "browser.newtabpage.activity-stream.feeds.telemetry": false, "toolkit.legacyUserProfileCustomizations.stylesheets": true, "widget.macos.native-context-menus": false } } }
Отсутствует
Может, что то в config.js не так?
Антиподписячий код не выглядит как последний выкладывавшийся.
Проверил с последним на 136.0 RC build3, CB и ATB установились нормально.
Ещё, UCF-стафф не последний, но это к вопросу отношения не имеет.
Отсутствует
Dumby
Спасибо за подсказку. Теперь все работает.
Ну и нашел еще одну кнопку, которая перестала работать в 136
Консоль браузера
/*Initialization Code*/ ({ title: "Browser Console", url: "chrome://devtools/content/webconsole/index.html", icon: "chrome://devtools/skin/images/tool-webconsole.svg", init() { var trg = document.getElementById("browser"); trg && addEventListener("DOMContentLoaded", this, false, trg); var id = "viewBrowserConsoleSidebar"; var menuitem = this.element("menuitem", { type: "checkbox", label: this.title, id: "menu_browserConsoleSidebar", oncommand: `(globalThis.SidebarController || globalThis.SidebarUI).toggle("${id}");` }, document.getElementById("viewSidebarMenu")); var btn = this.element("toolbarbutton", { type: "checkbox", label: this.title, id: "sidebar-switcher-browserConsole", oncommand: `(globalThis.SidebarController || globalThis.SidebarUI).show("${id}");`, class: "subviewbutton subviewbutton-iconic" }); document.querySelector( parseInt(Services.appinfo.platformVersion) >= 116 ? 'menuitem[id^="sidebar-switcher-"] + menuseparator' : 'toolbarbutton[id^="sidebar-switcher-"] + toolbarseparator' ).before(btn); (globalThis.SidebarController || globalThis.SidebarUI).sidebars.set(id, { url: this.url, buttonId: btn.id, title: this.title, menuId: menuitem.id }); (globalThis.SidebarController || globalThis.SidebarUI).isOpen && (globalThis.SidebarController || globalThis.SidebarUI).currentID == id && (globalThis.SidebarController || globalThis.SidebarUI).selectMenuItem(id); var popupset = this.popupset = this.element("popupset", { id: `CB${_id.slice(20)}-browserConsole-popupset` }, document.documentElement); var css = `\ #${btn.id} > .toolbarbutton-icon, #sidebar-box[sidebarcommand="${id}"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon { list-style-image: url(${this.icon}); }`; var str = (cbu.cb || "") + "data:text/css," + encodeURIComponent(css), type = windowUtils.USER_SHEET; windowUtils.loadSheetUsingURIString(str, type); addDestructor(() => { (globalThis.SidebarController || globalThis.SidebarUI).sidebars.delete(id); btn.remove(); menuitem.remove(); popupset.remove(); windowUtils.removeSheetUsingURIString(str, type); }); parseInt(Services.appinfo.platformVersion) < 73 && "insertFTLIfNeeded" in MozXULElement && MozXULElement.insertFTLIfNeeded("toolkit/main-window/editmenu.ftl"); self.onclick = e => { if (e.button == 2) return; if (!e.button && !e.shiftKey) return (globalThis.SidebarController || globalThis.SidebarUI).toggle(id); var st = gBrowser.selectedTab, tab; if (!e.ctrlKey) tab = gBrowser.visibleTabs.find(tab => { var br = gBrowser.getBrowserForTab(tab); return br.currentURI.spec == this.url || ( "_cachedCurrentURI" in br && br._cachedCurrentURI.spec == this.url ) }); if (tab == st) return; if (!tab) tab = gBrowser.addTrustedTab(this.url); gBrowser.moveTabTo(tab, st._tPos + 1); gBrowser.selectedTab = tab; } for(var br of gBrowser.browsers) { if (br.currentURI.spec != this.url) continue; var doc = br.contentDocument; if (doc && ( doc.readyState == "complete" || doc.readyState == "interactive" )) doc.querySelector( "main#app-wrapper,div#output-container" ).childElementCount ? this.defineDocPopupset(doc) : this.handleEvent({target: doc}); } if (!btn.hasAttribute("checked")) return; var doc = (globalThis.SidebarController || globalThis.SidebarUI).browser.contentDocument; if (doc.documentURI != this.url) btn.doCommand(); else if (doc.readyState == "complete") this.defineDocPopupset(doc); }, defineDocPopupset(doc) { this.definePopupset( doc.querySelector("popupset") || doc.documentElement.appendChild(doc.createXULElement("popupset")) ); }, get definePopupset() { var append = customElements.get("menuitem") ? popup => { this.popupset.appendChild(popup); popup.setAttribute("oncommand", "event.target.cmd()"); for(var node of [...popup.querySelectorAll("menuitem")]) { var menuitem = document.importNode(node, true); menuitem.cmd = Services.els.getListenerInfoFor(node) .find(inf => inf.type == "command").listenerObject; popup.replaceChild(menuitem, node); } return popup; } : this.popupset.appendChild.bind(this.popupset); delete this.definePopupset; return this.definePopupset = popupset => popupset.appendChild = append; }, lss: Services.scriptloader.loadSubScript, async handleEvent({target: doc}) { if (!doc || doc.documentURI != this.url) return; var win = doc.defaultView; if ( win.docShell.name == "toolbox-panel-iframe-webconsole" || doc.DOMContentLoadedEventHandled ) return; doc.DOMContentLoadedEventHandled = true; if (this instanceof XULElement) // Custom Buttons "custombuttonsConsole" in win || this.lss( "chrome://custombuttons/content/consoleOverlay.js", win ); var cw = win.isChromeWindow, bc; if (!cw) { if (doc.visibilityState == "hidden") { var {focus} = win; win.focus = () => win.focus = focus; } doc.title = this.title; var link = doc.createElement("link"); link.setAttribute("rel", "shortcut icon"); link.setAttribute("href", this.icon); doc.head.prepend(link); var br = win.docShell.chromeEventHandler; var cmAttr = br.getAttribute("contextmenu"); cmAttr && br.removeAttribute("contextmenu"); win.onbeforeunload = () => { if (bc) bc.chromeWindow = {close() {}}; cmAttr && br.setAttribute("contextmenu", cmAttr); } } bc = await this.console(win); }, get console() { // Bug 1579090 - WebConsole should handle ObjectFront when needed (for non-primitive Console API args + Evaluation results) (Firefox 73+) https://bugzilla.mozilla.org/show_bug.cgi?id=1579090 var vers = parseInt(Services.appinfo.platformVersion); this.bug1579090 = vers > 73 || (vers == 73 && !( "_setCurrentURI" in gBrowser.selectedBrowser // https://bugzil.la/1431214 )); delete this.console; return this.console = this.bug1579090 ? async win => { //await this.loader.bcm._browserConsoleInitializing; var key = "CBBrowserConsolePromise", {wins} = this.loader; win[key] = win.Object.create(null); win[key].promise = new win.Promise(resolve => win[key].resolve = resolve); win[key].destroy = () => { win[key].resolve(); delete win[key]; wins.splice(wins.indexOf(win), 1); } wins.unshift(win); wins.length > 1 && await wins[1][key].promise; var bc = await new this.loader.console(win).toggleBrowserConsole(); win[key].destroy(); return bc; } : async win => { this.loader.Services.ww.wins.push(win); return await new this.loader.HUDService().toggleBrowserConsole(); } }, get loader() { delete this.loader; var url = parseInt(Services.appinfo.platformVersion) >= 96 ? "resource://devtools/shared/loader/Loader.jsm" : "resource://devtools/shared/Loader.jsm"; if (this.bug1579090) { var g = Cu.import(url, {}), key = "CBBrowserConsoleLoader"; addDestructor(reason => reason[5] == e && key in g && g[key].destroy()); if (key in g) return this.loader = g[key]; var {BrowserConsoleManager} = g.require( "devtools/client/webconsole/browser-console-manager" ); return this.loader = g[key] = { wins: [], bcm: BrowserConsoleManager, console: class extends BrowserConsoleManager.constructor { constructor(win) { super(); this.win = win; } openWindow() { var {win} = this; win.addEventListener("unload", () => { win.CBBrowserConsolePromise && win.CBBrowserConsolePromise.destroy(); this.closeBrowserConsole.call(this); }, {once: true}); delete this.win; return win; } }, destroy() { this.wins = null; delete g[key]; } }; } var id = _id + "-browser-console"; url += "?" + id; var loader = {exports: {}}, nsvo = Cu.import(url, loader); addDestructor(reason => reason[5] == "e" && Cu.unload(url)); if (id in nsvo) return this.loader = nsvo[id]; var dir = "resource://devtools/client/webconsole/"; try { this.lss(dir + "hudservice.js", loader); } catch(ex) { // Bug 1570320 - Rename hudservice.js into browser-console-manager.js (Firefox 70+) // https://bugzilla.mozilla.org/show_bug.cgi?id=1570320 this.lss(dir + "browser-console-manager.js", loader); this.lss("data:,this.HUDService=BrowserConsoleManager", loader); } var e = new CustomEvent("DOMContentLoaded", {bubbles: false}), ww = loader.Services.ww; loader.Services.ww = Cu.getGlobalForObject(nsvo).Object.create(ww, { wins: {value: []}, openWindow: {value: function() { var win = this.wins.shift(); win.setTimeout(() => win.dispatchEvent(e), 0); return win; }} }); return this.loader = nsvo[id] = loader; }, element(name, attrs, parent) { var node = document.createXULElement(name); for(var attr in attrs) node.setAttribute(attr, attrs[attr]); parent && parent.append(node); return node; } }).init(); this.tooltipText = "Консоль браузера" +"\n"+"\n"+ "ЛКМ: В боковой панели" +"\n"+ "СКМ: В новой вкладке" +"\n"+ "ПКМ: Стандартное меню "
Отсутствует
Ну и нашел еще одну кнопку, которая перестала работать в 136
Консоль браузера
Нее, от кнопки я решил отказаться.
На новых версиях, перехожу на скрипт для UCF.
Для сандбокса, custom_script.js, scriptsbackground
(в окна не совать!)
Локализация там, по сути, особо не нужна,
просто эксперимент с mock-fluent'ом.
(async url => { var img = "chrome://devtools/skin/images/tool-webconsole.svg"; var strings = { ru: { label: "Консоль браузера", tooltip: [ "Л: Сайдбар", "С: Вкладка", "П: Окно" ] }, def: { label: "Browser console", tooltip: [ "L: Sidebar", "M: Tab", "R: Window" ] }, }; var fluentLabel = "browser-console-label"; var fluentButton = "browser-console-button"; var fluentFile = "user/browser-console.ftl"; var version = parseInt(Services.appinfo.platformVersion); for (var [loc, data] of Object.entries(strings)) { var lab = data.label; strings[loc] = `${ fluentButton } =\n.label = ${lab}\n.tooltiptext = ${ data.tooltip.map(str => "\n " + str).join("") }\n${ fluentLabel } =\n.label = ${lab}`; } var registry = L10nRegistry.getInstance(); var sourceName = sfx => "u-browser-console-" + sfx; var getSource = (locs, meta, name) => { var sources = Array.from(locs, loc => ({ path: `/localization/${loc}/${fluentFile}`, source: strings[loc] || strings.def })); return L10nFileSource.createMock( name || sourceName("pkg"), meta, locs, "/localization/{locale}/", sources ); } registry.registerSources([ getSource(Services.locale.packagedLocales, "app") ]); var fileSources = new Map(); var register = langpacks => { var sourcesToReg = []; for(var langpack of langpacks) { var {langpackId, languages} = langpack.startupData; var name = sourceName(langpackId); if (registry.hasSource(name)) continue; var fileSource = fileSources.get(langpackId); fileSource || fileSources.set( langpackId, fileSource = getSource(languages, langpackId, name) ); sourcesToReg.push(fileSource); } registry.registerSources(sourcesToReg); } var file = Services.dirsvc.get("ProfD", Ci.nsIFile); file.append("extensions.json"); try { var langpacks = JSON.parse(Cu.readUTF8File(file)) .addons.filter(a => a.startupData?.langpackId && a.active); langpacks?.length && register(langpacks); } catch {} var unreg = addon => { if (addon.type != "locale") return; var name = sourceName(addon.__AddonInternal__.startupData.langpackId); registry.hasSource(name) && registry.removeSources([name]); } var addonListener = Object.create(null); for(var p of ["onDisabled", "onUninstalling", "onUninstalled"]) addonListener[p] = unreg; AddonManager.addAddonListener(addonListener); var topicLng = "webextension-langpack-startup"; var topicWin = "browser-delayed-startup-finished"; var {addObserver: add, removeObserver: rem} = Services.obs; var reg = subj => register([subj.wrappedJSObject.langpack]); add(reg, topicLng); add(onBrowserWin, topicWin); add(function quit(s, topic) { rem(quit, topic); rem(reg, topicLng); rem(onBrowserWin, topicWin); }, "quit-application-granted"); var addFtlLink = (doc, href) => { var link = doc.createElement("link"); link.rel = "localization"; link.href = href; doc.head.prepend(link); } var maybeInsertFTL = doc => !( doc.head.querySelector(`[href="${fluentFile}"]`) || addFtlLink(doc, fluentFile) ); var impl; CustomizableUI.createWidget(impl = { l10nId: fluentButton, id: "browser-console-button", defaultArea: CustomizableUI.AREA_NAVBAR, onCreated(btn) { maybeInsertFTL(btn.ownerDocument); btn.image = img; for(var type of this.events) btn.addEventListener(type, this); }, events: ["command", "auxclick", "contextmenu"], handleEvent(e) { this[e.type](e); }, command(e) { e.view.SidebarController.toggle(id); }, auxclick(e) { if (e.button != 1) return; var gb = e.view.gBrowser; if (!e.ctrlKey && !e.shiftKey) for(var tab of gb.visibleTabs) if (tab.linkedBrowser?.currentURI.spec == url) return gb.selectedTab = tab; gb.selectedTab = gb.addTrustedTab(url, {index: gb.selectedTab._tPos + 1}); }, contextmenu(e) { if (!e.ctrlKey && !e.shiftKey) e.preventDefault(), this.bcm.openBrowserConsoleOrFocus(); }, get bcm() { delete this.bcm; return this.bcm = ChromeUtils.importESModule( "resource://devtools/shared/loader/Loader.sys.mjs" ).require( "devtools/client/webconsole/browser-console-manager" ).BrowserConsoleManager; } }); var revamp = true, pref = "sidebar.revamp"; if (Services.prefs.prefHasDefaultValue(pref)) { var obs = () => revamp = Services.prefs.getBoolPref(pref); Services.prefs.addObserver(pref, obs); obs(); } var id = "viewBrowserConsoleSidebar"; var addSidebar = version >= 135 ? (bars, sb) => bars.set(id, sb) : (bars, sb) => { // viewCustomizeSidebar breaks iteration in SidebarController.selectMenuItem() var arr = Array.from(bars); bars.clear(); bars.set(id, sb); for(var args of arr) bars.set(...args); } var maybeAddSidebar = (sc, sb) => { var bars = sc.sidebars; bars.has(id) || addSidebar(bars, sb); } var addFluentRes = sm => sm.fluentStrings.addResourceIds([fluentFile]); var ce = {configurable: true, enumerable: true}; function onBrowserWin(win) { win.addEventListener("DOMContentLoaded", onDOMContentLoaded); var doc = win.document; maybeInsertFTL(doc); var sc = win.SidebarController; var sep = doc.querySelector("#sidebarMenu-popup > menuseparator"); if (sep) { var switcher = doc.createXULElement("menuitem"); switcher.dataset.l10nId = fluentLabel; switcher.id = "sidebar-switcher-browser-console"; switcher.addEventListener("command", () => sc.toggle(id)); sep.before(switcher); } var sb = sc.makeSidebar({ url, iconUrl: img, elementId: switcher?.id, menuL10nId: fluentLabel, revampL10nId: fluentLabel, menuId: "menu_browserConsoleSidebar" }); var popup = doc.getElementById("viewSidebarMenu"); popup.insertBefore( sc.createMenuItem(id, sb), popup.querySelector(".webextension-menuitem") ); var o = win.Object; var def = (obj, prop, desc) => o.defineProperty(obj, prop, o.assign(desc, ce)); def(sb, "hasOwnProperty", {value(prop) { prop == "extensionId" && win.setTimeout(maybeAddSidebar, 0, sc, sb); return o.hasOwn(sb, prop); }}); addSidebar(sc.sidebars, sb); var br = sc.browser; def(UcfPrefs.dbg.ref("defaultTools", sc.init, win), id, {get() { var doc = br.contentDocument; var cust = doc?.querySelector("sidebar-customize"); cust && maybeInsertFTL(doc) && UcfPrefs.dbg.ref("l10nMap", cust.constructor, 0).set(id, fluentLabel); return "browserconsole"; }}); sc._toolsAndExtensions = null; var sm = sc.sidebarMain; if (revamp) addFluentRes(sm), sm.requestUpdate(); else win.customElements.whenDefined("sidebar-main").then(() => addFluentRes(sm)); } var noop = () => {}; var setSmall = hdr => hdr.shadowRoot .querySelector("moz-button").setAttribute("size", "small"); var addCloseBtn = async (doc, win) => { var main = doc.body.querySelector("main"); var {promise, resolve} = win.Promise.withResolvers(); var mo = new win.MutationObserver(resolve); mo.observe(main, {childList: true}); await promise; mo.disconnect(); var header = main.querySelector("header"); addFtlLink(doc, "browser/sidebar.ftl"); var url = "chrome://browser/content/sidebar/sidebar-panel-header.mjs"; UcfPrefs.dbg.makeGlobalObjectReference(win).executeInGlobal( `ChromeUtils.importESModule("${url}", {global: "current"});` ); var sph = doc.createElement("sidebar-panel-header"); header.append(sph); win.setTimeout(setSmall, 50, sph); var sheet = new win.CSSStyleSheet(); sheet.replaceSync(` h4 { display: none !important } :host { flex-grow: 1 !important; display: flex !important; justify-content: end !important; } moz-button, moz-button::part(button) { display: flex !important; height: 100% !important; min-height: 100% !important; } `); sph.shadowRoot.adoptedStyleSheets.push(sheet); } var onDOMContentLoaded = e => { var doc = e.target; if (doc?.documentURI != url) return; var win = doc.ownerGlobal, ds = win.docShell; ds.name != "toolbox-panel-iframe-webconsole" && onConsoleDOMContentLoaded(doc, win, ds); } var onConsoleDOMContentLoaded = async (doc, win, ds) => { try {Services.scriptloader.loadSubScript( "chrome://custombuttons/content/consoleOverlay.js", win )} catch {} var tabWin = !win.isChromeWindow; if (tabWin) { if (doc.visibilityState == "hidden") { var {focus} = win; win.focus = () => win.focus = focus; } win.browsingContext .currentWindowGlobal.windowGlobalChild .getActor("ContextMenu").handleEvent = noop; var br = ds.chromeEventHandler; var cmAttr = br.getAttribute("contextmenu"); var gb = br.ownerGlobal.gBrowser; gb.setIcon(gb.getTabForBrowser(br), img); } else if (revamp) addCloseBtn(doc, win); var bc = await getConsole(win); if (tabWin) { if (cmAttr) bc.cmAttr = cmAttr, (bc.br = br).removeAttribute("contextmenu"); bc.updateWindowTitle(win); } } var resolvers = []; var find = function(resolver) { return resolver.id == this; } var destroy = function() { this.resolve(); resolvers.splice(resolvers.indexOf(this), 1); } var getConsole = async win => { var resolver = Promise.withResolvers(); resolver.destroy = destroy; resolver.id = win.browsingContext.id; resolvers.unshift(resolver); resolvers.length > 1 && await resolvers[1].promise; var bc = await constructConsole(win); resolver.destroy(); return bc; } var constructConsole = win => { var closer = {close: noop}; var cc = class extends impl.bcm.constructor { constructor(win) { super(); this.win = win; } openWindow() { var {win} = this; win.addEventListener("unload", this, {once: true}); delete this.win; return win; } handleEvent(e) { resolvers.find(find, e.target.ownerGlobal.browsingContext.id)?.destroy(); var bc = this.getBrowserConsole(); bc.chromeWindow = closer; this.closeBrowserConsole(); bc.br?.isConnected && bc.br.setAttribute("contextmenu", bc.cmAttr); } } return (constructConsole = win => new cc(win).toggleBrowserConsole())(win); } })("chrome://devtools/content/webconsole/index.html");
Отредактировано Dumby (02-03-2025 19:15:11)
Отсутствует
А ты случайно не делал скрипт UserCSSLoader,
чето кнопка уменя не работает.
Нет. Я даже не знаю что это такое.
А не работает, скорее всего, из-за «on…» атрибутов
и/или C{u, hromeUtils}.import(). Это основной отвал на 136.
Отсутствует
"Ну и нашел еще одну кнопку, которая перестала работать в 136
Консоль браузера"
Прошу прощения, кнопка рабочая. Там был конфликт с одним раширением.
Отредактировано Garalf (02-03-2025 22:14:43)
Отсутствует
В 115
Думаешь я помню что там было в 115?
toggleRestartlessAddons.js В 115 не того,сдох ?
Неизвестно.
Возможно где-то есть, надо бы поискать, но я не искун.
И Dom inspector тоже...?
Хотелось бы думать, что подойдёт из этого поста.
Отсутствует
В 137 прикатил Bug 1946764, поэтому во всех CSS нужно заменить...
Жизнь иногда такое выкидывает, что хочется подобрать...
Отсутствует
Dumby
Это сдохло, а жаль..
((id, g) => { addDestructor(r => r[5] == "e" && id in g && g[id].destroy()); if (g[id]) return; var topic = "quit-application-granted", {obs} = Services; obs.addObserver(g[id] = { // true - disable, false - enable states: { "jid1-s2tSKqH4h0BHUw@jetpack": false, "mozilla_cc3@internetdownloadmanager.com": false, "{74145f27-f039-47ce-a470-a662b129930a}": false, "{acf99872-d701-4863-adc2-cdda1163aa34}": true, "{8f4bbf79-5514-4d04-a901-d5fabfe91d73}": true, }, filter(addon) { var state = this.states[addon.id]; if ( state !== undefined && addon.userDisabled != state && addon.type.endsWith("extension") && addon.location.name != "app-builtin" ) { addon.active = addon.location.get(addon.id).enabled = !(addon.userDisabled = state); return true; } }, observe() { this.destroy(); if (g.XPIDatabase.getAddons().filter(this.filter, this).length) g.XPIDatabase.saveChanges(), g.XPIStates.save(); }, destroy() { delete g[id]; obs.removeObserver(this, topic); } }, topic, false); })( "CBQuitApplicationExtensionsSwitcher", Cu.import("resource://gre/modules/addons/XPIDatabase.jsm", {}) );
Отредактировано green25 (05-03-2025 05:44:17)
Отсутствует
green25
Кнопка CB toggleRestartlessAddons для 115
// 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" // See "var style = " to modify styles for specific add-ons // (c) Infocatcher 2013-2019 // version 0.1.3pre4 - 2020-01-01 var options = { addonTypes: ["extension"], // Possible values: "extension", "plugin" // From extensions: "userstyle" (Stylish), "greasemonkey-user-script" (Greasemonkey), "userscript" (Scriptish) // (swap to reorder in the menu) showVersions: 1, // 0 - don't show versions // 1 - show after name: "Addon Name 1.2" // 2 - show as "acceltext" (in place for hotkey text) showHidden: 0, // 0 - don't show hidden add-ons // -1 - show only enabled hidden add-ons (e.g. to track new items) // 1 - show all hidden add-ons sort: { enabled: 0, clickToPlay: 0, disabled: 1 // Sort order: // 0, 0, 0 - sort add-ons of each type alphabetically // 0, 0, 1 - show enabled add-ons (of each type) first // 0, 1, 2 - enabled add-ons, then click-to-play and then disabled }, closeMenu: false, // Close menu after left-click closeMenuClickToPlay: false // Close menu after left-click, for click to play plugins // Use Shift+click to invert closeMenu* behavior }; var xulns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var mp = document.createElementNS(xulns, "menupopup"); mp.setAttribute("onpopupshowing", "this.updateMenu();"); mp.setAttribute("oncommand", "this.handleEvent(event);"); mp.setAttribute("onmousedown", "if(event.button == 0) this.handleEvent(event);"); mp.setAttribute("onclick", "if(event.button > 0) this.handleEvent(event);"); mp.setAttribute("oncontextmenu", "return false;"); mp.setAttribute("onpopuphidden", "this.destroyMenu();"); var tb = this.parentNode; if(tb && tb.getAttribute("orient") == "vertical") { // https://addons.mozilla.org/firefox/addon/vertical-toolbar/ var isRight = tb.parentNode.getAttribute("placement") == "right"; mp.setAttribute("position", isRight ? "start_before" : "end_before"); } var cleanupTimer = 0; mp.updateMenu = function() { clearTimeout(cleanupTimer); addStyle(); getRestartlessAddons(options.addonTypes, function(addons) { var df = document.createDocumentFragment(); var prevType; function sortPosition(addon) { if("STATE_ASK_TO_ACTIVATE" in AddonManager && addon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE) return options.sort.clickToPlay; if(addon.isActive) return options.sort.enabled; return options.sort.disabled; } function key(addon) { return options.addonTypes.indexOf(addon.type) + "\n" + sortPosition(addon) + "\n" + addon.name.toLowerCase(); } addons.sort(function(a, b) { var ka = key(a); var kb = key(b); return ka == kb ? 0 : ka < kb ? -1 : 1; }).forEach(function(addon) { var type = addon.type; if(prevType && type != prevType) df.appendChild(document.createElementNS(xulns, "menuseparator")); prevType = type; var icon = addon.iconURL || addon.icon64URL; var mi = document.createElementNS(xulns, "menuitem"); mi.className = "menuitem-iconic"; var label = addon.name; if(options.showVersions == 1) label += " " + addon.version; else if(options.showVersions == 2) mi.setAttribute("acceltext", addon.version); mi.setAttribute("label", label); mi.setAttribute("image", icon || mp.icons[type] || ""); if(!icon && mp.icons.useSVG) mi.style.fill = "#15c"; var tip = addon.description || ""; var delay = "delayedStartupAddons" in Services && Services.delayedStartupAddons[addon.id] || null; var isDelayed = delay !== null; mi.classList.toggle("toggleRestartlessAddons-isDelayed", isDelayed); if(isDelayed) tip = "[Delayed Startup: " + delay.toLocaleString() + "]" + (tip ? "\n" + tip : ""); tip && mi.setAttribute("tooltiptext", tip); mi.classList.toggle("toggleRestartlessAddons-isHidden", addon.hidden || false); setDisabled(mi, addon.userDisabled); mi._cbAddon = addon; df.appendChild(mi); }); mp.textContent = ""; mp.appendChild(df); }); }; mp.handleEvent = function(e) { var mi = e.target; if(!("_cbAddon" in mi)) return; var addon = mi._cbAddon; if(e.type == "mousedown") { var closeMenu = isAskToActivateAddon(addon) ? options.closeMenuClickToPlay : options.closeMenu; if(e.shiftKey) closeMenu = !closeMenu; mi.setAttribute("closemenu", closeMenu ? "auto" : "none"); return; } var hasMdf = hasModifier(e); if(e.type == "command" && (!hasMdf || e.shiftKey)) { let newDis = setNewDisabled(addon); setDisabled(mi, newDis); } else if(e.type == "command" && hasMdf || e.type == "click" && e.button == 1) { openAddonPage(addon); closeMenus(mi); } else if(e.type == "click" && e.button == 2) { if(openAddonOptions(addon)) closeMenus(mi); } }; mp.destroyMenu = function() { removeStyle(); clearTimeout(cleanupTimer); cleanupTimer = setTimeout(function() { mp.textContent = ""; }, 5000); }; mp.icons = { get platformVersion() { delete this.platformVersion; return this.platformVersion = parseFloat(Services.appinfo.platformVersion); }, get useSVG() { delete this.useSVG; return this.useSVG = Services.appinfo.name == "Firefox" && this.platformVersion >= 57; }, get plugin() { delete this.plugin; return this.plugin = this.useSVG ? this.platformVersion >= 65 ? "chrome://global/skin/plugins/pluginGeneric.svg" : "chrome://mozapps/skin/plugins/pluginGeneric.svg" : "chrome://mozapps/skin/plugins/pluginGeneric-16.png"; }, get extension() { delete this.extension; return this.extension = this.useSVG ? this.platformVersion >= 76 ? "chrome://mozapps/skin/extensions/extensionGeneric.svg" // Or chrome://mozapps/skin/extensions/extension.svg : "chrome://mozapps/skin/extensions/extensionGeneric-16.svg" : "chrome://mozapps/skin/extensions/extensionGeneric-16.png"; } }; function isAskToActivateAddon(addon) { return addon.type == "plugin" && "STATE_ASK_TO_ACTIVATE" in AddonManager && Services.prefs.getBoolPref("plugins.click_to_play", true); } function setNewDisabled(addon) { var newDis = getNewDisabled(addon); var oldDis = addon.userDisabled; try { addon.userDisabled = newDis; } catch(e) { // Error: Cannot disable hidden add-on firefox@getpocket.com _log("Can't set addon.userDisabled to " + newDis + ", error:\n" + e); if(addon.hidden) setNewDisabledRaw(addon, newDis); } var realDis = addon.userDisabled; if(realDis != newDis && addon.type == "extension") { // Firefox 62+? Weird things happens setNewDisabledRaw(addon, newDis); realDis = addon.userDisabled; } if(realDis != newDis) { // We can't enable vulnerable plugins let err = "Can't set addon.userDisabled to " + newDis + ", real value: " + realDis; if(newDis) { _log(err + "\nSTATE_ASK_TO_ACTIVATE not supported?"); newDis = false; } else { _log(err + "\nVulnerable plugin?"); if(oldDis == AddonManager.STATE_ASK_TO_ACTIVATE) newDis = true; else newDis = AddonManager.STATE_ASK_TO_ACTIVATE; } addon.userDisabled = newDis; } ensureSpecialDisabled(addon, newDis); return addon.userDisabled; } function getNewDisabled(addon) { // disabled -> STATE_ASK_TO_ACTIVATE -> enabled -> ... var curDis = addon.userDisabled; var newDis; if("STATE_ASK_TO_ACTIVATE" in AddonManager && curDis == AddonManager.STATE_ASK_TO_ACTIVATE) newDis = false; else if(!curDis) newDis = true; else { if(isAskToActivateAddon(addon)) newDis = AddonManager.STATE_ASK_TO_ACTIVATE; else newDis = false; } return newDis; } function setNewDisabledRaw(addon, newDis) { _log("Let's try set addon.userDisabled using raw hack"); let g = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm", {}); if("lazy" in g) g = g.lazy; if("XPIDatabase" in g && "updateAddonDisabledState" in g.XPIDatabase) { // Firefox 61+ let rawAddon = g.XPIDatabase.getAddons().find(function(rawAddon) { return rawAddon.id == addon.id; }); g.XPIDatabase.updateAddonDisabledState( rawAddon, g.XPIDatabase.updateAddonDisabledState.length == 1 // Firefox 74+ ? { userDisabled: newDis } : newDis ); } else if("eval" in g) { // See "set userDisabled(val)" let addonFor = g.eval("addonFor"); let rawAddon = addonFor(addon); //rawAddon.userDisabled = newDis; g.XPIProvider.updateAddonDisabledState(rawAddon, newDis); } else { // Firefox 57+? See https://forum.mozilla-russia.org/viewtopic.php?pid=745272#p745272 updateAddonDisabledState(addon, newDis); } } function updateAddonDisabledState(addon, newDis) { var nsvo = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm", {}); var key = "_cbToggleRestartlessAddonsData"; var url = URL.createObjectURL(new Blob([ "XPIProvider.updateAddonDisabledState(addonFor(this." + key + "[0]), this." + key + "[1]); delete this." + key + ";" ])); addDestructor(function() { URL.revokeObjectURL(url); }); (updateAddonDisabledState = function(addon, newDis) { nsvo[key] = [addon, newDis]; Services.scriptloader.loadSubScript(url, nsvo); })(addon, newDis); } function setDisabled(mi, disabled) { var askToActivate = "STATE_ASK_TO_ACTIVATE" in AddonManager && disabled == AddonManager.STATE_ASK_TO_ACTIVATE; var cl = mi.classList; cl.toggle("toggleRestartlessAddons-askToActivate", askToActivate); cl.toggle("toggleRestartlessAddons-disabled", disabled && !askToActivate); } function ensureSpecialDisabled(addon, newDis) { if(addon.id == "screenshots@mozilla.org") Services.prefs.setBoolPref("extensions.screenshots.disabled", newDis); } if( this instanceof XULElement // Custom Buttons && typeof event == "object" && !("type" in event) && typeof _phase == "string" && _phase == "init" // Initialization ) { this.type = "menu"; this.orient = "horizontal"; this.appendChild(mp); this.onmouseover = function(e) { if(e.target != this) return; Array.prototype.some.call( this.parentNode.getElementsByTagName("*"), function(node) { if( node != this && node.namespaceURI == xulns // See https://github.com/Infocatcher/Custom_Buttons/issues/28 //&& node.boxObject //&& node.boxObject instanceof Components.interfaces.nsIMenuBoxObject && "open" in node && node.open && node.getElementsByTagName("menupopup").length ) { node.open = false; this.open = true; return true; } return false; }, this ); }; this.onmousedown = function(e) { if(e.target == this && e.button == 0 && hasModifier(e)) e.preventDefault(); }; this.oncontextmenu = function(e) { if(e.target == this && !hasModifier(e) && hasUpdater()) e.preventDefault(); }; this.onclick = function(e) { if(e.target != this) return; if(e.button == 0 && hasModifier(e) || e.button == 1) openAddonsManager(); else if(e.button == 2 && !hasModifier(e) && hasUpdater()) checkForAddonsUpdates.call(this); }; } else { // Mouse gestures or something other... let e; if(typeof event == "object" && event instanceof Event && "screenX" in event) // FireGestures e = event; else if( this instanceof Components.interfaces.nsIDOMChromeWindow && "mgGestureState" in window && "endEvent" in mgGestureState // Mouse Gestures Redox ) e = mgGestureState.endEvent; else { let anchor = this instanceof XULElement && this || window.gBrowser && gBrowser.selectedBrowser || document.documentElement; if("boxObject" in anchor) { let bo = anchor.boxObject; e = { screenX: bo.screenX, screenY: bo.screenY }; if(this instanceof XULElement) e.screenY += bo.height; } } if(!e || !("screenX" in e)) throw new Error("[Toggle Restartless Add-ons]: Can't get event object"); document.documentElement.appendChild(mp); mp.addEventListener("popuphidden", function destroy(e) { mp.removeEventListener(e.type, destroy, false); setTimeout(function() { mp.destroyMenu(); mp.parentNode.removeChild(mp); }, 0); }, false); mp.openPopupAtScreen(e.screenX, e.screenY); } function getRestartlessAddons(addonTypes, callback, context) { if(!("AddonManager" in window)) Components.utils.import("resource://gre/modules/AddonManager.jsm"); if(!("Services" in window)) Components.utils.import("resource://gre/modules/Services.jsm"); var then, promise = AddonManager.getAddonsByTypes(addonTypes, then = function(addons) { callback.call(context, addons.filter(function(addon) { var ops = addon.operationsRequiringRestart; return !addon.appDisabled && !(ops & AddonManager.OP_NEEDS_RESTART_ENABLE || ops & AddonManager.OP_NEEDS_RESTART_DISABLE) && ( !addon.hidden || options.showHidden > 0 || options.showHidden == -1 && !addon.userDisabled ) && (addon.iconURL || "").substr(0, 29) != "resource://search-extensions/"; })); }); promise && typeof promise.then == "function" && promise.then(then, Components.utils.reportError); // Firefox 61+ } function openAddonOptions(addon) { // Based on code from chrome://mozapps/content/extensions/extensions.js // Firefox 21.0a1 (2013-01-27) var optionsURL = addon.optionsURL; if(!addon.isActive || !optionsURL) return false; if(addon.type == "plugin") // No options for now! return false; if( addon.optionsType == (AddonManager.OPTIONS_TYPE_INLINE || NaN) || addon.optionsType == (AddonManager.OPTIONS_TYPE_INLINE_INFO || NaN) || addon.optionsType == (AddonManager.OPTIONS_TYPE_INLINE_BROWSER || NaN) ) openAddonPage(addon, true); else if(addon.optionsType == AddonManager.OPTIONS_TYPE_TAB && "switchToTabHavingURI" in window) switchToTabHavingURI(optionsURL, true); else { let windows = Services.wm.getEnumerator(null); while(windows.hasMoreElements()) { let win = windows.getNext(); if(win.document.documentURI == optionsURL) { win.focus(); return true; } } // Note: original code checks browser.preferences.instantApply and may open modal windows window.openDialog(optionsURL, "", "chrome,titlebar,toolbar,centerscreen,dialog=no"); } return true; } function openAddonsManager(view) { var openAddonsMgr = window.BrowserOpenAddonsMgr // Firefox || window.openAddonsMgr // Thunderbird || window.toEM; // SeaMonkey openAddonsMgr(view); } function openAddonPage(addon, scrollToPreferences) { var platformVersion = parseFloat( Services.appinfo.name == "Pale Moon" ? Services.appinfo.version : Services.appinfo.platformVersion ); scrollToPreferences = scrollToPreferences && platformVersion >= 12 ? "/preferences" : ""; openAddonsManager("addons://detail/" + encodeURIComponent(addon.id) + scrollToPreferences); } function hasModifier(e) { return e.ctrlKey || e.shiftKey || e.altKey || e.metaKey; } function addStyle() { if(addStyle.hasOwnProperty("_style")) return; var style = '\ .toggleRestartlessAddons-isDelayed > .menu-iconic-text {\n\ opacity: 0.75;\n\ color: #070;\n\ }\n\ .toggleRestartlessAddons-isHidden > .menu-iconic-text {\n\ color: #609;\n\ }\n\ .toggleRestartlessAddons-disabled > .menu-iconic-left {\n\ opacity: 0.4;\n\ }\n\ .toggleRestartlessAddons-disabled > .menu-iconic-text,\n\ .toggleRestartlessAddons-disabled > .menu-accel-container {\n\ opacity: 0.5;\n\ }\n\ .toggleRestartlessAddons-askToActivate {\n\ color: -moz-nativehyperlinktext;\n\ }'; addStyle._style = document.insertBefore( document.createProcessingInstruction( "xml-stylesheet", 'href="' + "data:text/css," + encodeURIComponent(style) + '" type="text/css"' ), document.documentElement ); } function removeStyle() { if(!addStyle.hasOwnProperty("_style")) return; var s = addStyle._style; s.parentNode.removeChild(s); delete addStyle._style; } function closeMenus(node) { // Based on function closeMenus from chrome://browser/content/utilityOverlay.js for(; node && "tagName" in node; node = node.parentNode) { if( node.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" && (node.localName == "menupopup" || node.localName == "popup") ) node.hidePopup(); } } function _log(s) { if(typeof LOG == "function") // Custom Buttons LOG(s); else // Or something else Services.console.logStringMessage("Toggle Restartless Add-ons: " + s); } function hasUpdater() { var has = checkForAddonsUpdates.toString().indexOf("about:addons") != -1; hasUpdater = function() { return has; }; return has; } function checkForAddonsUpdates() { // http://infocatcher.ucoz.net/js/cb/checkForAddonsUpdates.js // https://forum.mozilla-russia.org/viewtopic.php?id=57958 // https://github.com/Infocatcher/Custom_Buttons/tree/master/Check_for_Addons_Updates // Check for Addons Updates button for Custom Buttons // (code for "code" section) // (c) Infocatcher 2012-2021 // version 0.1.6pre4 - 2021-03-28 // Button just open hidden tab with about:addons and trigger built-in "Check for Updates" function. // And show tab, if found updates. (function() { var btn = this instanceof XULElement ? this : { // Launched not from custom button image: "", // Base64-encoded icon (if empty, will be used "imgLoading") label: "Check for Addons Updates", tooltipText: "" }; if("_cb_disabled" in btn) return; btn._cb_disabled = true; if(!("Services" in window)) Components.utils.import("resource://gre/modules/Services.jsm"); var app = Services.appinfo.name; var pv = parseFloat(Services.appinfo.platformVersion); var ADDONS_URL = "about:addons"; var progressIcon = new ProgressIcon(btn); var image = btn.image || progressIcon.imgLoading; var tip = btn.tooltipText; btn.tooltipText = "Open " + ADDONS_URL + "…"; var tab, browser, gBrowser; var tbTabInfo, tbTab; var trgWindow = Services.wm.getMostRecentWindow("navigator:browser") || app == "Thunderbird" && Services.wm.getMostRecentWindow("mail:3pane") || window; var trgDocument = trgWindow.document; var tabmail = trgDocument.getElementById("tabmail"); if(tabmail && app == "Thunderbird") { // Note: SeaMonkey doesn't support content tabs in mail window let addonsWin; let receivePong = function(subject, topic, data) { addonsWin = subject; }; Services.obs.addObserver(receivePong, "EM-pong", false); Services.obs.notifyObservers(null, "EM-ping", ""); Services.obs.removeObserver(receivePong, "EM-pong"); if(addonsWin) { let rootWindow = addonsWin .QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIWebNavigation) .QueryInterface(Components.interfaces.nsIDocShellTreeItem) .rootTreeItem .QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIDOMWindow); tabmail = rootWindow.document.getElementById("tabmail"); tbTabInfo = tabmail.getBrowserForDocument(addonsWin); tbTab = tab = tbTabInfo.tabNode; processAddonsTab(addonsWin); } else { Services.obs.addObserver(function observer(subject, topic, data) { Services.obs.removeObserver(observer, topic); if(subject.document.readyState == "complete") processAddonsTab(subject); else { subject.addEventListener("load", function onLoad(e) { subject.removeEventListener(e.type, onLoad, false); processAddonsTab(subject); }, false); } }, "EM-loaded", false); // See openAddonsMgr() -> openContentTab() tbTabInfo = tabmail.openTab("contentTab", { contentPage: ADDONS_URL, clickHandler: "specialTabs.siteClickHandler(event, /addons\.mozilla\.org/);", background: true }); tbTab = tab = tbTabInfo.tabNode; tbTab.collapsed = true; // Note: dontSelectHiddenTab() not implemented } } else if("gBrowser" in trgWindow && trgWindow.gBrowser.tabs) { let isPending = false; let ws = Services.wm.getEnumerator("navigator:browser"); windowsLoop: while(ws.hasMoreElements()) { let w = ws.getNext(); let tabs = w.gBrowser.tabs; for(let i = 0, l = tabs.length; i < l; ++i) { let t = tabs[i]; if( !t.closing && t.linkedBrowser && t.linkedBrowser.currentURI.spec == ADDONS_URL ) { tab = t; break windowsLoop; } } } gBrowser = trgWindow.gBrowser; if(!tab) { tab = gBrowser.addTab(ADDONS_URL, { triggeringPrincipal: "Services" in window // Firefox 63+ && Services.scriptSecurityManager && Services.scriptSecurityManager.getSystemPrincipal() }); tab.collapsed = true; tab.closing = true; // See "visibleTabs" getter in chrome://browser/content/tabbrowser.xml trgWindow.addEventListener("TabSelect", dontSelectHiddenTab, false); } else if( tab.getAttribute("pending") == "true" // Gecko >= 9.0 || tab.linkedBrowser.contentDocument.readyState == "uninitialized" // || tab.linkedBrowser.__SS_restoreState == 1 ) isPending = true; browser = tab.linkedBrowser; if( isPending || browser.webProgress.isLoadingDocument || browser.currentURI.spec == "about:blank" // Firefox 79+ ) { browser.addEventListener("load", processAddonsTab, true); if(isPending) { if(pv >= 41) { // Workaround to correctly restore pending tab // See https://github.com/Infocatcher/Custom_Buttons/issues/39 let selTab = gBrowser.selectedTab; gBrowser.selectedTab = tab; gBrowser.selectedTab = selTab; } else { browser.reload(); } } } else { processAddonsTab(); } } else { progressIcon.restore(); btn.tooltipText = tip; delete btn._cb_disabled; Services.prompt.alert(window, btn.label, "Error: Can't find supported window!"); return; } function processAddonsTab(e, again) { var doc; if(e && e instanceof Components.interfaces.nsIDOMWindow) { doc = e.document; } else if(e) { doc = e.target; if(doc.location != ADDONS_URL) return; browser.removeEventListener(e.type, processAddonsTab, true); } else { doc = browser.contentDocument; } btn.tooltipText = "Process " + ADDONS_URL + "…"; progressIcon.loading(); var origAttr = "_cb_checkForAddonsUpdates_origImage"; if(!tab.hasAttribute(origAttr)) { var link = doc.querySelector('link[rel="shortcut icon"]'); // Not loaded yet? tab.setAttribute(origAttr, link && link.href || tab.image); } tab.image = image; var fu = $("cmd_findAllUpdates"); if(!fu) { // Firefox 72+ var win = doc.defaultView; var vb = doc.getElementById("html-view-browser"); if(!vb) { if(!HTMLHtmlElement.isInstance(doc.documentElement)) { // Firefox 87+ win.setTimeout(processAddonsTab, 20, win); return; } vb = browser; } if(!again) { // Strange errors happens // chrome://mozapps/content/extensions/aboutaddons.js // getTelemetryViewName() -> el.closest(...) is null win.setTimeout(processAddonsTab, 20, win, true); return; } var vbDoc = vb.contentDocument; fu = vbDoc.querySelector('[action="check-for-updates"]'); var um = vbDoc.getElementById("updates-message"); } var notFound = $("updates-noneFound") || { get hidden() { return um.getAttribute("state") != "none-found"; } }; var updated = $("updates-installed") || { get hidden() { return um.getAttribute("state") != "installed"; } }; // Avoid getting false results from the past update check (may not be required for "noneFound") if(um) { // Firefox 72+ um.hidden = true; um.removeAttribute("state"); } else { notFound.hidden = updated.hidden = true; } //fu.doCommand(); fu.click(); function localize(node, key, callback) { if(um) { // Firefox 72+ doc.l10n.formatValue(key).then(function(s) { callback(s || key); }, Components.utils.reportError); return; } callback(node.getAttribute("value") || key); } var inProgress = $("updates-progress") || { get hidden() { return um.getAttribute("state") != "updating"; } }; localize(inProgress, "addon-updates-updating", function(s) { btn.tooltipText = s; }); var waitTimer = setInterval(function() { if(!doc.defaultView || doc.defaultView.closed) { stopWait(); notify("Tab with add-ons manager was closed!"); return; } if(!inProgress.hidden) return; var autoUpdate = $("utils-autoUpdateDefault") || vbDoc.querySelector('[action="set-update-automatically"]'); var autoUpdateChecked = autoUpdate.getAttribute("checked") == "true" || autoUpdate.checked; var found = $("updates-manualUpdatesFound-btn") || { get hidden() { return um.getAttribute("state") != "manual-updates-found"; } }; if( autoUpdateChecked ? notFound.hidden && updated.hidden : notFound.hidden && found.hidden ) // Too early? return; stopWait(); if(!tbTab) tab.closing = false; function removeTab() { if(!tab.collapsed) return; if(tbTab) { tabmail.closeTab(tbTabInfo, true /*aNoUndo*/); return; } gBrowser.removeTab(tab); (function forgetClosedTab(isSecondTry) { var ss = "nsISessionStore" in Components.interfaces ? ( Components.classes["@mozilla.org/browser/sessionstore;1"] || Components.classes["@mozilla.org/suite/sessionstore;1"] ).getService(Components.interfaces.nsISessionStore) : trgWindow.SessionStore; // Firefox 61+ https://bugzilla.mozilla.org/show_bug.cgi?id=1450559 if(!("forgetClosedTab" in ss)) return; var closedTabs = JSON.parse(ss.getClosedTabData(window)); for(let i = 0, l = closedTabs.length; i < l; ++i) { let closedTab = closedTabs[i]; let state = closedTab.state; if(state.entries[state.index - 1].url == ADDONS_URL) { ss.forgetClosedTab(window, i); return; } } if(!isSecondTry) // May be needed in SeaMonkey setTimeout(forgetClosedTab, 0, true); })(); } if(!notFound.hidden) { removeTab(); localize(notFound, "addon-updates-none-found", function(s) { notify(s); }); return; } if(autoUpdateChecked) { removeTab(); localize(updated, "addon-updates-installed", function(s) { notify(s); }); return; } tab.collapsed = false; var cats = $("categories"); var upds = $("category-availableUpdates"); if(cats && upds) { if(vb && cats.selectedItem == upds) // Only for Firefox 72+ cats.selectedItem = $("category-extension"); // Trick to force update cats.selectedItem = upds; } else { // Firefox 76+ ? vbDoc.querySelector('.category[name="available-updates"]').click(); } var tabWin = tab.ownerDocument.defaultView; if(tbTab) tabmail.switchToTab(tbTabInfo); else tabWin.gBrowser.selectedTab = tab; setTimeout(function() { tabWin.focus(); doc.defaultView.focus(); var al = $("addon-list") || vb; al.focus(); }, 0); }, 50); function $(id) { return doc.getElementById(id); } function stopWait() { clearInterval(waitTimer); progressIcon.restore(); btn.tooltipText = tip; if(tab.image == image) tab.image = tab.getAttribute(origAttr); tab.removeAttribute(origAttr); trgWindow.removeEventListener("TabSelect", dontSelectHiddenTab, false); setTimeout(function() { delete btn._cb_disabled; }, 500); } function notify(msg) { Components.classes["@mozilla.org/alerts-service;1"] .getService(Components.interfaces.nsIAlertsService) .showAlertNotification( app == "Firefox" && pv >= 57 ? "chrome://mozapps/skin/extensions/extensionGeneric.svg" : "chrome://mozapps/skin/extensions/extensionGeneric.png", btn.label, msg, false, "", null ); } } function dontSelectHiddenTab(e) { // <tab /><tab collapsed="true" /> // Close first tab: collapsed tab becomes selected var trgTab = e.originalTarget || e.target; if(trgTab != tab) return; if(/\n(?:BrowserOpenAddonsMgr|toEM)@chrome:\/\//.test(new Error().stack)) { // User open Add-ons Manager, show tab trgWindow.removeEventListener("TabSelect", dontSelectHiddenTab, false); setTimeout(function() { // Hidden tab can't be selected, so select it manually... tab.collapsed = tab.closing = false; gBrowser.selectedTab = tab; }, 0); } function done(t) { if(!t.hidden && !t.closing) { e.preventDefault(); e.stopPropagation(); return gBrowser.selectedTab = t; } return false; } for(var t = tab.nextSibling; t; t = t.nextSibling) if(done(t)) return; for(var t = tab.previousSibling; t; t = t.previousSibling) if(done(t)) return; } function ProgressIcon(btn) { var app = Services.appinfo.name; var pv = parseFloat(Services.appinfo.platformVersion); if(app == "SeaMonkey") this.imgConnecting = this.imgLoading = "chrome://communicator/skin/icons/loading.gif"; else if(app == "Thunderbird") { this.imgConnecting = "chrome://messenger/skin/icons/connecting.png"; this.imgLoading = "chrome://messenger/skin/icons/loading.png"; } else { this.imgConnecting = app == "Firefox" && pv >= 58 ? "chrome://browser/skin/tabbrowser/tab-connecting.png" : "chrome://browser/skin/tabbrowser/connecting.png"; this.imgLoading = app == "Firefox" && pv >= 48 ? "chrome://global/skin/icons/loading.png" : "chrome://browser/skin/tabbrowser/loading.png"; } if(!(btn instanceof XULElement)) { this.loading = this.restore = function() {}; return; } var useAnimation = app == "Firefox" && pv >= 32 && pv < 48; var btnIcon = btn.icon || btn.ownerDocument.getAnonymousElementByAttribute(btn, "class", "toolbarbutton-icon"); var origIcon = btnIcon.src; btnIcon.src = this.imgConnecting; if(useAnimation) { let cs = btnIcon.ownerDocument.defaultView.getComputedStyle(btnIcon, null); let s = btnIcon.style; s.margin = [cs.marginTop, cs.marginRight, cs.marginBottom, cs.marginLeft].join(" "); s.padding = [cs.paddingTop, cs.paddingRight, cs.paddingBottom, cs.paddingLeft].join(" "); s.width = cs.width; s.height = cs.height; s.boxShadow = "none"; s.borderColor = s.background = "transparent"; btnIcon.setAttribute("fadein", "true"); btnIcon.setAttribute("busy", "true"); btnIcon.classList.add("tab-throbber"); btnIcon._restore = function() { delete btnIcon._restore; btnIcon.removeAttribute("busy"); btnIcon.removeAttribute("progress"); setTimeout(function() { btnIcon.classList.remove("tab-throbber"); btnIcon.removeAttribute("style"); btnIcon.removeAttribute("fadein"); }, 0); }; } this.loading = function() { btnIcon.src = this.imgLoading; if(useAnimation) btnIcon.setAttribute("progress", "true"); }; this.restore = function() { btnIcon.src = origIcon; if(useAnimation) btnIcon._restore(); }; } }).call(this); //== Check for Addons Updates end } this.tooltipText = "Переключатель джетпаков" + "\n\nУправление:\nЛКМ – открыть меню" + "\nПКМ – проверить обновления" + "\nСКМ – открыть страницу дополнений" + "\nShift+ПКМ – меню кнопки" + "\n\nВ меню: \nЛКМ – включить/выключить дополнение" + "\nShift+ЛКМ – включить/выключить дополнение без закрытия меню" + "\nСКМ – открыть страницу дополнения в управлении дополнениями" + "\nПКМ – открыть настройки дополнения (если есть)";
Кнопка CB для 136
// 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" // See "var style = " to modify styles for specific add-ons // (c) Infocatcher 2013-2019 // version 0.1.3pre4 - 2020-01-01 var options = { addonTypes: ["extension", "plugin"], // Possible values: "extension", "plugin" // From extensions: "userstyle" (Stylish), "greasemonkey-user-script" (Greasemonkey), "userscript" (Scriptish) // (swap to reorder in the menu) showVersions: 1, // 0 - don't show versions // 1 - show after name: "Addon Name 1.2" // 2 - show as "acceltext" (in place for hotkey text) showHidden: 0, // 0 - don't show hidden add-ons // -1 - show only enabled hidden add-ons (e.g. to track new items) // 1 - show all hidden add-ons sort: { enabled: 0, clickToPlay: 0, disabled: 1 // Sort order: // 0, 0, 0 - sort add-ons of each type alphabetically // 0, 0, 1 - show enabled add-ons (of each type) first // 0, 1, 2 - enabled add-ons, then click-to-play and then disabled }, closeMenu: false, // Close menu after left-click closeMenuClickToPlay: false // Close menu after left-click, for click to play plugins // Use Shift+click to invert closeMenu* behavior }; var xulns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var mp = document.createElementNS(xulns, "menupopup"); addEventListener("popupshowing", () => mp.updateMenu(), false, mp); addEventListener("command", mp.onmousedown = mp.onclick = e => { if (!e.button || e.type.endsWith("k")) mp.handleEvent(e); }, false, mp); mp.toggleAttribute("context"); addEventListener("popuphidden", () => mp.destroyMenu(), false, mp); var tb = this.parentNode; if(tb && tb.getAttribute("orient") == "vertical") { // https://addons.mozilla.org/firefox/addon/vertical-toolbar/ var isRight = tb.parentNode.getAttribute("placement") == "right"; mp.setAttribute("position", isRight ? "start_before" : "end_before"); } var cleanupTimer = 0; mp.updateMenu = function() { clearTimeout(cleanupTimer); addStyle(); getRestartlessAddons(options.addonTypes, function(addons) { var df = document.createDocumentFragment(); var prevType; function sortPosition(addon) { if("STATE_ASK_TO_ACTIVATE" in AddonManager && addon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE) return options.sort.clickToPlay; if(addon.isActive) return options.sort.enabled; return options.sort.disabled; } function key(addon) { return options.addonTypes.indexOf(addon.type) + "\n" + sortPosition(addon) + "\n" + addon.name.toLowerCase(); } addons.sort(function(a, b) { var ka = key(a); var kb = key(b); return ka == kb ? 0 : ka < kb ? -1 : 1; }).forEach(function(addon) { var type = addon.type; if(prevType && type != prevType) df.appendChild(document.createElementNS(xulns, "menuseparator")); prevType = type; var icon = addon.iconURL || addon.icon64URL; var mi = document.createElementNS(xulns, "menuitem"); mi.className = "menuitem-iconic"; var label = addon.name; if(options.showVersions == 1) label += " " + addon.version; else if(options.showVersions == 2) mi.setAttribute("acceltext", addon.version); mi.setAttribute("label", label); mi.setAttribute("image", icon || mp.icons[type] || ""); if(!icon && mp.icons.useSVG) mi.style.fill = "#15c"; var tip = addon.description || ""; var delay = "delayedStartupAddons" in Services && Services.delayedStartupAddons[addon.id] || null; var isDelayed = delay !== null; mi.classList.toggle("toggleRestartlessAddons-isDelayed", isDelayed); if(isDelayed) tip = "[Delayed Startup: " + delay.toLocaleString() + "]" + (tip ? "\n" + tip : ""); tip && mi.setAttribute("tooltiptext", tip); mi.classList.toggle("toggleRestartlessAddons-isHidden", addon.hidden || false); setDisabled(mi, addon.userDisabled); mi._cbAddon = addon; df.appendChild(mi); }); mp.textContent = ""; mp.appendChild(df); }); }; mp.handleEvent = function(e) { var mi = e.target; if(!("_cbAddon" in mi)) return; var addon = mi._cbAddon; if(e.type == "mousedown") { var closeMenu = isAskToActivateAddon(addon) ? options.closeMenuClickToPlay : options.closeMenu; if(e.shiftKey) closeMenu = !closeMenu; mi.setAttribute("closemenu", closeMenu ? "auto" : "none"); return; } var hasMdf = hasModifier(e); if(e.type == "command" && (!hasMdf || e.shiftKey)) { let newDis = setNewDisabled(addon); setDisabled(mi, newDis); } else if(e.type == "command" && hasMdf || e.type == "click" && e.button == 1) { openAddonPage(addon); closeMenus(mi); } else if(e.type == "click" && e.button == 2) { if(openAddonOptions(addon)) closeMenus(mi); } }; mp.destroyMenu = function() { removeStyle(); clearTimeout(cleanupTimer); cleanupTimer = setTimeout(function() { mp.textContent = ""; }, 5000); }; mp.icons = { get platformVersion() { delete this.platformVersion; return this.platformVersion = parseFloat(Services.appinfo.platformVersion); }, get useSVG() { delete this.useSVG; return this.useSVG = Services.appinfo.name == "Firefox" && this.platformVersion >= 57; }, get plugin() { delete this.plugin; return this.plugin = this.useSVG ? this.platformVersion >= 65 ? "chrome://global/skin/plugins/pluginGeneric.svg" : "chrome://mozapps/skin/plugins/pluginGeneric.svg" : "chrome://mozapps/skin/plugins/pluginGeneric-16.png"; }, get extension() { delete this.extension; return this.extension = this.useSVG ? this.platformVersion >= 76 ? "chrome://mozapps/skin/extensions/extensionGeneric.svg" // Or chrome://mozapps/skin/extensions/extension.svg : "chrome://mozapps/skin/extensions/extensionGeneric-16.svg" : "chrome://mozapps/skin/extensions/extensionGeneric-16.png"; } }; function isAskToActivateAddon(addon) { return addon.type == "plugin" && "STATE_ASK_TO_ACTIVATE" in AddonManager && Services.prefs.getBoolPref("plugins.click_to_play", true); } function setNewDisabled(addon) { var newDis = getNewDisabled(addon); var oldDis = addon.userDisabled; if(Components.interfaces.nsIWebTransportHash) { // random, Fx 123+ var func = function() { func = false; } var thread = Services.tm.currentThread; var meth = newDis ? "disable" : "enable"; addon[meth]({allowSystemAddons: true}).finally(func); while(func) thread.processNextEvent(true); } else try { addon.userDisabled = newDis; } catch(e) { // Error: Cannot disable hidden add-on firefox@getpocket.com _log("Can't set addon.userDisabled to " + newDis + ", error:\n" + e); if(addon.hidden) setNewDisabledRaw(addon, newDis); } var realDis = addon.userDisabled; if(realDis != newDis && addon.type == "extension") { // Firefox 62+? Weird things happens setNewDisabledRaw(addon, newDis); realDis = addon.userDisabled; } if(realDis != newDis) { // We can't enable vulnerable plugins let err = "Can't set addon.userDisabled to " + newDis + ", real value: " + realDis; if(newDis) { _log(err + "\nSTATE_ASK_TO_ACTIVATE not supported?"); newDis = false; } else { _log(err + "\nVulnerable plugin?"); if(oldDis == AddonManager.STATE_ASK_TO_ACTIVATE) newDis = true; else newDis = AddonManager.STATE_ASK_TO_ACTIVATE; } addon.userDisabled = newDis; } ensureSpecialDisabled(addon, newDis); return addon.userDisabled; } function getNewDisabled(addon) { // disabled -> STATE_ASK_TO_ACTIVATE -> enabled -> ... var curDis = addon.userDisabled; var newDis; if("STATE_ASK_TO_ACTIVATE" in AddonManager && curDis == AddonManager.STATE_ASK_TO_ACTIVATE) newDis = false; else if(!curDis) newDis = true; else { if(isAskToActivateAddon(addon)) newDis = AddonManager.STATE_ASK_TO_ACTIVATE; else newDis = false; } return newDis; } function setNewDisabledRaw(addon, newDis) { _log("Let's try set addon.userDisabled using raw hack"); if("lazy" in g) g = g.lazy; if("XPIDatabase" in g && "updateAddonDisabledState" in g.XPIDatabase) { // Firefox 61+ let rawAddon = g.XPIDatabase.getAddons().find(function(rawAddon) { return rawAddon.id == addon.id; }); g.XPIDatabase.updateAddonDisabledState( rawAddon, g.XPIDatabase.updateAddonDisabledState.length == 1 // Firefox 74+ ? { userDisabled: newDis } : newDis ); } else if("eval" in g) { // See "set userDisabled(val)" let addonFor = g.eval("addonFor"); let rawAddon = addonFor(addon); //rawAddon.userDisabled = newDis; g.XPIProvider.updateAddonDisabledState(rawAddon, newDis); } else { // Firefox 57+? See https://forum.mozilla-russia.org/viewtopic.php?pid=745272#p745272 updateAddonDisabledState(addon, newDis); } } function updateAddonDisabledState(addon, newDis) { var key = "_cbToggleRestartlessAddonsData"; var url = URL.createObjectURL(new Blob([ "XPIProvider.updateAddonDisabledState(addonFor(this." + key + "[0]), this." + key + "[1]); delete this." + key + ";" ])); addDestructor(function() { URL.revokeObjectURL(url); }); (updateAddonDisabledState = function(addon, newDis) { nsvo[key] = [addon, newDis]; Services.scriptloader.loadSubScript(url, nsvo); })(addon, newDis); } function setDisabled(mi, disabled) { var askToActivate = "STATE_ASK_TO_ACTIVATE" in AddonManager && disabled == AddonManager.STATE_ASK_TO_ACTIVATE; var cl = mi.classList; cl.toggle("toggleRestartlessAddons-askToActivate", askToActivate); cl.toggle("toggleRestartlessAddons-disabled", disabled && !askToActivate); } function ensureSpecialDisabled(addon, newDis) { if(addon.id == "screenshots@mozilla.org") Services.prefs.setBoolPref("extensions.screenshots.disabled", newDis); } if( this instanceof XULElement // Custom Buttons && typeof event == "object" && !("type" in event) && typeof _phase == "string" && _phase == "init" // Initialization ) { this.type = "menu"; this.orient = "horizontal"; this.appendChild(mp); this.onmouseover = function(e) { if(e.target != this) return; Array.prototype.some.call( this.parentNode.getElementsByTagName("*"), function(node) { if( node != this && node.namespaceURI == xulns // See https://github.com/Infocatcher/Custom_Buttons/issues/28 //&& node.boxObject //&& node.boxObject instanceof Components.interfaces.nsIMenuBoxObject && "open" in node && node.open && node.getElementsByTagName("menupopup").length ) { node.open = false; this.open = true; return true; } return false; }, this ); }; this.onmousedown = function(e) { if(e.target == this && e.button == 0 && hasModifier(e)) e.preventDefault(); }; this.oncontextmenu = function(e) { if(e.target == this && !hasModifier(e) && hasUpdater()) e.preventDefault(); }; this.onclick = function(e) { if(e.target != this) return; if(e.button == 0 && hasModifier(e) || e.button == 1) openAddonsManager(); else if(e.button == 2 && !hasModifier(e) && hasUpdater()) checkForAddonsUpdates.call(this); }; } else { // Mouse gestures or something other... let e; if(typeof event == "object" && event instanceof Event && "screenX" in event) // FireGestures e = event; else if( this instanceof Components.interfaces.nsIDOMChromeWindow && "mgGestureState" in window && "endEvent" in mgGestureState // Mouse Gestures Redox ) e = mgGestureState.endEvent; else { let anchor = this instanceof XULElement && this || window.gBrowser && gBrowser.selectedBrowser || document.documentElement; if("boxObject" in anchor) { let bo = anchor.boxObject; e = { screenX: bo.screenX, screenY: bo.screenY }; if(this instanceof XULElement) e.screenY += bo.height; } } if(!e || !("screenX" in e)) throw new Error("[Toggle Restartless Add-ons]: Can't get event object"); document.documentElement.appendChild(mp); mp.addEventListener("popuphidden", function destroy(e) { mp.removeEventListener(e.type, destroy, false); setTimeout(function() { mp.destroyMenu(); mp.parentNode.removeChild(mp); }, 0); }, false); mp.openPopupAtScreen(e.screenX, e.screenY); } function getRestartlessAddons(addonTypes, callback, context) { if(!("AddonManager" in window)); var then, promise = AddonManager.getAddonsByTypes(addonTypes, then = function(addons) { callback.call(context, addons.filter(function(addon) { var ops = addon.operationsRequiringRestart; return !addon.appDisabled && !(ops & AddonManager.OP_NEEDS_RESTART_ENABLE || ops & AddonManager.OP_NEEDS_RESTART_DISABLE) && ( !addon.hidden || options.showHidden > 0 || options.showHidden == -1 && !addon.userDisabled ) && (addon.iconURL || "").substr(0, 29) != "resource://search-extensions/"; })); }); promise && typeof promise.then == "function" && promise.then(then, Components.utils.reportError); // Firefox 61+ } function openAddonOptions(addon) { // Based on code from chrome://mozapps/content/extensions/extensions.js // Firefox 21.0a1 (2013-01-27) var optionsURL = addon.optionsURL; if(!addon.isActive || !optionsURL) return false; if(addon.type == "plugin") // No options for now! return false; if( addon.optionsType == (AddonManager.OPTIONS_TYPE_INLINE || NaN) || addon.optionsType == (AddonManager.OPTIONS_TYPE_INLINE_INFO || NaN) || addon.optionsType == (AddonManager.OPTIONS_TYPE_INLINE_BROWSER || NaN) ) openAddonPage(addon, true); else if(addon.optionsType == AddonManager.OPTIONS_TYPE_TAB && "switchToTabHavingURI" in window) switchToTabHavingURI(optionsURL, true); else { let windows = Services.wm.getEnumerator(null); while(windows.hasMoreElements()) { let win = windows.getNext(); if(win.document.documentURI == optionsURL) { win.focus(); return true; } } // Note: original code checks browser.preferences.instantApply and may open modal windows window.openDialog(optionsURL, "", "chrome,titlebar,toolbar,centerscreen,dialog=no"); } return true; } function openAddonsManager(view) { var openAddonsMgr = window.BrowserOpenAddonsMgr || window.BrowserAddonUI.openAddonsMgr // Firefox || window.openAddonsMgr // Thunderbird || window.toEM; // SeaMonkey openAddonsMgr(view); } function openAddonPage(addon, scrollToPreferences) { var platformVersion = parseFloat( Services.appinfo.name == "Pale Moon" ? Services.appinfo.version : Services.appinfo.platformVersion ); scrollToPreferences = scrollToPreferences && platformVersion >= 12 ? "/preferences" : ""; openAddonsManager("addons://detail/" + encodeURIComponent(addon.id) + scrollToPreferences); } function hasModifier(e) { return e.ctrlKey || e.shiftKey || e.altKey || e.metaKey; } function addStyle() { if(addStyle.hasOwnProperty("_style")) return; var style = '\ .toggleRestartlessAddons-isDelayed > .menu-iconic-text {\n\ opacity: 0.75;\n\ color: #070;\n\ }\n\ .toggleRestartlessAddons-isHidden > .menu-iconic-text {\n\ color: #609;\n\ }\n\ .toggleRestartlessAddons-disabled > .menu-iconic-left {\n\ opacity: 0.4;\n\ }\n\ .toggleRestartlessAddons-disabled > .menu-iconic-text,\n\ .toggleRestartlessAddons-disabled > .menu-accel-container {\n\ opacity: 0.5;\n\ }\n\ .toggleRestartlessAddons-askToActivate {\n\ color: -moz-nativehyperlinktext;\n\ }'; addStyle._style = document.insertBefore( document.createProcessingInstruction( "xml-stylesheet", 'href="' + "data:text/css," + encodeURIComponent(style) + '" type="text/css"' ), document.documentElement ); } function removeStyle() { if(!addStyle.hasOwnProperty("_style")) return; var s = addStyle._style; s.parentNode.removeChild(s); delete addStyle._style; } function closeMenus(node) { // Based on function closeMenus from chrome://browser/content/utilityOverlay.js for(; node && "tagName" in node; node = node.parentNode) { if( node.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" && (node.localName == "menupopup" || node.localName == "popup") ) node.hidePopup(); } } function _log(s) { if(typeof LOG == "function") // Custom Buttons LOG(s); else // Or something else Services.console.logStringMessage("Toggle Restartless Add-ons: " + s); } function hasUpdater() { var has = checkForAddonsUpdates.toString().indexOf("about:addons") != -1; hasUpdater = function() { return has; }; return has; } function checkForAddonsUpdates() { //== Check for Addons Updates begin // http://infocatcher.ucoz.net/js/cb/checkForAddonsUpdates.js // https://forum.mozilla-russia.org/viewtopic.php?id=57958 // https://github.com/Infocatcher/Custom_Buttons/tree/master/Check_for_Addons_Updates // Check for Addons Updates button for Custom Buttons // (code for "code" section) // (c) Infocatcher 2012-2021 // version 0.1.6pre4 - 2021-03-28 // Button just open hidden tab with about:addons and trigger built-in "Check for Updates" function. // And show tab, if found updates. (function() { var btn = this instanceof XULElement ? this : { // Launched not from custom button image: "", // Base64-encoded icon (if empty, will be used "imgLoading") label: "Check for Addons Updates", tooltipText: "" }; if("_cb_disabled" in btn) return; btn._cb_disabled = true; var app = Services.appinfo.name; var pv = parseFloat(Services.appinfo.platformVersion); var ADDONS_URL = "about:addons"; var progressIcon = new ProgressIcon(btn); var image = btn.image || progressIcon.imgLoading; var tip = btn.tooltipText; btn.tooltipText = "Open " + ADDONS_URL + "…"; var tab, browser, gBrowser; var tbTabInfo, tbTab; var trgWindow = Services.wm.getMostRecentWindow("navigator:browser") || app == "Thunderbird" && Services.wm.getMostRecentWindow("mail:3pane") || window; var trgDocument = trgWindow.document; var tabmail = trgDocument.getElementById("tabmail"); if(tabmail && app == "Thunderbird") { // Note: SeaMonkey doesn't support content tabs in mail window let addonsWin; let receivePong = function(subject, topic, data) { addonsWin = subject; }; Services.obs.addObserver(receivePong, "EM-pong", false); Services.obs.notifyObservers(null, "EM-ping", ""); Services.obs.removeObserver(receivePong, "EM-pong"); if(addonsWin) { let rootWindow = addonsWin .QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIWebNavigation) .QueryInterface(Components.interfaces.nsIDocShellTreeItem) .rootTreeItem .QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIDOMWindow); tabmail = rootWindow.document.getElementById("tabmail"); tbTabInfo = tabmail.getBrowserForDocument(addonsWin); tbTab = tab = tbTabInfo.tabNode; processAddonsTab(addonsWin); } else { Services.obs.addObserver(function observer(subject, topic, data) { Services.obs.removeObserver(observer, topic); if(subject.document.readyState == "complete") processAddonsTab(subject); else { subject.addEventListener("load", function onLoad(e) { subject.removeEventListener(e.type, onLoad, false); processAddonsTab(subject); }, false); } }, "EM-loaded", false); // See openAddonsMgr() -> openContentTab() tbTabInfo = tabmail.openTab("contentTab", { contentPage: ADDONS_URL, clickHandler: "specialTabs.siteClickHandler(event, /addons\.mozilla\.org/);", background: true }); tbTab = tab = tbTabInfo.tabNode; tbTab.collapsed = true; // Note: dontSelectHiddenTab() not implemented } } else if("gBrowser" in trgWindow && trgWindow.gBrowser.tabs) { let isPending = false; let ws = Services.wm.getEnumerator("navigator:browser"); windowsLoop: while(ws.hasMoreElements()) { let w = ws.getNext(); let tabs = w.gBrowser.tabs; for(let i = 0, l = tabs.length; i < l; ++i) { let t = tabs[i]; if( !t.closing && t.linkedBrowser && t.linkedBrowser.currentURI.spec == ADDONS_URL ) { tab = t; break windowsLoop; } } } gBrowser = trgWindow.gBrowser; if(!tab) { tab = gBrowser.addTab(ADDONS_URL, { triggeringPrincipal: "Services" in window // Firefox 63+ && Services.scriptSecurityManager && Services.scriptSecurityManager.getSystemPrincipal() }); tab.collapsed = true; tab.closing = true; // See "visibleTabs" getter in chrome://browser/content/tabbrowser.xml trgWindow.addEventListener("TabSelect", dontSelectHiddenTab, false); } else if( tab.getAttribute("pending") == "true" // Gecko >= 9.0 || tab.linkedBrowser.contentDocument.readyState == "uninitialized" // || tab.linkedBrowser.__SS_restoreState == 1 ) isPending = true; browser = tab.linkedBrowser; if( isPending || browser.webProgress.isLoadingDocument || browser.currentURI.spec == "about:blank" // Firefox 79+ ) { browser.addEventListener("load", processAddonsTab, true); if(isPending) { if(pv >= 41) { // Workaround to correctly restore pending tab // See https://github.com/Infocatcher/Custom_Buttons/issues/39 let selTab = gBrowser.selectedTab; gBrowser.selectedTab = tab; gBrowser.selectedTab = selTab; } else { browser.reload(); } } } else { processAddonsTab(); } } else { progressIcon.restore(); btn.tooltipText = tip; delete btn._cb_disabled; Services.prompt.alert(window, btn.label, "Error: Can't find supported window!"); return; } function processAddonsTab(e, again) { var doc; if(e && e instanceof Components.interfaces.nsIDOMWindow) { doc = e.document; } else if(e) { doc = e.target; if(doc.location != ADDONS_URL) return; browser.removeEventListener(e.type, processAddonsTab, true); } else { doc = browser.contentDocument; } btn.tooltipText = "Process " + ADDONS_URL + "…"; progressIcon.loading(); var origAttr = "_cb_checkForAddonsUpdates_origImage"; if(!tab.hasAttribute(origAttr)) { var link = doc.querySelector('link[rel="shortcut icon"]'); // Not loaded yet? tab.setAttribute(origAttr, link && link.href || tab.image); } tab.image = image; var fu = $("cmd_findAllUpdates"); if(!fu) { // Firefox 72+ var win = doc.defaultView; var vb = doc.getElementById("html-view-browser"); if(!vb) { if(!HTMLHtmlElement.isInstance(doc.documentElement)) { // Firefox 87+ win.setTimeout(processAddonsTab, 20, win); return; } vb = browser; } if(!again) { // Strange errors happens // chrome://mozapps/content/extensions/aboutaddons.js // getTelemetryViewName() -> el.closest(...) is null win.setTimeout(processAddonsTab, 20, win, true); return; } var vbDoc = vb.contentDocument; fu = vbDoc.querySelector('[action="check-for-updates"]'); var um = vbDoc.getElementById("updates-message"); } var notFound = $("updates-noneFound") || { get hidden() { return um.getAttribute("state") != "none-found"; } }; var updated = $("updates-installed") || { get hidden() { return um.getAttribute("state") != "installed"; } }; // Avoid getting false results from the past update check (may not be required for "noneFound") if(um) { // Firefox 72+ um.hidden = true; um.removeAttribute("state"); } else { notFound.hidden = updated.hidden = true; } //fu.doCommand(); fu.click(); function localize(node, key, callback) { if(um) { // Firefox 72+ doc.l10n.formatValue(key).then(function(s) { callback(s || key); }, Components.utils.reportError); return; } callback(node.getAttribute("value") || key); } var inProgress = $("updates-progress") || { get hidden() { return um.getAttribute("state") != "updating"; } }; localize(inProgress, "addon-updates-updating", function(s) { btn.tooltipText = s; }); var waitTimer = setInterval(function() { if(!doc.defaultView || doc.defaultView.closed) { stopWait(); notify("Tab with add-ons manager was closed!"); return; } if(!inProgress.hidden) return; var autoUpdate = $("utils-autoUpdateDefault") || vbDoc.querySelector('[action="set-update-automatically"]'); var autoUpdateChecked = autoUpdate.getAttribute("checked") == "true" || autoUpdate.checked; var found = $("updates-manualUpdatesFound-btn") || { get hidden() { return um.getAttribute("state") != "manual-updates-found"; } }; if( autoUpdateChecked ? notFound.hidden && updated.hidden : notFound.hidden && found.hidden ) // Too early? return; stopWait(); if(!tbTab) tab.closing = false; function removeTab() { if(!tab.collapsed) return; if(tbTab) { tabmail.closeTab(tbTabInfo, true /*aNoUndo*/); return; } gBrowser.removeTab(tab); (function forgetClosedTab(isSecondTry) { var ss = "nsISessionStore" in Components.interfaces ? ( Components.classes["@mozilla.org/browser/sessionstore;1"] || Components.classes["@mozilla.org/suite/sessionstore;1"] ).getService(Components.interfaces.nsISessionStore) : trgWindow.SessionStore; // Firefox 61+ https://bugzilla.mozilla.org/show_bug.cgi?id=1450559 if(!("forgetClosedTab" in ss)) return; var closedTabs = (ss.getClosedTabDataForWindow(window)); for(let i = 0, l = closedTabs.length; i < l; ++i) { let closedTab = closedTabs[i]; let state = closedTab.state; if(state.entries[state.index - 1].url == ADDONS_URL) { ss.forgetClosedTab(window, i); return; } } if(!isSecondTry) // May be needed in SeaMonkey setTimeout(forgetClosedTab, 0, true); })(); } if(!notFound.hidden) { removeTab(); localize(notFound, "addon-updates-none-found", function(s) { notify(s); }); return; } if(autoUpdateChecked) { removeTab(); localize(updated, "addon-updates-installed", function(s) { notify(s); }); return; } tab.collapsed = false; var cats = $("categories"); var upds = $("category-availableUpdates"); if(cats && upds) { if(vb && cats.selectedItem == upds) // Only for Firefox 72+ cats.selectedItem = $("category-extension"); // Trick to force update cats.selectedItem = upds; } else { // Firefox 76+ ? vbDoc.querySelector('.category[name="available-updates"]').click(); } var tabWin = tab.ownerDocument.defaultView; if(tbTab) tabmail.switchToTab(tbTabInfo); else tabWin.gBrowser.selectedTab = tab; setTimeout(function() { tabWin.focus(); doc.defaultView.focus(); var al = $("addon-list") || vb; al.focus(); }, 0); }, 50); function $(id) { return doc.getElementById(id); } function stopWait() { clearInterval(waitTimer); progressIcon.restore(); btn.tooltipText = tip; if(tab.image == image) tab.image = tab.getAttribute(origAttr); tab.removeAttribute(origAttr); trgWindow.removeEventListener("TabSelect", dontSelectHiddenTab, false); setTimeout(function() { delete btn._cb_disabled; }, 500); } function notify(msg) { Components.classes["@mozilla.org/alerts-service;1"] .getService(Components.interfaces.nsIAlertsService) .showAlertNotification( app == "Firefox" && pv >= 57 ? "chrome://mozapps/skin/extensions/extensionGeneric.svg" : "chrome://mozapps/skin/extensions/extensionGeneric.png", btn.label, msg, false, "", null ); } } function dontSelectHiddenTab(e) { // <tab /><tab collapsed="true" /> // Close first tab: collapsed tab becomes selected var trgTab = e.originalTarget || e.target; if(trgTab != tab) return; if(/\n(?:BrowserOpenAddonsMgr|toEM)@chrome:\/\//.test(new Error().stack)) { // User open Add-ons Manager, show tab trgWindow.removeEventListener("TabSelect", dontSelectHiddenTab, false); setTimeout(function() { // Hidden tab can't be selected, so select it manually... tab.collapsed = tab.closing = false; gBrowser.selectedTab = tab; }, 0); } function done(t) { if(!t.hidden && !t.closing) { e.preventDefault(); e.stopPropagation(); return gBrowser.selectedTab = t; } return false; } for(var t = tab.nextSibling; t; t = t.nextSibling) if(done(t)) return; for(var t = tab.previousSibling; t; t = t.previousSibling) if(done(t)) return; } function ProgressIcon(btn) { var app = Services.appinfo.name; var pv = parseFloat(Services.appinfo.platformVersion); if(app == "SeaMonkey") this.imgConnecting = this.imgLoading = "chrome://communicator/skin/icons/loading.gif"; else if(app == "Thunderbird") { this.imgConnecting = "chrome://messenger/skin/icons/connecting.png"; this.imgLoading = "chrome://messenger/skin/icons/loading.svg"; } else { this.imgConnecting = app == "Firefox" && pv >= 58 ? "chrome://browser/skin/tabbrowser/tab-connecting.png" : "chrome://browser/skin/tabbrowser/connecting.png"; this.imgLoading = app == "Firefox" && pv >= 48 ? "chrome://global/skin/icons/loading.png" : "chrome://browser/skin/tabbrowser/loading.png"; } if(!(btn instanceof XULElement)) { this.loading = this.restore = function() {}; return; } var useAnimation = app == "Firefox" && pv >= 32 && pv < 48; var btnIcon = btn.icon || btn.ownerDocument.getAnonymousElementByAttribute(btn, "class", "toolbarbutton-icon"); var origIcon = btnIcon.src; btnIcon.src = this.imgConnecting; if(useAnimation) { let cs = btnIcon.ownerDocument.defaultView.getComputedStyle(btnIcon, null); let s = btnIcon.style; s.margin = [cs.marginTop, cs.marginRight, cs.marginBottom, cs.marginLeft].join(" "); s.padding = [cs.paddingTop, cs.paddingRight, cs.paddingBottom, cs.paddingLeft].join(" "); s.width = cs.width; s.height = cs.height; s.boxShadow = "none"; s.borderColor = s.background = "transparent"; btnIcon.setAttribute("fadein", "true"); btnIcon.setAttribute("busy", "true"); btnIcon.classList.add("tab-throbber"); btnIcon._restore = function() { delete btnIcon._restore; btnIcon.removeAttribute("busy"); btnIcon.removeAttribute("progress"); setTimeout(function() { btnIcon.classList.remove("tab-throbber"); btnIcon.removeAttribute("style"); btnIcon.removeAttribute("fadein"); }, 0); }; } this.loading = function() { btnIcon.src = this.imgLoading; if(useAnimation) btnIcon.setAttribute("progress", "true"); }; this.restore = function() { btnIcon.src = origIcon; if(useAnimation) btnIcon._restore(); }; } }).call(this); //== Check for Addons Updates end } this.tooltipText = "Переключатель джетпаков" + "\nПКМ – проверить обновления" + "\nСКМ – открыть страницу дополнений" + "\n\nВ меню: \nЛКМ – включить/выключить дополнение без закрытия меню" + "\nShift+ЛКМ – включить/выключить дополнение" + "\nСКМ – открыть страницу дополнения в управлении дополнениями" + "\nПКМ – открыть настройки дополнения (если есть)"; // Autoopen/close feature var openDelay = 200; var closeDelay = 350; var _openTimer = 0; var _closeTimer = 0; this.onmouseover = function(e) { clearTimeout(_closeTimer); if(e.target == this && closeOtherMenus()) { this.open = true; return; } _openTimer = setTimeout(function() { self.open = true; }, openDelay); }; this.onmouseout = function(e) { clearTimeout(_openTimer); _closeTimer = setTimeout(function() { self.open = false; }, closeDelay); }; function closeOtherMenus() { return Array.prototype.some.call( self.parentNode.getElementsByTagName("*"), function(node) { if( node != self && node.namespaceURI == xulns // See https://github.com/Infocatcher/Custom_Buttons/issues/28 //&& node.boxObject //&& node.boxObject instanceof Components.interfaces.nsIMenuBoxObject && "open" in node && node.open && node.getElementsByTagName("menupopup").length ) { node.open = false; return true; } return false; } ); }
Отсутствует