Здравствуйте! для старых FF, была отличная кнопка для переключения Proxy
С таким
// Proxy, от 25.02.2016. // Настройка функций кликов мыши для кнопки ................... this.onmousedown =e=> { this.onmouseup =e=>{ // левый клик if ( e.button ) return; clearTimeout(self.timer); switch( cbu.getPrefs("network.proxy.type") ) { case 0: var data = 1; break; case 1: var data = 2; break; case 2: var data = 0; break; default: var data = 0; } cbu.setPrefs("network.proxy.type", data); } if ( e.button == 0 ) // длинный левый клик self.timer = setTimeout(()=>{ self.onmouseup = ''; cbu.getPrefs("CB.Proxy.connectionsInTab") ? openConnectionsInTab() : openConnections(); }, 500); if ( e.button == 2 ) // правый клик menuPopup.showPopup(self, -1, -1, "popup", "bottomleft", "topleft"); }; self.onclick =e=> e.preventDefault(); // Подсказка для кнопки ................... this.onmouseover =()=> { this.tooltipText = "Proxy \nЛ: Переключить прокси \nДЛ: Открыть настройки прокси" + "\nП: Mеню кнопки \n\nТекущие настройки прокси: " + "\nIP: " + Services.prefs.getComplexValue("network.proxy.http", Ci.nsISupportsString).data + "\nПорт: "+ cbu.getPrefs("network.proxy.http_port"); }; // Создать меню для кнопки ................... var array = [ { label: "Добавление прокси в контекстом меню", value: 'CB.Proxy.inContextMenu' }, { label: "Открывать настройки прокси как вкладку", value: 'CB.Proxy.connectionsInTab' }, { label: "Переключать на режим 'Без прокси' при закрытии браузера ", value: 'CB.Proxy.reset' } ]; var menuPopup = document.getElementById('mainPopupSet').appendChild(document.createElement("menupopup")); array.forEach((m)=> { var mItem = document.createElement("menuitem"); mItem.setAttribute("label", m.label); mItem.setAttribute('type', 'checkbox'); mItem.setAttribute('checked', cbu.getPrefs(m.value) ); mItem.onclick =()=> cbu.setPrefs(m.value, !cbu.getPrefs(m.value)); menuPopup.appendChild(mItem); }); addDestructor(()=> menuPopup.remove() ); // добавить стандартное контекстное меню menuPopup.appendChild(document.createElement("menuseparator")); menuPopup.appendChild(document.createElement("menu")).setAttribute("label", "Меню кнопки"); var clone = menuPopup.lastChild.appendChild(document.getElementById("custombuttons-contextpopup").cloneNode(true)); clone.setAttribute("onpopupshowing", "document.popupNode = document.getElementById('" + _id + "')"); // Функция открывает настройки прокси в окне ................... function openConnections() { for ( var win, nm = Services.wm.getEnumerator(null); win = nm.getNext(); ) if ( win.name == 'Proxy') { win.focus(); break; } var win = openDialog("chrome://browser/content/preferences/connection.xul", "Proxy", "centerscreen"); // добавить атрибут "prefwindow" win.addEventListener("load", function f(e) { this.removeEventListener("load", f, true); e.target.documentElement.setAttribute("type", "prefwindow"); }, true ); // закрыть настройки прокси по клику на странице gBrowser.addEventListener("click", function c() { this.removeEventListener("click", c ); try { win.close() } catch(e) {}; }, true ); }; // Функция открывает настройки прокси в вкладке ................... function openConnectionsInTab() { var connections = gBrowser.getBrowserForTab( gBrowser.selectedTab = gBrowser.addTab("chrome://browser/content/preferences/connection.xul") ); // oбработчик ждет пока откроется прокси, удаляет себя и добавляет атрибут connections.addEventListener("pageshow", function c(e) { this.removeEventListener(e.type, c); e.originalTarget.documentElement.setAttribute("type", "prefwindow"); }) }; // Установливать нужную иконку кнопки при старте баузера или при изменениях в 'about:config' ................... var s = "network.proxy.type"; function toggleImage() { var icon = self.ownerDocument.getAnonymousElementByAttribute(self, "class", "toolbarbutton-icon"); switch( cbu.getPrefs(s) ) { case 0: icon.src = self.image; break; case 1: icon.src = 'data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAQAAAAAIAA4GQAAnFmkAHQ5fAAQAKAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEBAQECAgICAgICAgICAgMBAQEAAAQBJBFQOLQ+nX38ecev/mu6of8gfFvtAyUXewAAAAsAAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEBAAAAAAMLUza7PKd//3S7oP2849X9zuvh/mW4mf4XiV7/AB4QZwAAAAAAAAAAAQEBAQAAAAAZGhgTKSwnLyYqJDErKCUnID8vXgaAUP9BlnH8b7ea/ojHrv+q2sf/a7CT+zGWbf8PakXGAAIAAAEBAQMHBwcbAAAAD2BiXn76/ff/4ebg/Onm4f+DtZ7/A31L/j2Wb/+Fwaj/ls23/7rh0v9+vaT+M5du/xKGWO0DIxIdAAAAAAEBAQEAAAABBgYFEaSmorbP08z239vX/4OwnP4ail3/RJlz/5HHsP/T7+X/ms64/3K2mP40k2r/D3tM7AUiExwhIx8meXt1mXt+eKJ3eXSce353n6esouDMysf/o7eq/kOdeP92uZv/vuPT/9Hs4P/C4tT/eLWa+juWbv8bcEq7AAYBAF1gWn7//////f39/P//////////////////////////lcKx/3i9pf/K7OD/2O/l/7ndzf6Fw6n/VK+I/AsxHj8AAAAAXF5bf+Ln2P+AnU/4fZ1N+4WiV/yKp13+jKlh/5CsZf+GpFj/Zpxh/4C5nf+i0L7+k8ex/1udf+UTOCZFAAAAAAEBAQJfYF5/3uXR/16IIPxciiH/Z5Iv/26YOP9ymz3/cpw+/3OcPf9wlzb/YI80/1mKNPu707X/YmZjiAAAAAAEBAQGAAAAAF9gXoDg5tT/cJU6/HGaPf9/pE3/hqtX/4uvXf+NsF7/iKxZ/4KoU/9+o0r/cpY6+9zjyf9ubm2JAAAAAAMEAwQAAAAAX2BegODm1P94nEX8e6JJ/4quXP+Vt2n/nb1z/6LBef+jwXz/ob96/527d/+NrGP71+HG/2praogAAAAABAQDBAAAAABfYF2A4ObU/4WlVvyPsmP/osB7/7HMj/+81J3/wdik/8DXo/+60pz/tc6X/6G6ffvY4sf/amtqiAAAAAAEBAMEAAAAAF9gXn/e5dL/n7l7/LLMk//B16X/zuG2/9jpwv/b68b/2enE/9Pkvv/Q4bv/uMud+9jhyP9qa2mHAAAAAAQEAwQAAAAAX2Bef97k0v+gt335sceT/LrNnfzC1Kj8ydmx/MzatfzK2bP8xtav/MbVr/ywwpL41+HH/2tsaokAAAAABAQDBAAAAABZW1Z3+fz1/+Dm1Pzj6db/5u3b/+nv3v/r8eD/6vDe/+ft2//k69j/4efT/9ngzPv7//b/ZGdhfwAAAAADBAMEAAAAABcZFRpZW1Z6YGFfgWBiYIBhYmGAYmJhgGJjYoBiY2KAYmJhgGFiYYBgYWCAX2BegF1fWoAbHRkeAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='; break; case 2: icon.src = 'data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAQAAAAAIAAcHQAAYGGkAEBBfAAEBKAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAABAQEAAgICAAICAgACAgMBAQEAAAEBJAA6OrQAf3/8ALCw/gCiov8AXl7tABkZewAAAAsAAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEBAAAAAAMAOTm7AIOD/wCjo/0A1tb9AOHh/gCcnP4AY2P/ABISZwAAAAAAAAAAAAEBAQAAAAAAGBgTACgoLwAmJjEAJiYnADIyXgBWVv8Adnb8AJ2d/gCxsf8Aycn/AJeX+wBycv8ASkrGAAACAAABAQMABwcbAAAADwBfX34A+fn/AOHh/ADj4/8AoaH/AFJS/gB1df8Aq6v/ALm5/wDT0/8Ap6f+AHNz/wBeXu0AFRUdAAAAAAABAQEAAAABAAUFEQCjo7YAzs72ANnZ/wCfn/4AY2P/AHl5/wCzs/8A5ub/ALu7/wCcnP4AcHD/AFNT7AAVFRwAICAmAHd3mQB6eqIAdXWcAHl5nwClpeAAyMj/AK2t/gB9ff8An5//ANXV/wDh4f8A1tb/AJ6e+gB0dP8AUFC7AAEGAABcXH4A////AP39/AD///8A////AP///wD///8A////ALOz/wCnp/8A4eH/AObm/wDPz/4ArKz/AI2N/AAhIT8AAAAAAFxcfwDd3f8Aa2v4AGpq+wBycvwAeHj+AHt7/wB/f/8Ac3P/AHNz/wCiov8AwMD+ALS0/wCEhOUAKSlFAAAAAAABAQIAXl5/ANjY/wBGRvwARkb/AFJS/wBaWv8AX1//AF9f/wBfX/8AWVn/AFRU/wBRUfsAvr7/AGNjiAAAAAAABAQGAAAAAABeXoAA2tr/AFtb/ABeXv8AbGz/AHV1/wB6ev8Ae3v/AHd3/wBxcf8Aamr/AFtb+wDS0v8AbW2JAAAAAAADAwQAAAAAAF5egADa2v8AZGT8AGlp/wB5ef8AhYX/AI2N/wCTk/8AlJT/AJKS/wCPj/8AfX37AM/P/wBqaogAAAAAAAMDBAAAAAAAXl6AANra/wBycvwAf3//AJOT/wClpf8AsLD/ALa2/wC1tf8Ar6//AKqq/wCTk/sA0ND/AGpqiAAAAAAAAwMEAAAAAABeXn8A2dn/AJGR/ACnp/8At7f/AMXF/wDQ0P8A09P/ANHR/wDLy/8AyMj/AK2t+wDR0f8AaWmHAAAAAAADAwQAAAAAAF5efwDY2P8AkpL5AKWl/ACurvwAuLj8AL+//ADCwvwAwMD8AL29/AC8vPwAo6P4ANDQ/wBqaokAAAAAAAMDBAAAAAAAV1d3APf3/wDa2vwA3d3/AOHh/wDk5P8A5ub/AOTk/wDh4f8A39//ANra/wDT0/sA+fn/AGNjfwAAAAAAAwMEAAAAAAAWFhoAV1d6AF9fgQBgYIAAYWGAAGFhgABiYoAAYmKAAGFhgABhYYAAYGCAAF5egABbW4AAGhoeAAAAAAABAQEAAAAA/oOAQeEAgEH6AIBBoACAQQAAAEGAAABBAACAQQAAgEEAAQBBAAKAQQACgEEAAoBBAAKAQQACgEEAAoBBAAKAQQACgEE='; break; default:icon.src = self.image; } }; toggleImage(); gPrefService.addObserver(s, toggleImage, false); addDestructor(()=> gPrefService.removeObserver(s, toggleImage) ); // Переключать на режим 'Без прокси' при закрытии браузера если это разрешено в 'about:config' ................... var switchOffProxy = { observe: function(subject, topic, data) { if ( data == "shutdown" && cbu.getPrefs("CB.Proxy.reset") ) cbu.setPrefs("network.proxy.type", 0); } }; Services.obs.addObserver(switchOffProxy, "quit-application", false); // Создаем меню для добавление прокси в контекстном меню выделенного текста на странице ................... ((contextMenu)=> { // создать новый пункт меню var menuitem = contextMenu.appendChild( document.createElement("menuitem") ); menuitem.setAttribute("label", "Добавить прокси"); menuitem.setAttribute("class", "menuitem-iconic"); menuitem.setAttribute("image", self.image); menuitem.onclick =()=> addNewProxy(); addDestructor(()=> menuitem.remove() ); // устанавливаем где показывать пункт меню addEventListener("popupshowing", ()=>{ menuitem.hidden = !cbu.getPrefs("CB.Proxy.inContextMenu") || !gContextMenu.isContentSelected; // !gContextMenu.isTextSelected; }, false, contextMenu); // добавление прокси function addNewProxy(sel) { var selection = document.commandDispatcher.focusedWindow.getSelection().toString(); var sel = ( sel == undefined ) ? selection : sel.toString(); sel = sel.replace(/^\s+|\s+$/g, ""); // удалить пробелы, слева и справа от строки sel = sel.replace(/\s+/g,":"); // заменить пробелы внутри строки // если только порт ... if ( sel.length < 6 && isFinite(sel) ) { sel = sel.replace(/:/g, ""); var lab = 'порт'; cbu.setPrefs("network.proxy.http_port", +sel); } // если только адрес ... if ( sel.length > 5 && !/:/.test(sel) && sel.split(".").length == 4 ) { var lab = 'адрес'; cbu.setPrefs("network.proxy.http", convertFromUnicode("UTF-8", sel)); } // если адрес и порт ... if ( sel.length > 5 && /:/.test(sel) && sel.split(":").length == 2 && sel.split(".").length == 4 ) { var lab = 'адрес и порт'; var array = sel.split(":"); array.forEach((str)=> addNewProxy(str) ); } if ( lab == undefined ) return; // всплывающая подсказка рядом с выделенным текстом ... function showTooltip() { var tooltip = gBrowser.appendChild( document.createElement("tooltip") ); tooltip.style.cssText = "color: red !important; font-weight: bold !important; font-size: 14px !important; -moz-box-orient: horizontal; text-align: center;"; var image = tooltip.appendChild( document.createElement("image") ); image.setAttribute("src", self.image); var label = tooltip.appendChild( document.createElement("label")); label.setAttribute("value", "Установлен " + lab + " прокси: " + sel); var focused = document.commandDispatcher.focusedWindow; var selection = focused.getSelection().getRangeAt(0).getBoundingClientRect(); var posX = focused.mozInnerScreenX + selection.left; var posY = focused.mozInnerScreenY + selection.bottom - 5; tooltip.showPopup(gBrowser, posX, posY); setTimeout(()=> gBrowser.removeChild(tooltip), 3000); }; showTooltip(); }; })(document.getElementById("contentAreaContextMenu"));
К сожалению на FF 84 и выше, перестала работать.
Помогите пожалуйста. Поправьте
Отсутствует
vv07
я что-то там менял, не помню что, то ли цвета кнопки, то ли еще что-то по-мелочи
/*Initialization Code*/ /* https://forum.mozilla-russia.org/viewtopic.php?pid=783830#p783830 */ // Настройка функций кликов мыши для кнопки ................... this.onmousedown = e => { if (e.button == 0) // длинный левый клик self.timer = setTimeout(() => { self.onmouseup = null; cbu.getPrefs("CB.Proxy.connectionsInTab") ? openConnectionsInTab() : openConnections(); }, 500); this.onmouseup = e => { // левый клик if (e.button) return; clearTimeout(self.timer); switch(cbu.getPrefs("network.proxy.type")) { case 0: var data = 1; break; case 1: var data = 2; break; case 2: var data = 0; break; default: var data = 0; } cbu.setPrefs("network.proxy.type", data); } } // правый клик this.oncontextmenu = e => e.detail == 2 && !menuPopup.hidePopup() || e.ctrlKey || !!menuPopup.openPopup(this, "after_start"); // Подсказка для кнопки ................... this.onmouseover = () => this.tooltipText = "Proxy \nЛ: Переключить прокси \nДЛ: Открыть настройки прокси" + "\nП: Mеню кнопки \nДП: CB меню \n\nТекущие настройки прокси: " + "\nIP: " + cbu.getPrefs("network.proxy.http") + "\nПорт: " + cbu.getPrefs("network.proxy.http_port"); // Создать меню для кнопки ................... var array = [ {label: "Добавление прокси в контекстом меню", value: 'CB.Proxy.inContextMenu'}, {label: "Открывать настройки прокси как вкладку", value: 'CB.Proxy.connectionsInTab'}, {label: "Переключать на режим 'Без прокси' при закрытии браузера ", value: 'CB.Proxy.reset'} ]; var menuPopup = document.getElementById('mainPopupSet').appendChild(document.createElementNS(xulns, "menupopup")); array.forEach(m => { var mItem = document.createElementNS(xulns, "menuitem"); mItem.setAttribute("label", m.label); mItem.setAttribute("type", "checkbox"); mItem.setAttribute("checked", cbu.getPrefs(m.value)); mItem.onclick = () => cbu.setPrefs(m.value, !cbu.getPrefs(m.value)); menuPopup.appendChild(mItem); }); addDestructor(() => menuPopup.remove()); var listenClick = win => { var args = ["click", win.close.bind(win), true]; var unload = () => gBrowser.removeEventListener(...args); gBrowser.addEventListener(...args); win.addEventListener("unload", unload, {once: true}); } var version = parseInt(Services.appinfo.platformVersion); var url = `chrome://browser/content/preferences/${version >= 77 ? "dialogs/" : ""}connection.x${version >= 72 ? "htm" : "u"}l`; var fox73 = version >= 73, noop = () => {}; if (fox73) var grid = win => { var url = "data:text/css;charset=utf-8," + encodeURIComponent(` #proxy-grid, #dnsOverHttps-grid { display: grid; grid-template-columns: auto 1fr; align-items: center; } #proxy-grid > .thin { grid-column-end: 3; height: 20px; } #dnsOverHttps-grid.custom-container-hidden #networkCustomDnsOverHttpsInput, #dnsOverHttps-grid.custom-container-hidden #networkCustomDnsOverHttpsInputLabelContainer { display: none; } `); (grid = win => win.windowUtils.loadSheetUsingURIString(url, win.windowUtils.AUTHOR_SHEET))(win); } var winOpen = win => win.addEventListener("readystatechange", winReady, {once: true, capture: true}); var winReady = e => { var win = e.target.ownerGlobal, cw = win.isChromeWindow; if (cw || (win.location == url && !win.docShell.name)) winPatch(win, cw); } var winPatch = (win, cw) => { win.opener = {gSubDialog: {_dialogs: [{ _frame: {get contentDocument() { cw && listenClick(win); delete this.contentDocument; return this.contentDocument = win.document; }}, resizeVertically: cw ? () => win.sizeToContent() : noop }]}}; fox73 && grid(win); } addEventListener("MozBeforeInitialXULLayout", winReady, false, gBrowser.tabpanels || 1); for(var {contentWindow: win} of gBrowser.browsers) win && win.location == url && !win.opener && winPatch(win); // Функция открывает настройки прокси в окне ................... function openConnections() { var win = [...Services.wm.getEnumerator(null)].find(w => w.location == url); win ? win.focus() : winOpen(openDialog(url, "Proxy", "centerscreen")); } // Функция открывает настройки прокси в вкладке ................... function openConnectionsInTab() { var connections = gBrowser.getBrowserForTab( gBrowser.selectedTab = gBrowser.addTrustedTab(url) ); // oбработчик ждет пока откроется прокси, удаляет себя и добавляет атрибут connections.addEventListener("pageshow", e => e.target.documentElement.setAttribute("type", "prefwindow") , {once: true}); } // Установливать нужную иконку кнопки при старте баузера или при изменениях в 'about:config' ................... var s = "network.proxy.type"; function toggleImage() { var {icon} = self; switch( cbu.getPrefs(s) ) { //case 0: icon.src = self.image; break; case 2: icon.src = 'data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAQAAAAAIAA4GQAAnFmkAHQ5fAAQAKAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEBAQECAgICAgICAgICAgMBAQEAAAQBJBFQOLQ+nX38ecev/mu6of8gfFvtAyUXewAAAAsAAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEBAAAAAAMLUza7PKd//3S7oP2849X9zuvh/mW4mf4XiV7/AB4QZwAAAAAAAAAAAQEBAQAAAAAZGhgTKSwnLyYqJDErKCUnID8vXgaAUP9BlnH8b7ea/ojHrv+q2sf/a7CT+zGWbf8PakXGAAIAAAEBAQMHBwcbAAAAD2BiXn76/ff/4ebg/Onm4f+DtZ7/A31L/j2Wb/+Fwaj/ls23/7rh0v9+vaT+M5du/xKGWO0DIxIdAAAAAAEBAQEAAAABBgYFEaSmorbP08z239vX/4OwnP4ail3/RJlz/5HHsP/T7+X/ms64/3K2mP40k2r/D3tM7AUiExwhIx8meXt1mXt+eKJ3eXSce353n6esouDMysf/o7eq/kOdeP92uZv/vuPT/9Hs4P/C4tT/eLWa+juWbv8bcEq7AAYBAF1gWn7//////f39/P//////////////////////////lcKx/3i9pf/K7OD/2O/l/7ndzf6Fw6n/VK+I/AsxHj8AAAAAXF5bf+Ln2P+AnU/4fZ1N+4WiV/yKp13+jKlh/5CsZf+GpFj/Zpxh/4C5nf+i0L7+k8ex/1udf+UTOCZFAAAAAAEBAQJfYF5/3uXR/16IIPxciiH/Z5Iv/26YOP9ymz3/cpw+/3OcPf9wlzb/YI80/1mKNPu707X/YmZjiAAAAAAEBAQGAAAAAF9gXoDg5tT/cJU6/HGaPf9/pE3/hqtX/4uvXf+NsF7/iKxZ/4KoU/9+o0r/cpY6+9zjyf9ubm2JAAAAAAMEAwQAAAAAX2BegODm1P94nEX8e6JJ/4quXP+Vt2n/nb1z/6LBef+jwXz/ob96/527d/+NrGP71+HG/2praogAAAAABAQDBAAAAABfYF2A4ObU/4WlVvyPsmP/osB7/7HMj/+81J3/wdik/8DXo/+60pz/tc6X/6G6ffvY4sf/amtqiAAAAAAEBAMEAAAAAF9gXn/e5dL/n7l7/LLMk//B16X/zuG2/9jpwv/b68b/2enE/9Pkvv/Q4bv/uMud+9jhyP9qa2mHAAAAAAQEAwQAAAAAX2Bef97k0v+gt335sceT/LrNnfzC1Kj8ydmx/MzatfzK2bP8xtav/MbVr/ywwpL41+HH/2tsaokAAAAABAQDBAAAAABZW1Z3+fz1/+Dm1Pzj6db/5u3b/+nv3v/r8eD/6vDe/+ft2//k69j/4efT/9ngzPv7//b/ZGdhfwAAAAADBAMEAAAAABcZFRpZW1Z6YGFfgWBiYIBhYmGAYmJhgGJjYoBiY2KAYmJhgGFiYYBgYWCAX2BegF1fWoAbHRkeAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='; break; case 1: icon.src = 'data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAQAAAAAIAAcHQAAYGGkAEBBfAAEBKAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAABAQEAAgICAAICAgACAgMBAQEAAAEBJAA6OrQAf3/8ALCw/gCiov8AXl7tABkZewAAAAsAAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEBAAAAAAMAOTm7AIOD/wCjo/0A1tb9AOHh/gCcnP4AY2P/ABISZwAAAAAAAAAAAAEBAQAAAAAAGBgTACgoLwAmJjEAJiYnADIyXgBWVv8Adnb8AJ2d/gCxsf8Aycn/AJeX+wBycv8ASkrGAAACAAABAQMABwcbAAAADwBfX34A+fn/AOHh/ADj4/8AoaH/AFJS/gB1df8Aq6v/ALm5/wDT0/8Ap6f+AHNz/wBeXu0AFRUdAAAAAAABAQEAAAABAAUFEQCjo7YAzs72ANnZ/wCfn/4AY2P/AHl5/wCzs/8A5ub/ALu7/wCcnP4AcHD/AFNT7AAVFRwAICAmAHd3mQB6eqIAdXWcAHl5nwClpeAAyMj/AK2t/gB9ff8An5//ANXV/wDh4f8A1tb/AJ6e+gB0dP8AUFC7AAEGAABcXH4A////AP39/AD///8A////AP///wD///8A////ALOz/wCnp/8A4eH/AObm/wDPz/4ArKz/AI2N/AAhIT8AAAAAAFxcfwDd3f8Aa2v4AGpq+wBycvwAeHj+AHt7/wB/f/8Ac3P/AHNz/wCiov8AwMD+ALS0/wCEhOUAKSlFAAAAAAABAQIAXl5/ANjY/wBGRvwARkb/AFJS/wBaWv8AX1//AF9f/wBfX/8AWVn/AFRU/wBRUfsAvr7/AGNjiAAAAAAABAQGAAAAAABeXoAA2tr/AFtb/ABeXv8AbGz/AHV1/wB6ev8Ae3v/AHd3/wBxcf8Aamr/AFtb+wDS0v8AbW2JAAAAAAADAwQAAAAAAF5egADa2v8AZGT8AGlp/wB5ef8AhYX/AI2N/wCTk/8AlJT/AJKS/wCPj/8AfX37AM/P/wBqaogAAAAAAAMDBAAAAAAAXl6AANra/wBycvwAf3//AJOT/wClpf8AsLD/ALa2/wC1tf8Ar6//AKqq/wCTk/sA0ND/AGpqiAAAAAAAAwMEAAAAAABeXn8A2dn/AJGR/ACnp/8At7f/AMXF/wDQ0P8A09P/ANHR/wDLy/8AyMj/AK2t+wDR0f8AaWmHAAAAAAADAwQAAAAAAF5efwDY2P8AkpL5AKWl/ACurvwAuLj8AL+//ADCwvwAwMD8AL29/AC8vPwAo6P4ANDQ/wBqaokAAAAAAAMDBAAAAAAAV1d3APf3/wDa2vwA3d3/AOHh/wDk5P8A5ub/AOTk/wDh4f8A39//ANra/wDT0/sA+fn/AGNjfwAAAAAAAwMEAAAAAAAWFhoAV1d6AF9fgQBgYIAAYWGAAGFhgABiYoAAYmKAAGFhgABhYYAAYGCAAF5egABbW4AAGhoeAAAAAAABAQEAAAAA/oOAQeEAgEH6AIBBoACAQQAAAEGAAABBAACAQQAAgEEAAQBBAAKAQQACgEEAAoBBAAKAQQACgEEAAoBBAAKAQQACgEE='; break; default: icon.src = self.image; } } toggleImage(); Services.prefs.addObserver(s, toggleImage, false); addDestructor(() => Services.prefs.removeObserver(s, toggleImage)); // Переключать на режим 'Без прокси' при закрытии браузера если это разрешено в 'about:config' ................... var toggleButton = { observe(s, t, data) { cbu.getPrefs("CB.Proxy.reset") && data == "shutdown" && cbu.setPrefs("network.proxy.type", 0); } }; Services.obs.addObserver(toggleButton, "quit-application", false); // Создаем меню для добавление прокси в контекстном меню выделенного текста на странице ................... var contextMenu = document.getElementById("contentAreaContextMenu"); var menuitem = document.createElementNS(xulns,"menuitem"); menuitem.setAttribute("label", "Добавить прокси"); menuitem.setAttribute("class", "menuitem-iconic"); menuitem.setAttribute("image", self.image); menuitem.onclick =()=> addNewProxy(menuitem); contextMenu.appendChild(menuitem); // как последний пункт меню addDestructor(() => menuitem.remove()); addEventListener("popupshowing", () => { menuitem.hidden = !cbu.getPrefs("CB.Proxy.inContextMenu") || !gContextMenu.isContentSelected; // !gContextMenu.isTextSelected; }, false, contextMenu); // добавление прокси ................... function addNewProxy(menuitem) { var sel = gBrowser.contentDocument ? gBrowser.contentDocument.defaultView.getSelection().toString() // Pale Moon : gContextMenu.selectionInfo.fullText; // Firefox sel = sel.replace(/^\s+|\s+$/g, ""); // удалить пробелы, слева и справа от строки sel = sel.replace(/\s+/g, ":"); // заменить пробелы внутри строки // если только порт ... if (sel.length < 6 && isFinite(sel)) { var lab = 'порт'; cbu.setPrefs("network.proxy.http_port", +sel); } // если только адрес ... if (sel.length > 5 && !/:/.test(sel) && sel.split(".").length == 4) { var lab = 'адрес'; cbu.setPrefs("network.proxy.http", convertFromUnicode("UTF-8", sel)); } // если адрес и порт ... if (sel.length > 5 && /:/.test(sel) && sel.split(":").length == 2 && sel.split(".").length == 4) { var lab = 'адрес и порт'; var arr = sel.split(":"), IP = arr[0], port = arr[1]; cbu.setPrefs("network.proxy.http_port", +port); cbu.setPrefs("network.proxy.http", convertFromUnicode("UTF-8", IP)); } // всплывающая подсказка рядом с выделенным текстом ... var mainPopupSet = document.getElementById('mainPopupSet'); var tooltip = mainPopupSet.appendChild(document.createElementNS(xulns,"tooltip")); tooltip.style.cssText = "color: red !important; font-weight: bold !important; font-size: 14px !important; -moz-box-orient: horizontal; text-align: center;"; var image = tooltip.appendChild(document.createElementNS(xulns, "image")); image.setAttribute("src", self.image); var label = tooltip.appendChild(document.createElementNS(xulns, "label")); label.setAttribute("value", "Установлен " + lab + " прокси: " + sel); tooltip.openPopup(menuitem.parentNode, "before_start"); setTimeout(() => mainPopupSet.removeChild(tooltip), 3000); }; // Конвертировать текст в юникод ............. function convertFromUnicode(charset, str) { var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); converter.charset = charset; str = converter.ConvertFromUnicode(str); return str + converter.Finish(); }
а... ну в коде есть ссылка, откуда я эту кнопку выкопал и чуть ниже скрипт, сделанный из этой кнопки
Отредактировано sonyas75 (10-03-2022 12:13:40)
Отсутствует
Dumby
Откуда появляется дополнительный border или не border при select / И в #loginTextbox тоже. Причем в loginTextbox сходу появляется без выделения ....
data:image/jpeg;charset=utf-8;base64,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
Отсутствует
Откуда появляется дополнительный border или не border при select
В текстовых полях панельки со скриншота — это, наверно, outline.
Добавляется по :focus-visible этим фрагментом из chrome://browser/skin/browser.css
#editBookmarkPanelRows > vbox > html|input:focus-visible, #editBookmarkPanelRows > vbox > hbox > html|input:focus-visible { outline: 2px solid var(--focus-outline-color); }
И в #loginTextbox тоже. Причем в loginTextbox сходу появляется без выделения ....
Это не знаю. Если его документ в своём отдельном окне, то такого не вижу,
есть outline только в subdialog'ах, видимо из chrome://global/skin/in-content/common.css
html|input:is([type="email"], [type="tel"], [type="text"], [type="password"], [type="url"], [type="number"]):focus, html|textarea:focus, xul|search-textbox[focused], xul|tree:focus-visible, xul|richlistbox:focus-visible { border-color: transparent; outline: 2px solid var(--in-content-focus-outline-color); outline-offset: -1px; /* Prevents antialising around the corners */ }
Отсутствует
скрытый текстВыделить кодКод:
(async repl => { var obj = `{\n ${ (await (await fetch("chrome://browser/content/places/controller.js")).text()) .match(/async _removeRange\(.+?\n\ +}(?=,\n)/s)[0] .replace("// This is a common bookmark item.", repl) }\n}` var ps = await ChromeUtils.compileScript("data:,(" + encodeURIComponent(`${obj => { var patch = async ctor => { var proto = ctor.prototype, meth = proto?._removeRange; meth && Object.assign(proto, obj); } var key = "PlacesController"; var desc = Object.getOwnPropertyDescriptor(window, key); if (!desc) return; var {get} = desc; if (get) desc.get = () => { var val = get(); patch(val); return val; }, Object.defineProperty(window, key, desc); else patch(desc.value); }})(${obj});`)); var obs = doc => "PlacesController" in doc.ownerGlobal && ps.executeInGlobal(doc); var topic = "chrome-document-loaded"; Services.obs.addObserver(obs, topic); Services.obs.addObserver(function quit(s, t) { Services.obs.removeObserver(quit, t); Services.obs.removeObserver(obs, topic); }, "quit-application-granted"); })( `$& if (!removedFolders.ignore) { let info = await PlacesUtils.bookmarks.fetch(node.bookmarkGuid); if ( info?.parentGuid == "${PlacesUtils.bookmarks.toolbarGuid}" && !(removedFolders.ignore ??= Services.prompt.confirm( null, null, "Удалять с панели закладок?" )) ) { totalItems--; continue; } }` );
Dumby
Возможно ли добавить, чтобы при удалении закладки находящейся внутри папки, тоже появлялось предупреждение.
«The Truth Is Out There»
Отсутствует
Возможно ли добавить, чтобы при удалении закладки находящейся внутри папки, тоже появлялось предупреждение.
Есть вариант получше - можно подключить через UCF скрипт восстановления удалённых закладок/папок:
// ==UserScript== // @name undoBookmarksContextMenu.uc.js // @namespace http://space.geocities.yahoo.co.jp/gl/alice0775 // @description add undo menu in Bookmarks Context Menu // @include * // @compatibility Firefox 91 // @author alice0775 // @version 2021/10/02 00:00 do not close popup when middle mouse click on the undo/redo menu // @version 2019/11/20 23:00 Bug 1553188 - Rename browser.xul to browser.xhtml // @version 2019/11/20 23:00 fix redeclaration error // @version 2019/07/10 10:00 fix 70 Bug 1558914 - Disable Array generics in Nightly // @version 2018/10/04 20:00 remove conflict shortcuts key for main window // @version 2018/10/04 60+ // ==/UserScript== if (typeof window.undobookmarksmenu == "undefined") { window.undobookmarksmenu = { popup: null, handleEvent: function(event) { switch (event.type) { case 'unload': this.uninit(); break; case 'popupshown': this.popupshown(event); break; } }, init: function() { window.addEventListener('unload', this, false); this.popup = document.getElementById("placesContext"); if (!this.popup) return; this.popup.addEventListener('popupshown', this, false); let template = (location.href == "chrome://browser/content/browser.xhtml" || location.href == "chrome://browser/content/browser.xul") ? [ ["menuitem", {id: "undobookmarksmenuUndo", disabled: "true", label: "Откат удаления", key: "key_undo", oncommand: "PlacesTransactions.undo().catch(Cu.reportError);", accesskey: "U", selection: "any", onmouseup: "undobookmarksmenu.shouldPreventHide(event);" }], ["menuitem", {id:"undobookmarksmenuRedo", disabled: "true", label: "Удалить снова", key: "key_redo", oncommand: "PlacesTransactions.redo().catch(Cu.reportError);", accesskey: "R", selection: "any", onmouseup: "undobookmarksmenu.shouldPreventHide(event);" }] ] : [ ["menuitem", {id: "undobookmarksmenuUndo", disabled: "true", label: "Откат удаления", key: "key_undo", oncommand: "PlacesTransactions.undo().catch(Cu.reportError);", acceltext: "Ctrl+Z", accesskey: "U", selection: "any", onmouseup: "undobookmarksmenu.shouldPreventHide(event);" }], ["menuitem", {id:"undobookmarksmenuRedo", disabled: "true", label: "Удалить снова", key: "key_redo", oncommand: "PlacesTransactions.redo().catch(Cu.reportError);", acceltext: "Ctrl+Y", accesskey: "R", selection: "any", onmouseup: "undobookmarksmenu.shouldPreventHide(event);" }] ]; let ref = document.getElementById("placesContext_deleteSeparator"); ref.parentNode.insertBefore(this.jsonToDOM(template, document, {}), ref); }, uninit: function() { window.removeEventListener('unload', this, false); if (!this.popup) return; this.popup.removeEventListener('popupshown', this, false); }, popupshown: function(event){ var menuitem = document.getElementById("undobookmarksmenuUndo"); if (menuitem) menuitem.setAttribute('disabled', PlacesTransactions.topUndoEntry == null); menuitem = document.getElementById("undobookmarksmenuRedo"); if (menuitem) menuitem.setAttribute('disabled', PlacesTransactions.topRedoEntry == null); }, shouldPreventHide: function(aEvent) { const menuitem = event.target; if (event.button == 1) { menuitem.setAttribute('closemenu', 'none'); menuitem.parentNode.addEventListener('popuphidden', () => { menuitem.removeAttribute('closemenu'); }, { once: true }); if (event.ctrlKey) menuitem.parentNode.hidePopup(); } }, jsonToDOM: function(jsonTemplate, doc, nodes) { jsonToDOM.namespaces = { html: "http://www.w3.org/1999/xhtml", xul: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" }; jsonToDOM.defaultNamespace = jsonToDOM.namespaces.xul; function jsonToDOM(jsonTemplate, doc, nodes) { function namespace(name) { var reElemNameParts = /^(?:(.*):)?(.*)$/.exec(name); return { namespace: jsonToDOM.namespaces[reElemNameParts[1]], shortName: reElemNameParts[2] }; } // Note that 'elemNameOrArray' is: either the full element name (eg. [html:]div) or an array of elements in JSON notation function tag(elemNameOrArray, elemAttr) { // Array of elements? Parse each one... if (Array.isArray(elemNameOrArray)) { var frag = doc.createDocumentFragment(); Array.prototype.forEach.call(arguments, function(thisElem) { frag.appendChild(tag.apply(null, thisElem)); }); return frag; } // Single element? Parse element namespace prefix (if none exists, default to defaultNamespace), and create element var elemNs = namespace(elemNameOrArray); var elem = doc.createElementNS(elemNs.namespace || jsonToDOM.defaultNamespace, elemNs.shortName); // Set element's attributes and/or callback functions (eg. onclick) for (var key in elemAttr) { var val = elemAttr[key]; if (nodes && key == "key") { nodes[val] = elem; continue; } var attrNs = namespace(key); if (typeof val == "function") { // Special case for function attributes; don't just add them as 'on...' attributes, but as events, using addEventListener elem.addEventListener(key.replace(/^on/, ""), val, false); } else { // Note that the default namespace for XML attributes is, and should be, blank (ie. they're not in any namespace) elem.setAttributeNS(attrNs.namespace || "", attrNs.shortName, val); } } // Create and append this element's children var childElems = Array.prototype.slice.call(arguments, 2); childElems.forEach(function(childElem) { if (childElem != null) { elem.appendChild( childElem instanceof doc.defaultView.Node ? childElem : Array.isArray(childElem) ? tag.apply(null, childElem) : doc.createTextNode(childElem)); } }); return elem; } return tag.apply(null, jsonTemplate); } return jsonToDOM(jsonTemplate, doc, nodes); } } window.undobookmarksmenu.init(); }
Отсутствует
Dobrov
Восстановление сделал Dumby по аналогии с приведённым скриптом от alice0775 (там выше и ниже поста обсуждение) https://forum.mozilla-russia.org/viewto … 78#p798678
Как я понял, unter_officer спрашивает про подтверждение перед удалением.
Отредактировано xrun1 (19-03-2022 03:43:59)
Отсутствует
Возможно ли добавить, чтобы при удалении закладки находящейся внутри папки, тоже появлялось предупреждение.
Почему бы нет
/* let info = await PlacesUtils.bookmarks.fetch(node.bookmarkGuid); */ let args = [node.bookmarkGuid]; let isBookmark = PlacesUtils.nodeIsBookmark(node); isBookmark && args.push(null, {includePath: true}); let info = await PlacesUtils.bookmarks.fetch(...args); if (isBookmark) info.parentGuid = info.path[0].guid;
Отсутствует
Почему бы нет
скрытый текстВыделить кодКод:
/* let info = await PlacesUtils.bookmarks.fetch(node.bookmarkGuid); */ let args = [node.bookmarkGuid]; let isBookmark = PlacesUtils.nodeIsBookmark(node); isBookmark && args.push(null, {includePath: true}); let info = await PlacesUtils.bookmarks.fetch(...args); if (isBookmark) info.parentGuid = info.path[0].guid;
Большое спасибо.
«The Truth Is Out There»
Отсутствует
Здравствуйте.
А где собственно скачать этот Custom Buttons? Все три ссылки в начале темы ведут в никуда.
Отсутствует
Отсутствует
pandarianinhttps://www.upload.ee/files/13987518/cu … x.zip.html
Спасибо. А как установить это чудо? Пишет что дополнение повреждено и не может быть установлено.
Отсутствует
pandarianin
Нужны два файла: config.js и config-prefs.js. Как создать и куда положить смотрите здесь.
Для config.js актуальный код нужно брать отсюда. После этого запускаете и ставите версию custom_buttons-0.0.7.0.0.23-fx-bootstrap.xpi.
Отсутствует
без bootstrap не взлетит, нужен такой config.js
для 99 будет такой антиподписальщик
// try {(nsvo => { var o = Cu.getGlobalForObject(nsvo).Object, {freeze} = o, NEW; o.freeze = obj => { if (Components.stack.caller.filename != "resource://gre/modules/AppConstants.jsm") return freeze(obj); obj.MOZ_REQUIRE_SIGNING = false; if ((NEW = "MOZ_ALLOW_ADDON_SIDELOAD" in obj)) lockPref("extensions.experiments.enabled", true); else obj.MOZ_ALLOW_LEGACY_EXTENSIONS = true, lockPref("extensions.legacy.enabled", true); return (o.freeze = freeze)(obj); } lockPref("xpinstall.signatures.required", false); lockPref("extensions.langpacks.signatures.required", false); nsvo = Cu.import("resource://gre/modules/addons/XPIInstall.jsm", {}); var shouldVerify = nsvo.shouldVerifySignedState; nsvo.shouldVerifySignedState = addon => !addon.id && shouldVerify(addon); if (NEW) nsvo.XPIDatabase.isDisabledLegacy = () => false; })( "permitCPOWsInScope" in Cu ? Cu.import("resource://gre/modules/WebRequestCommon.jsm", {}) : Cu );} catch(ex) {Cu.reportError(ex);} // bootstrap-loader.js https://forum.mozilla-russia.org/viewtopic.php?pid=795196#p795196 try {(ios => { var subst = "bootstrap-loader-config-script"; ios.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler).setSubstitution(subst, ios.newURI(String.raw` data:,/%2A%2A%2A RDFDataSource.jsm %2A%2A%2A/%0A%0Aconst NS_XML = "http://www.w3.org/XML/1998/namespace";%0Aconst NS_XMLNS = "http://www.w3.org/2000/xmlns/";%0Aconst NS_RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns%23";%0Aconst NS_NC = "http://home.netscape.com/NC-rdf%23";%0A%0Afunction isElement(obj) {%0A return Element.isInstance(obj);%0A}%0Afunction isText(obj) {%0A return obj && typeof obj == "object" && ChromeUtils.getClassName(obj) == "Text";%0A}%0A%0A/%2A%2A%0A %2A Returns either an rdf namespaced attribute or an un-namespaced attribute%0A %2A value. Returns null if neither exists,%0A %2A/%0Afunction getRDFAttribute(element, name) {%0A if (element.hasAttributeNS(NS_RDF, name))%0A return element.getAttributeNS(NS_RDF, name);%0A if (element.hasAttribute(name))%0A return element.getAttribute(name);%0A return undefined;%0A}%0A%0A/%2A%2A%0A %2A Represents an assertion in the datasource%0A %2A/%0Aclass RDFAssertion {%0A constructor(subject, predicate, object) {%0A // The subject on this assertion, an RDFSubject%0A this._subject = subject;%0A // The predicate, a string%0A this._predicate = predicate;%0A // The object, an RDFNode%0A this._object = object;%0A // The datasource this assertion exists in%0A this._ds = this._subject._ds;%0A // Marks that _DOMnode is the subject's element%0A this._isSubjectElement = false;%0A // The DOM node that represents this assertion. Could be a property element,%0A // a property attribute or the subject's element for rdf:type%0A this._DOMNode = null;%0A }%0A%0A getPredicate() {%0A return this._predicate;%0A }%0A%0A getObject() {%0A return this._object;%0A }%0A}%0A%0Aclass RDFNode {%0A equals(rdfnode) {%0A return (rdfnode.constructor === this.constructor &&%0A rdfnode._value == this._value);%0A }%0A}%0A%0A/%2A%2A%0A %2A A simple literal value%0A %2A/%0Aclass RDFLiteral extends RDFNode {%0A constructor(value) {%0A super();%0A this._value = value;%0A }%0A%0A getValue() {%0A return this._value;%0A }%0A}%0A%0A/%2A%2A%0A %2A This is an RDF node that can be a subject so a resource or a blank node%0A %2A/%0Aclass RDFSubject extends RDFNode {%0A constructor(ds) {%0A super();%0A // A lookup of the assertions with this as the subject. Keyed on predicate%0A this._assertions = {};%0A // A lookup of the assertions with this as the object. Keyed on predicate%0A this._backwards = {};%0A // The datasource this subject belongs to%0A this._ds = ds;%0A // The DOM elements in the document that represent this subject. Array of Element%0A this._elements = [];%0A }%0A%0A /%2A%2A%0A %2A Parses the given Element from the DOM document%0A %2A/%0A /%2A eslint-disable complexity %2A/%0A _parseElement(element) {%0A this._elements.push(element);%0A%0A // There might be an inferred rdf:type assertion in the element name%0A if (element.namespaceURI != NS_RDF ||%0A element.localName != "Description") {%0A var assertion = new RDFAssertion(this, RDF_R("type"),%0A this._ds.getResource(element.namespaceURI + element.localName));%0A assertion._DOMnode = element;%0A assertion._isSubjectElement = true;%0A this._addAssertion(assertion);%0A }%0A%0A // Certain attributes can be literal properties%0A for (let attr of element.attributes) {%0A if (attr.namespaceURI == NS_XML || attr.namespaceURI == NS_XMLNS ||%0A attr.nodeName == "xmlns")%0A continue;%0A if ((attr.namespaceURI == NS_RDF || !attr.namespaceURI) &&%0A (["nodeID", "about", "resource", "ID", "parseType"].includes(attr.localName)))%0A continue;%0A var object = null;%0A if (attr.namespaceURI == NS_RDF) {%0A if (attr.localName == "type")%0A object = this._ds.getResource(attr.nodeValue);%0A }%0A if (!object)%0A object = new RDFLiteral(attr.nodeValue);%0A assertion = new RDFAssertion(this, attr.namespaceURI + attr.localName, object);%0A assertion._DOMnode = attr;%0A this._addAssertion(assertion);%0A }%0A%0A var child = element.firstChild;%0A element.listCounter = 1;%0A while (child) {%0A if (isElement(child)) {%0A object = null;%0A var predicate = child.namespaceURI + child.localName;%0A if (child.namespaceURI == NS_RDF) {%0A if (child.localName == "li") {%0A predicate = RDF_R(%60_%24{element.listCounter}%60);%0A element.listCounter++;%0A }%0A }%0A%0A // Check for and bail out on unknown attributes on the property element%0A for (let attr of child.attributes) {%0A // Ignore XML namespaced attributes%0A if (attr.namespaceURI == NS_XML)%0A continue;%0A // These are reserved by XML for future use%0A if (attr.localName.substring(0, 3).toLowerCase() == "xml")%0A continue;%0A // We can handle these RDF attributes%0A if ((!attr.namespaceURI || attr.namespaceURI == NS_RDF) &&%0A ["resource", "nodeID"].includes(attr.localName))%0A continue;%0A // This is a special attribute we handle for compatibility with Mozilla RDF%0A if (attr.namespaceURI == NS_NC &&%0A attr.localName == "parseType")%0A continue;%0A }%0A%0A var parseType = child.getAttributeNS(NS_NC, "parseType");%0A%0A var resource = getRDFAttribute(child, "resource");%0A var nodeID = getRDFAttribute(child, "nodeID");%0A%0A if (resource !== undefined) {%0A var base = Services.io.newURI(element.baseURI);%0A object = this._ds.getResource(base.resolve(resource));%0A } else if (nodeID !== undefined) {%0A object = this._ds.getBlankNode(nodeID);%0A } else {%0A var hasText = false;%0A var childElement = null;%0A var subchild = child.firstChild;%0A while (subchild) {%0A if (isText(subchild) && /\S/.test(subchild.nodeValue)) {%0A hasText = true;%0A } else if (isElement(subchild)) {%0A childElement = subchild;%0A }%0A subchild = subchild.nextSibling;%0A }%0A%0A if (childElement) {%0A object = this._ds._getSubjectForElement(childElement);%0A object._parseElement(childElement);%0A } else%0A object = new RDFLiteral(child.textContent);%0A }%0A%0A assertion = new RDFAssertion(this, predicate, object);%0A this._addAssertion(assertion);%0A assertion._DOMnode = child;%0A }%0A child = child.nextSibling;%0A }%0A }%0A /%2A eslint-enable complexity %2A/%0A%0A /%2A%2A%0A %2A Adds a new assertion to the internal hashes. Should be called for every%0A %2A new assertion parsed or created programmatically.%0A %2A/%0A _addAssertion(assertion) {%0A var predicate = assertion.getPredicate();%0A if (predicate in this._assertions)%0A this._assertions[predicate].push(assertion);%0A else%0A this._assertions[predicate] = [ assertion ];%0A%0A var object = assertion.getObject();%0A if (object instanceof RDFSubject) {%0A // Create reverse assertion%0A if (predicate in object._backwards)%0A object._backwards[predicate].push(assertion);%0A else%0A object._backwards[predicate] = [ assertion ];%0A }%0A }%0A%0A /%2A%2A%0A %2A Returns all objects in assertions with this subject and the given predicate.%0A %2A/%0A getObjects(predicate) {%0A if (predicate in this._assertions)%0A return Array.from(this._assertions[predicate],%0A i => i.getObject());%0A%0A return [];%0A }%0A%0A /%2A%2A%0A %2A Retrieves the first property value for the given predicate.%0A %2A/%0A getProperty(predicate) {%0A if (predicate in this._assertions)%0A return this._assertions[predicate][0].getObject();%0A return null;%0A }%0A}%0A%0A/%2A%2A%0A %2A Creates a new RDFResource for the datasource. Private.%0A %2A/%0Aclass RDFResource extends RDFSubject {%0A constructor(ds, uri) {%0A super(ds);%0A // This is the uri that the resource represents.%0A this._uri = uri;%0A }%0A}%0A%0A/%2A%2A%0A %2A Creates a new blank node. Private.%0A %2A/%0Aclass RDFBlankNode extends RDFSubject {%0A constructor(ds, nodeID) {%0A super(ds);%0A // The nodeID of this node. May be null if there is no ID.%0A this._nodeID = nodeID;%0A }%0A%0A /%2A%2A%0A %2A Sets attributes on the DOM element to mark it as representing this node%0A %2A/%0A _applyToElement(element) {%0A if (!this._nodeID)%0A return;%0A if (USE_RDFNS_ATTR) {%0A var prefix = this._ds._resolvePrefix(element, RDF_R("nodeID"));%0A element.setAttributeNS(prefix.namespaceURI, prefix.qname, this._nodeID);%0A } else {%0A element.setAttribute("nodeID", this._nodeID);%0A }%0A }%0A%0A /%2A%2A%0A %2A Creates a new Element in the document for holding assertions about this%0A %2A subject. The URI controls what tagname to use.%0A %2A/%0A _createNewElement(uri) {%0A // If there are already nodes representing this in the document then we need%0A // a nodeID to match them%0A if (!this._nodeID && this._elements.length > 0) {%0A this._ds._createNodeID(this);%0A for (let element of this._elements)%0A this._applyToElement(element);%0A }%0A%0A return super._createNewElement.call(uri);%0A }%0A%0A /%2A%2A%0A %2A Adds a reference to this node to the given property Element.%0A %2A/%0A _addReferenceToElement(element) {%0A if (this._elements.length > 0 && !this._nodeID) {%0A // In document elsewhere already%0A // Create a node ID and update the other nodes referencing%0A this._ds._createNodeID(this);%0A for (let element of this._elements)%0A this._applyToElement(element);%0A }%0A%0A if (this._nodeID) {%0A if (USE_RDFNS_ATTR) {%0A let prefix = this._ds._resolvePrefix(element, RDF_R("nodeID"));%0A element.setAttributeNS(prefix.namespaceURI, prefix.qname, this._nodeID);%0A } else {%0A element.setAttribute("nodeID", this._nodeID);%0A }%0A } else {%0A // Add the empty blank node, this is generally right since further%0A // assertions will be added to fill this out%0A var newelement = this._ds._addElement(element, RDF_R("Description"));%0A newelement.listCounter = 1;%0A this._elements.push(newelement);%0A }%0A }%0A%0A /%2A%2A%0A %2A Removes any reference to this node from the given property Element.%0A %2A/%0A _removeReferenceFromElement(element) {%0A if (element.hasAttributeNS(NS_RDF, "nodeID"))%0A element.removeAttributeNS(NS_RDF, "nodeID");%0A if (element.hasAttribute("nodeID"))%0A element.removeAttribute("nodeID");%0A }%0A%0A getNodeID() {%0A return this._nodeID;%0A }%0A}%0A%0A/%2A%2A%0A %2A Creates a new RDFDataSource from the given document. The document will be%0A %2A changed as assertions are added and removed to the RDF. Pass a null document%0A %2A to start with an empty graph.%0A %2A/%0Aclass RDFDataSource {%0A constructor(document) {%0A // All known resources, indexed on URI%0A this._resources = {};%0A // All blank nodes%0A this._allBlankNodes = [];%0A%0A // The underlying DOM document for this datasource%0A this._document = document;%0A this._parseDocument();%0A }%0A%0A static loadFromString(text) {%0A let parser = new DOMParser();%0A let document = parser.parseFromString(text, "application/xml");%0A%0A return new this(document);%0A }%0A%0A /%2A%2A%0A %2A Returns an rdf subject for the given DOM Element. If the subject has not%0A %2A been seen before a new one is created.%0A %2A/%0A _getSubjectForElement(element) {%0A var about = getRDFAttribute(element, "about");%0A%0A if (about !== undefined) {%0A let base = Services.io.newURI(element.baseURI);%0A return this.getResource(base.resolve(about));%0A }%0A return this.getBlankNode(null);%0A }%0A%0A /%2A%2A%0A %2A Parses the document for subjects at the top level.%0A %2A/%0A _parseDocument() {%0A var domnode = this._document.documentElement.firstChild;%0A while (domnode) {%0A if (isElement(domnode)) {%0A var subject = this._getSubjectForElement(domnode);%0A subject._parseElement(domnode);%0A }%0A domnode = domnode.nextSibling;%0A }%0A }%0A%0A /%2A%2A%0A %2A Gets a blank node. nodeID may be null and if so a new blank node is created.%0A %2A If a nodeID is given then the blank node with that ID is returned or created.%0A %2A/%0A getBlankNode(nodeID) {%0A var rdfnode = new RDFBlankNode(this, nodeID);%0A this._allBlankNodes.push(rdfnode);%0A return rdfnode;%0A }%0A%0A /%2A%2A%0A %2A Gets the resource for the URI. The resource is created if it has not been%0A %2A used already.%0A %2A/%0A getResource(uri) {%0A if (uri in this._resources)%0A return this._resources[uri];%0A%0A var resource = new RDFResource(this, uri);%0A this._resources[uri] = resource;%0A return resource;%0A }%0A}%0A%0A%0A/%2A%2A%2A RDFManifestConverter.jsm %2A%2A%2A/%0A%0Aconst RDFURI_INSTALL_MANIFEST_ROOT = "urn:mozilla:install-manifest";%0A%0Afunction EM_R(aProperty) {%0A return %60http://www.mozilla.org/2004/em-rdf%23%24{aProperty}%60;%0A}%0A%0Afunction getValue(literal) {%0A return literal && literal.getValue();%0A}%0A%0Afunction getProperty(resource, property) {%0A return getValue(resource.getProperty(EM_R(property)));%0A}%0A%0Aclass Manifest {%0A constructor(ds) {%0A this.ds = ds;%0A }%0A%0A static loadFromString(text) {%0A return new this(RDFDataSource.loadFromString(text));%0A }%0A}%0A%0Aclass InstallRDF extends Manifest {%0A _readProps(source, obj, props) {%0A for (let prop of props) {%0A let val = getProperty(source, prop);%0A if (val != null) {%0A obj[prop] = val;%0A }%0A }%0A }%0A%0A _readArrayProp(source, obj, prop, target, decode = getValue) {%0A let result = Array.from(source.getObjects(EM_R(prop)),%0A target => decode(target));%0A if (result.length) {%0A obj[target] = result;%0A }%0A }%0A%0A _readArrayProps(source, obj, props, decode = getValue) {%0A for (let [prop, target] of Object.entries(props)) {%0A this._readArrayProp(source, obj, prop, target, decode);%0A }%0A }%0A%0A _readLocaleStrings(source, obj) {%0A this._readProps(source, obj, ["name", "description", "creator", "homepageURL"]);%0A this._readArrayProps(source, obj, {%0A locale: "locales",%0A developer: "developers",%0A translator: "translators",%0A contributor: "contributors",%0A });%0A }%0A%0A decode() {%0A let root = this.ds.getResource(RDFURI_INSTALL_MANIFEST_ROOT);%0A let result = {};%0A%0A let props = ["id", "version", "type", "updateURL", "optionsURL",%0A "optionsType", "aboutURL", "iconURL",%0A "bootstrap", "unpack", "strictCompatibility"];%0A this._readProps(root, result, props);%0A%0A let decodeTargetApplication = source => {%0A let app = {};%0A this._readProps(source, app, ["id", "minVersion", "maxVersion"]);%0A return app;%0A };%0A%0A let decodeLocale = source => {%0A let localized = {};%0A this._readLocaleStrings(source, localized);%0A return localized;%0A };%0A%0A this._readLocaleStrings(root, result);%0A%0A this._readArrayProps(root, result, {"targetPlatform": "targetPlatforms"});%0A this._readArrayProps(root, result, {"targetApplication": "targetApplications"},%0A decodeTargetApplication);%0A this._readArrayProps(root, result, {"localized": "localized"},%0A decodeLocale);%0A this._readArrayProps(root, result, {"dependency": "dependencies"},%0A source => getProperty(source, "id"));%0A%0A return result;%0A }%0A}%0A%0A%0A/%2A%2A%2A BootstrapLoader.jsm %2A%2A%2A/%0A%0Avar {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");%0Avar {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");%0A%0AXPCOMUtils.defineLazyModuleGetters(this, {%0A ConsoleAPI: "resource://gre/modules/Console.jsm",%0A Blocklist: "resource://gre/modules/Blocklist.jsm",%0A XPIProvider: "resource://gre/modules/addons/XPIProvider.jsm"%0A});%0A%0Avar OPTIONS_TYPE_DIALOG = 1;%0A%0AServices.obs.addObserver(doc => {%0A if (doc.location.protocol + doc.location.pathname === 'about:addons' ||%0A doc.location.protocol + doc.location.pathname === 'chrome:/content/extensions/aboutaddons.html') {%0A const win = doc.defaultView;%0A let handleEvent_orig = win.customElements.get('addon-card').prototype.handleEvent;%0A win.customElements.get('addon-card').prototype.handleEvent = function (e) {%0A if (e.type === 'click' &&%0A e.target.getAttribute('action') === 'preferences' &&%0A this.addon.optionsType == OPTIONS_TYPE_DIALOG) {%0A var windows = Services.wm.getEnumerator(null);%0A while (windows.hasMoreElements()) {%0A var win2 = windows.getNext();%0A if (win2.closed) {%0A continue;%0A }%0A if (win2.document.documentURI == this.addon.optionsURL) {%0A win2.focus();%0A return;%0A }%0A }%0A var features = 'chrome,titlebar,toolbar,centerscreen';%0A var instantApply = Services.prefs.getBoolPref('browser.preferences.instantApply');%0A features += instantApply ? ',dialog=no' : '';%0A win.docShell.rootTreeItem.domWindow.openDialog(this.addon.optionsURL, this.addon.id, features); %0A } else {%0A handleEvent_orig.apply(this, arguments);%0A }%0A }%0A let update_orig = win.customElements.get('addon-options').prototype.update;%0A win.customElements.get('addon-options').prototype.update = function (card, addon) {%0A update_orig.apply(this, arguments);%0A if (addon.optionsType == OPTIONS_TYPE_DIALOG)%0A this.querySelector('panel-item[data-l10n-id="preferences-addon-button"]').hidden = false;%0A }%0A }%0A}, 'chrome-document-loaded');%0A%0Aconst {AddonManager} = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");%0Aconst {XPIDatabase, AddonInternal} = ChromeUtils.import("resource://gre/modules/addons/XPIDatabase.jsm");%0A%0ACu.import("resource://gre/modules/addons/XPIDatabase.jsm", {}).defineAddonWrapperProperty("optionsType", function optionsType() {%0A if (!this.isActive) {%0A return null;%0A }%0A%0A let addon = this.__AddonInternal__;%0A let hasOptionsURL = !!this.optionsURL;%0A%0A if (addon.optionsType) {%0A switch (parseInt(addon.optionsType, 10)) {%0A case OPTIONS_TYPE_DIALOG:%0A case AddonManager.OPTIONS_TYPE_TAB:%0A case AddonManager.OPTIONS_TYPE_INLINE_BROWSER:%0A return hasOptionsURL ? addon.optionsType : null;%0A }%0A return null;%0A }%0A%0A return null;%0A});%0A%0AXPIDatabase.isDisabledLegacy = () => false;%0A%0AXPCOMUtils.defineLazyGetter(this, 'BOOTSTRAP_REASONS', () => XPIProvider.BOOTSTRAP_REASONS);%0A%0Aconst {Log} = ChromeUtils.import('resource://gre/modules/Log.jsm');%0Avar logger = Log.repository.getLogger('addons.bootstrap');%0A%0A/%2A%2A%0A %2A Valid IDs fit this pattern.%0A %2A/%0Avar gIDTest = /^(\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}|[a-z0-9-\._]%2A\@[a-z0-9-\._]+)$/i;%0A%0A// Properties that exist in the install manifest%0Aconst PROP_METADATA = ['id', 'version', 'type', 'internalName', 'updateURL',%0A 'optionsURL', 'optionsType', 'aboutURL', 'iconURL'];%0Aconst PROP_LOCALE_SINGLE = ['name', 'description', 'creator', 'homepageURL'];%0Aconst PROP_LOCALE_MULTI = ['developers', 'translators', 'contributors'];%0A%0A// Map new string type identifiers to old style nsIUpdateItem types.%0A// Retired values:%0A// 32 = multipackage xpi file%0A// 8 = locale%0A// 256 = apiextension%0A// 128 = experiment%0A// theme = 4%0Aconst TYPES = {%0A extension: 2,%0A dictionary: 64,%0A};%0A%0Aconst COMPATIBLE_BY_DEFAULT_TYPES = {%0A extension: true,%0A dictionary: true,%0A};%0A%0Aconst hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty);%0A%0Afunction isXPI(filename) {%0A let ext = filename.slice(-4).toLowerCase();%0A return ext === '.xpi' || ext === '.zip';%0A}%0A%0A/%2A%2A%0A %2A Gets an nsIURI for a file within another file, either a directory or an XPI%0A %2A file. If aFile is a directory then this will return a file: URI, if it is an%0A %2A XPI file then it will return a jar: URI.%0A %2A%0A %2A @param {nsIFile} aFile%0A %2A The file containing the resources, must be either a directory or an%0A %2A XPI file%0A %2A @param {string} aPath%0A %2A The path to find the resource at, '/' separated. If aPath is empty%0A %2A then the uri to the root of the contained files will be returned%0A %2A @returns {nsIURI}%0A %2A An nsIURI pointing at the resource%0A %2A/%0Afunction getURIForResourceInFile(aFile, aPath) {%0A if (!isXPI(aFile.leafName)) {%0A let resource = aFile.clone();%0A if (aPath)%0A aPath.split('/').forEach(part => resource.append(part));%0A%0A return Services.io.newFileURI(resource);%0A }%0A%0A return buildJarURI(aFile, aPath);%0A}%0A%0A/%2A%2A%0A %2A Creates a jar: URI for a file inside a ZIP file.%0A %2A%0A %2A @param {nsIFile} aJarfile%0A %2A The ZIP file as an nsIFile%0A %2A @param {string} aPath%0A %2A The path inside the ZIP file%0A %2A @returns {nsIURI}%0A %2A An nsIURI for the file%0A %2A/%0Afunction buildJarURI(aJarfile, aPath) {%0A let uri = Services.io.newFileURI(aJarfile);%0A uri = 'jar:' + uri.spec + '!/' + aPath;%0A return Services.io.newURI(uri);%0A}%0A%0Avar BootstrapLoader = {%0A name: 'bootstrap',%0A manifestFile: 'install.rdf',%0A async loadManifest(pkg) {%0A /%2A%2A%0A %2A Reads locale properties from either the main install manifest root or%0A %2A an em:localized section in the install manifest.%0A %2A%0A %2A @param {Object} aSource%0A %2A The resource to read the properties from.%0A %2A @param {boolean} isDefault%0A %2A True if the locale is to be read from the main install manifest%0A %2A root%0A %2A @param {string[]} aSeenLocales%0A %2A An array of locale names already seen for this install manifest.%0A %2A Any locale names seen as a part of this function will be added to%0A %2A this array%0A %2A @returns {Object}%0A %2A an object containing the locale properties%0A %2A/%0A function readLocale(aSource, isDefault, aSeenLocales) {%0A let locale = {};%0A if (!isDefault) {%0A locale.locales = [];%0A for (let localeName of aSource.locales || []) {%0A if (!localeName) {%0A logger.warn('Ignoring empty locale in localized properties');%0A continue;%0A }%0A if (aSeenLocales.includes(localeName)) {%0A logger.warn('Ignoring duplicate locale in localized properties');%0A continue;%0A }%0A aSeenLocales.push(localeName);%0A locale.locales.push(localeName);%0A }%0A%0A if (locale.locales.length == 0) {%0A logger.warn('Ignoring localized properties with no listed locales');%0A return null;%0A }%0A }%0A%0A for (let prop of [...PROP_LOCALE_SINGLE, ...PROP_LOCALE_MULTI]) {%0A if (hasOwnProperty(aSource, prop)) {%0A locale[prop] = aSource[prop];%0A }%0A }%0A%0A return locale;%0A }%0A%0A let manifestData = await pkg.readString('install.rdf');%0A let manifest = InstallRDF.loadFromString(manifestData).decode();%0A%0A let addon = new AddonInternal();%0A for (let prop of PROP_METADATA) {%0A if (hasOwnProperty(manifest, prop)) {%0A addon[prop] = manifest[prop];%0A }%0A }%0A%0A if (!addon.type) {%0A addon.type = 'extension';%0A } else {%0A let type = addon.type;%0A addon.type = null;%0A for (let name in TYPES) {%0A if (TYPES[name] == type) {%0A addon.type = name;%0A break;%0A }%0A }%0A }%0A%0A if (!(addon.type in TYPES))%0A throw new Error('Install manifest specifies unknown type: ' + addon.type);%0A%0A if (!addon.id)%0A throw new Error('No ID in install manifest');%0A if (!gIDTest.test(addon.id))%0A throw new Error('Illegal add-on ID ' + addon.id);%0A if (!addon.version)%0A throw new Error('No version in install manifest');%0A%0A addon.strictCompatibility = (!(addon.type in COMPATIBLE_BY_DEFAULT_TYPES) ||%0A manifest.strictCompatibility == 'true');%0A%0A // Only read these properties for extensions.%0A if (addon.type == 'extension') {%0A if (manifest.bootstrap != 'true') {%0A throw new Error('Non-restartless extensions no longer supported');%0A }%0A%0A if (addon.optionsType &&%0A addon.optionsType != OPTIONS_TYPE_DIALOG &&%0A addon.optionsType != AddonManager.OPTIONS_TYPE_INLINE_BROWSER &&%0A addon.optionsType != AddonManager.OPTIONS_TYPE_TAB) {%0A throw new Error('Install manifest specifies unknown optionsType: ' + addon.optionsType);%0A }%0A%0A if (addon.optionsType)%0A addon.optionsType = parseInt(addon.optionsType);%0A }%0A%0A addon.defaultLocale = readLocale(manifest, true);%0A%0A let seenLocales = [];%0A addon.locales = [];%0A for (let localeData of manifest.localized || []) {%0A let locale = readLocale(localeData, false, seenLocales);%0A if (locale)%0A addon.locales.push(locale);%0A }%0A%0A let dependencies = new Set(manifest.dependencies);%0A addon.dependencies = Object.freeze(Array.from(dependencies));%0A%0A let seenApplications = [];%0A addon.targetApplications = [];%0A for (let targetApp of manifest.targetApplications || []) {%0A if (!targetApp.id || !targetApp.minVersion ||%0A !targetApp.maxVersion) {%0A logger.warn('Ignoring invalid targetApplication entry in install manifest');%0A continue;%0A }%0A if (seenApplications.includes(targetApp.id)) {%0A logger.warn('Ignoring duplicate targetApplication entry for ' + targetApp.id +%0A ' in install manifest');%0A continue;%0A }%0A seenApplications.push(targetApp.id);%0A addon.targetApplications.push(targetApp);%0A }%0A%0A // Note that we don't need to check for duplicate targetPlatform entries since%0A // the RDF service coalesces them for us.%0A addon.targetPlatforms = [];%0A for (let targetPlatform of manifest.targetPlatforms || []) {%0A let platform = {%0A os: null,%0A abi: null,%0A };%0A%0A let pos = targetPlatform.indexOf('_');%0A if (pos != -1) {%0A platform.os = targetPlatform.substring(0, pos);%0A platform.abi = targetPlatform.substring(pos + 1);%0A } else {%0A platform.os = targetPlatform;%0A }%0A%0A addon.targetPlatforms.push(platform);%0A }%0A%0A addon.userDisabled = false;%0A addon.softDisabled = addon.blocklistState == Blocklist.STATE_SOFTBLOCKED;%0A addon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DEFAULT;%0A%0A addon.userPermissions = null;%0A%0A addon.icons = {};%0A if (await pkg.hasResource('icon.png')) {%0A addon.icons[32] = 'icon.png';%0A addon.icons[48] = 'icon.png';%0A }%0A%0A if (await pkg.hasResource('icon64.png')) {%0A addon.icons[64] = 'icon64.png';%0A }%0A%0A return addon;%0A },%0A%0A loadScope(addon) {%0A let file = addon.file || addon._sourceBundle;%0A let uri = getURIForResourceInFile(file, 'bootstrap.js').spec;%0A let principal = Services.scriptSecurityManager.getSystemPrincipal();%0A%0A let sandbox = new Cu.Sandbox(principal, {%0A sandboxName: uri,%0A addonId: addon.id,%0A wantGlobalProperties: ['ChromeUtils'],%0A metadata: { addonID: addon.id, URI: uri },%0A });%0A%0A try {%0A Object.assign(sandbox, BOOTSTRAP_REASONS);%0A%0A XPCOMUtils.defineLazyGetter(sandbox, 'console', () =>%0A new ConsoleAPI({ consoleID: %60addon/%24{addon.id}%60 }));%0A%0A Services.scriptloader.loadSubScript(uri, sandbox);%0A } catch (e) {%0A logger.warn(%60Error loading bootstrap.js for %24{addon.id}%60, e);%0A }%0A%0A function findMethod(name) {%0A if (sandbox[name]) {%0A return sandbox[name];%0A }%0A%0A try {%0A let method = Cu.evalInSandbox(name, sandbox);%0A return method;%0A } catch (err) { }%0A%0A return () => {%0A logger.warn(%60Add-on %24{addon.id} is missing bootstrap method %24{name}%60);%0A };%0A }%0A%0A let install = findMethod('install');%0A let uninstall = findMethod('uninstall');%0A let startup = findMethod('startup');%0A let shutdown = findMethod('shutdown');%0A%0A return {%0A install(...args) {%0A install(...args);%0A // Forget any cached files we might've had from this extension.%0A Services.obs.notifyObservers(null, 'startupcache-invalidate');%0A },%0A%0A uninstall(...args) {%0A uninstall(...args);%0A // Forget any cached files we might've had from this extension.%0A Services.obs.notifyObservers(null, 'startupcache-invalidate');%0A },%0A%0A startup(...args) {%0A if (addon.type == 'extension') {%0A logger.debug(%60Registering manifest for %24{file.path}\n%60);%0A Components.manager.addBootstrappedManifestLocation(file);%0A }%0A return startup(...args);%0A },%0A%0A shutdown(data, reason) {%0A try {%0A return shutdown(data, reason);%0A } catch (err) {%0A throw err;%0A } finally {%0A if (reason != BOOTSTRAP_REASONS.APP_SHUTDOWN) {%0A logger.debug(%60Removing manifest for %24{file.path}\n%60);%0A Components.manager.removeBootstrappedManifestLocation(file);%0A }%0A }%0A },%0A };%0A },%0A};%0A%0AAddonManager.addExternalExtensionLoader(BootstrapLoader);%0A%0AObject.defineProperty(%0A AddonInternal.prototype,%0A "providesUpdatesSecurely",%0A {enumerable: true, value: true}%0A);%0A `.trim())); Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader) .loadSubScript("resource://" + subst, new Cu.Sandbox(Cu.getObjectPrincipal(this), {wantGlobalProperties: ["ChromeUtils", "DOMParser", "Element", "fetch"]})); })(Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService));} catch(ex) {Cu.reportError(ex);} // try {({ ids: [ "custombuttons@xsms.org", ], init(xrt) { if (xrt.inSafeMode) return; Cu.import("resource://gre/modules/addons/XPIProvider.jsm", this); var load = async file => { var rootURI = this.XPIInternal.getURIForResourceInFile(file, ""); Cu.import(rootURI.resolve("startup.jsm"), {}).start(rootURI); } var proto = this.XPIInternal.BootstrapScope.prototype; var func = proto._beforeCallBootstrapMethod; proto._beforeCallBootstrapMethod = () => { proto._beforeCallBootstrapMethod = func; for(var addon of this.XPIInternal.XPIStates.enabledAddons()) this.ids.includes(addon.id) && !addon.loader && load(addon.file); } } }).init(Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime));} catch(ex) {Cu.reportError(ex);}
Отредактировано Farby (23-03-2022 12:38:12)
Жизнь иногда такое выкидывает, что хочется подобрать...
Отсутствует
Всем добра!
Много лет пользуюсь этой сборкой FF.
http://www1.plala.or.jp/tete009/en-US/software.html
Начиная с 94-ой версии после установки Сustom Buttons интерфейс FF частично становится на английском языке.
Может кто знает как это побороть?
Отсутствует
questmanlockPref("intl.locale.requested", "ru");И саму locale смени правильно...В обоих omni.ja
lockPref("intl.locale.requested", "ru");
Этот параметр само сабой стоит в RU
Как менять locale в omni.ja к сожалениию не знаю.Всегда обходился установкой русского языка с офф.сайта
Есть ещё одна проблемка.
После установки Сustom Buttons начиная с 94-ой версии FF на странице "Дополнения и темы" в разделе <<Сustom Buttons>>
отсутствуют кнопки.Вместо кнопок дублированный раздел <<Расширения>>
https://hkar.ru/15lBt
Отредактировано questman (31-03-2022 18:03:32)
Отсутствует
questman
https://anonfiles.com/x37b50S5x9/custom … ms.org_xpi
omni.ja - вскрыть winrar сменить все папки с языком . в нижнем omni.ja сменить папку res
Отредактировано ВВП (01-04-2022 09:58:25)
Отсутствует
Отсутствует