momo2000
Могу выложить свой, он отличается пунктами от тех, что нужны были _zt или Dobrov.
// Quick Toggle https://forum.mozilla-russia.org/viewtopic.php?pid=784139#p784139 // https://forum.mozilla-russia.org/viewtopic.php?pid=784165#p784165 // Быстрое переключение параметров about:config (async (name, id, func) => { if (name == "Object") return CustomizableUI.createWidget(func()); var win = name == "Window", g = Components.utils.import("resource://gre/modules/Services.jsm", {}); if (g[id]) {if (win) return;} else g[id] = func(); if (win) return CustomizableUI.createWidget(g[id]); addDestructor(r => r[5] == "e" && delete g[id]); g[id].onCreated(this); })(this.constructor.name, "QuickToggleAboutConfigSettings", () => { var {prefs} = Services, db = prefs.getDefaultBranch(""); var pv = parseInt(Services.appinfo.platformVersion); var xul_ns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; //===================================================================================== // refresh: // false - reload current tab // true - reload current tab skip cache // // restart: // false - restart browser // true - restart browser with confirm var primary = [{ pref: ["network.proxy.share_proxy_settings", "Прокси для всех протоколов при ручной настройке"], userChoice: true, refresh: true, values: [[true, "Да"], [false, "Нет"]] },{ pref: ["network.proxy.type", "Настройки прокси"], userChoice: 0, userAlt: 2, refresh: true, values: [ [0, "Без прокси", "0"], [5, "Системные (из IE)", "5"], [2, "Автонастройка с URL (pacfile)", "2"], [1, "Ручная настройка", "1"], [4, "Автоопределение", "4"] ]},{ pref: ["network.trr.mode", "DNS через HTTPS"], userChoice: 2, userAlt: 0, refresh: true, values: [ [0, "Выключен", "0"], [2, "DNS через HTTPS TRR + мой", "2"], [3, "DNS через HTTPS только TRR", "3"] ]}, null, { pref: ["permissions.default.image", "Разрешить загрузку изображений"], userChoice: 1, userAlt: 3, refresh: true, values: [[1, "Да"], [3, "Только с сайта"], [2, "Нет"]] },{ pref: ["image.animation_mode", "Анимация изображений"], userChoice: "none", refresh: true, values: [["none", "Выключена"], ["normal", "Включена"], ["once", "Единожды"]] },{ pref: ["browser.display.use_document_fonts", "Загружать web-шрифты"], userChoice: 1, refresh: true, values: [[1, "Да"], [0, "Нет"]] }, null, { pref: ["gfx.webrender.all", "WebRender для всего"], userChoice: false, refresh: true, values: [[true, "Да"], [false, "Нет"]] },{ pref: ["media.webm.enabled", "Декодер WebM VP8"], userChoice: false, refresh: true, values: [[true, "Да"], [false, "Нет"]] }, null, { pref: ["media.autoplay.default", "Автовоспроизведение аудио и видео"], userChoice: 5, refresh: true, values: [ [0, "Разрешить автовоспроизведение", "0"], [1, "Не разрешать автовоспроизведение", "1"], [2, "Всегда спрашивать", "2"], [5, "Блокировать аудио и видео", "5"] ]},{ pref: ["media.autoplay.blocking_policy", "Автозапуск (политика)"], userChoice: 1, userAlt: 2, refresh: true, values: [ [1, "Временная", "1"], [2, "По действию", "2"], [0, "Постоянная", "0"] ]},{ pref: ["plugin.state.flash", "Flash-plugin"], userChoice: 2, refresh: true, values: [ [2, "Всегда включать", "2"], [1, "Включать по запросу", "1"], [0, "Никогда не включать", "0"] ]}, null, { pref: ["network.cookie.cookieBehavior", "Cookies"], userChoice: 1, userAlt: 3, refresh: false, values: [ [1, "Не принимать сторонние"], [3, "Не принимать с не посещенных"], [4, "Не принимать от трекеров"], [2, "Не принимать со всех"], [0, "Принимать со всех"] ]}, null, { pref: ["dom.storage.enabled", "Локальное хранилище"], userChoice: true } ]; //===================================================================================== var secondary = [{ pref: ["dom.enable_performance", "Статус загрузки страницы"], userChoice: false },{ pref: ["javascript.enabled", "Выполнять скрипты Java"], userChoice: true, refresh: true, values: [[true, "Да"], [false, "Нет"]] }, null, { pref: ["intl.accept_languages", "Язык для веб-страниц"], userChoice: "ru-RU, ru, en-US, en", values: [["en-US, en, ru-RU, ru", "Английская локаль"], ["ru-RU, ru, en-US, en", "Русская локаль"]] },{ pref: ["browser.display.document_color_use", "Использовать цвета сайтов"], userChoice: 0, values: [[0, "Авто", "0"], [1, "Всегда", "1"], [2, "Никогда", "2"]] }, null, { pref: ["network.http.sendRefererHeader", "Referer - для чего"], userChoice: 1, values: [[0, "Ни для чего", "0"], [1, "Только ссылки", "1"], [2, "Ссылки и изобр.", "2"]] },{ pref: ["media.peerconnection.enabled", "WebRTC утечка IP"], userChoice: false } ]; return { label: "Quick toggle", id: "QuickToggleAboutConfigSettings", tooltiptext: "Quick toggle about preferences", localized: false, image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFPSURBVDhPnVPNSsNAEJ5tamnBk+A7BMEcikohp/gi9i18nRafQoT00kK16tnn8CJo4vp9m5m41eSgH0zmd3d+diJ/gfdedvl0QW7k1PcLwem+3TjowZagK+Nn6yc3gNCJ+LCCh9LzzTMdqeoNbkQSFZmpJLGCW5Gx2hZaQahMbZ52VuDSfHpnAVJXOb4FKzianbzCXiLrHLYl5C3t5NTRwtxaKJxUTZ/JcOTr6q2Rxwf0aVb2/hLs4KqL3Isckz/mmSdRRksjyg+z7IM6LzDCBfuvAEOJmIKBOqAWmo1YodxLlQNsyO0rsIV/AZM+JGc2a4GgzhZ2p9mFmrpboCMqNYBDdMlwompoTWN6F2nFT5hBXb0PEpmo/Gk+oH+RrqNZINPeIlnZViV1jQuLFJQuWGB0gJdwgShvqdPXZv6J+F/QS7oXqQ9xBTFZ5oa8fAGs9fed5YhPSwAAAABJRU5ErkJggg==", onCreated(btn) { btn.setAttribute("image", this.image); var doc = btn.ownerDocument; btn.btn = true; btn.domParent = null; btn.popups = new btn.ownerGlobal.Array(); this.createPopup(doc, btn, "primary", primary); this.createPopup(doc, btn, "secondary", secondary); this.createCloseMenusOption(doc, btn); btn.linkedObject = this; for(var type of ["command", "contextmenu"]) btn.setAttribute("on" + type, `linkedObject.${type}(event)`); }, createPopup(doc, btn, name, data) { var popup = doc.createElementNS(xul_ns, "menupopup"); var prop = name + "Popup"; btn.popups.push(btn[prop] = popup); popup.id = this.id + "-" + prop; for (var type of ["popupshowing", "click"]) popup.setAttribute("on" + type, `parentNode.linkedObject.${type}(event)`); for(var obj of data) popup.append(this.createElement(doc, obj)); btn.append(popup); }, map: {b: "Bool", n: "Int", s: "String"}, createElement(doc, obj) { if (!obj) return doc.createElementNS(xul_ns, "menuseparator"); var pref = doc.ownerGlobal.Object.create(null), node, img, bool; for(var [key, val] of Object.entries(obj)) { if (key == "pref") { var [apref, lab, akey, ttt] = val; pref.pref = apref; pref.lab = lab || apref; if (ttt) pref.ttt = ttt; } else if (key == "image") img = val, pref.img = true; else if (key != "values") pref[key] = val; else pref.hasVals = true; } var type = prefs.getPrefType(pref.pref); var str = this.map[type == prefs.PREF_INVALID ? obj.values ? (typeof obj.values[0][0])[0] : "b" : type == prefs.PREF_BOOL ? "b" : type == prefs.PREF_INT ? "n" : "s" ]; pref.get = prefs[`get${str}Pref`]; pref.set = prefs[`set${str}Pref`]; node = doc.createElementNS(xul_ns, "menu"); node.className = "menu-iconic"; node.setAttribute("closemenu", "none"); img && node.setAttribute("image", img); akey && node.setAttribute("accesskey", akey); (node.pref = pref).vals = doc.ownerGlobal.Object.create(null); this.createRadios(doc, str.startsWith("B") && !pref.hasVals ? [[true, "true"], [false, "false"]] : obj.values, node.appendChild(doc.createElementNS(xul_ns, "menupopup")) ); if ("userChoice" in obj) pref.noAlt = !("userAlt" in obj); return node; }, createCloseMenusOption(doc, btn) { var pn = this.closePref = "QuickToggleAboutConfigSettings.closeMenus"; var data = [null, { pref: [pn, "Закрывать меню этой кнопки"], values: [[true, "Да"], [false, "Нет"]] }]; var setCloseMenus = e => { e.stopPropagation(); var trg = e.target, {pref, val} = trg, updPopup = true, clear; switch(e.type) { case "command": pref = (trg = trg.closest("menu")).pref; updPopup = false; break; case "click": if (e.button) return; break; case "contextmenu": e.preventDefault(); clear = pref; } if (!pref) return; if (clear) prefs.clearUserPref(pn); else if (!updPopup && val === pref.val) return; else pref.set(pn, val !== undefined ? val : !pref.val); this.upd(trg); updPopup && this.popupshowing(null, trg.querySelector("menupopup")); } (this.createCloseMenusOption = (doc, btn) => { for(var obj of data) btn.secondaryPopup.append(this.createElement(doc, obj)); var m = btn.secondaryPopup.lastChild; m.style.cssText = "fill: lightblue !important; list-style-image: url(chrome://browser/skin/menu.svg) !important;"; m.setAttribute("oncommand", "setCloseMenus(event)"); m.onclick = m.oncontextmenu = m.setCloseMenus = setCloseMenus; })(doc, btn); }, UserChoiceImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACRUlEQVR42qWTS2gTQRjH/zPJZo2BDfgkB62vYg5CjQdvRUE8WB8HKyahYotIQQOeFKGCF7EgvQlBqOCjWFKlevBRDyL4uHloLXhYqWJroaEqlETSptndGb+ZPDH0ojN8O8vA98vv+/Itw38u1nSRYRE6UhKyg4FF1R292/Q+xhhLi4TIrgjgIzwe4MbgmR2nrZMtxxEN63zYORuPZp7gzpehvCu9XjfuPmwCUHIiEtw4fK89zVvD2+FHAD56quXBpV3CVO4ret6nxHzxZxdBRuqADCKmz7RHD9y2tlmbYbBVfwE8DXBkEd/y39H5+mze8ZyoSIpsFXC9u/VE3/ldpyg5AAMEoJMTQi2hANKBgyKdy0h/eoChqcf9MimvVAHjd/fdiG0NRwgQpDAp1agBpDZwdHKJLKZzc+h5e3kCSexh5c5j8fmhW0HGpNZXFkqfsQpAKgcFKGmAlAxHXp5bkkmsrhosjh4cCIJ5pG5qfQXgtMslqO1qgEMWTPrR+eriEhoA4wN7L8TWh0KVXzfgY2RQAUjVBenWLH4UCrj04Wa9BNXEo5va+w63xCiJ6WRVP2MVgNQIgjgEA17MTODZ7Lt+AtSaGDG4377a1m2FAkKrc11/dUwIID1dSKHEcW3yft4RbpR6kK1PYgaJtaY1nNp5jIeMsjKNbs1AWRUcjvTnp2Kh9LtLJGTDINUhcTIZ3L+hzdq9ZgvWmSF9/Wu5gI8L03gzP5l3hddL/3/zKDdA9MdE0UERrdzaFGMUaap75Y/pX9Yfap76EQYaCeEAAAAASUVORK5CYII=", notUserChoiceImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACNUlEQVR42qXTT2jTUBwH8G9e0ta2ks5ND0Ww/qX1oGyevEwQnOBA6EHXwLwoUh3eRGRs501RPE6xgp6KrexQECZY8DBPXmbRS4Z/K0gRtmmDa2yb5PlLX7p2Gwpi4EfCy8sn3/dPwn9e0saGnCRF6XYFnA9DkhKtRs51ep6jmtEcp/JHIM9Yivl9mf0XNDV2Ngn1YLzVxdB1lJ8U8P5hzuCWnR6xrPwmIM8kLRjdkT326BaLHNgLKAFA9ouXdhOw6qi++4j589cd89vSaMqyc2sAPUXlgF8fyt9WI3t2Av4w4NsCMJ8AHAKav6hqqH76iuLINcNuNhOawyttYCp+7tRE/6XT9GFQAG4CpniATQkIaNQIMVG6/xSL2WfTGueTbWDh5L2rA9t29QGBrQQEPUDuAuoEmFSr+P5lGc8v33mtAUfaQO3M4/GgDOoYCIkUin8D0BDDoBQ2ZMxqN0wCQh0gMxaUnYb4uzt+dwIZ8wBHTGQbYAHMpu+uAxaGxpMDvSr3AHcFaAIlD+BtoN6ag5WqhOLNwrohTMWPH5roP7pdLIwb3wW6EziWGAZhpVdLWHzxdpqAyc4yKrJ+4uKg2oMV+lgRK9CdwAVsG1WpF8UH84Zt2QkCKmsbiRAtFAllB5OHWQ9fpr81OwlcgBL9kPrwsvDGMQ1zNMV5ZyN1ISlZYZl9/TE1tjuMSFgA1VWO8uef+FAqG47tpFMcm7dyFyIOEzBMlfCadao5qhk39l9P479evwFbiOcRSXKueAAAAABJRU5ErkJggg==", UserAltImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVDhPpVM9b9NQFD02cSKKFVGKIFFREFsmFiCA1AEQQrQjC0gssLCkC0jJj0iFWFoGdiT4Ay0SEmJBhPI5FBokikL4SCC0Te2UxInt13Mdu1CVrVc6713fe86x/T6w09DCeTNKJ7Q0pzyUmoCmZYOiUhXms8RMcd6vB7UwthhM5fTLWix2L3PmYjKdOwdz9DDFGtr1KuovnqD29JGlfO9Goew9DCV/DaZy2pXE8PD9Y/mbupk6xE6cVWPQhEujHo2+4fXdO76ztnq1UPYfSCcwKB1HWjeMyunCraSZOsDqbkBPsBOTNoMGvkOTLto/f+F56bble262OK/qesiYzIydTJojFLjrgEe4bcIOEdXWYe6LITN2KgmFSRFGBuPpo0eAngX0SexTJHD5LOgLpEZTcgKuUuMijAyy5l7+r0NSb21g5LQI5gGYSy2AjYBLjQyRAUniTnJXsBoayBzm3RBBndwwIoOK3fgNdIREQYCV/0DqLdiNZqCRITKYayx85RfQuUNiZ3k7IgO+vfGeXGpkiAyma++WLHtZhZ8o5H/FEVpos1V7u8TFwLQId8nw+Afa51Oq2vyycmlk9KCW0GXFZeu63IUO8z88Bx5s28SbuUXfddzrxVcobxpI0GTh7H734/dPzQt9d0/CGBpCPB7nbhmwbAPVxR4+PPtsuU7/WuElth/lKORUcsoTE8TgMg0WbJaY4Zu3XKYdBrABARUk+ls4DfQAAAAASUVORK5CYII=", upd(node) { var {pref} = node, def = false, user = false, val; if (prefs.getPrefType(pref.pref) != prefs.PREF_INVALID) { var pn = pref.pref; try {val = pref.defVal = db[pref.get.name](pn); def = true} catch(ex) {def = false;} var user = prefs.prefHasUserValue(pn); if (user) try {val = pref.get(pn, undefined);} catch(ex) {} } if (val == pref.val && def == pref.def && user == pref.user) return; pref.val = val; pref.def = def; pref.user = user; var exists = def || user; var ttt = exists ? val : "Этого префа не существует"; if (ttt === "") ttt = "[ empty_string ]"; ttt += "\n" + pref.pref; if (pref.ttt) ttt += "\n" + pref.ttt; node.tooltipText = ttt; var img, alt = "userAlt" in pref && val == pref.userAlt; if (alt) img = this.UserAltImg; if ("userChoice" in pref) if (val == pref.userChoice) //node.style.removeProperty("color"), img = this.UserChoiceImg; else { //node.style.setProperty("color", "maroon", "important"); if (!alt) img = this.notUserChoiceImg; } if (!pref.img) img ? node.setAttribute("image", img) : node.removeAttribute("image"); user ? node.style.setProperty("font-style", "italic", "important") : node.style.removeProperty("font-style"); var {lab} = pref; if (exists && pref.hasVals) { if (val in pref.vals) var sfx = pref.vals[val] || val; else var sfx = user ? "Другое" : "По умолчанию"; lab += ` — "${sfx}"`; } node.setAttribute("label", lab); }, createRadios(doc, vals, popup) { for(var arr of vals) { if (!arr) { popup.append(doc.createElementNS(xul_ns, "menuseparator")); continue; } var [val, lab, key, ttt] = arr; var menuitem = doc.createElementNS(xul_ns, "menuitem"); menuitem.setAttribute("type", "radio"); menuitem.setAttribute("closemenu", "none"); menuitem.style.setProperty("font-style", "italic", "important"), menuitem.setAttribute("label", popup.parentNode.pref.vals[val] = lab); key && menuitem.setAttribute("accesskey", key); var tip = menuitem.val = val; if (ttt) tip += "\n" + ttt; menuitem.tooltipText = tip; popup.append(menuitem); } }, openPopup(popup) { var btn = popup.parentNode; if (btn.domParent != btn.parentNode) { btn.domParent = btn.parentNode; var pos; if (btn.matches(".widget-overflow-list > :scope")) pos = "after_start"; else var win = btn.ownerGlobal, {width, height, top, bottom, left, right} = btn.closest("toolbar").getBoundingClientRect(), pos = width > height ? `${win.innerHeight - bottom > top ? "after" : "before"}_start` : `${win.innerWidth - right > left ? "end" : "start"}_before`; for(var p of btn.popups) p.setAttribute("position", pos); } popup.openPopup(btn); }, maybeRestart(node, conf) { var msgRest = "Перезапустить браузер?", msgAbort = "Запрос на выход отменен."; if (pv >= 77) { var title = node.closest("toolbarbutton").label; var pp = domWin => Services.prompt.wrappedJSObject.pickPrompter({ domWin, modalType: Ci.nsIPrompt.MODAL_TYPE_WINDOW }); var confirm = win => pp(win).confirm(title, msgRest); var alert = win => pp(win).alert(title, msgAbort); } else { var confirm = win => win.confirm(msgRest); var alert = win => win.alert(msgAbort); } return (this.mayBeRestart = (node, conf) => { var win = node.ownerGlobal; if (conf && !confirm(win)) return; if (win.BrowserUtils.restartApplication() === false) alert(win); else return true; })(node, conf); }, regexpRefresh: /^(?:view-source:)?(?:https?|ftp)/, maybeRe(node, fe) { var {pref} = node; if ("restart" in pref) { if (this.maybeRestart(node, pref.restart)) return; } else this.popupshowing(fe, node.parentNode); if ("refresh" in pref) { var win = node.ownerGlobal; if (this.regexpRefresh.test(win.gBrowser.currentURI.spec)) pref.refresh ? win.BrowserReloadSkipCache() : win.BrowserReload(); } }, maybeClosePopup(e, trg) { !e.ctrlKey && prefs.getBoolPref(this.closePref, undefined) && trg.parentNode.hidePopup(); }, command(e) { var trg = e.target; if (trg.btn) return this.openPopup(trg.primaryPopup); var menu = trg.closest("menu"), newVal = trg.val; this.maybeClosePopup(e, menu); if (newVal != menu.pref.val) menu.pref.set(menu.pref.pref, newVal), this.maybeRe(menu, true); }, popupshowing(e, trg = e.target) { if (trg.state == "closed") return; if (trg.id) { for(var node of trg.children) { if (node.nodeName.endsWith("r")) continue; this.upd(node); !e && node.open && this.popupshowing(null, node.querySelector("menupopup")); } return; } var {pref} = trg.closest("menu"), findChecked = true; var findDef = "defVal" in pref; var checked = trg.querySelector("[checked]"); if (checked) { if (checked.val == pref.val) { if (findDef) findChecked = false; else return; } else checked.removeAttribute("checked"); } if (findDef) { var def = trg.querySelector("menuitem:not([style*=font-style]"); if (def) if (def.val == pref.defVal) { if (findChecked) findDef = false; else return; } else def.style.setProperty("font-style", "italic", "important"); } for(var node of trg.children) if ("val" in node) { if (findChecked && node.val == pref.val) { node.setAttribute("checked", true); if (findDef) findChecked = false; else break; } if (findDef && node.val == pref.defVal) { node.style.removeProperty("font-style"); if (findChecked) findDef = false; else break; } } }, contextmenu(e) { var trg = e.target; if (trg.btn) { if (e.ctrlKey || e.shiftKey) return; if (e.detail == 2) return trg.secondaryPopup.hidePopup(); this.openPopup(trg.secondaryPopup); } else if ("pref" in trg) { this.maybeClosePopup(e, trg); if (trg.pref.user) prefs.clearUserPref(trg.pref.pref), this.maybeRe(trg); } e.preventDefault(); }, click(e) { if (e.button) return; var trg = e.target, {pref} = trg; if (!pref) return; this.maybeClosePopup(e, trg); if (!("noAlt" in pref)) return; if (pref.val == pref.userChoice) if (pref.noAlt) return; else pref.set(pref.pref, pref.userAlt); else pref.set(pref.pref, pref.userChoice); this.maybeRe(trg); } }; });
Отсутствует
QuickToggleAboutConfigSettings автор Dumby
Как это использовать для CB я не знаю.
При использовании в UCF подключать в custom_script.js.
Создает кнопку с двумя меню вызываемыми щелчками ЛКМ иил ПКМ.
Каждый пункт прописывается по существующим в скрипте шаблонам.
Основные характеристики:
Каждый пункт имеет подменю с прописанными в скрипте значениями, в котором также можно переключать значения щелчком ЛКМ.
Каждый пункт имеет подсказку с текущим значением и заголовком параметра.
userChoice: value, userAlt: value,
ЛКМ по пункту переключет его значение на userChoice (создает параметр, если его не существует), а с userChoice на userAlt.
ПКМ по пункту сбрасывает его значение на по умолчанию, либо удаляет его, если такого параметра по умолчанию в Firefox не существует.
refresh: true, restart: true,
Назначает обновление страницы, перезагрузку браузера, при изменении значения.
Индикация иконкой
Каждый пункт имеет иконку
зеленая = userChoice
оранжевая = userAlt
красная = все остальное
Индикация шрифтом (работает также и в подменю)
норамльный = значение браузера по умолчанию
курсив = значение отличное от по умолчанию браузера
Хоткеи
Хоткеи доступны как в основных меню, так и в подменю
Для логических, похоже, в основных меню не отображаются.
{ pref: ["javascript.enabled", "Выполнять скрипты Java", "хоткей"], userChoice: true, refresh: true, values: [[true, "Да", "хоткей"], [false, "Нет", "хоткей"]] },
// Быстрое переключение параметров about:config, автор Dumby // готовые варианты - https://forum.mozilla-russia.org/viewtopic.php?id=9591&p=602 (async (name, id, func) => { if (name == "Object") return CustomizableUI.createWidget(func()); var win = name == "Window", g = Components.utils.import("resource://gre/modules/Services.jsm", {}); if (g[id]) {if (win) return;} else g[id] = func(); if (win) return CustomizableUI.createWidget(g[id]); addDestructor(r => r[5] == "e" && delete g[id]); g[id].onCreated(this); })(this.constructor.name, "QuickToggleAboutConfigSettings", () => { var {prefs} = Services, db = prefs.getDefaultBranch(""); var pv = parseInt(Services.appinfo.platformVersion); var xul_ns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; //============================================================================= // refresh: // false - reload current tab // true - reload current tab skip cache // // restart: // false - restart browser // true - restart browser with confirm var primary = [{ pref: ["network.proxy.type", "Настройки прокси"], userChoice: 5, userAlt: 0, refresh: true, values: [ [0, "Не проксировать", "0"], [5, "Системные (IE)", "5"], [2, "Авто (pacfile)", "2"], [1, "Прописанные", "1"], [4, "Автоопределение", "4"] ]}, null, { pref: ["permissions.default.image", "Загружать графику"], userChoice: 1, refresh: true, values: [ [1, "Да"], [3, "С сайта"], [2, "Нет"] ]},{ pref: ["browser.display.use_document_fonts", "Загружать web-шрифты"], userChoice: 1, refresh: true, values: [[1, "Да"], [0, "Нет"]] },{ pref: ["browser.display.document_color_use", "Загружать цвета сайтов"], userChoice: 0, refresh: true, values: [ [0, "Авто", "0"], [1, "Всегда", "1"], [2, "Никогда", "2"] ]},{ pref: ["javascript.enabled", "Выполнять скрипты Java", "j"], userChoice: true, refresh: true, values: [[true, "Да", "y"], [false, "Нет", "n"]] },{ pref: ["intl.accept_languages", "Язык для веб-страниц"], userChoice: "en-US, en", userAlt: "en-US, en, ru-RU, ru", refresh: true, values: [ ["en-US, en", "EN"], ["en-US, en, ru-RU, ru", "EN, RU"] ]},{ pref: ["privacy.spoof_english", "Язык для веб-страниц с RFP"], userChoice: 2, refresh: true, values: [ ["2", "EN"] ]}, null, { pref: ["userChromeJS.enabled", "userChromeJS.enabled"], userChoice: true, userAlt: false, restart: true, values: [[true, "Да"], [false, "Нет"]] } ]; //============================================================================= var secondary = [{ pref: ["ui.prefersReducedMotion", "Анимация chrome"], userChoice: 1, userAlt: 2, restart: true, values: [[1, "Отключена"], [0, "Включена"]] },{ pref: ["gfx.webrender.enabled", "Web render"], userChoice: false, restart: true, values: [[true, "Включен"], [false, "Отключен"]] },{ pref: ["gfx.webrender.force-disabled", "Web render (force-disabled)"], userChoice: true, userAlt: false, restart: true, values: [[true, "Да"], [false, "Нет"]] }, null, { pref: ["network.predictor.enabled", "Предзагрузка ссылок"], userChoice: false, refresh: true, values: [[true, "Включена"], [false, "Отключена"]] },{ pref: ["network.predictor.enable-prefetch", "Предвыборка ссылок"], userChoice: false, refresh: true, values: [[true, "Включена"], [false, "Отключена"]] },{ pref: ["browser.send_pings", "Аудит гиперссылок"], userChoice: false, refresh: true, values: [[true, "Включен"], [false, "Отключен"]] },{ pref: ["media.peerconnection.enabled", "WebRTC"], userChoice: false, refresh: true, values: [[true, "Включен"], [false, "Отключен"]] } ]; return { id: "QuickToggleAboutConfigSettings", label: "Quick Toggle Settings", tooltiptext: "Quick Toggle Settings\n ЛКМ ПКМ", localized: false, image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAKdSURBVDhPjZNLTxNRFMenM9OWTulTEx4KkSg+0mCCujExNTyiLKiQAUofIcR+AOPOlStdGDd+AzdGDQvF+IhBBY0ro8aNUkAXxFhKERRaYOhjOuP/j0NidONNfj2Puef0nHvPFUzT/C9EQQiC5p/JoXeQJ8Ax2jZ+/HtJNpsDwqiapm7ZnmoqWchq2qNGRYl8yRdetPq83dLN20zyezEIiNwMsxZ4obuAm/aitvVQkeX9CBoIOp1N6bX8K/g92+W1u1x+ZAqwJDOVNAsj0TfQW+EPQbbk4uoD+qGfAz2gn/a02vtSsEuSj0Za7b2BD8f10eGKtfnMcmLgg6WfnlUjk7DnGLySGJydUXunoPeIhmG4C+XK2yP+2ovo870kybKuV8rQJ3bX1LRPZXO3UGrwkN/bmdsq5uAfXy4Ws4f9vg74FSERCJxCppNmKmYS6IldkhSlXh0d1mHH6LMYYiWQbIPthG0sk/+EbAIOKA5RBuu08W/PKLnwLQaxBTYAr457SuJOMLbzZye4ZLG9MptaGqIINIsVkAerwgGHI45SBnlYVgvdLI221YIKoqAPdH6N9j+B5O20gr02/HQ87+k639lYP4KM26ta1Us4TCf1hU1tunls/Craufs5X5g86PN2za9vTLR4as+iraOIF1YYjEH5CMcQgnVJsjk5ME8z2bE9biXERJ9W114HnY4m+Pu8dvu+ubXCFNwBVlCviGKdZhh+OPyZmHqlQXG1YWOyTpYrS7peTquRC7xG+HjIPCM7r5PTyAQcXR+zAb4BjjHLNwDfAg/WPjMQucwK6u7cu/Q9MXiNsxC6//i6iAfDjDzRBbBkyXnwDWQs3zJ7/1EsZ/4ZpD+eqwPIwAX4dInHshtAGwhz/iE5SLgdIfwLnaFD0PXeqXgAAAAASUVORK5CYII=", onCreated(btn) { btn.setAttribute("image", this.image); var doc = btn.ownerDocument; btn.btn = true; btn.domParent = null; btn.popups = new btn.ownerGlobal.Array(); this.createPopup(doc, btn, "primary", primary); this.createPopup(doc, btn, "secondary", secondary); this.createCloseMenusOption(doc, btn); btn.linkedObject = this; for(var type of ["command", "contextmenu"]) btn.setAttribute("on" + type, `linkedObject.${type}(event)`); }, createPopup(doc, btn, name, data) { var popup = doc.createElementNS(xul_ns, "menupopup"); var prop = name + "Popup"; btn.popups.push(btn[prop] = popup); popup.id = this.id + "-" + prop; for (var type of ["popupshowing", "click"]) popup.setAttribute("on" + type, `parentNode.linkedObject.${type}(event)`); for(var obj of data) popup.append(this.createElement(doc, obj)); btn.append(popup); }, map: {b: "Bool", n: "Int", s: "String"}, createElement(doc, obj) { if (!obj) return doc.createElementNS(xul_ns, "menuseparator"); var pref = doc.ownerGlobal.Object.create(null), node, img, bool; for(var [key, val] of Object.entries(obj)) { if (key == "pref") { var [apref, lab, akey, ttt] = val; pref.pref = apref; pref.lab = lab || apref; if (ttt) pref.ttt = ttt; } else if (key == "image") img = val, pref.img = true; else if (key != "values") pref[key] = val; else pref.hasVals = true; } var type = prefs.getPrefType(pref.pref); var str = this.map[type == prefs.PREF_INVALID ? obj.values ? (typeof obj.values[0][0])[0] : "b" : type == prefs.PREF_BOOL ? "b" : type == prefs.PREF_INT ? "n" : "s" ]; pref.get = prefs[`get${str}Pref`]; pref.set = prefs[`set${str}Pref`]; node = doc.createElementNS(xul_ns, "menu"); node.className = "menu-iconic"; node.setAttribute("closemenu", "none"); img && node.setAttribute("image", img); akey && node.setAttribute("accesskey", akey); (node.pref = pref).vals = doc.ownerGlobal.Object.create(null); this.createRadios(doc, str.startsWith("B") && !pref.hasVals ? [[true, "true"], [false, "false"]] : obj.values, node.appendChild(doc.createElementNS(xul_ns, "menupopup")) ); if ("userChoice" in obj) pref.noAlt = !("userAlt" in obj); return node; }, createCloseMenusOption(doc, btn) { var pn = this.closePref = "QuickToggleAboutConfigSettings.closeMenus"; var data = [null, { pref: [pn, "Автозакрытие этого меню"], values: [[true, "Да"], [false, "Нет"]] }]; var setCloseMenus = e => { e.stopPropagation(); var trg = e.target, {pref, val} = trg, updPopup = true, clear; switch(e.type) { case "command": pref = (trg = trg.closest("menu")).pref; updPopup = false; break; case "click": if (e.button) return; break; case "contextmenu": e.preventDefault(); clear = pref; } if (!pref) return; if (clear) prefs.clearUserPref(pn); else if (!updPopup && val === pref.val) return; else pref.set(pn, val !== undefined ? val : !pref.val); this.upd(trg); updPopup && this.popupshowing(null, trg.querySelector("menupopup")); } (this.createCloseMenusOption = (doc, btn) => { for(var obj of data) btn.secondaryPopup.append(this.createElement(doc, obj)); var m = btn.secondaryPopup.lastChild; m.style.cssText = "fill: lightblue !important; list-style-image: url(chrome://browser/skin/menu.svg) !important;"; m.setAttribute("oncommand", "setCloseMenus(event)"); m.onclick = m.oncontextmenu = m.setCloseMenus = setCloseMenus; })(doc, btn); }, UserChoiceImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHqSURBVDhPpVJBTxNBGH1LLakxVEJQQIkhlZCAJDYR/BGScNCDwZMcuEji2ZP+BD14MCGciDEaEw8e1At3QGLlwAUOFtm6tut2uwtb2t3p8GbZ0iXlVF/y5ttkv+/Nmzej5XI5/A+6otoxTh1ks9mwhniJHvRiBAHXLjRIEy7yeIqjqAPNuXYHS5jGVby7PTT27eHo7Or9zL3Va/19Xyj5FsuYjLpOcdbBG9xFGh+fZRaGJ5O3tB7tMrcXcGQZP+pb8tXuyjpdPcA89HYHynYazxdvzg5nkgOapFsPNleXP+uY6L6hzYxMT+EC5vCVa4SWAM880Ju4cyVxUXNkERUeuyJLIR1+O6wTqcEEUngEA5eiqZgAAxtMpfur0sIBLA7+hS2NkK5UGVpsqgEJjLMkT4biAkzbE27D5u7/ZAFWSB1l0iRtUokyEj+aCBEXMHcOA70Y/IElfsMUeyiJPIpBHiZZEvv4Vcsrge9Mi1ZO0BJQ98yw9w4tWT4yYNV1ki78AuyggHLNwLZjC1Txnpl60VRMQD2SBl5sGsHaT88XJd+DEzioCAd6rYpN1xf7Jj5T4BMe00eE9pf4GteZ8Ry6mbYKDDyzxAblP4TDT1BUbc2585+yumd1Vc201ZmV7djObQKdopVBRwCOAVyl9qcQtNEaAAAAAElFTkSuQmCC", notUserChoiceImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHqSURBVDhPpVJNSxtRFD1PJ9GMMVpaKyWhRGwRFy7Utv+gVFyUgoWif8Ct+APMsvQX+BuUWhdBcOvSDwi1XVhK0WgmTr4mmphoJvPRe5NnxhLdpAcO9828d869794nXNfF/6BLxo7RqiAcDjciYx3oDwFRBxikT4ey5CtAcg64aZ4ANE1rxDaDLeB176Aae/zx/ZR/NDqEuu1UD39oxsZ2wnIRmwV+8rl7DeLAGzXg+/pidSWivBwVCPQDvH91AfPot/tn6fOedW3NzTT0TYNWD7hsVfWtjH1ZjCjPggImFV25AKpE+xr+6CMxsvzpVXePmE8AipR5Bnzn4bcT0yJoCZSyQDkPXOrEDDHXYG8k0B18/nSBdvukzDPghqlB/xOUi4BBgiIJDUleF0lmVaEo7ngd8EnZP2N0uiolBwXKmksDegrISubovvyPWauR3kPLgBb5q+O8hnMyOD8jJoknTaZPKZLRSQp2+eaA6q9JmWcwTHPWv2cT0E0XGcqos4lkhgz4X7Jql3O1NZNaK2WewSQ9EtqIHcWPd5FybWQNoECNNApkdgmcwv61k47TbDbf0VykrP0hfaPlADAfCmFBERiHQN2sY79UwTqLP1BX+NyDL5HBc+ZR3Xab78xl383cZtAp7o6xAwB/AT+Y7GFJS/NjAAAAAElFTkSuQmCC", UserAltImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAH7SURBVDhPpVJLa1NBFP5mJolNcrWhtiq9Betjk0VFfNS1O7ciXbQguBDXxR9g3Lnown8g3SqCi24K/gCxVbqogiBaxdyY5nFrkt5H5j7GmZvxphDdxA8+Dgzn+86Zcw4RQuB/QHUcG2kHpmkmUWHtEo6DY55mUCIhYkHQOlXA97vv4esUWJaVxBGDp2Vcz54klakbN69kZ8wZRHHsVT9b7e2tHdFH5eEuPqi8vxqsLWDxmIGX5+8/mMufPkdA8zIBiMMuvNo3sbf+bCt2cWd1V+kHBukMVNuFE3h08d7SXHF6glC4oHFXGnTBmA9j1iBnb9+6xvJYfryIjJYdGaL889TlC1cLkyFhQQek3wThjYSUt8GCX9Iky/JniitGF0WtGhpQgdLEJJvO8AMpUgIbtK/JbflmI0cc2Y0oy/JZLRsaEIKYcCemXgvUlVXdOpj/c0Bnf0BXdhXxQEsSpAZqVU7NtkRPJh5aoAmrCYnzA9SpIbDr4G74Lsihr2VDA7Xn5kdvx2mGgnr7soNaSubXQb0GelUv8lt4Pj8rJ6yRGqgjERyVT68P3rarJIo6HojrJOS2h8Yejb6+OdyIe3i1tIlIy0YP6ckCTCOH5WIJKxmGsnwKeB/bbgcvlHj1Cxoq75+XqKD2rFb1Z9rqz6rto5VHDMZFOoPxAPwGQ077rbKVfhEAAAAASUVORK5CYII=", upd(node) { var {pref} = node, def = false, user = false, val; if (prefs.getPrefType(pref.pref) != prefs.PREF_INVALID) { var pn = pref.pref; try {val = pref.defVal = db[pref.get.name](pn); def = true} catch(ex) {def = false;} var user = prefs.prefHasUserValue(pn); if (user) try {val = pref.get(pn, undefined);} catch(ex) {} } if (val == pref.val && def == pref.def && user == pref.user) return; pref.val = val; pref.def = def; pref.user = user; var exists = def || user; var ttt = exists ? val : "Этот преф не существует"; if (ttt === "") ttt = "[ empty_string ]"; ttt += "\n" + pref.pref; if (pref.ttt) ttt += "\n" + pref.ttt; node.tooltipText = ttt; var img, alt = "userAlt" in pref && val == pref.userAlt; if (alt) img = this.UserAltImg; if ("userChoice" in pref) if (val == pref.userChoice) img = this.UserChoiceImg; else { if (!alt) img = this.notUserChoiceImg; } if (!pref.img) img ? node.setAttribute("image", img) : node.removeAttribute("image"); user ? node.style.setProperty("font-style", "italic", "important") : node.style.removeProperty("font-style"); var {lab} = pref; if (exists && pref.hasVals) { if (val in pref.vals) var sfx = pref.vals[val] || val; else var sfx = user ? "Другое" : "По умолчанию"; lab += ` — "${sfx}"`; } node.setAttribute("label", lab); }, createRadios(doc, vals, popup) { for(var arr of vals) { if (!arr) { popup.append(doc.createElementNS(xul_ns, "menuseparator")); continue; } var [val, lab, key, ttt] = arr; var menuitem = doc.createElementNS(xul_ns, "menuitem"); menuitem.setAttribute("type", "radio"); menuitem.setAttribute("closemenu", "none"); menuitem.style.setProperty("font-style", "italic", "important"), menuitem.setAttribute("label", popup.parentNode.pref.vals[val] = lab); key && menuitem.setAttribute("accesskey", key); var tip = menuitem.val = val; if (ttt) tip += "\n" + ttt; menuitem.tooltipText = tip; popup.append(menuitem); } }, openPopup(popup) { var btn = popup.parentNode; if (btn.domParent != btn.parentNode) { btn.domParent = btn.parentNode; var pos; if (btn.matches(".widget-overflow-list > :scope")) pos = "after_start"; else var win = btn.ownerGlobal, {width, height, top, bottom, left, right} = btn.closest("toolbar").getBoundingClientRect(), pos = width > height ? `${win.innerHeight - bottom > top ? "after" : "before"}_start` : `${win.innerWidth - right > left ? "end" : "start"}_before`; for(var p of btn.popups) p.setAttribute("position", pos); } popup.openPopup(btn); }, maybeRestart(node, conf) { var msgRest = "Перезапустить браузер?", msgAbort = "Запрос на выход отменен."; if (pv >= 77) { var title = node.closest("toolbarbutton").label; var pp = domWin => Services.prompt.wrappedJSObject.pickPrompter({ domWin, modalType: Ci.nsIPrompt.MODAL_TYPE_WINDOW }); var confirm = win => pp(win).confirm(title, msgRest); var alert = win => pp(win).alert(title, msgAbort); } else { var confirm = win => win.confirm(msgRest); var alert = win => win.alert(msgAbort); } return (this.mayBeRestart = (node, conf) => { var win = node.ownerGlobal; if (conf && !confirm(win)) return; if (win.BrowserUtils.restartApplication() === false) alert(win); else return true; })(node, conf); }, regexpRefresh: /^(?:view-source:)?(?:https?|ftp)/, maybeRe(node, fe) { var {pref} = node; if ("restart" in pref) { if (this.maybeRestart(node, pref.restart)) return; } else this.popupshowing(fe, node.parentNode); if ("refresh" in pref) { var win = node.ownerGlobal; if (this.regexpRefresh.test(win.gBrowser.currentURI.spec)) pref.refresh ? win.BrowserReloadSkipCache() : win.BrowserReload(); } }, maybeClosePopup(e, trg) { !e.ctrlKey && prefs.getBoolPref(this.closePref, undefined) && trg.parentNode.hidePopup(); }, command(e) { var trg = e.target; if (trg.btn) return this.openPopup(trg.primaryPopup); var menu = trg.closest("menu"), newVal = trg.val; this.maybeClosePopup(e, menu); if (newVal != menu.pref.val) menu.pref.set(menu.pref.pref, newVal), this.maybeRe(menu, true); }, popupshowing(e, trg = e.target) { if (trg.state == "closed") return; if (trg.id) { for(var node of trg.children) { if (node.nodeName.endsWith("r")) continue; this.upd(node); !e && node.open && this.popupshowing(null, node.querySelector("menupopup")); } return; } var {pref} = trg.closest("menu"), findChecked = true; var findDef = "defVal" in pref; var checked = trg.querySelector("[checked]"); if (checked) { if (checked.val == pref.val) { if (findDef) findChecked = false; else return; } else checked.removeAttribute("checked"); } if (findDef) { var def = trg.querySelector("menuitem:not([style*=font-style]"); if (def) if (def.val == pref.defVal) { if (findChecked) findDef = false; else return; } else def.style.setProperty("font-style", "italic", "important"); } for(var node of trg.children) if ("val" in node) { if (findChecked && node.val == pref.val) { node.setAttribute("checked", true); if (findDef) findChecked = false; else break; } if (findDef && node.val == pref.defVal) { node.style.removeProperty("font-style"); if (findChecked) findDef = false; else break; } } }, contextmenu(e) { var trg = e.target; if (trg.btn) { if (e.ctrlKey || e.shiftKey) return; if (e.detail == 2) return trg.secondaryPopup.hidePopup(); this.openPopup(trg.secondaryPopup); } else if ("pref" in trg) { this.maybeClosePopup(e, trg); if (trg.pref.user) prefs.clearUserPref(trg.pref.pref), this.maybeRe(trg); } e.preventDefault(); }, click(e) { if (e.button) return; var trg = e.target, {pref} = trg; if (!pref) return; this.maybeClosePopup(e, trg); if (!("noAlt" in pref)) return; if (pref.val == pref.userChoice) if (pref.noAlt) return; else pref.set(pref.pref, pref.userAlt); else pref.set(pref.pref, pref.userChoice); this.maybeRe(trg); } }; });
Отредактировано _zt (10-09-2020 19:48:58)
Отсутствует
Question
Я специально для вас последнюю строку в свой пост добавил.
Параметры прописываете СВОИ, готовые добавлены в качестве примера.
Кстати, и хоткеи должен работать, например pref: ["network.proxy.type", "Настройки прокси", "хоткей"], Dumby вроде не вырезал их. И их, как бы это не было странно, тоже придется вам добавлять самостоятельно.
Еще раз для непонятливых:
userChoice: value, userAlt: value,
ЛКМ по пункту переключет его значение на userChoice (создает параметр, если его не существует), а с userChoice на userAlt.
ПКМ по пункту сбрасывает его значение на по умолчанию, либо удаляет его, если такого параметра по умолчанию в Firefox не существует.
Т.е., если в пункте не прописаны userChoice и userAlt, то клики ЛКМ работать не будут.
Если прописан только userChoice, то клик ЛКМ будет работать только, если текущее значение не равно userChoice.
Если прописаны оба, то клик ЛКМ будет переключать значение между ними (или на userChoice, если текущее значение не равно ни userChoice, ни userAlt).
Клик ПКМ тоже работать не будет, если текущее значение уже равно значению по умолчанию.
Добавлено 10-09-2020 18:44:08
Question
Да нет, я то все понял, а вот ты двух написанных слов понять не можешь.
вообще кто придумал такое?
Я придумал. Не нравится, пользуйся старым.
Отредактировано bunda1 (19-09-2020 10:25:45)
Отсутствует
Question
Какой-то не доделок получился.
Да, есть такое, но только не в скрипте.
(userChoice: true, userAlt: false) переключать по ЛКМ стало удобнее, но цвет не красный.
С какого препугу там красный должен быть? Возвращайтесь назад и читайте все заново, до просветления.
Исправил основной пост выше. Просвещайтесь. Хоткеи еще и к значениям добавлять надо.
Отсутствует
После долгого перерыва решил вернуть CustomButtons в свой Firefox.
Но если учесть то, что меня на несколько лет отключали от Интернета, то... я немного уже отстал от технологий...
А желание вернуть прежний комфорт с использованием CustomButtons есть. Другие расширения не всегда спасают в самостоятельных пожеланиях организовать комфорт в работе.
На данный момент у меня установлены Firefox 77 и CustomBattons 16 (последняя)
Работает уже часть кнопок которые вы здесь обсуждаете...
Но из старых кнопок, которые стояли в Firefox 56 ещё, не работает ни одна.
А к некоторым кнопкам я как бы уже настолько привык, что без них не вижу даже смысла использовать дальше CustomButtons.
Подскажите в этой связи, какую кнопку установить, чтобы реализовать функции быстрого сохранения открытых вкладок в отдельную папку закладок на панели закладок одним нажатием кнопки...?! Папка при этом должна создаваться автоматом, скажем, с указанием даты...
Кто-то из вас испульзует сейчас такие кнопки...?! Может быть старые модифицировал уже кто-то под себя???
Неплохо будет, если у такой кнопки будут и дополнительные функции... например добавление в уже созданную папку одной отдельной вкладки через ПКМ и т.д.
Ну вобщем чем круче будет такая кнопка, и чем больше у неё будет реализовано полезных функций, тем лучше.
Очень надо бы такую кнопку...! Раньше их было много... на выбор и на любой вкус... А как быть сейчас?!
И ещё просьба в этой связи...
У кого-нибудь есть понятный и подробный мануал по работе с DOM-инспектором...?!
Вообще... чем вы отлаживаете кнопки, которые не работают на новых версиях Firefox и CustomButtons...?!
Заранее благодарен всем, кто возможно откликнется на этот мой пост...!
Отсутствует
Всем экспертам — просьба от начинающих пользователей, желающих расширить функционал Firefox скриптами:
Необходимо создать тему, где объясняется, как подключить запуск скриптов, работающих на «системном» уровне.
То есть нужно доступно рассказать, как добавить расширение CustomButtons и UCF (user_chrome_files от VitaliyV), к разным версиям Firefox.
Это может быть отдельная тема или один пост, в котором собраны наиболее информативные сообщения.
На данный момент очень сложно с нуля подключить CustomButtons или user_chrome_files скрипты, к разным версиям Firefox.
То есть, даже опытный админ должен перечитать множество страниц данного форума, потратив значительное время.
Даже опытный пользователь ПК может быть не знаком с Firefox на таком серьёзном уровне, как подключение CustomButtons или UCF скриптов.
Невозможно знать всё! Поэтому и необходима отдельная статья/тема, в которой это объясняется!
Отсутствует
Dobrov
UCF подключается одинаково ко всем версиям, кроме < 60, и все подробно расписано в самом архиве UCF.
Скрипты, в зависимости от функций применения, подключаются в трех разных файлах UCF и для каждого скрипта (которые, в массе своей, выкладываются в теме CSS, а не здесь), как правило, следует инструкция по подключению. Для начала подключите сам UCF, а когда возникнет вопрос по подключению определенного скрипта, задайте его в соответствующей теме и вам ответят. Или воспользуйтесь поиском по версии для печати темы по CSS.
Если коротко и упрощенно, то:
скрипты создающие кнопки, подключаются в custom_script.js,
скрипты работающие в главном окне, подключаются в custom_script_win.js,
скрипты для других окон и сайдбара подключаются, в custom_script_all_win.js.
Для всего существуют исключения, например, есть варианты скриптов состоящие из двух частей - кнопка для custom_script.js и основная часть для *_win.js или *_all_win.js. Также, скрипты для *_all_win.js, определенным образом (описанном далее в теме CSS), можно подключить в *_win.js. Еще есть варианты импорта скриптов из внешних файлов, их было много, но актуален последний в теме.
Поскольку VitaliyV все постоянно улучшает, то статический пост с единой инструкцией вряд ли получится. Ну и, если человек не может осилить инструкцию по подключению самомго UCF, то ему никакие описания не помогут, пример смотрите выше, на этой странице.
Отредактировано _zt (15-09-2020 20:23:45)
Отсутствует
очень сложно с нуля подключить CustomButtons
А тут в теме только один Dumby поддерживает исправления и на нем все держится, если не он, темы не было. Уйдет и не будет больше CustomButtons, а больше энтузиастов нет и модераторы не горят желанием здесь поработать, так что поиск в помощь. Раньше больше было людей кто творил, а сейчас одни потребители. Никто здесь ни кому не обязан.
Отсутствует
Dumby
В новых крякнула кнопка или код "Поиск Seasonvar"
Services.search.addEngine("data:text/xml," + encodeURIComponent(` <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/"> <ShortName>Seasonvar.ru</ShortName> <Description>Сериалы ТУТ! Сериалы онлайн смотреть бесплатно. Смотреть онлайн.</Description> <InputEncoding>UTF-8</InputEncoding> <Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADvklEQVRYhb1XTYgcRRR+JtNVr0ail0gUPLkehBwEVwgakMHNdr1XKwQ8RFQwF39uOXnxtkIwieAhetWLeoh7VVBE3IPgYY1gCIFA0OzOdL0aMYoH4y5xZsrDdjUzk91sz8BsQTFU09Pfz3uvXhXAjEax2FjoWP34MsCBWWHsDm7VKWGMwrh+7SiofScQnAlC+j9xeHvfwQvSbwnpO4FxIKTveKs+2TcXCsKF4EwMjINqOhODM1Fs9tRMwX9fgCPCGIX0oLvUjNV0ZhCciZ7wh5stwJkR6OTq1aR+hMBSs3LEW/3tzAh4q04OExj+DYwDYYxi8fWZgLcXG7kwbg6rT2S2y1H3hPRXMwEHABBnLgeH/cA46DozSLEvc+LrmQGn4UlfGY99cuD6cTg0U/B23nhOGO9OvtKB4PD7iT/qc/PsXu8I45vC2E3gaQ470HVmIKT/XgE4WAt4I89OF6S2PKnPA+ON3xbgyPg7geGhwPidMMauM4NU5+Oll1zwpLc6z4Cpp5zwlif9MwDAagsaweEXI6pz9YQn1R9Rm5Juh7ldBbp3JYf7axEorLoa2HwEALACcLCwahMA7gMA2DiBjw3bvRvoeAg84a3aIbg8D9ly2b9XW9DwrP8FAFi38Ig47EsqtaGNZjflVRISnq4FPj6uH4dDnvESAIA4c7FUFMO9Yj629QpjmAocAKCTq/eFtF0GODCJ9SkptxuQvjg1AWGMNxgeEMazeyneKfbBmbg+bQsubPakt7oLACCEa7XVjzlwswUPT6ee8LOCcAEAILCRWolXKq+2YWeitODw5ODz0PSkN9M6LDX/qhuC6gRUdsGC4dEp1OszwmatWrP5sxaBdPKx+K6w7gVnYnsxe3oKAihC+oO09ozFXvYPh6G92MiFUIQxetZvTwTeZj3nScci1y8MEVqrcuAeTlSll6uXOqReFMZYkFqZiMC2fRglz+bTs8KqT9PH99r3gzOxsOoUAIA4vO1J/zIZAdIfCmP0uV5Mzzp5dqzqfLspT1sv6UEnz44BAHjGS5701kQEpLTO8+jptTxY9HcsvSo/TN9b9U/6T5vUy9v3AfXKZC6w/rK81/306wl4sHTm4+FsHwF3JnaXTF8YY/t5mFttQWO5bGjCGAurrso8NKHsqjWd0Gc84x/pRBsc9kZuPCknqqOX7gVnup5xQxi3POGPJfFvSjEjeVVrXDsKqs16zlt1smOzN4TUO8J41hOe86wveNYXvFXnPalzBeF7aXqL54s8q1qwkLaFzV5Lbo6P/wEF7JeDr5SEggAAAABJRU5ErkJggg==</Image> <Url type="text/html" method="GET" template="http://seasonvar.ru/search"> <Param name="q" value="{searchTerms}"/> </Url> <SearchForm>http://seasonvar.ru/</SearchForm> </SearchPlugin> `), null, null);
Отсутствует
solombala
Bug 1632448 - Remove window.external.AddSearchProvider code
//Services.search.addEngine("data:text/xml," + encodeURIComponent(` (Services.search.addOpenSearchEngine || Services.search.addEngine)("data:text/xml," + encodeURIComponent(`
Отсутствует
Доброго Времени!,не судите строго
Нашел в прошлой теме ,что в Firefox 60 и выше отвалились кнопки и есть решение
Ссылка
изменив в скрипте chrome://custombuttons/content/overlay.js
var custombuttons = { на var cbu custombuttons = {
Кто пробывал, и если работает не пойму как изменить.
то есть перехожу по ссылке нажимаю F12 -дальше не как ,не поиму что делать : толи консуль толи отладчик.
Distance Subordinatio!
Отсутствует
Dumby покажи пожалуйста свою рабочую кнопку Консоль браузера, что-то у меня из-за нее в Appmenu пункты проподают и вообще ничего не пойму простой код не хочет работать, не появляется в меню, только при двойной инициализии
// Добавить новый пункт "Перезапуск" в главном меню (()=> { var menuItem = document.createXULElement("toolbarbutton"); menuItem.setAttribute("id", "restart_firefox"); menuItem.setAttribute("label", "Перезапуск"); menuItem.setAttribute("class", "subviewbutton subviewbutton-iconic"); menuItem.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAuZJREFUeNqkU0lPU1EUPvcNHaCUWlpsERGooIhxwQPFSNUgKpEYTRQXhpi44g+48W8YFy7cmOgC4hRjDEGjosEQpQRRKQQoFmgZSqGldHrDvZ7XohJWJr7kyx3e/b57vnPOJYwx+J9POHpnJj8RRRAEATietxFCvLh1CtGEKERMIQbxsqeU0jDP81249r67Wdot7BCsFjh2rarMfKS81FxnLRSqcc+aSKp1C6uZlpn55BXK2KCmqu2/CdwfKmNug8C8HcedrspSs9VAiFGRKegQCSnY5zCVn29ynFaR3HnGLeGYj5xqGmDIBgJa3blGl3U9mgGNAzoRjIfmllIR3UKFq9DWULvLE19X4LLXJW3Esygs5wU0RdHHkkqX1RJdSQLlCXnzOTyOoh84QXil4sFAMHs3EFxrvtpWKS0vxMFiNYKazeYF5PzEYi8QDHJWod/nY4uo3k8IjKiplB5dF6L5eketlIhlQDTorhnIvwX0G9C/YjbyEVXVVoNz0YRGtZG8NQ5EUfTqpX7wZMy3PdsomlsL6WRSX9x+/vqHtLPGlKk+JHdj2SB3ESFSq/dAkYil6ns7HvwbAYDUfrFJSmXymS0pNsKzx0M+FP6Idc+RRYOhYXeZ/Ww0QxNUTi8r2Ww4J6BseVnMAKwmGFQ4TND7aEAPbwjJDzW0gg12AfNy0uHZa46CkEyFF2XkbW5PIsR5A9icJhiLKVBzqVVa+TJmi8yGhvFXsniPQ3bW16TDnCngLhLAPzW/qSlqdLsFMFpM8Olej6/yRqc0LzPgpUaP+5jeybCRUVkoRFnAVciBr+flhpJM+7Hlc0TCOQ8C33JreCtvfcRoPOE4XLtf9FTZid1eoAuw6FpAnp7xx/zTY8rCt146+SJAVyZAr45AIxPlsOwfh2x8lPruD3Clh94v/WxrgZKaeuBE/S1sgpr5Cqv+UTbdP8nWZ02450SsITSiPxaEqNtB8P/wgvXWTSHSGAH9JcAAMrRspwHKXNQAAAAASUVORK5CYII="); menuItem.onclick =()=> setTimeout(()=> Services.startup.quit(Services.startup.eAttemptQuit | Services.startup.eRestart), 500); addDestructor(()=> menuItem.remove()); var it = document.getElementById("appMenu-quit-button"); it.parentNode.insertBefore(menuItem, it); // или it.insertBefore(menuItem, it); })();
и кнопка накрылась Custom Buttons: Source Editor
if(true) return; // Disabled by Disable Initialization button // https://github.com/Infocatcher/Custom_Buttons/tree/master/CB_Source_Editor // http://infocatcher.ucoz.net/js/cb/cbSourceEditor.js // Source Editor (formerly Orion Editor) button for Custom Buttons // (code for "initialization" section) // (c) Infocatcher 2012-2019 // version 0.1.0a10 - 2019-12-25 var options = { cssInHelp: true, codeMirror: { lineNumbers: true, enableCodeFolding: true, showTrailingSpace: true, lineWrapping: true, autocomplete: true, fontSize: 12 }, orion: { lineNumbers: true } }; // Also see devtools.editor.* preferences in about:config const watcherId = "customButtonsSourceEditor_" + this.id; var {Components} = window; // Prevent garbage collection in Firefox 3.6 and older var storage = (function() { if(!("Services" in window)) // Firefox 3.6 and older return Application.storage; // Simple replacement for Application.storage // See https://bugzilla.mozilla.org/show_bug.cgi?id=1090880 //var global = Components.utils.getGlobalForObject(Services); // Ensure, that we have global object (because window.Services may be overwritten) var global = Components.utils.import("resource://gre/modules/Services.jsm", {}); var ns = "_cbSourceEditorStorage"; // Note: Firefox 57+ returns NonSyntacticVariablesObject w/o .Object property var storage = global[ns] || (global[ns] = Components.utils.getGlobalForObject(global).Object.create(null)); return { get: function(key, defaultVal) { if(key in storage) return storage[key]; return defaultVal; }, set: function(key, val) { if(key === null) delete storage[key]; else storage[key] = val; } }; })(); var watcher = storage.get(watcherId, null); if(!watcher) { watcher = { REASON_STARTUP: 1, REASON_SHUTDOWN: 2, REASON_WINDOW_LOADED: 3, REASON_WINDOW_CLOSED: 4, get obs() { delete this.obs; return this.obs = Components.classes["@mozilla.org/observer-service;1"] .getService(Components.interfaces.nsIObserverService); }, get ww() { delete this.ww; return this.ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] .getService(Components.interfaces.nsIWindowWatcher); }, get wm() { delete this.wm; return this.wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator); }, get platformVersion() { delete this.platformVersion; return this.platformVersion = parseFloat(Services.appinfo.platformVersion); }, get hasCodeMirror() { delete this.hasCodeMirror; return this.hasCodeMirror = Services.appinfo.name == "Pale Moon" //~ todo: test || this.platformVersion >= 27; }, init: function(reason) { if(!this.hasCodeMirror) { this.isBrowserWindow = function() { return false; }; } this.obs.addObserver(this, "quit-application-granted", false); var ws = this.wm.getEnumerator(null); while(ws.hasMoreElements()) this.initWindow(ws.getNext(), reason); this.ww.registerNotification(this); }, destroy: function(reason) { this.obs.removeObserver(this, "quit-application-granted"); var ws = this.wm.getEnumerator(null); while(ws.hasMoreElements()) this.destroyWindow(ws.getNext(), reason); this.ww.unregisterNotification(this); }, initWindow: function(window, reason, isFrame) { if(this.isBrowserWindow(window)) { this.initBrowserWindow(window, reason); return; } if(!this.isEditorWindow(window)) return; _log("initWindow(): isFrame: " + isFrame); var document = window.document; if(isFrame) window.addEventListener("unload", this, false); Components.classes["@mozilla.org/moz/jssubscript-loader;1"] .getService(Components.interfaces.mozIJSSubScriptLoader) .loadSubScript("chrome://global/content/globalOverlay.js", window); var isCodeMirror = false; try { // See chrome://browser/content/devtools/scratchpad.js Components.utils.import("resource:///modules/source-editor.jsm", window); } catch(e) { var loader = this.platformVersion >= 44 // See https://bugzilla.mozilla.org/show_bug.cgi?id=912121 ? "resource://devtools/shared/Loader.jsm" : "resource://gre/modules/devtools/Loader.jsm"; var g = Components.utils.import(loader, {}); var require = (g.devtools || g).require; [ "devtools/sourceeditor/editor", "devtools/client/sourceeditor/editor", // Firefox 44+ "devtools/client/shared/sourceeditor/editor" // Firefox 68+ ].some(function(path) { try { return window.SourceEditor = require(path); } catch(e) { } return null; }); isCodeMirror = true; } var SourceEditor = window.SourceEditor; // See view-source:chrome://browser/content/devtools/scratchpad.xul // + view-source:chrome://browser/content/devtools/source-editor-overlay.xul var psXUL = (isCodeMirror ? '<!DOCTYPE popupset [\ <!ENTITY % editMenuStrings SYSTEM "chrome://global/locale/editMenuOverlay.dtd">\ %editMenuStrings;\ <!ENTITY % sourceEditorStrings SYSTEM "' + ( Services.appinfo.name == "Pale Moon" || Services.appinfo.name == "Basilisk" ? this.platformVersion >= 4.1 ? "chrome://devtools/locale/sourceeditor.dtd" : "chrome://global/locale/devtools/sourceeditor.dtd" : this.platformVersion >= 45 ? "chrome://devtools/locale/sourceeditor.dtd" : "chrome://browser/locale/devtools/sourceeditor.dtd" ) + '">\ %sourceEditorStrings;\ ]>\ <popupset id="sourceEditorPopupset"\ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">\ <menupopup id="sourceEditorContext"\ onpopupshowing="goUpdateSourceEditorMenuItems()">\ <menuitem id="menu_undo" label="&undoCmd.label;" accesskey="&undoCmd.accesskey;"\ oncommand="goDoCommand(\'cmd_undo\')" />\ <menuitem id="menu_redo" label="&redoCmd.label;" accesskey="&redoCmd.accesskey;"\ oncommand="goDoCommand(\'cmd_redo\')" />\ <menuseparator/>\ <menuitem id="menu_cut" label="&cutCmd.label;" accesskey="&cutCmd.accesskey;"\ oncommand="goDoCommand(\'cmd_cut\')" />\ <menuitem id="menu_copy" label="©Cmd.label;" accesskey="©Cmd.accesskey;"\ oncommand="goDoCommand(\'cmd_copy\')" />\ <menuitem id="menu_paste" label="&pasteCmd.label;" accesskey="&pasteCmd.accesskey;"\ oncommand="goDoCommand(\'cmd_paste\')" />\ <menuitem id="menu_delete" label="&deleteCmd.label;" accesskey="&deleteCmd.accesskey;"\ oncommand="goDoCommand(\'cmd_delete\')" />\ <menuseparator/>\ <menuitem id="menu_selectAll" label="&selectAllCmd.label;" accesskey="&selectAllCmd.accesskey;"\ oncommand="goDoCommand(\'cmd_selectAll\')" />\ <menuseparator/>\ <menuitem id="menu_find" label="&findCmd.label;" accesskey="&findCmd.accesskey;" />\ <menuitem id="menu_findAgain" label="&findAgainCmd.label;" accesskey="&findAgainCmd.accesskey;" />\ <menuseparator/>\ <menuitem id="se-menu-gotoLine"\ label="&gotoLineCmd.label;"\ accesskey="&gotoLineCmd.accesskey;"\ key="key_gotoLine"\ oncommand="goDoCommand(\'cmd_gotoLine\')"/>\ </menupopup>\ </popupset>' : '<popupset id="sourceEditorPopupset"\ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">\ <menupopup id="sourceEditorContext"\ onpopupshowing="goUpdateSourceEditorMenuItems()">\ <menuitem id="se-menu-undo"/>\ <menuitem id="se-menu-redo"/>\ <menuseparator/>\ <menuitem id="se-menu-cut"/>\ <menuitem id="se-menu-copy"/>\ <menuitem id="se-menu-paste"/>\ <menuitem id="se-menu-delete"/>\ <menuseparator/>\ <menuitem id="se-menu-selectAll"/>\ <menuseparator/>\ <menuitem id="se-menu-find"/>\ <menuitem id="se-menu-findAgain"/>\ <menuseparator/>\ <menuitem id="se-menu-gotoLine"/>\ </menupopup>\ </popupset>' ).replace(/>\s+</g, "><"); var ps = this.parseXULFromString(psXUL); // "Edit Custom Button in Tab" button, Firefox 71+ if(isFrame && "parseFromSafeString" in window.DOMParser.prototype) ps = window.MozXULElement.parseXULToFragment(ps.outerHTML); document.documentElement.appendChild(ps); window.setTimeout(function() { function appendNode(nodeName, id) { var node = document.createElementNS(xulns, nodeName); node.id = id; document.documentElement.appendChild(node); } appendNode("commandset", "editMenuCommands"); appendNode("commandset", "sourceEditorCommands"); appendNode("keyset", "sourceEditorKeys"); appendNode("keyset", "editMenuKeys"); this.loadOverlays( window, function done() { window.setTimeout(function() { var mp = document.getElementById("sourceEditorContext"); if(mp.state == "closed") return; Array.prototype.forEach.call( mp.getElementsByAttribute("command", "*"), function(mi) { var cmd = mi.getAttribute("command"); var controller = document.commandDispatcher .getControllerForCommand(cmd); if(controller && !controller.isCommandEnabled(cmd)) mi.setAttribute("disabled", "true"); } ); }, 0); if(!isCodeMirror) return; // See view-source:chrome://browser/content/devtools/scratchpad.xul in Firefox 27.0a1 window.goUpdateSourceEditorMenuItems = function() { goUpdateGlobalEditMenuItems(); var commands = ["cmd_undo", "cmd_redo", "cmd_cut", "cmd_paste", "cmd_delete"]; commands.forEach(goUpdateCommand); }; var cmdsMap = { "se-menu-undo": "cmd_undo", "se-menu-redo": "cmd_redo", "se-menu-cut": "cmd_cut", "se-menu-copy": "cmd_copy", "se-menu-paste": "cmd_paste", "se-menu-delete": "cmd_delete", __proto__: null }; for(var id in cmdsMap) { var mi = document.getElementById(id); mi && mi.setAttribute("command", cmdsMap[id]); } // We can't use command="cmd_selectAll", menuitem will be wrongly disabled sometimes var enabledCmdsMap = { "se-menu-selectAll": "cmd_selectAll", "se-menu-findAgain": "cmd_findAgain", __proto__: null }; for(var id in enabledCmdsMap) { var mi = document.getElementById(id); if(mi) { mi.removeAttribute("command"); mi.removeAttribute("disabled"); mi.setAttribute("oncommand", "goDoCommand('" + enabledCmdsMap[id] + "');"); } } // Workaround: emulate keyboard shortcut var keyCmdsMap = { "menu_find": { keyCode: KeyboardEvent.DOM_VK_F, charCode: "f".charCodeAt(0), ctrlKey: true }, "menu_findAgain": { keyCode: KeyboardEvent.DOM_VK_G, charCode: "g".charCodeAt(0), ctrlKey: true }, __proto__: null }; var _key = function() { var e = this._keyData; var evt = document.createEvent("KeyboardEvent"); evt.initKeyEvent( "keydown", true /*bubbles*/, true /*cancelable*/, window, e.ctrlKey || false, e.altKey || false, e.shiftKey || false, e.metaKey || false, e.keyCode || 0, e.charCode || 0 ); document.commandDispatcher.focusedElement.dispatchEvent(evt); }; for(var id in keyCmdsMap) { var mi = document.getElementById(id); if(mi) { mi.removeAttribute("command"); mi.removeAttribute("disabled"); mi.setAttribute("oncommand", "this._key();"); mi._keyData = keyCmdsMap[id]; mi._key = _key; } } // Fix styles for autocomplete tooltip function css(uri) { document.insertBefore(document.createProcessingInstruction( "xml-stylesheet", 'href="' + uri + '" type="text/css"' ), document.documentElement); } css("resource://devtools/client/themes/variables.css"); css("resource://devtools/client/themes/common.css"); css("chrome://devtools/skin/tooltips.css"); if(this.platformVersion >= 68) window.setTimeout(function fixSelection() { var sheets = document.styleSheets; for(var i = sheets.length - 1; i >= 0; --i) { var sheet = sheets[i]; if(sheet.href != "resource://devtools/client/themes/common.css") continue; try { var rules = sheet.cssRules; } catch(e) { // InvalidAccessError: // A parameter or an operation is not supported by the underlying object return window.setTimeout(fixSelection, 10); } for(var j = 0, len = rules.length; j < len; ++j) if(rules[j].selectorText == "::selection") return !sheet.deleteRule(j); break; } return false; }, 10); }.bind(this), ["chrome://global/content/editMenuOverlay.xul", function check(window) { return window.document.getElementById("editMenuCommands").hasChildNodes(); }], ["chrome://browser/content/devtools/source-editor-overlay.xul", function check(window) { return window.document.getElementById("sourceEditorCommands").hasChildNodes(); }] ); }.bind(this), 500); // We should wait to not break other extensions with document.loadOverlay() var tabs = document.getElementById("custombuttons-editbutton-tabbox"); var selectedPanel = tabs.selectedPanel; Array.prototype.slice.call(document.getElementsByTagName("cbeditor")).forEach(function(cbEditor) { if("__sourceEditor" in cbEditor) return; var code = cbEditor.value; var isCSS = options.cssInHelp && cbEditor.id == "help"; if(isCodeMirror) { var opts = { mode: isCSS ? SourceEditor.modes.css : SourceEditor.modes.js, value: code, lineNumbers: true, enableCodeFolding: true, showTrailingSpace: true, autocomplete: true, contextMenu: "sourceEditorContext" }; var optsOvr = options.codeMirror; for(var opt in optsOvr) if(optsOvr.hasOwnProperty(opt)) opts[opt] = optsOvr[opt]; var se = new SourceEditor(opts); if("codeMirror" in se) window.setTimeout(function() { if("insertCommandsController" in se) se.insertCommandsController(); // Pale Moon and Basilisk else this.insertCommandsController(se); }.bind(this), 200); } else { var se = new SourceEditor(); } se.__isCodeMirror = isCodeMirror; var seElt = document.createElementNS(xulns, "hbox"); if(cbEditor.id) seElt.id = "sourceEditor-" + cbEditor.id; seElt.className = "sourceEditor"; seElt.setAttribute("flex", 1); seElt.__sourceEditor = se; cbEditor.parentNode.insertBefore(seElt, cbEditor); //cbEditor.setAttribute("hidden", "true"); cbEditor.setAttribute("collapsed", "true"); cbEditor.parentNode.appendChild(cbEditor); cbEditor.__sourceEditor = se; cbEditor.__sourceEditorElt = seElt; cbEditor.__defineGetter__("value", function() { if("__sourceEditor" in this) { var se = this.__sourceEditor; if(!se.__initialized) return se.__value; return se.getText().replace(/\r\n?|\n\r?/g, "\n"); } return this.textbox.value; }); cbEditor.__defineSetter__("value", function(v) { if("__sourceEditor" in this) { var se = this.__sourceEditor; if(!se.__initialized) { var _this = this; se.__onLoadCallbacks.push(function() { _this.value = v; }); return se.__value = v; } return se.setText(v.replace(/\r\n?|\n\r?/g, "\n")); } return this.textbox.value = v; }); cbEditor.selectLine = function(lineNumber) { if("__sourceEditor" in this) { var se = this.__sourceEditor; if(!se.__initialized) { var _this = this, args = arguments; se.__onLoadCallbacks.push(function() { _this.selectLine.apply(_this, args); }); return undefined; } if(se.__isCodeMirror) { //se.focus(); //se.setCursor({ line: lineNumber - 1, ch: 0 }); //~ todo: optimize var val = this.value; var lines = val.split("\n"); var line = Math.min(lineNumber - 1, lines.length); var ch = lines[line].length; se.focus(); return se.setSelection({ line: line, ch: 0 }, { line: line, ch: ch }); } else { var selStart = se.getLineStart(lineNumber - 1); var selEnd = se.getLineEnd(lineNumber - 1, false); se.focus(); return se.setSelection(selStart, selEnd); } } return this.__proto__.selectLine.apply(this, arguments); }; // For edit_button() from chrome://custombuttons/content/editExternal.js seElt.__cbEditor = cbEditor; seElt.__defineGetter__("localName", function() { return "cbeditor"; }); seElt.__defineGetter__("value", function() { return this.__cbEditor.value; }); seElt.__defineSetter__("value", function(val) { this.__cbEditor.value = val; }); se.__initialized = false; se.__onLoadCallbacks = []; se.__value = code; var onTextChanged = se.__onTextChanged = function() { window.editor.changed = true; }; var isLoaded = reason == this.REASON_WINDOW_LOADED; function done() { se.__initialized = true; se.__onLoadCallbacks.forEach(function(fn) { try { fn(); } catch(e) { Components.utils.reportError(e); } }); delete se.__onLoadCallbacks; delete se.__value; } if(isCodeMirror) { se.appendTo(seElt).then(function() { try { se.setupAutoCompletion(); } catch(e) { Components.utils.reportError(e); } if("setFontSize" in se) try { se.setFontSize(options.codeMirror.fontSize); } catch(e) { Components.utils.reportError(e); } window.setTimeout(function() { window.editor.changed = false; // Strange... window.setTimeout(function() { // Workaround for unexpected onTextChanged() calls if(window.editor.changed && cbEditor.value == code) window.editor.changed = false; }, 100); se.on("change", onTextChanged); if(isLoaded) { if("clearHistory" in se) se.clearHistory(); else { var seGlobal = Components.utils.getGlobalForObject(SourceEditor.prototype); // Note: this is resource://app/modules/devtools/gDevTools.jsm scope in Firefox 34+ var cm = seGlobal.editors.get(se); cm.clearHistory(); } } }, isFrame ? 50 : 15); // Oh, magic delays... done(); // See resource:///modules/devtools/sourceeditor/editor.js // doc.defaultView.controllers.insertControllerAt(0, controller(this, doc.defaultView)); var controllers = window.controllers; // nsIControllers var controller = se.__cmdController = controllers.getControllerAt(0); if("__cmdControllers" in tabs) tabs.__cmdControllers.push(controller); else { tabs.__cmdControllers = [controller]; var onSelect = tabs.__onSelect = function() { var seElt = tabs.selectedPanel; if(!seElt || !("__sourceEditor" in seElt)) return; var se = seElt.__sourceEditor; var curController = se.__cmdController; tabs.__cmdControllers.forEach(function(controller) { try { if(controller == curController) controllers.insertControllerAt(0, controller); else controllers.removeController(controller); } catch(e) { } }); }; tabs.addEventListener("select", onSelect, false); window.setTimeout(onSelect, 0); // Activate controller from selected tab } }); } else { var opts = { mode: isCSS ? SourceEditor.MODES.CSS : SourceEditor.MODES.JAVASCRIPT, showLineNumbers: true, initialText: code, placeholderText: code, // For backward compatibility contextMenu: "sourceEditorContext" }; var optsOvr = options.orion; for(var opt in optsOvr) if(optsOvr.hasOwnProperty(opt)) opts[opt] = optsOvr[opt]; se.init(seElt, opts, function callback() { done(); isLoaded && se.resetUndo && se.resetUndo(); se.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onTextChanged); // Hack to use selected editor var controller = se.ui._controller; controller.__defineGetter__("_editor", function() { var seElt = tabs.selectedPanel; var se = seElt && seElt.__sourceEditor || document.getElementsByTagName("cbeditor")[0].__sourceEditor; return se; }); controller.__defineSetter__("_editor", function() {}); }); } }, this); // Trick to select correct tab (especially if was selected "Button settings" tab) tabs.tabs.advanceSelectedTab(1, true); tabs.tabs.advanceSelectedTab(-1, true); var origExecCmd = window.editor.execute_oncommand_code; window.editor.execute_oncommand_code = function() { var cd = document.commandDispatcher; var cdFake = { __proto__: cd, get focusedElement() { var selectedTab = tabs.selectedTab; if(selectedTab && selectedTab.id == "code-tab") return document.getElementById("code").textbox.inputField; return cd.focusedElement; } }; document.__defineGetter__("commandDispatcher", function() { return cdFake; }); try { var ret = origExecCmd.apply(this, arguments); } catch(e) { Components.utils.reportError(e); } // document.hasOwnProperty("commandDispatcher") == false, so we cat just delete our fake property delete document.commandDispatcher; return ret; }; window.addEventListener("load", function ensureObserversAdded() { window.removeEventListener("load", ensureObserversAdded, false); window.setTimeout(function() { window.editor.removeObservers(); }, 0); window.setTimeout(function() { window.editor.addObservers(); }, 0); }, false); // Fix for Ctrl+S hotkey (catched by CodeMirror) var hke = this.handleKeyEvent; window.addEventListener("keydown", hke, true); window.addEventListener("keypress", hke, true); window.addEventListener("keyup", hke, true); }, insertCommandsController: function(se) { this.insertCommandsController = insertCommandsController; return insertCommandsController(se); // devtools/client/sourceeditor/editor-commands-controller in Pale Moon/Basilisk function createController(ed) { return { supportsCommand: function (cmd) { switch (cmd) { case "cmd_find": case "cmd_findAgain": case "cmd_gotoLine": case "cmd_undo": case "cmd_redo": case "cmd_delete": case "cmd_selectAll": return true; } return false; }, isCommandEnabled: function (cmd) { let cm = ed.codeMirror; switch (cmd) { case "cmd_find": case "cmd_gotoLine": case "cmd_selectAll": return true; case "cmd_findAgain": return cm.state.search != null && cm.state.search.query != null; case "cmd_undo": return ed.canUndo(); case "cmd_redo": return ed.canRedo(); case "cmd_delete": return ed.somethingSelected(); } return false; }, doCommand: function (cmd) { let cm = ed.codeMirror; let map = { "cmd_selectAll": "selectAll", "cmd_find": "find", "cmd_undo": "undo", "cmd_redo": "redo", "cmd_delete": "delCharAfter", "cmd_findAgain": "findNext" }; if (map[cmd]) { cm.execCommand(map[cmd]); return; } if (cmd == "cmd_gotoLine") { ed.jumpToLine(); } }, onEvent: function () {} }; } function insertCommandsController(sourceEditor) { let input = sourceEditor.codeMirror.getInputField(); let controller = createController(sourceEditor); input.controllers.insertControllerAt(0, controller); } }, destroyWindow: function(window, reason, isFrame) { if(reason == this.REASON_WINDOW_CLOSED) window.removeEventListener(this.loadEvent, this, false); // Window can be closed before DOMContentLoaded if(this.isBrowserWindow(window)) { this.destroyBrowserWindow(window, reason); return; } if(!this.isEditorWindow(window) || !("SourceEditor" in window)) return; _log("destroyWindow(): isFrame: " + isFrame); var document = window.document; if(isFrame) window.removeEventListener("unload", this, false); var tabs = document.getElementById("custombuttons-editbutton-tabbox"); if("__onSelect" in tabs) { tabs.removeEventListener("select", tabs.__onSelect, false); delete tabs.__onSelect; delete tabs.__cmdControllers; } Array.prototype.slice.call(document.getElementsByTagName("cbeditor")).forEach(function(cbEditor) { if(!("__sourceEditor" in cbEditor)) return; var se = cbEditor.__sourceEditor; var isCodeMirror = se.__isCodeMirror; if(isCodeMirror) se.off("change", se.__onTextChanged); else se.removeEventListener(window.SourceEditor.EVENTS.TEXT_CHANGED, se.__onTextChanged); delete se.__onTextChanged; if(reason == this.REASON_SHUTDOWN) { var val = cbEditor.value; delete cbEditor.value; delete cbEditor.selectLine; var seElt = cbEditor.__sourceEditorElt; seElt.parentNode.insertBefore(cbEditor, seElt); seElt.parentNode.removeChild(seElt); delete cbEditor.__sourceEditorElt; delete cbEditor.__sourceEditor; delete seElt.__sourceEditor; delete seElt.__cbEditor; cbEditor.value = val; window.setTimeout(function() { cbEditor.removeAttribute("collapsed"); }, 0); } se.destroy(); if("__cmdController" in se) { try { window.controllers.removeController(se.__cmdController); } catch(e) { } delete se.__cmdController; } }, this); if(reason == this.REASON_SHUTDOWN) { delete window.editor.execute_oncommand_code; [ "sourceEditorPopupset", "editMenuCommands", "sourceEditorCommands", "sourceEditorKeys", "editMenuKeys" ].forEach(function(id) { var node = document.getElementById(id); node && node.parentNode.removeChild(node); }); [ // chrome://global/content/globalOverlay.js "closeWindow", "canQuitApplication", "goQuitApplication", "goUpdateCommand", "goDoCommand", "goSetCommandEnabled", "goSetMenuValue", "goSetAccessKey", "goOnEvent", "visitLink", "setTooltipText", "NS_ASSERT", // chrome://global/content/editMenuOverlay.xul => view-source:chrome://global/content/editMenuOverlay.js "goUpdateGlobalEditMenuItems", "goUpdateUndoEditMenuItems", "goUpdatePasteMenuItems" ].forEach(function(p) { delete window[p]; }); for(var child = document.documentElement; child = child.previousSibling; ) { if( child.nodeType == child.PROCESSING_INSTRUCTION_NODE && child.data.indexOf("://devtools/") != -1 ) { setTimeout(function(child) { child.parentNode.removeChild(child); }, 0, child); } } delete window.SourceEditor; } var hke = this.handleKeyEvent; window.removeEventListener("keydown", hke, true); window.removeEventListener("keypress", hke, true); window.removeEventListener("keyup", hke, true); //~ todo: we have one not removed controller! //LOG("getControllerCount(): " + window.controllers.getControllerCount()); }, initBrowserWindow: function(window, reason) { _log("initBrowserWindow()"); window.addEventListener("DOMContentLoaded", this, false); Array.prototype.forEach.call(window.frames, function(frame) { this.initWindow(frame, reason, true); }, this); }, destroyBrowserWindow: function(window, reason) { _log("destroyBrowserWindow()"); window.removeEventListener("DOMContentLoaded", this, false); Array.prototype.forEach.call(window.frames, function(frame) { this.destroyWindow(frame, reason, true); }, this); }, isEditorWindow: function(window) { return window.location.href.substr(0, 41) == "chrome://custombuttons/content/editor.xul"; }, isBrowserWindow: function(window) { var loc = window.location.href; return loc == "chrome://browser/content/browser.xul" || loc == "chrome://browser/content/browser.xhtml" // Firefox 69+ || loc == "chrome://navigator/content/navigator.xul"; }, get loadEvent() { // "DOMContentLoaded" -> initWindow() may hang editor window (and browser) delete this.loadEvent; return this.loadEvent = this.platformVersion >= 73 ? "load" : "DOMContentLoaded"; }, observe: function(subject, topic, data) { if(topic == "quit-application-granted") this.destroy(); else if(topic == "domwindowopened") subject.addEventListener(this.loadEvent, this, false); else if(topic == "domwindowclosed") this.destroyWindow(subject, this.REASON_WINDOW_CLOSED); }, handleEvent: function(e) { switch(e.type) { case "DOMContentLoaded": case "load": //var window = e.currentTarget; var window = e.target.defaultView || e.target; window.removeEventListener(e.type, this, false); var isFrame = window != e.currentTarget; this.initWindow(window, this.REASON_WINDOW_LOADED, isFrame); break; case "unload": //var window = e.currentTarget; var window = e.target.defaultView || e.target; window.removeEventListener(e.type, this, false); this.destroyWindow(window, this.REASON_WINDOW_CLOSED, true); } }, handleKeyEvent: function(e) { if( (e.keyCode == e.DOM_VK_S || String.fromCharCode(e.charCode).toUpperCase() == "S") && e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey ) { e.preventDefault(); e.stopPropagation(); if(e.type == "keydown") { var window = e.currentTarget; window.editor.updateButton(); } } }, loadOverlays: function() { this.runGenerator(this.loadOverlaysGen, this, arguments); }, get loadOverlaysGen() { var fn = this._loadOverlaysGen.toString() .replace(/__yield/g, "yield"); try { new Function("function test() { yield 0; }"); } catch(e) { // Firefox 58+: SyntaxError: yield expression is only valid in generators fn = fn.replace("function", "function*"); // Firefox 26+ } delete this.loadOverlaysGen; return this.loadOverlaysGen = eval("(" + fn + ")"); }, _loadOverlaysGen: function loadOverlaysGen(window, callback/*, overlayData1, ...*/) { var gen = loadOverlaysGen.__generator; for(var i = 2, l = arguments.length; i < l; ++i) { var overlayData = arguments[i]; this.loadOverlay(window, overlayData[0], overlayData[1], function() { gen.next(); }); __yield(0); } callback(); __yield(0); }, loadOverlay: function(window, uri, check, callback) { var document = window.document; var stopWait = Date.now() + 4500; window.setTimeout(function load() { _log("loadOverlay(): " + uri); var tryAgain = Date.now() + 800; try { document.loadOverlay(uri, null); } catch(e) { window.setTimeout(callback, 0); return; } window.setTimeout(function ensureLoaded() { if(check(window)) window.setTimeout(callback, 0); else if(Date.now() > stopWait) return; else if(Date.now() > tryAgain) window.setTimeout(load, 0); else window.setTimeout(ensureLoaded, 50); }, 50); }, 0); }, runGenerator: function(genFunc, context, args) { var gen = genFunc.apply(context, args); genFunc.__generator = gen; gen.next(); }, parseXULFromString: function(xul) { xul = xul.replace(/>\s+</g, "><"); try { return new DOMParser().parseFromString(xul, "application/xml").documentElement; } catch(e) { // See http://custombuttons.sourceforge.net/forum/viewtopic.php?f=5&t=3720 // + https://forum.mozilla-russia.org/viewtopic.php?pid=732243#p732243 var dummy = document.createElement("dummy"); dummy.innerHTML = xul.trimLeft(); return dummy.firstChild; } } }; storage.set(watcherId, watcher); setTimeout(function() { watcher.init(watcher.REASON_STARTUP); }, 50); } function destructor(reason) { if(reason == "update" || reason == "delete") { watcher.destroy(watcher.REASON_SHUTDOWN); storage.set(watcherId, null); } } if( typeof addDestructor == "function" // Custom Buttons 0.0.5.6pre4+ && addDestructor != ("addDestructor" in window && window.addDestructor) ) addDestructor(destructor, this); else this.onDestroy = destructor; function ts() { var d = new Date(); var ms = d.getMilliseconds(); return d.toTimeString().replace(/^.*\d+:(\d+:\d+).*$/, "$1") + ":" + "000".substr(("" + ms).length) + ms + " "; } function _log(s) { Services.console.logStringMessage("[Custom Buttons :: Source Editor] " + ts() + s); }
Отредактировано Andrey_Krropotkin (25-09-2020 18:06:36)
Отсутствует
Dumby
этот код сдох?
try {
Components.interfaces.nsIUDPSocketChild ||
Cc["@mozilla.org/process/environment;81.0"].getService(Ci.nsIEnvironment).set(
"MOZ_FORCE_DISABLE_E10S",
Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch)
.getBoolPref("browser.tabs.remote.autostart", true) ? "" : "81.0"
);
} catch(ex) {}
Зачем? Теперь есть аддоны, что ни черта не настраиваются без мультирежима...
Отредактировано solombala (26-09-2020 11:09:37)
Отсутствует
Доброго времени.
Может кто подправить под Firefox 81.0 ?
Autocopy+3 Автоматически копирует выделенный текст
Distance Subordinatio!
Отсутствует
Может кто подправить под Firefox 81.0 ?
Autocopy+3 Автоматически копирует выделенный текст
https://forum.mozilla-russia.org/viewto … 95#p783695, и не ленитесь использовать поиск, частенько выручает!
Отредактировано kokoss (26-09-2020 17:53:57)
Win7
Отсутствует
Ходьба по кругу какая-то.
ничего не пойму простой код не хочет работать, не появляется в меню
Я же писал, что будут всё больше совать в <html:template>
А добро внутри него не является частью документа. Дошло время и до гамбургера.
Да вот совсем недавно подобное обсуждалось, неужели не прояснительно.
Можно записать похуже, но попроще, и можно даже без getElementById,
но тогда обратная совместимость пропадёт.
... //var it = document.getElementById("appMenu-quit-button"); var it = document.getElementById("appMenu-quit-button") || PanelMultiView.getViewNode(document, "appMenu-quit-button");
ошибка синтактического анализа XML
Опять же, писал про это, и даже какой-то патч пробовал набросать.
Ошибки не было потому, что в ru локали выпиленные <!ENTITY> оставались.
Вот теперь добрались и зачистили. Вобщем, возвращаю код с теми правками,
но они не одобрены и не интегрированы.
// https://github.com/Infocatcher/Custom_Buttons/tree/master/CB_Source_Editor // http://infocatcher.ucoz.net/js/cb/cbSourceEditor.js // Source Editor (formerly Orion Editor) button for Custom Buttons // (code for "initialization" section) // (c) Infocatcher 2012-2019 // version 0.1.0a10 - 2019-12-25 var options = { cssInHelp: true, codeMirror: { lineNumbers: true, enableCodeFolding: true, showTrailingSpace: true, lineWrapping: true, autocomplete: true, fontSize: 12 }, orion: { lineNumbers: true } }; // Also see devtools.editor.* preferences in about:config const watcherId = "customButtonsSourceEditor_" + this.id; var {Components} = window; // Prevent garbage collection in Firefox 3.6 and older var storage = (function() { if(!("Services" in window)) // Firefox 3.6 and older return Application.storage; // Simple replacement for Application.storage // See https://bugzilla.mozilla.org/show_bug.cgi?id=1090880 //var global = Components.utils.getGlobalForObject(Services); // Ensure, that we have global object (because window.Services may be overwritten) var global = Components.utils.import("resource://gre/modules/Services.jsm", {}); var ns = "_cbSourceEditorStorage"; // Note: Firefox 57+ returns NonSyntacticVariablesObject w/o .Object property var storage = global[ns] || (global[ns] = Components.utils.getGlobalForObject(global).Object.create(null)); return { get: function(key, defaultVal) { if(key in storage) return storage[key]; return defaultVal; }, set: function(key, val) { if(key === null) delete storage[key]; else storage[key] = val; } }; })(); var watcher = storage.get(watcherId, null); if(!watcher) { watcher = { REASON_STARTUP: 1, REASON_SHUTDOWN: 2, REASON_WINDOW_LOADED: 3, REASON_WINDOW_CLOSED: 4, get obs() { delete this.obs; return this.obs = Components.classes["@mozilla.org/observer-service;1"] .getService(Components.interfaces.nsIObserverService); }, get ww() { delete this.ww; return this.ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] .getService(Components.interfaces.nsIWindowWatcher); }, get wm() { delete this.wm; return this.wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator); }, get platformVersion() { delete this.platformVersion; return this.platformVersion = parseFloat(Services.appinfo.platformVersion); }, get hasCodeMirror() { delete this.hasCodeMirror; return this.hasCodeMirror = Services.appinfo.name == "Pale Moon" //~ todo: test || this.platformVersion >= 27; }, init: function(reason) { if(!this.hasCodeMirror) { this.isBrowserWindow = function() { return false; }; } this.obs.addObserver(this, "quit-application-granted", false); var ws = this.wm.getEnumerator(null); while(ws.hasMoreElements()) this.initWindow(ws.getNext(), reason); this.ww.registerNotification(this); }, destroy: function(reason) { this.obs.removeObserver(this, "quit-application-granted"); var ws = this.wm.getEnumerator(null); while(ws.hasMoreElements()) this.destroyWindow(ws.getNext(), reason); this.ww.unregisterNotification(this); }, initWindow: function(window, reason, isFrame) { if(this.isBrowserWindow(window)) { this.initBrowserWindow(window, reason); return; } if(!this.isEditorWindow(window)) return; _log("initWindow(): isFrame: " + isFrame); var document = window.document; if(isFrame) window.addEventListener("unload", this, false); Components.classes["@mozilla.org/moz/jssubscript-loader;1"] .getService(Components.interfaces.mozIJSSubScriptLoader) .loadSubScript("chrome://global/content/globalOverlay.js", window); var isCodeMirror = false; try { // See chrome://browser/content/devtools/scratchpad.js Components.utils.import("resource:///modules/source-editor.jsm", window); } catch(e) { var loader = this.platformVersion >= 44 // See https://bugzilla.mozilla.org/show_bug.cgi?id=912121 ? "resource://devtools/shared/Loader.jsm" : "resource://gre/modules/devtools/Loader.jsm"; var g = Components.utils.import(loader, {}); var require = (g.devtools || g).require; [ "devtools/sourceeditor/editor", "devtools/client/sourceeditor/editor", // Firefox 44+ "devtools/client/shared/sourceeditor/editor" // Firefox 68+ ].some(function(path) { try { return window.SourceEditor = require(path); } catch(e) { } return null; }); isCodeMirror = true; } var SourceEditor = window.SourceEditor; if(this.platformVersion >= 73) { var psXUL = '<popupset id="sourceEditorPopupset">\ <linkset>\ <html:link rel="localization" href="toolkit/global/textActions.ftl" />\ </linkset>\ <menupopup id="sourceEditorContext"\ onpopupshowing="popupHandler(event.target)"\ oncommand="popupHandler(event.target)">\ \ <menuitem id="menu_undo" data-l10n-id="text-action-undo" />\ <menuitem id="menu_redo" data-l10n-id="text-action-redo" />\ <menuseparator/>\ <menuitem id="menu_cut" data-l10n-id="text-action-cut" />\ <menuitem id="menu_copy" data-l10n-id="text-action-copy" />\ <menuitem id="menu_paste" data-l10n-id="text-action-paste" />\ <menuitem id="menu_delete" data-l10n-id="text-action-delete" />\ <menuseparator/>\ <menuitem id="menu_selectAll" data-l10n-id="text-action-select-all" />\ <menuseparator/>\ <menuitem id="menu_find" label="&findCmd.label;" accesskey="&findCmd.accesskey;" />\ <menuitem id="menu_findAgain" label="&findAgainCmd.label;" accesskey="&findAgainCmd.accesskey;" />\ <menuseparator/>\ <menuitem id="se-menu-gotoLine" label="&gotoLineCmd.label;" accesskey="&gotoLineCmd.accesskey;" />\ </menupopup>\ </popupset>'; var ps = window.MozXULElement.parseXULToFragment(psXUL, [ "chrome://global/locale/editMenuOverlay.dtd", "chrome://devtools/locale/sourceeditor.dtd" ]); if(!this.popupHandler) { var commands = {module: {}}; ps.querySelectorAll("menuitem").forEach(function(menuitem) { commands[menuitem.id] = menuitem.id.replace(/^(se-)?menu./, "cmd_"); }); Services.scriptloader.loadSubScript( "resource://devtools/client/shared/sourceeditor/editor-commands-controller.js", commands ); var createController = function(editor) { var res = editor.popupCmdController = commands.createController(editor); res.docShell = editor.container.contentWindow.docShell; return res; } var getObj = function(cmd, controller) { return controller.supportsCommand(cmd) ? controller: controller.docShell; } var setDisabled = function(menuitem) { var cmd = commands[menuitem.id]; menuitem.disabled = !getObj(cmd, this).isCommandEnabled(cmd); } this.popupHandler = function(node) { var ed = node.ownerDocument.activeElement.contentWindow.editor; var controller = ed.popupCmdController || createController(ed); var cmd = commands[node.id]; if(cmd) getObj(cmd, controller).doCommand(cmd); else node.menuitems.forEach(setDisabled, controller); } } var popup = ps.querySelector("menupopup"); popup.menuitems = popup.querySelectorAll("menuitem"); popup.popupHandler = this.popupHandler; } else { // See view-source:chrome://browser/content/devtools/scratchpad.xul // + view-source:chrome://browser/content/devtools/source-editor-overlay.xul var psXUL = (isCodeMirror ? '<!DOCTYPE popupset [\ <!ENTITY % editMenuStrings SYSTEM "chrome://global/locale/editMenuOverlay.dtd">\ %editMenuStrings;\ <!ENTITY % sourceEditorStrings SYSTEM "' + ( Services.appinfo.name == "Pale Moon" || Services.appinfo.name == "Basilisk" ? this.platformVersion >= 4.1 ? "chrome://devtools/locale/sourceeditor.dtd" : "chrome://global/locale/devtools/sourceeditor.dtd" : this.platformVersion >= 45 ? "chrome://devtools/locale/sourceeditor.dtd" : "chrome://browser/locale/devtools/sourceeditor.dtd" ) + '">\ %sourceEditorStrings;\ ]>\ <popupset id="sourceEditorPopupset"\ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">\ <menupopup id="sourceEditorContext"\ onpopupshowing="goUpdateSourceEditorMenuItems()">\ <menuitem id="menu_undo" label="&undoCmd.label;" accesskey="&undoCmd.accesskey;"\ oncommand="goDoCommand(\'cmd_undo\')" />\ <menuitem id="menu_redo" label="&redoCmd.label;" accesskey="&redoCmd.accesskey;"\ oncommand="goDoCommand(\'cmd_redo\')" />\ <menuseparator/>\ <menuitem id="menu_cut" label="&cutCmd.label;" accesskey="&cutCmd.accesskey;"\ oncommand="goDoCommand(\'cmd_cut\')" />\ <menuitem id="menu_copy" label="©Cmd.label;" accesskey="©Cmd.accesskey;"\ oncommand="goDoCommand(\'cmd_copy\')" />\ <menuitem id="menu_paste" label="&pasteCmd.label;" accesskey="&pasteCmd.accesskey;"\ oncommand="goDoCommand(\'cmd_paste\')" />\ <menuitem id="menu_delete" label="&deleteCmd.label;" accesskey="&deleteCmd.accesskey;"\ oncommand="goDoCommand(\'cmd_delete\')" />\ <menuseparator/>\ <menuitem id="menu_selectAll" label="&selectAllCmd.label;" accesskey="&selectAllCmd.accesskey;"\ oncommand="goDoCommand(\'cmd_selectAll\')" />\ <menuseparator/>\ <menuitem id="menu_find" label="&findCmd.label;" accesskey="&findCmd.accesskey;" />\ <menuitem id="menu_findAgain" label="&findAgainCmd.label;" accesskey="&findAgainCmd.accesskey;" />\ <menuseparator/>\ <menuitem id="se-menu-gotoLine"\ label="&gotoLineCmd.label;"\ accesskey="&gotoLineCmd.accesskey;"\ key="key_gotoLine"\ oncommand="goDoCommand(\'cmd_gotoLine\')"/>\ </menupopup>\ </popupset>' : '<popupset id="sourceEditorPopupset"\ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">\ <menupopup id="sourceEditorContext"\ onpopupshowing="goUpdateSourceEditorMenuItems()">\ <menuitem id="se-menu-undo"/>\ <menuitem id="se-menu-redo"/>\ <menuseparator/>\ <menuitem id="se-menu-cut"/>\ <menuitem id="se-menu-copy"/>\ <menuitem id="se-menu-paste"/>\ <menuitem id="se-menu-delete"/>\ <menuseparator/>\ <menuitem id="se-menu-selectAll"/>\ <menuseparator/>\ <menuitem id="se-menu-find"/>\ <menuitem id="se-menu-findAgain"/>\ <menuseparator/>\ <menuitem id="se-menu-gotoLine"/>\ </menupopup>\ </popupset>' ).replace(/>\s+</g, "><"); var ps = this.parseXULFromString(psXUL); // "Edit Custom Button in Tab" button, Firefox 71+ if(isFrame && "parseFromSafeString" in window.DOMParser.prototype) ps = window.MozXULElement.parseXULToFragment(ps.outerHTML); } document.documentElement.appendChild(ps); window.setTimeout(function() { function appendNode(nodeName, id) { var node = document.createElementNS(xulns, nodeName); node.id = id; document.documentElement.appendChild(node); } appendNode("commandset", "editMenuCommands"); appendNode("commandset", "sourceEditorCommands"); appendNode("keyset", "sourceEditorKeys"); appendNode("keyset", "editMenuKeys"); this.loadOverlays( window, function done() { window.setTimeout(function() { var mp = document.getElementById("sourceEditorContext"); if(mp.state == "closed") return; Array.prototype.forEach.call( mp.getElementsByAttribute("command", "*"), function(mi) { var cmd = mi.getAttribute("command"); var controller = document.commandDispatcher .getControllerForCommand(cmd); if(controller && !controller.isCommandEnabled(cmd)) mi.setAttribute("disabled", "true"); } ); }, 0); if(!isCodeMirror) return; // See view-source:chrome://browser/content/devtools/scratchpad.xul in Firefox 27.0a1 window.goUpdateSourceEditorMenuItems = function() { goUpdateGlobalEditMenuItems(); var commands = ["cmd_undo", "cmd_redo", "cmd_cut", "cmd_paste", "cmd_delete"]; commands.forEach(goUpdateCommand); }; var cmdsMap = { "se-menu-undo": "cmd_undo", "se-menu-redo": "cmd_redo", "se-menu-cut": "cmd_cut", "se-menu-copy": "cmd_copy", "se-menu-paste": "cmd_paste", "se-menu-delete": "cmd_delete", __proto__: null }; for(var id in cmdsMap) { var mi = document.getElementById(id); mi && mi.setAttribute("command", cmdsMap[id]); } // We can't use command="cmd_selectAll", menuitem will be wrongly disabled sometimes var enabledCmdsMap = { "se-menu-selectAll": "cmd_selectAll", "se-menu-findAgain": "cmd_findAgain", __proto__: null }; for(var id in enabledCmdsMap) { var mi = document.getElementById(id); if(mi) { mi.removeAttribute("command"); mi.removeAttribute("disabled"); mi.setAttribute("oncommand", "goDoCommand('" + enabledCmdsMap[id] + "');"); } } // Workaround: emulate keyboard shortcut var keyCmdsMap = { "menu_find": { keyCode: KeyboardEvent.DOM_VK_F, charCode: "f".charCodeAt(0), ctrlKey: true }, "menu_findAgain": { keyCode: KeyboardEvent.DOM_VK_G, charCode: "g".charCodeAt(0), ctrlKey: true }, __proto__: null }; var _key = function() { var e = this._keyData; var evt = document.createEvent("KeyboardEvent"); evt.initKeyEvent( "keydown", true /*bubbles*/, true /*cancelable*/, window, e.ctrlKey || false, e.altKey || false, e.shiftKey || false, e.metaKey || false, e.keyCode || 0, e.charCode || 0 ); document.commandDispatcher.focusedElement.dispatchEvent(evt); }; for(var id in keyCmdsMap) { var mi = document.getElementById(id); if(mi) { mi.removeAttribute("command"); mi.removeAttribute("disabled"); mi.setAttribute("oncommand", "this._key();"); mi._keyData = keyCmdsMap[id]; mi._key = _key; } } // Fix styles for autocomplete tooltip function css(uri) { document.insertBefore(document.createProcessingInstruction( "xml-stylesheet", 'href="' + uri + '" type="text/css"' ), document.documentElement); } css("resource://devtools/client/themes/variables.css"); css("resource://devtools/client/themes/common.css"); css("chrome://devtools/skin/tooltips.css"); if(this.platformVersion >= 68) window.setTimeout(function fixSelection() { var sheets = document.styleSheets; for(var i = sheets.length - 1; i >= 0; --i) { var sheet = sheets[i]; if(sheet.href != "resource://devtools/client/themes/common.css") continue; try { var rules = sheet.cssRules; } catch(e) { // InvalidAccessError: // A parameter or an operation is not supported by the underlying object return window.setTimeout(fixSelection, 10); } for(var j = 0, len = rules.length; j < len; ++j) if(rules[j].selectorText == "::selection") return !sheet.deleteRule(j); break; } return false; }, 10); }.bind(this), ["chrome://global/content/editMenuOverlay.xul", function check(window) { return window.document.getElementById("editMenuCommands").hasChildNodes(); }], ["chrome://browser/content/devtools/source-editor-overlay.xul", function check(window) { return window.document.getElementById("sourceEditorCommands").hasChildNodes(); }] ); }.bind(this), 500); // We should wait to not break other extensions with document.loadOverlay() var tabs = document.getElementById("custombuttons-editbutton-tabbox"); var selectedPanel = tabs.selectedPanel; Array.prototype.slice.call(document.getElementsByTagName("cbeditor")).forEach(function(cbEditor) { if("__sourceEditor" in cbEditor) return; var code = cbEditor.value; var isCSS = options.cssInHelp && cbEditor.id == "help"; if(isCodeMirror) { var opts = { mode: isCSS ? SourceEditor.modes.css : SourceEditor.modes.js, value: code, lineNumbers: true, enableCodeFolding: true, showTrailingSpace: true, autocomplete: true, contextMenu: "sourceEditorContext" }; var optsOvr = options.codeMirror; for(var opt in optsOvr) if(optsOvr.hasOwnProperty(opt)) opts[opt] = optsOvr[opt]; var se = new SourceEditor(opts); if("codeMirror" in se) window.setTimeout(function() { if("insertCommandsController" in se) se.insertCommandsController(); // Pale Moon and Basilisk else this.insertCommandsController(se); }.bind(this), 200); } else { var se = new SourceEditor(); } se.__isCodeMirror = isCodeMirror; var seElt = document.createElementNS(xulns, "hbox"); if(cbEditor.id) seElt.id = "sourceEditor-" + cbEditor.id; seElt.className = "sourceEditor"; seElt.setAttribute("flex", 1); seElt.__sourceEditor = se; cbEditor.parentNode.insertBefore(seElt, cbEditor); //cbEditor.setAttribute("hidden", "true"); cbEditor.setAttribute("collapsed", "true"); cbEditor.parentNode.appendChild(cbEditor); cbEditor.__sourceEditor = se; cbEditor.__sourceEditorElt = seElt; cbEditor.__defineGetter__("value", function() { if("__sourceEditor" in this) { var se = this.__sourceEditor; if(!se.__initialized) return se.__value; return se.getText().replace(/\r\n?|\n\r?/g, "\n"); } return this.textbox.value; }); cbEditor.__defineSetter__("value", function(v) { if("__sourceEditor" in this) { var se = this.__sourceEditor; if(!se.__initialized) { var _this = this; se.__onLoadCallbacks.push(function() { _this.value = v; }); return se.__value = v; } return se.setText(v.replace(/\r\n?|\n\r?/g, "\n")); } return this.textbox.value = v; }); cbEditor.selectLine = function(lineNumber) { if("__sourceEditor" in this) { var se = this.__sourceEditor; if(!se.__initialized) { var _this = this, args = arguments; se.__onLoadCallbacks.push(function() { _this.selectLine.apply(_this, args); }); return undefined; } if(se.__isCodeMirror) { //se.focus(); //se.setCursor({ line: lineNumber - 1, ch: 0 }); //~ todo: optimize var val = this.value; var lines = val.split("\n"); var line = Math.min(lineNumber - 1, lines.length); var ch = lines[line].length; se.focus(); return se.setSelection({ line: line, ch: 0 }, { line: line, ch: ch }); } else { var selStart = se.getLineStart(lineNumber - 1); var selEnd = se.getLineEnd(lineNumber - 1, false); se.focus(); return se.setSelection(selStart, selEnd); } } return this.__proto__.selectLine.apply(this, arguments); }; // For edit_button() from chrome://custombuttons/content/editExternal.js seElt.__cbEditor = cbEditor; seElt.__defineGetter__("localName", function() { return "cbeditor"; }); seElt.__defineGetter__("value", function() { return this.__cbEditor.value; }); seElt.__defineSetter__("value", function(val) { this.__cbEditor.value = val; }); se.__initialized = false; se.__onLoadCallbacks = []; se.__value = code; var onTextChanged = se.__onTextChanged = function() { window.editor.changed = true; }; var isLoaded = reason == this.REASON_WINDOW_LOADED; function done() { se.__initialized = true; se.__onLoadCallbacks.forEach(function(fn) { try { fn(); } catch(e) { Components.utils.reportError(e); } }); delete se.__onLoadCallbacks; delete se.__value; } if(isCodeMirror) { se.appendTo(seElt).then(function() { try { se.setupAutoCompletion(); } catch(e) { Components.utils.reportError(e); } if("setFontSize" in se) try { se.setFontSize(options.codeMirror.fontSize); } catch(e) { Components.utils.reportError(e); } window.setTimeout(function() { window.editor.changed = false; // Strange... window.setTimeout(function() { // Workaround for unexpected onTextChanged() calls if(window.editor.changed && cbEditor.value == code) window.editor.changed = false; }, 100); se.on("change", onTextChanged); if(isLoaded) { if("clearHistory" in se) se.clearHistory(); else { var seGlobal = Components.utils.getGlobalForObject(SourceEditor.prototype); // Note: this is resource://app/modules/devtools/gDevTools.jsm scope in Firefox 34+ var cm = seGlobal.editors.get(se); cm.clearHistory(); } } }, isFrame ? 50 : 15); // Oh, magic delays... done(); // See resource:///modules/devtools/sourceeditor/editor.js // doc.defaultView.controllers.insertControllerAt(0, controller(this, doc.defaultView)); var controllers = window.controllers; // nsIControllers var controller = se.__cmdController = controllers.getControllerAt(0); if("__cmdControllers" in tabs) tabs.__cmdControllers.push(controller); else { tabs.__cmdControllers = [controller]; var onSelect = tabs.__onSelect = function() { var seElt = tabs.selectedPanel; if(!seElt || !("__sourceEditor" in seElt)) return; var se = seElt.__sourceEditor; var curController = se.__cmdController; tabs.__cmdControllers.forEach(function(controller) { try { if(controller == curController) controllers.insertControllerAt(0, controller); else controllers.removeController(controller); } catch(e) { } }); }; tabs.addEventListener("select", onSelect, false); window.setTimeout(onSelect, 0); // Activate controller from selected tab } }); } else { var opts = { mode: isCSS ? SourceEditor.MODES.CSS : SourceEditor.MODES.JAVASCRIPT, showLineNumbers: true, initialText: code, placeholderText: code, // For backward compatibility contextMenu: "sourceEditorContext" }; var optsOvr = options.orion; for(var opt in optsOvr) if(optsOvr.hasOwnProperty(opt)) opts[opt] = optsOvr[opt]; se.init(seElt, opts, function callback() { done(); isLoaded && se.resetUndo && se.resetUndo(); se.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onTextChanged); // Hack to use selected editor var controller = se.ui._controller; controller.__defineGetter__("_editor", function() { var seElt = tabs.selectedPanel; var se = seElt && seElt.__sourceEditor || document.getElementsByTagName("cbeditor")[0].__sourceEditor; return se; }); controller.__defineSetter__("_editor", function() {}); }); } }, this); // Trick to select correct tab (especially if was selected "Button settings" tab) tabs.tabs.advanceSelectedTab(1, true); tabs.tabs.advanceSelectedTab(-1, true); var origExecCmd = window.editor.execute_oncommand_code; window.editor.execute_oncommand_code = function() { var cd = document.commandDispatcher; var cdFake = { __proto__: cd, get focusedElement() { var selectedTab = tabs.selectedTab; if(selectedTab && selectedTab.id == "code-tab") return document.getElementById("code").textbox.inputField; return cd.focusedElement; } }; document.__defineGetter__("commandDispatcher", function() { return cdFake; }); try { var ret = origExecCmd.apply(this, arguments); } catch(e) { Components.utils.reportError(e); } // document.hasOwnProperty("commandDispatcher") == false, so we cat just delete our fake property delete document.commandDispatcher; return ret; }; window.addEventListener("load", function ensureObserversAdded() { window.removeEventListener("load", ensureObserversAdded, false); window.setTimeout(function() { window.editor.removeObservers(); }, 0); window.setTimeout(function() { window.editor.addObservers(); }, 0); }, false); // Fix for Ctrl+S hotkey (catched by CodeMirror) var hke = this.handleKeyEvent; window.addEventListener("keydown", hke, true); window.addEventListener("keypress", hke, true); window.addEventListener("keyup", hke, true); }, insertCommandsController: function(se) { this.insertCommandsController = insertCommandsController; return insertCommandsController(se); // devtools/client/sourceeditor/editor-commands-controller in Pale Moon/Basilisk function createController(ed) { return { supportsCommand: function (cmd) { switch (cmd) { case "cmd_find": case "cmd_findAgain": case "cmd_gotoLine": case "cmd_undo": case "cmd_redo": case "cmd_delete": case "cmd_selectAll": return true; } return false; }, isCommandEnabled: function (cmd) { let cm = ed.codeMirror; switch (cmd) { case "cmd_find": case "cmd_gotoLine": case "cmd_selectAll": return true; case "cmd_findAgain": return cm.state.search != null && cm.state.search.query != null; case "cmd_undo": return ed.canUndo(); case "cmd_redo": return ed.canRedo(); case "cmd_delete": return ed.somethingSelected(); } return false; }, doCommand: function (cmd) { let cm = ed.codeMirror; let map = { "cmd_selectAll": "selectAll", "cmd_find": "find", "cmd_undo": "undo", "cmd_redo": "redo", "cmd_delete": "delCharAfter", "cmd_findAgain": "findNext" }; if (map[cmd]) { cm.execCommand(map[cmd]); return; } if (cmd == "cmd_gotoLine") { ed.jumpToLine(); } }, onEvent: function () {} }; } function insertCommandsController(sourceEditor) { let input = sourceEditor.codeMirror.getInputField(); let controller = createController(sourceEditor); input.controllers.insertControllerAt(0, controller); } }, destroyWindow: function(window, reason, isFrame) { if(reason == this.REASON_WINDOW_CLOSED) window.removeEventListener(this.loadEvent, this, false); // Window can be closed before DOMContentLoaded if(this.isBrowserWindow(window)) { this.destroyBrowserWindow(window, reason); return; } if(!this.isEditorWindow(window) || !("SourceEditor" in window)) return; _log("destroyWindow(): isFrame: " + isFrame); var document = window.document; if(isFrame) window.removeEventListener("unload", this, false); var tabs = document.getElementById("custombuttons-editbutton-tabbox"); if("__onSelect" in tabs) { tabs.removeEventListener("select", tabs.__onSelect, false); delete tabs.__onSelect; delete tabs.__cmdControllers; } Array.prototype.slice.call(document.getElementsByTagName("cbeditor")).forEach(function(cbEditor) { if(!("__sourceEditor" in cbEditor)) return; var se = cbEditor.__sourceEditor; var isCodeMirror = se.__isCodeMirror; if(isCodeMirror) se.off("change", se.__onTextChanged); else se.removeEventListener(window.SourceEditor.EVENTS.TEXT_CHANGED, se.__onTextChanged); delete se.__onTextChanged; if(reason == this.REASON_SHUTDOWN) { var val = cbEditor.value; delete cbEditor.value; delete cbEditor.selectLine; var seElt = cbEditor.__sourceEditorElt; seElt.parentNode.insertBefore(cbEditor, seElt); seElt.parentNode.removeChild(seElt); delete cbEditor.__sourceEditorElt; delete cbEditor.__sourceEditor; delete seElt.__sourceEditor; delete seElt.__cbEditor; cbEditor.value = val; window.setTimeout(function() { cbEditor.removeAttribute("collapsed"); }, 0); } se.destroy(); if("__cmdController" in se) { try { window.controllers.removeController(se.__cmdController); } catch(e) { } delete se.__cmdController; } }, this); if(reason == this.REASON_SHUTDOWN) { delete window.editor.execute_oncommand_code; [ "sourceEditorPopupset", "editMenuCommands", "sourceEditorCommands", "sourceEditorKeys", "editMenuKeys" ].forEach(function(id) { var node = document.getElementById(id); node && node.parentNode.removeChild(node); }); [ // chrome://global/content/globalOverlay.js "closeWindow", "canQuitApplication", "goQuitApplication", "goUpdateCommand", "goDoCommand", "goSetCommandEnabled", "goSetMenuValue", "goSetAccessKey", "goOnEvent", "visitLink", "setTooltipText", "NS_ASSERT", // chrome://global/content/editMenuOverlay.xul => view-source:chrome://global/content/editMenuOverlay.js "goUpdateGlobalEditMenuItems", "goUpdateUndoEditMenuItems", "goUpdatePasteMenuItems" ].forEach(function(p) { delete window[p]; }); for(var child = document.documentElement; child = child.previousSibling; ) { if( child.nodeType == child.PROCESSING_INSTRUCTION_NODE && child.data.indexOf("://devtools/") != -1 ) { setTimeout(function(child) { child.parentNode.removeChild(child); }, 0, child); } } delete window.SourceEditor; } var hke = this.handleKeyEvent; window.removeEventListener("keydown", hke, true); window.removeEventListener("keypress", hke, true); window.removeEventListener("keyup", hke, true); //~ todo: we have one not removed controller! //LOG("getControllerCount(): " + window.controllers.getControllerCount()); }, initBrowserWindow: function(window, reason) { _log("initBrowserWindow()"); window.addEventListener("DOMContentLoaded", this, false); Array.prototype.forEach.call(window.frames, function(frame) { this.initWindow(frame, reason, true); }, this); }, destroyBrowserWindow: function(window, reason) { _log("destroyBrowserWindow()"); window.removeEventListener("DOMContentLoaded", this, false); Array.prototype.forEach.call(window.frames, function(frame) { this.destroyWindow(frame, reason, true); }, this); }, isEditorWindow: function(window) { return window.location.href.substr(0, 41) == "chrome://custombuttons/content/editor.xul"; }, isBrowserWindow: function(window) { var loc = window.location.href; return loc == "chrome://browser/content/browser.xul" || loc == "chrome://browser/content/browser.xhtml" // Firefox 69+ || loc == "chrome://navigator/content/navigator.xul"; }, get loadEvent() { // "DOMContentLoaded" -> initWindow() may hang editor window (and browser) delete this.loadEvent; return this.loadEvent = this.platformVersion >= 73 ? "load" : "DOMContentLoaded"; }, observe: function(subject, topic, data) { if(topic == "quit-application-granted") this.destroy(); else if(topic == "domwindowopened") subject.addEventListener(this.loadEvent, this, false); else if(topic == "domwindowclosed") this.destroyWindow(subject, this.REASON_WINDOW_CLOSED); }, handleEvent: function(e) { switch(e.type) { case "DOMContentLoaded": case "load": //var window = e.currentTarget; var window = e.target.defaultView || e.target; window.removeEventListener(e.type, this, false); var isFrame = window != e.currentTarget; this.initWindow(window, this.REASON_WINDOW_LOADED, isFrame); break; case "unload": //var window = e.currentTarget; var window = e.target.defaultView || e.target; window.removeEventListener(e.type, this, false); this.destroyWindow(window, this.REASON_WINDOW_CLOSED, true); } }, handleKeyEvent: function(e) { if( (e.keyCode == e.DOM_VK_S || String.fromCharCode(e.charCode).toUpperCase() == "S") && e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey ) { e.preventDefault(); e.stopPropagation(); if(e.type == "keydown") { var window = e.currentTarget; window.editor.updateButton(); } } }, loadOverlays: function() { this.runGenerator(this.loadOverlaysGen, this, arguments); }, get loadOverlaysGen() { var fn = this._loadOverlaysGen.toString() .replace(/__yield/g, "yield"); try { new Function("function test() { yield 0; }"); } catch(e) { // Firefox 58+: SyntaxError: yield expression is only valid in generators fn = fn.replace("function", "function*"); // Firefox 26+ } delete this.loadOverlaysGen; return this.loadOverlaysGen = eval("(" + fn + ")"); }, _loadOverlaysGen: function loadOverlaysGen(window, callback/*, overlayData1, ...*/) { var gen = loadOverlaysGen.__generator; for(var i = 2, l = arguments.length; i < l; ++i) { var overlayData = arguments[i]; this.loadOverlay(window, overlayData[0], overlayData[1], function() { gen.next(); }); __yield(0); } callback(); __yield(0); }, loadOverlay: function(window, uri, check, callback) { var document = window.document; var stopWait = Date.now() + 4500; window.setTimeout(function load() { _log("loadOverlay(): " + uri); var tryAgain = Date.now() + 800; try { document.loadOverlay(uri, null); } catch(e) { window.setTimeout(callback, 0); return; } window.setTimeout(function ensureLoaded() { if(check(window)) window.setTimeout(callback, 0); else if(Date.now() > stopWait) return; else if(Date.now() > tryAgain) window.setTimeout(load, 0); else window.setTimeout(ensureLoaded, 50); }, 50); }, 0); }, runGenerator: function(genFunc, context, args) { var gen = genFunc.apply(context, args); genFunc.__generator = gen; gen.next(); }, parseXULFromString: function(xul) { xul = xul.replace(/>\s+</g, "><"); try { return new DOMParser().parseFromString(xul, "application/xml").documentElement; } catch(e) { // See http://custombuttons.sourceforge.net/forum/viewtopic.php?f=5&t=3720 // + https://forum.mozilla-russia.org/viewtopic.php?pid=732243#p732243 var dummy = document.createElement("dummy"); dummy.innerHTML = xul.trimLeft(); return dummy.firstChild; } } }; storage.set(watcherId, watcher); setTimeout(function() { watcher.init(watcher.REASON_STARTUP); }, 50); } function destructor(reason) { if(reason == "update" || reason == "delete") { watcher.destroy(watcher.REASON_SHUTDOWN); storage.set(watcherId, null); } } if( typeof addDestructor == "function" // Custom Buttons 0.0.5.6pre4+ && addDestructor != ("addDestructor" in window && window.addDestructor) ) addDestructor(destructor, this); else this.onDestroy = destructor; function ts() { var d = new Date(); var ms = d.getMilliseconds(); return d.toTimeString().replace(/^.*\d+:(\d+:\d+).*$/, "$1") + ":" + "000".substr(("" + ms).length) + ms + " "; } function _log(s) { Services.console.logStringMessage("[Custom Buttons :: Source Editor] " + ts() + s); }
({ title: "Консоль браузера", 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: `SidebarUI.toggle("${id}");` }, document.getElementById("viewSidebarMenu")); var btn = this.element("toolbarbutton", { type: "checkbox", label: this.title, id: "sidebar-switcher-browserConsole", oncommand: `SidebarUI.show("${id}");`, class: "subviewbutton subviewbutton-iconic" }); document.querySelector( 'toolbarbutton[id^="sidebar-switcher-"] + toolbarseparator' ).before(btn); SidebarUI.sidebars.set(id, { url: this.url, buttonId: btn.id, title: this.title, menuId: menuitem.id }); SidebarUI.isOpen && SidebarUI.currentID == id && 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(() => { 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 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 = 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; "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 = "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();
этот код сдох?
Зачем? Теперь есть аддоны, что ни черта не настраиваются без мультирежима...
Да, сдох, уже давно, что неоднократо перетёрто.
И да, видимо стоит повторить, что конфигурация отсутствия отдельных XPCOM процессов
заявлена мазилой как нетестируемая и как неподдерживающаяся. Или, проще говоря, «вас нет».
Отсутствует
Dumby спасибо
Отсутствует
Можно сделать скрипт, который до открытия страницы включает/выключает прокси в зависимости от открываемого URL ?
Хотелось бы автоматически менять настройки прокси и затем открывать конкретные url (список заблокированных провайдером) http://flibusta.is https://rutracker.org https://nnm-club.me …
network.proxy.type = 0 или 2
network.proxy.autoconfig_url = https://antizapret.prostovpn.org/proxy.pac (или пусто)
Dumby - а можно пост «Merge Date» перенести в постоянное место (или тему) ? Так новичкам будет проще искать.
И в этот пост только дописывать конфиги, указывая версию браузера. То есть примерно так:
«Merge Date» Firefox 68
custom_buttons-0.0.7.0.0.6-fx-paxmod.xpi
custom_buttons-0.0.7.0.0.6-fx-bootstrap.xpi
скрипты bootstrap-loader.js и config.js
«Merge Date» Firefox 79+
тоже самое…
Отсутствует
Можно сделать скрипт, который до открытия страницы включает/выключает прокси в зависимости от открываемого URL ?
Для этого давным-давно, был придуман механизм и файл proxy.pac Proxy Auto Configuration (PAC), PAC – файл автоконфигурации
я так в ВК хожу
// Alternate Proxy Server const tor = "SOCKS5 127.0.0.1:9050", browsec = "SOCKS 127.0.0.1:49736", usurf = "SOCKS5 127.0.0.1:9666", zabor = "SOCKS5 socks.zaborona.help:1488", deny = "PROXY 127.0.0.1:65535"; // Default localhost for denied connections let ukroBanned = [ "ria.ru", "vk.com","vk.cc","vk.me","vkuservideo.com","vkuservideo.net","vk-cdn.net","vkontakte.ru", "userapi.com", "mail.ru","ok.ru","yandex.ru","yandex.ua","yandex.net","yandex.com", "yadi.sk", "kinopoisk.ru" ]; function FindProxyForURL (url, host) { let addr; if ( dnsDomainIs(host, ".onion") ) return tor; for (addr of ukroBanned) { if ( host === addr || dnsDomainIs(host, "." + addr) ) return zabor; // return tor; // return usurf; } };
...программисты словно войну какую-то ведут за свои обновления. Блин, почему сейчас повсюду мания ухудшать интерфейсы и делать их максимально неудобными?! Radiation
Отсутствует