Скачал комплект UserChromeFiles - 2021-9-23. Обновил/перезаписал все файлы по нужным папкам.
Скрипты подключились и заработали сразу, а вот стили ни один не подключился.
Ранее в файле custom_style_user.css было прописано следующее содержимое и всё работало:
/* Этот файл для правил CSS с правами USER_SHEET */ /* значки папок закладок желтого цвета */ @import url("./css/Colored-folders-91.css"); /* скрыть элементы меню закладок */ @import url("./css/hide_bookmarks_elements.css"); /* скрыть элементы контекстного меню на странице */ @import url("./css/hide_context_elements.css"); /* убрать history-dropmarker из адресной строки */ @import url("./css/history-dropmarker.css"); /* компактная панель поиска сверху справа */ @import url("./css/findbar_compakt.css"); /* панель быстрого поиска такая хе, как и полного поиска */ @import url("./css/findbar_show_full_quickfindbar.css"); /* в приложении GISMETEO - белый шрифт значка погоды */ @import url("./css/gismeteo.css"); /* изменение высоты панели вкладок, компактное меню (Proton) */ @import url("./css/bar_compact_proton.css");
Отсутствует
Inko7
Так все стили по умолчанию отключены в CustomStylesScripts.jsm (зачем включать пустые файлы, они там только для примера)
можете изменить это в styleschrome (стили подключенные в styleschrome работают там же где и userChrome.css)
ну или в stylesall: [ // Для всех документов
И вместо @import можно просто подключить ваши файлы там же в CustomStylesScripts.jsm, например
{ path: "css/Colored-folders-91.css", type: "USER_SHEET", sheet(f) { preloadSheet(this, f); }, },
Отредактировано Vitaliy V. (10-10-2021 14:44:28)
Отсутствует
Vitaliy V.
вот теперь все стили заработали, спасибо!
получается, раз скрипты заработали сразу, то файлы custom_script.js / custom_script_all_win.js / custom_script_win.js обрабатываются изначально и их прописывать дополнительно не нужно?
Отсутствует
файлы custom_script.js / custom_script_all_win.js / custom_script_win.js обрабатываются изначально и их прописывать дополнительно не нужно?
custom_script.js добавлен в CustomStylesScripts.jsm, но его можно удалить, переименовать,
а custom_script_all_win.js / custom_script_win.js обрабатываются изначально и их прописывать, удалять, переименовывать нельзя
Отсутствует
Vitaliy V.
Вы можете написать скрипт отключающий отображение пунктов контекстного меню, с определенным в скрипте ID, для разных контекстов. С перечислением исключений для каждого добавленного пользователем ID. Что-то типа:
"#context-copy" this.hidden = gContextMenu.onLink || gContextMenu.onMailtoLink || gContextMenu.onImage || gContextMenu.onCanvas;
"#other-addon" this.hidden = gContextMenu.onTextInput || gContextMenu.isContentSelected;
Например, #context-copy появляется везде при выделенном на странице тексте, но главное здесь расширения, очень часто они добавляют свои пункты без учета контекста.
Второй пример, сепараторы, при переупорядочивании меню некоторые сепараторы надо удалить только для определенных контекстов.
И, если будете делать, добавьте примеры, в том числе для контекстов: фрейм, страница, вкладка, адресная строка и textarea (если такой есть отдельно от .onTextInput).
ps^ и есть ли контексты в закладках панели - папка, отдельныя закладка? Видел расширение которое добавляло свой пункт и туда и туда, а нужно было только для папок.
Отредактировано _zt (15-10-2021 13:27:40)
Отсутствует
_zt
не я пас, не охота это делать, что касается расширений это их проблемы, апи позволяет учитывать контекст, все зависит от разраба расширения.
если не заметили недавно обновил ваши скрипты
https://forum.mozilla-russia.org/viewto … 24#p784824
https://forum.mozilla-russia.org/viewto … 55#p783755
Отсутствует
Vitaliy V.
SidebarTabs обновлял, там беда со сплиттером
оставил так и выкинул after
#st_splitter { -moz-appearance: none !important; appearance: none !important; background-color: var(--chrome-content-separator-color, rgba(127,127,127,.5)) !important; background-clip: content-box !important; border-inline: 1px solid transparent !important; min-width: 3px !important; margin-inline: -1px !important; position: relative !important; z-index: 2 !important; -moz-box-ordinal-group: ${this.ST_RIGHT ? "100" : "0"} !important; -moz-box-orient: vertical !important;
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" width="16" height="16"><path d="M4 1C1.804688 1 0 2.800781 0 5L0 15C0 17.195313 1.804688 19 4 19L6.3125 19L8.0625 23.375C8.207031 23.765625 8.582031 24.027344 9 24.027344C9.417969 24.027344 9.792969 23.765625 9.9375 23.375L11.6875 19L22 19C24.195313 19 26 17.195313 26 15L26 5C26 2.800781 24.195313 1 22 1 Z M 4 3L22 3C23.117188 3 24 3.882813 24 5L24 15C24 16.113281 23.113281 17 22 17L11 17C10.589844 16.996094 10.214844 17.242188 10.0625 17.625L9 20.28125L7.9375 17.625C7.785156 17.242188 7.410156 16.996094 7 17L4 17C2.886719 17 2 16.113281 2 15L2 5C2 3.882813 2.882813 3 4 3Z" fill="#D0D0D0" /></svg>
Отредактировано _zt (16-10-2021 11:38:37)
Отсутствует
оставил так и выкинул after
надо только добавил
border: none !important;
background: none !important;
отображение заголовка перед адресом более удобно, как их местами поменять?
// el.title = title = `${href}${title === "" ? "" : `\nTitle: ${title}`}`;
el.title = title = `${title === "" ? "" : `Title: ${title}\nUrl: `}${href}`;
Но сначала обновите все полностью, я там изменил немного
Отредактировано Vitaliy V. (16-10-2021 14:20:10)
Отсутствует
поправить вот этот скрипт для 94.0
Заменить residentSetSize и residentUniqueSize на memory
как добавить двойной клик на UCF-кнопку, чтобы вместе с ним не срабатывало событие "click" ?
скрытый текстВыделить кодКод:
try { CustomizableUI.createWidget({ id: "add-additional-personaltoolbar-button", type: "custom", localized: false, label: "Панели, Папки", tooltiptext: `ЛКМ: ★ Закладки\n…+ Alt Домашняя папка ПКМ: ⟳ История\n…+ Alt Папка установки СКМ: Папка профиля\n…+ Alt user_chrome_files`, onBuild(doc) { var trbn = doc.createXULElement("toolbarbutton"); trbn.id = this.id; trbn.tooltipText = this.tooltiptext; trbn.label = this.label; trbn.className = "toolbarbutton-1 chromeclass-toolbar-additional"; trbn.setAttribute("context", false); trbn.style.setProperty("list-style-image", `url("chrome://user_chrome_files/content/vertical_top_bottom_bar/svg/bookmark-16.svg")`, "important"); trbn.addEventListener("dblclick", function(e) { e.view.alert("DBL Click"); }, false); trbn.explorer =(dir, subdir = undefined)=> { var dirs = Services.dirsvc.get(dir, Ci.nsIFile); if (subdir) dirs.append(subdir); if (dirs.exists()) dirs.launch(); }; trbn.bar =(bar)=> { var win = Services.wm.getMostRecentWindow("navigator:browser"); if ("SidebarUI" in win) win.SidebarUI.toggle(bar); else if ("toggleSidebar" in win) win.toggleSidebar(bar); }; trbn.addEventListener("click", function(e) { if (e.button == 0) e.altKey ? trbn.explorer("Home") : trbn.bar("viewBookmarksSidebar") else if (e.button == 1) e.altKey ? trbn.explorer("UChrm", "user_chrome_files") : trbn.explorer("ProfD") else if (e.button == 2) e.altKey ? trbn.explorer("GreD") : trbn.bar("viewHistorySidebar") }, false); return trbn; }, }); } catch(e) {}
С помощью таймаута наверно, как же ещё.
(async (bar, exp, tid, self) => CustomizableUI.createWidget(self = { label: "Панели, Папки", tooltiptext: [ "ЛКМ: ★ Закладки\n…+ Alt Домашняя папка", "ПКМ: ⟳ История\n…+ Alt Папка установки", "СКМ: Папка профиля\n…+ Alt user_chrome_files" ].join("\n"), id: "add-additional-personaltoolbar-button", localized: false, onCreated(btn) { btn.onclick = this.click; btn.style.setProperty("list-style-image", "url(chrome://user_chrome_files/content/vertical_top_bottom_bar/svg/bookmark-16.svg)", "important"); }, exec(num, win) { tid = null; self[num](win); }, context: win => win.document.getElementById(self.id) .dispatchEvent(new win.MouseEvent("contextmenu", self.a)), a: {__proto__: null, bubbles: true, screenX: 0, screenY: 0}, click(e) { if (e.detail > 2) return; var n2 = e.button != 2; var dbl = e.detail == 2; var num = 16 * e.button + 8 * e.ctrlKey + 4 * e.shiftKey + 2 * e.altKey + dbl; if (!self[num]) { if (n2) return; num = "context"; for(var p in self.a) self.a[p] = e[p]; } n2 || e.preventDefault(); var win = e.view; if (dbl) tid &&= win.clearTimeout(tid), self[num](win); else tid = win.setTimeout(self.exec, 300, num, win); }, 0: w => bar(w, "viewBookmarksSidebar"), // ЛКМ 2: () => exp("Home"), // Alt+ЛКМ 16: () => exp("ProfD"), // СКМ 18: () => exp("UChrm", "user_chrome_files"), // Alt+СКМ 32: w => bar(w, "viewHistorySidebar"), // ПКМ 34: () => exp("GreD"), // Alt+ПКМ 1(win) { // Double Left Click win.alert("DBL Click"); }, 33(win) { // Double Right Click win.alert("DBL Right Click"); }, 29(win) { // Ctrl + Shift + Double Middle Click win.alert("Ctrl + Shift + DBL Middle Click"); }, }))( (win, bar) => win.SidebarUI.toggle(bar), (dir, sub) => { dir = Services.dirsvc.get(dir, Ci.nsIFile); sub && dir.append(sub); dir.exists() && dir.launch(); } );
Отсутствует
Vitaliy V.
Подскажите пожалуйста, как в этом скрипте запретить AutoPopup на некоторых кнопках? И спасибо за скрипт!
Add, вроде получилось что хотел, удалил из скрипта часть кода: this.ExtensionParent.WebExtensionPolicy.getByID(id).extension . Правильно ли я это сделал? Нужно было отключить AutoPopup значков расширений.
Add, и ешё вопрос, для чего нужен этот скрипт?
Отредактировано kokoss (12-11-2021 09:54:23)
Win7
Отсутствует
Dumby - Спасибо, скрипт очень компактный и крутой, но в двойной клик на UCF-кнопке правый клик мыши работает неверно.
Вместе с правым кликом в MacOS и вероятно Linux открывается контекстное меню панели, пробовал отключить и не получилось:
var reset = e => e.target.linkedObject = this; var id, lo = {click: e => n2 || reset(e)}; var lin = /macos|linux/.test(e.view.AppConstants.platform); var stop = e => reset(e) && e.preventDefault(); lo.contextmenu = lin ? e => e.ctrlKey || e.shiftKey ? 0 : stop(e) : stop; n2 || reset(e) && e.preventDefault(); ……
Dumby - ещё просьба по твоему скрипту перехвата кликов на кнопках > добавить Двойной клик (у меня не удалось):
Конкретно - добавить двойной клик на "PanelUI-menu-button" (строка 133) и по возможности на "downloads-button"…
Второе (если это возможно) > изменить способ перехвата кнопок со стандартного addEventListener на такой же «продвинутый», как и в новом скрипте,
то есть способом: var num = 16 * e.button + 8 * e.ctrlKey + 4 * e.shiftKey + 2 * e.altKey + dbl;
(async (id, func) => { // дополнительные клики на downloads-button, PanelUI-menu для custom_script_win.js await window.delayedStartupPromise; var btn = document.getElementById("downloads-button"), pui = document.getElementById("PanelUI-menu-button"); if (!btn) return; btn.tooltipText = GetDynamicShortcutTooltipText(btn.id) +` ПКМ: Сохранить как единый html всё | выделенное на странице …+ Shift Обзор папки [Загрузки]\n Ролик: Сохранить как файл .txt …+ Shift Сайт: графика Вкл/Выкл\n Колёсико на рисунке: ➜ Сохранить Двойной клик: найти Похожие фото`, PanelUI_help = `Браузер Firefox, версия ${Services.appinfo.platformVersion}\n Колёсико: Развернуть | окно …+ Alt Полный экран Правый клик ⇲ Свернуть …+ Shift Закрыть ✕ …+ Alt Персонализация`; var addDestructor = nextDestructor => { var {destructor} = ucf[id]; ucf[id].destructor = () => { try {destructor();} catch(ex) {Cu.reportError(ex);} nextDestructor(); } }, showInStatusPanel = (info, time = 5000) => { var win = Services.wm.getMostRecentWindow("navigator:browser"); StatusPanel = win.StatusPanel; if (StatusPanel.update.tid) clearTimeout(StatusPanel.update.tid) else { var {update} = StatusPanel; StatusPanel.update = () => {}; StatusPanel.update.ret = () => { StatusPanel.update = update; StatusPanel.update(); } } StatusPanel.update.tid = setTimeout(StatusPanel.update.ret, time); StatusPanel._label = info; }, saveSelectionToTxt = async () => { // сохранить страницу или выделенный текст как файл .txt var splice = saveURL.length == 10; var msgName = id + ":Save:GetSelection"; var receiver = msg => { var title = document.title || gBrowser.selectedTab.label; var args = [ "data:text/plain," + encodeURIComponent(gBrowser.currentURI.spec + "\n\n" + msg.data), title.replace(/[:\\\/<>?*|"]+/g,'_').replace(/\s+/g,' ').slice(0, 100).trim() + '_' + new Date().toLocaleString('ru').replace(', ','-').replace(/:/g, '։') + '.txt', null, false, true, null, window.document ]; splice && args.splice(5, 0, null); saveURL(...args) && showInStatusPanel("√ текст сохранён: " + title.slice(0, 60)); } messageManager.addMessageListener(msgName, receiver); addDestructor(() => messageManager.removeMessageListener(msgName, receiver)); var func = fm => { var res, fed, win = {}, fe = fm.getFocusedElementForWindow(content, true, win); var sel = (win = win.value).getSelection(); if (sel.isCollapsed) { var ed = fe && fe.editor; if (ed && ed instanceof Ci.nsIEditor) sel = ed.selection, fed = fe; } if (sel.isCollapsed) fed && fed.blur(), docShell.doCommand("cmd_selectAll"), res = win.getSelection().toString(), docShell.doCommand("cmd_selectNone"), fed && fed.focus(); res = res || sel.toString(); /\S/.test(res) && sendAsyncMessage("saveSelectionToTxt", res); } var url = "data:;charset=utf-8," + encodeURIComponent(`(${func})`.replace("saveSelectionToTxt", msgName)) + '(Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager));'; (saveSelectionToTxt = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))(); }, // end save = async () => { // автор: Лекс, правка: Dumby, Dobrov (пути сохранения HTML) var msgName = id + "ucfDwnldsBtnSaveSnapshotToHTML"; if (typeof IOUtils != "object") { // Firefox 78 ESR var {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); var PathUtils = {join: (...args) => OS.Path.join(...args)}; var IOUtils = {writeUTF8: (path, txt) => OS.File.writeAtomic(path, new TextEncoder().encode(txt))}; } var write = IOUtils.writeUTF8 ? "writeUTF8" : "writeAtomicUTF8"; var Title = (type) => { // получить заголовок (без обрезки, если type не указан) или домен (type <0) var title = (document.title || gBrowser.selectedTab.label); if ( !type ) return title; // заголовок if ( type > 0 ) return title.slice(0, type).replace(/ \| Форум Mozilla Россия$| — Mozilla Firefox|[\\\/?*\"'`]+/g,'').replace(/\s+/g,' ').replace(/[|<>]+/g,'_').replace(/:/g,'։').trim(); // ограничить длину имени var host = (/^file:\/\//.test(gURLBar.value)) ? '' : gURLBar.value.replace(/^.*url=|https?:\/\/|www\.|\/.*/g,''); return host.replace(/^ru\.|^m\.|forum\./,'').replace(/^club\.dns/,'dns'); } var msgListener = async msg => { var [fileContent, fileName] = msg.data, dir; try {dir = prefs.getComplexValue("browser.download.dir", Ci.nsIFile);} catch {dir = dirsvc.get("DfltDwnld", Ci.nsIFile);} var arr = prefs.getStringPref("ucf_save.dirs", "_Web||_Images|0").split('|').slice(0, 2); // Dir/subdir: пусто|0 title|1 домен arr[1] = (arr[1] == "0") ? Title(100) : (arr[1] == "1") ? Title(-1) : ""; // имя вкладки или домен arr.forEach(dir.append); // для ucf_save.dirs = "_Web||_Pics|1" HTML сохранится в папку [Загрузки]/_Web/имя вкладки dir.exists() && dir.isDirectory() || dir.create(dir.DIRECTORY_TYPE, 0o777); // создать папку, если не существует… var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); file.initWithPath(dir.path); dir.append(fileName); await IOUtils[write](dir.path, fileContent) && showInStatusPanel("√ страница записана: " + fileName.slice(0, 60)); var d = await Downloads.createDownload({ source: "about:blank", target: FileUtils.File(dir.path)}); // Fake download (await Downloads.getList(Downloads.ALL)).add(d); d.refresh(d.succeeded = true); // кнопка Загрузки мигает } messageManager.addMessageListener(msgName, msgListener); addDestructor(() => messageManager.removeMessageListener(msgName, msgListener)); var svc = 'globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services'; var url = "data:;charset=utf8," + encodeURIComponent(`(${func})(${svc});`.replace("%MSG_NAME%", msgName)); (save = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))(); }, // end save listener = e => { var trg = e.target; // Downloads Clicks if (e.button == 1) { if (e.shiftKey) { // СКМ + Shift if ( prefs.getIntPref("permissions.default.image", 1) == 1) prefs.setIntPref("permissions.default.image", 2), trg.style.filter = "hue-rotate(180deg) brightness(95%)" else prefs.setIntPref("permissions.default.image", 1), trg.style.filter = ""; BrowserReload(); } else // СКМ Click saveSelectionToTxt(); // сохранить .txt } else if (e.button == 2) { if (e.shiftKey) Downloads.getSystemDownloadsDirectory().then(path => FileUtils.File(path).launch(), Cu.reportError) // Обзор папки «Загрузки» else // ПКМ Click save(); // Single HTML } }, listener_pui = e => { // PanelUI-menu Clicks if (e.button == 1) { if (e.altKey) window.BrowserFullScreen() else if( window.windowState != window.STATE_MAXIMIZED ) window.maximize() else window.restore(); } else if (e.button == 2) if (e.altKey) return else { e.stopPropagation(); (e.shiftKey) ? window.close() : window.minimize(); } }, // end Clicks keydown_win = e => { // нажатие клавиш if (!(e.keyCode == 83 && e.shiftKey && e.altKey)) return; var singlesave = document.getElementById(save_ex); // SingleSave singlesave ? singlesave.click() : save(); // имитировать клик по кнопке, используя её ID }, {prefs, dirsvc} = Services, tmax = btn.tooltipText.split("\n")[0].length, save_ex = "_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action"; btn.setAttribute("context", "event.stopPropagation()"); prefs.setBoolPref("browser.download.autohideButton", false); // не скрывать кнопку Загрузки (async () => { // SingleSave - дополнить подсказку setTimeout((but = document.getElementById(save_ex))=> { if (but) btn.tooltipText = btn.tooltipText + '\n\nAlt⇧S нажатие SingleSave'; if (!/Закрыть/.test(pui.tooltipText)) pui.tooltipText = PanelUI_help; }, 9000); // после запуска ждать от 3 сек })(); btn.addEventListener("click", listener), pui.addEventListener("click", listener_pui); window.addEventListener("keydown", keydown_win); var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win; ucf[id] = {destructor() { btn.removeEventListener("click", listener), pui.removeEventListener("click", listener_pui); window.removeEventListener("keydown", keydown_win); }}; ucf.unloadlisteners.push(id); })("downloads-button-click-listener", ({io, focus}) => { // SingleHTML не сохраняет svg графику var resolveURL = function (url, base) { try { return io.newURI(url, null, io.newURI(base)).spec; } catch {} }, getSelWin = function (w) { if (w.getSelection().toString()) return w; for (var i = 0, f, r; f = w.frames[i]; i++) { try { if (r = getSelWin(f)) return r; } catch(e) {} } }, encodeImg = function (src, obj) { var canvas, img, ret = src; if (/^https?:\/\//.test(src)) { canvas = doc.createElement('canvas'); if (!obj || obj.nodeName.toLowerCase() != 'img') { img = doc.createElement('img'); img.src = src; } else img = obj; if (img.complete) try{ canvas.width = img.width; canvas.height = img.height; canvas.getContext('2d').drawImage(img, 0, 0); ret = canvas.toDataURL((/\.jpe?g/i.test(src) ? 'image/jpeg' : 'image/png')); } catch (e) {}; if (img != obj) img.src = 'about:blank'; }; return ret; }, toSrc = function (obj) { var strToSrc = function (str) { var chr, ret = '', i = 0, meta = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\x22' : '\\\x22', '\\': '\\\\'}; while (chr = str.charAt(i++)) { ret += meta[chr] || chr; }; return '\x22' + ret + '\x22'; }, arrToSrc = function (arr) { var ret = []; for (var i = 0; i < arr.length; i++) { ret[i] = toSrc(arr[i]) || 'null'; }; return '[' + ret.join(',') + ']'; }, objToSrc = function (obj) { var val, ret = []; for (var prop in obj) { if (obj.hasOwnProperty(prop) && (val = toSrc(obj[prop]))) ret.push(strToSrc(prop) + ': ' + val); }; return '{' + ret.join(',') + '}'; }; switch (Object.prototype.toString.call(obj).slice(8, -1)) { case 'Array': return arrToSrc(obj); case 'Boolean': case 'Function': case 'RegExp': return obj.toString(); case 'Date': return 'new Date(' + obj.getTime() + ')'; case 'Math': return 'Math'; case 'Number': return isFinite(obj) ? String(obj) : 'null'; case 'Object': return objToSrc(obj); case 'String': return strToSrc(obj); default: return obj ? (obj.nodeType == 1 && obj.id ? 'document.getElementById(' + strToSrc(obj.id) + ')' : '{}') : 'null'; } }, mainWin = {}; focus.getFocusedElementForWindow(content, true, mainWin); mainWin = mainWin.value; var selWin = getSelWin(mainWin), win = selWin || mainWin, doc = win.document, loc = win.location; var ele, pEle, clone, reUrl = /(url\(\x22)(.+?)(\x22\))/g; if (selWin) { var rng = win.getSelection().getRangeAt(0); pEle = rng.commonAncestorContainer; ele = rng.cloneContents(); } else { pEle = doc.documentElement; ele = (doc.body || doc.getElementsByTagName('body')[0]).cloneNode(true); }; while (pEle) { if (pEle.nodeType == 1) { clone = pEle.cloneNode(false); clone.appendChild(ele); ele = clone; }; pEle = pEle.parentNode }; var sel = doc.createElement('div'); sel.appendChild(ele); for (var el, all = sel.getElementsByTagName('*'), i = all.length; i--;) { el = all[i]; if (el.style && el.style.backgroundImage) el.style.backgroundImage = el.style.backgroundImage.replace(reUrl, function (a, prev, url, next) { if (!/^[a-z]+:/.test(url)) url = resolveURL(url, loc.href); return prev + encodeImg(url) + next; }); switch (el.nodeName.toLowerCase()) { case 'link': case 'style': case 'script': el.parentNode.removeChild(el); break; case 'a': case 'area': if (el.hasAttribute('href') && el.getAttribute('href').charAt(0) != '#') el.href = el.href; break; case 'img': case 'input': if (el.hasAttribute('src')) el.src = encodeImg(el.src, el); break; case 'audio': case 'video': case 'embed': case 'frame': case 'iframe': if (el.hasAttribute('src')) el.src = el.src; break; case 'object': if (el.hasAttribute('data')) el.data = el.data; break; case 'form': if (el.hasAttribute('action')) el.action = el.action; break; } }; var head = ele.insertBefore(doc.createElement('head'), ele.firstChild), meta = doc.createElement('meta'), sheets = doc.styleSheets, title = doc.getElementsByTagName('title')[0]; meta.httpEquiv = 'content-type'; meta.content = 'text/html; charset=utf-8'; head.appendChild(meta); if (title) head.appendChild(title.cloneNode(true)); head.copyScript = function (unsafeWin) { if ('$' in unsafeWin) return; var f = doc.createElement('iframe'); f.src = 'about:blank'; f.setAttribute('style', 'position:fixed;left:0;top:0;visibility:hidden;width:0;height:0;'); doc.documentElement.appendChild(f); var str, script = doc.createElement('script'); script.type = 'text/javascript'; for (var name in unsafeWin) { if (name in f.contentWindow || !/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) continue; try { str = toSrc(unsafeWin[name]); if (!/\{\s*\[native code\]\s*\}/.test(str)) { script.appendChild(doc.createTextNode('var ' + name + ' = ' + str.replace(/<\/(script>)/ig, '<\\/$1') + ';\n')); } } catch (e) {}; }; f.parentNode.removeChild(f); if (script.childNodes.length) this.nextSibling.appendChild(script); }; head.copyScript(win.wrappedJSObject || win); head.copyStyle = function (s) { if (!s) return; var style = doc.createElement('style'); style.type = 'text/css'; if (s.media && s.media.mediaText) style.media = s.media.mediaText; try { for (var i = 0, rule; rule = s.cssRules[i]; i++) { if (rule.type != 3) { if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) { var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) { if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href); if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url); return prev + url + next; }); style.appendChild(doc.createTextNode(css + '\n')); } } else { this.copyStyle(rule.styleSheet); } } } catch(e) { if (s.ownerNode) style = s.ownerNode.cloneNode(false); }; this.appendChild(style); }; for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]); head.appendChild(doc.createTextNode('\n')); var doctype = '', dt = doc.doctype; if (dt && dt.name) { doctype += '<!DOCTYPE ' + dt.name; if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22'; if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22'; doctype += '>\n'; }; var fileName = selWin ? win.getSelection().toString() : (title && title.text ? title.text : loc.pathname.split('/').pop()); fileName = fileName.replace(/[:\\\/<>?*|"]+/g, '_').replace(/\s+/g, ' ').slice(0, 100).trim(); fileName += "_" + new Date().toLocaleDateString('ru', {day: 'numeric', month: 'numeric', year: '2-digit'}) +'-'+ new Date().toLocaleTimeString().replace(/:/g, "։"); if (!/\.html?$/.test(fileName)) fileName += '.html'; sendAsyncMessage("%MSG_NAME%", [doctype + sel.innerHTML +'\n<a href='+ (loc.protocol != 'data:' ? loc.href : 'data:uri') +'><small><blockquote>источник: '+ new Date().toLocaleString("ru") +'</blockquote></small></a>', fileName]); }); // END hookClicks
В скрипт Quick Toggle about:config тоже добавить Двойной клик на кнопке (в коде есть ещё Долгое нажатие)
// Quick Toggle Быстрое переключение параметров about:config для custom_script.js (async (name, id, func) => { // https://forum.mozilla-russia.org/viewtopic.php?pid=789824#p789824 if (name == "Object") return CustomizableUI.createWidget(func()); var win = name == "Window", g = Cu.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); // BEGIN QuickToggle… })(this.constructor.name, "ToggleAboutConfig", () => { var help = `клик+Alt Библиотека закладок …+ Shift ± zoom Текст/страница ։нажать Антизапрет ⇆ proxy\n ПКМ Меню быстрых настроек ։нажать © Краткая справка …+ Alt Опции about:config\n СКМ Вкладка «Топ сайтов» …+ Alt Восстановить вкладку …+ Shift ● Захват цвета, Zoom ։нажать Консоль браузера\n ⟳ Обновить ↯ Перезапуск ЛкМ: Левый клик, СкМ: Колёсико нажать: долгий клик мыши ≥1 сек`, // ЛКМ+Alt+Shift: настройки User Chrome Files. свободные hotkeys: СКМ+Alt ЛКМ+Alt+⇧ Нет в подсказке: ЛКМ панель Журнала, СКМ+Shift – Пипетка help_ucf = ['chrome://user_chrome_files/content/help.html', 'http://forum.puppyrus.org/index.php?topic=22762'], // Ctrl+Click или правый клик - сброс параметра по-умолчанию // клик по параметру с Shift блокирует авто-закрытие меню // строки с userAlt имеют шрифт italic // refresh: false - reload current tab, true - reload current tab skip cache // restart: false - restart browser, true - restart browser with confirm // Разделитель: Имя меню "—,⟳,↯" Опция, ⟳ обновить страницу, ↯ перезапуск браузера // иконки равны ключам: userChoice:зелёный, userAlt:жёлтый, userPro:серый, нет userChoice:серый, ни один:красный // пути сохранения Html/Pics в [Загрузки]/dir/subdir заданы в ucf_save.dirs="_Html dir|subdir|_Pics dir|subdir" : пусто|0 заголовок|1 домен // ucf_save.dirs="_Web||_Pics|1" save Html: [Загрузки]/_Web/имя страницы.html, save Pic: [Загрузки]/_Pics/имя вкладки/имя картинки {prefs, dirsvc} = Services, db = prefs.getDefaultBranch(""), my_vpn = "https://antizapret.prostovpn.org/proxy.pac", icon_vpn = "hue-rotate(270deg) brightness(95%)", menuactive = (AppConstants.platform == "macosx") ? '#e8e8e8' : '#124', // текст, подсвеченный курсором xul_ns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", fonts = ["Arial","Cantarell","DejaVu Sans","Roboto","PT Serif","Segoe UI","Ubuntu","Cambria","Fira Sans","Georgia","Noto Sans","Calibri","Times","системный"], font_pref = (font) => { return font.map(function(name) { // массив с вложениями return (name == font[font.length -1]) ? ["", name,,, `prefs.setIntPref("browser.display.use_document_fonts", 1)`] : [name, name,,, `prefs.setIntPref("browser.display.use_document_fonts", 0)`]; }); }, fontserif = font_pref(fonts), fontsans = [["PT Sans","PT Sans"], ...fontserif], dw; // путь загрузки try {dw = prefs.getComplexValue("browser.download.dir",Ci.nsIFile);} catch {dw = dirsvc.get("DfltDwnld", Ci.nsIFile);}; var secondary = [{ // pref … [apref, lab, akey, hint, js-code] pref: ["dom.disable_open_during_load", "Всплывающие окна"], userChoice: 2, userAlt: true, values: [[true, "Блокировать"], [false, "Разрешить"]] },{ pref: ["browser.safebrowsing.downloads.remote.block_dangerous", "Опасные файлы, сайты",,"browser.safebrowsing.downloads.remote.block_dangerous_host"], userChoice: true, userAlt: false, values: [[true, "Отключить",,,`prefs.setBoolPref('browser.safebrowsing.downloads.remote.block_dangerous_host',true)`], [false, "Загружать",,,`prefs.setBoolPref('browser.safebrowsing.downloads.remote.block_dangerous_host',false)`]] },{ pref: ["permissions.default.image", "Загрузка графики"], userChoice: 1, userAlt: 3, refresh: true, values: [[1, "Разрешена"], [3, "Только с сайта"], [2, "Отключить"]] },{ pref: ["ucf_save.dirs", `Сайт|Графика`,,`\nПути сохранения страниц | графики\n[Загрузки] — папка по-умолчанию${dw ? ":\n"+ dw.path : ""}`], userChoice: "_Сайты||_Фото|1", userAlt: "", userPro: "_Web||_Images|1", values: [ ["", "папка [Загрузки]"], // subdir: пусто | 0 заголовок | 1 домен [`_Сайты||_Фото|1`, "_Сайты|_Фото/имя…"], // _Web/host|_Pics/title [`_Сайты||_Рисунки|1`, "_Сайты|_Рисунки/…"], [`_Web||_Images|`, "_Web|_Images"], [`_Web||_Images|1`, "_Web|_Images/имя"], [`_Web||_Photo|1`, "_Web|_Photo/имя"], [`_Web|1|_Pics|0`, "_Web/сайт|_Pics/…"], [`_Web|1|_Pics|`, "_Web/сайт|_Pics"], [`_Web|1|_Images|0`, "ввести свои пути"]] // здесь нужно открыть about:config },null,{ pref: ["network.cookie.cookieBehavior", "Получать куки",, "\nПерсональные настройки посещённых сайтов"], userChoice: 3, userAlt: 0, userPro: 4, refresh: false, values: [[0, "со всех сайтов"], [3, "кроме не посещённых"], [4, "кроме трекеров"], [1, "кроме сторонних"], [2, "никогда"]] },{ pref: ["network.proxy.autoconfig_url", "Прокси (VPN) URL", "п"], userChoice: my_vpn, userAlt: "127.0.0.1", userPro: "", refresh: true, values: [ ["", "сброшен", ""], [my_vpn, "АнтиЗапрет", "1", "\nНадёжный доступ на заблокированные сайты\n«Режим прокси» меняется на 2", `prefs.setIntPref('network.proxy.type', 2); node.parentNode.parentNode.style.filter = icon_vpn;`], ["https://git.io/ac-anticensority-pac", "ac-anticensority", "2"], // ["localhost", "Tor Browser", "4", "Только для Linux, MacOS\nУстановите сервис: «tor»"], [prefs.getStringPref("user.pacfile", "file:///etc/proxy.pac"), "user .pac файл", "3"], // нужен диалог выбора pac-файла ["127.0.0.1", "local host", "0",, `prefs.setIntPref('network.proxy.type', 0); node.parentNode.parentNode.style.filter = '';`]] },{ pref: ["network.proxy.type", "Режим прокси", "р"], userChoice: 0, userAlt: 2, refresh: true, values: [ [0, "Без прокси", "0", "по-умолчанию"], [5, "Системные (из IE)", "5"], [2, "Автонастройка", "2", "about:config - user.pacfile"], [1, "Ручная настройка", "1", "Используется network.proxy.autoconfig_url"], [4, "Автоопределение", "4"] ] },{ // pref: ["network.proxy.share_proxy_settings", "Все протоколы через прокси"], userAlt: true, refresh: true, // values: [[true, "Да", "", "Прокси для всех протоколов при ручной настройке"], [false, "Нет"]] // },{ pref: ["network.trr.mode", "DNS поверх HTTPS",, "\nШифрование DNS-трафика для\nзащиты персональных данных"], userChoice: 1, userAlt: 2, userPro: 5, refresh: true, values: [ [0, "по-умолчанию", "0"], [1, "автоматически", "1", "используется DNS или DoH, в зависимости от того, что быстрее"], [2, "DoH, затем DNS", "2"], [3, "только DoH", "3"], [4, "DNS и DoH", "4"], [5, "отключить DoH", "5"] ] },null,{ pref: ["browser.zoom.full", "Масштабировать"], userChoice: false, userAlt: true, values: [[true, "всю страницу"], [false, "только текст"]] },{ pref: ["font.name.sans-serif.x-cyrillic", "Шрифт без засечек ",,"\nТакже влияет на всплывающие подсказки\nСистемный: загрузка шрифтов документа"], userAlt: "", values: fontsans },{ pref: ["font.name.serif.x-cyrillic", "Шрифт с засечками"], userAlt: "", values: fontserif },{ pref: ["image.animation_mode", "Анимация изображений"], userChoice: "none", userAlt: "normal", refresh: true, values: [["none", "Выключена"], ["normal", "По циклу"], ["once", "Единожды"]] },null,{ pref: ["media.autoplay.default", "Авто-play аудио/видео"], userChoice: 0, userAlt: 2, userPro: 5, refresh: true, values: [ [0, "Разрешить", "0"], [2, "Спрашивать", "2"], [1, "Запретить", "1"], [5, "Блокировать", "5"]] },{ pref: ["media.autoplay.blocking_policy", "Автозапуск (политика)"], userChoice: 1, userAlt: 2, refresh: true, values: [[1, "Временная", "1"], [2, "По действию", "2"], [0, "Постоянная", "0"]] },{ pref: ["gfx.webrender.all", "Аппаратное ускорение графики"], userChoice: true, refresh: true, values: [[true, "Да"], [false, "Нет"]] },{ pref: ["gfx.webrender.force-disabled", "Web render disabled", , "gfx.webrender.compositor.force-enabled\n\nАппаратная отрисовка страниц видеокартой.\nотключите при разных проблемах с графикой"], userChoice: false, restart: true, values: [ [true, "Да",,, `prefs.setBoolPref("gfx.webrender.compositor.force-enabled", false)`], [false, "Нет",,, `prefs.setBoolPref("gfx.webrender.compositor.force-enabled", true)`]] },null,{ pref: ["network.http.sendRefererHeader", "Referer: для чего"], userChoice: 2, userAlt: 1, values: [[0, "Ни для чего", "0"], [1, "Только ссылки", "1"], [2, "Ссылки, графика", "2"]] },{ pref: ["dom.storage.enabled", "Локальное хранилище",, "\nСохранение персональных данных, по\nкоторым вас можно идентифицировать"], userChoice: false, userAlt: true, values: [[true, "Разрешить"], [false, "Запретить"]] },{ pref: ["privacy.resistFingerprinting", "Изоляция Firstparty-Fingerprint", ,"privacy.firstparty.isolate\n\nЗащита данных пользователя также\nзапрещает запоминать размер окна"], userChoice: false, values: [[true, "Да", , "Защита от слежки",`prefs.setBoolPref('privacy.firstparty.isolate', true);`], [false, "Нет", , "Защита от слежки",`prefs.setBoolPref('privacy.firstparty.isolate', false);`]] },{ pref: ["media.peerconnection.enabled", "WebRTC ваш реальный IP"], userChoice: false, values: [[true, "Выдать"], [false, "Скрыть"]] },null,{ pref: ["browser.tabs.remote.force-enable", "Многопоточный режим вкладок",,"\nПо-умолчанию режим разрешён"], userChoice: null, userAlt: true, userPro: false, values: [[true, "Да"], [false, "Нет"]] },{ pref: ["javascript.enabled", "Выполнять скрипты Java",,"\nПоддержка интерактивных сайтов (и рекламы)"], userChoice: true, refresh: true, values: [[true, "Да"], [false, "Нет"]] },{ pref: ["browser.cache.disk.capacity", "Кэш браузера",,"browser.cache.memory.enable\n\ncache.memory.max_entry_size:\nдиск и память: 5120\nтолько память: -1"], userChoice: 1048576, userAlt: 0, values: [ [1048576, "Диск и Память",,, `prefs.setBoolPref("browser.cache.memory.enable", true); prefs.setBoolPref("browser.cache.disk.enable", true); prefs.setIntPref('browser.cache.memory.max_entry_size', 5120)`], [0, "только Память",,, `prefs.setBoolPref("browser.cache.memory.enable", true); prefs.setBoolPref("browser.cache.disk.enable", false); prefs.setIntPref('browser.cache.memory.max_entry_size', -1)`], [2097152, "только Диск",,, `prefs.setBoolPref("browser.cache.memory.enable", false); prefs.setBoolPref("browser.cache.disk.enable", true)`]] },{ pref: ["dom.enable_performance", "Статус загрузки страницы",,"\nПередача данных разрешит определять\nфакт использования прокси-сервера"], userAlt: true },{ pref: ["general.useragent.override", "User Agent",,"\nот user-агент зависит вид сайтов"], userChoice: null, userAlt: "Mozilla/5.0 (Android 9; Mobile; rv:68.0) Gecko/68.0 Firefox/68.0", userPro: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:68.0) Gecko/20100101 Firefox/68.0", refresh: true, values: [ (arr => { var pref = "general.useragent.override"; var has = prefs.prefHasUserValue(pref); if (has) { var val = prefs.getStringPref(pref); prefs.clearUserPref(pref); } var ua = Cc["@mozilla.org/network/protocol;1?name=http"] .getService(Ci.nsIHttpProtocolHandler).userAgent; // текущий юзерагент has && prefs.setStringPref(pref, val); var find = node => node.pref && node.pref.pref == pref; var redef = (doc, hint) => { var popup = doc.getElementById("ToggleAboutConfig-secondaryPopup"); var menuitem = Array.from(popup.children).find(find).menupopup.firstChild; menuitem.tooltipText = hint ? ua + "\n" + hint : ua; menuitem.setAttribute("oncommand", `event.stopPropagation(); this.closest("toolbarbutton").linkedObject.contextmenu({ preventDefault: Boolean, target: this.parentNode.parentNode });` ); } Object.defineProperty(arr, "0", {enumerable: true, get() { if (Components.stack.formattedStack.includes("createRadios")) { var win = Services.wm.getMostRecentWindow("navigator:browser"); win.setTimeout(redef, 0, win.document, this[3]); } else return ""; }}); return arr; })([null, "По-умолчанию"]), ["Mozilla/5.0 (Android 9; Mobile; rv:68.0) Gecko/68.0 Firefox/68.0", "Firefox Android9"], ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:68.0) Gecko/20100101 Firefox/68.0", "Firefox 68 MacOSX"], ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", "Chrome61 Win10"], ["Mozilla/5.0 (Windows NT 6.1; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0", "Firefox 56"], ["Mozilla/5.0 (X11; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0", "Firefox 56 Linux"], ["Mozilla/5.0 (Windows; U; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)", "MSIE 6.0 Windows"], ["Mozilla/5.0 (Linux; Android 7.0; PLUS Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", "Chrome61 Android7"], ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.1 Safari/603.1.30", "Safari 6 MacOSX"], ["Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12 Version/12.16", "Opera12 W8"], ["Mozilla/5.0 (Linux; Android 5.1.1; SM-G928X Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.83 Mobile Safari/537.36", "Samsung Galaxy S6"], ["Mozilla/5.0 (PlayStation 4 3.11) AppleWebKit/537.73 (KHTML, like Gecko)", "Playstation 4"], ["Xbox (Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586", "Xbox One (mobile)"], ["Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586", "Microsoft Lumia 950"], ["Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; GT-I8350)", "Windows Phone"], ["Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", "GoogleBot"]] },{ pref: ["browser.cache.disk.free_space_soft_limit", "Неактивные вкладки",, "\nПри запуске загружаются все вкладки,\nэто может замедлить работу браузера.\nОптимально - Выгружать старые табы."], userChoice: 5121, userAlt: 5120, userPro: 5122, values: [ [5120, "Загружать",,, `prefs.setBoolPref("browser.sessionstore.restore_on_demand", true); prefs.setBoolPref("browser.tabs.unloadOnLowMemory", false)`], [5121, "Оптимально",, "Выгружать старые вкладки, экономя память", `prefs.setBoolPref("browser.sessionstore.restore_on_demand", true); prefs.setBoolPref("browser.tabs.unloadOnLowMemory", true)`], [5122, "Не загружать",,, `prefs.setBoolPref("browser.sessionstore.restore_on_demand", false); prefs.setBoolPref("browser.tabs.unloadOnLowMemory", true)`]] }]; return { label: "Quick Toggle Settings", id: "ToggleAboutConfig", tooltiptext: help, localized: false, image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAADhUlEQVR4AaWUIYzsNhCG91WVelKfqoWrpwMLFxQYGhoGBgYGBgYGGhoGBhoGGhoaBhoaGhqcdIFhf+dGt2n09rpq1ZE+2bHl+eyxd0993yVjNIwxq9F6/WjtaNd5nBnq85g2PMeMo8EwDEUI0Z7+jm/EY2it87ZtuAf1EUqAzZZZcuCxnyOlBFoLkuhnkgdBjBG36YqzP+EaTqgmSckyjrGuK8paWGythVLKfv/9t/O/OkEIC6pZoskCfanQuQYLSTm2/ZQkjSil8Pc8z6iqyp/P58tn2l92wWjGnEuG9gO6uUVtaygnMOQaU+nR+hotjfeugwmaHNv9pJzYOYcQAp+kbVv3cBJrbA45QIQLVLyizRI6t5R8gC0aY+nQZYWK5lT4E3nNn2XaiJX5PAmLXl9fuweBz54X97mCoYR21SwYc8+yjsbrKKGCvAu4TDnne3IO7z2oTP1RwCVKJXGJ+rlHaxu0ocZQahLWaO4lmjtov5eI7yDZFnFqWXQUPL1kFzwaV3GpmqQo+cMlc1li9MBCyacbUnC74MePy3NBiAukFRDLBTd/QWUVUk44BJclx5lMPVYvEJ3e7+CZYN+dSw5TmpiQA1/oPTYip4SV5gANRIloa5Ku/LKeCqhljrHmhLzMSIFYPGLw3N/KCMAAuUYeBUkXLDE9vCIW0K45MbXYoW/aFZdiyxYoM9Y0oiwGaxyBjcAElAHFCETTw40T6tvVXP749eUfBe/v78xdlJaAvNwTGmo1YYiRIME6YosGxWnEaUDQbXFt5adazKO6DEcBX97b29tRAq4tl0XzpZKAkzJFEx31iY1bYuANIBtkW6engl1CRD6JAYrh5Mg90QBRAYsgbkAkksS2VJvT0jXqUj0R7HzOrViCQ1kGILZAUAQl9AxLVl/BDTI24tyK1+/8n/SVYOexVDMlaQAvAHdjOHmQLPS6grxe9ZeviDgKuM/jzIZM38kbbE4ekguGBV7CDwLXy1k/vKJtPf4ODmAPFhbf74mLa5DmFltQwCKJCskIiPNpprTi42+bRcaYTIv3Z/oVhcgpUrIOm1NYbIvZWtjJIliSLgpIFdZZohMvgQRqFyilRimFF0I4+QXik7ZR3vRqqSsRpJSO1jEf/bFXGUsNhAq2uWS63eb0X+NjN/uuforb9UXYXjqEBkkLyMupP85/I/53fDzLsZV6am8zCdR9/C+4MZTbZ2zc/gAAAABJRU5ErkJggg==", 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, "secondary", secondary); this.createCloseMenusOption(doc, btn); if (prefs.getIntPref('network.proxy.type') == 2) btn.style.filter = icon_vpn; // btn.style.cssText = "background-image: -moz-linear-gradient(#c0c8c0, #c0c8c0, #c0c8c0) !important"; btn.linkedObject = this; for(var type of ["command", "contextmenu", "mousedown", "auxclick"]) // события btn.setAttribute("on" + type, `linkedObject.${type}(event)`); this.addSheet(btn); }, addSheet(btn) { var cb = Array.isArray(btn._destructors); var id = cb ? btn.id : "ToggleAboutConfig"; var css = `#${id} menu[_moz-menuactive] { color: ${menuactive} !important; }`; var args = [ "data:text/css;charset=utf-8," + encodeURIComponent(css), Ci.nsIDOMWindowUtils.USER_SHEET ]; if (cb) var destructor = function() { this.removeSheetUsingURIString(...args); } var add = b => b.ownerGlobal.windowUtils.loadSheetUsingURIString(...args); (this.addSheet = !cb ? add : btn => { add(btn); btn._destructors.push({destructor, context: btn.ownerGlobal.windowUtils}); })(btn); }, 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, hint] = val; pref.pref = apref; pref.lab = lab || apref; if (hint) pref.hint = hint; } 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`]; var map, set = prefs[`set${str}Pref`]; if (pref.hasVals) { for(var [val, , , , code] of obj.values) code && (map || (map = new Map())).set(val, code); if (map) pref.set = (key, val) => { set(key, val); map.has(val) && eval(map.get(val)); // выполнить код } } if (!map) pref.set = set; 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 = "ToggleAboutConfig.closeMenus"; var data = [null, { pref: [pn, "Закрывать меню этой кнопки"], values: [[true, "Да"], [false, "Нет"]] }]; var setCloseMenus = (e, trg = e.target) => { e.stopPropagation(); var {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: dimgray !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); }, UserImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAe1BMVEUAAAB1dXV1dXV1dXV1dXV1dXV1dXV1dXV8fHyRkZGfn5+oqKipqamqqqqysrKzs7O6urq8vLy9vb3ExMTFxcXHx8fNzc3Ozs7Pz8/Q0NDY2NjZ2dna2tre3t7g4ODi4uLj4+Pk5OTl5eXn5+fs7Ozv7+/w8PDx8fHy8vLK4aRZAAAACHRSTlMAGFiAiNDw+LBTincAAACRSURBVBgZBcFBTsMADAAwJ20pqjgM+P8TgQua2Nok2AAAAiIzdfcgkOv2/ub357yaIF8+jwgz969nS7He9pnumf22hrSse1d1V/W+LlIc3d1V3d1HCPsHkWjj+5FUTVdVTdcQtmMNkXrMdT/Dur0KYYy/8wqx7QugHucE+bIFmPPZArkuS+qqqwmIzNTdAwAA/zI6Uy+Vzu5KAAAAAElFTkSuQmCC", // серый UserChoiceImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABGElEQVR4AWKgPgAQSmbgEsNQFB53GHz43GGcioPF4mCxGCwWi8FiMBgMBoPFYOzOPWf2/cv3Z/3P7Wo2W2VQolIJ59zb/grvlfLnO1lWJ7lmwDn2cEbnY3jciF0XSTUqSfKZRCLP4NB9c9tlyrOE4iXUwMAd2OMZHLiPj2O0uUZcWcQXp3jKsQTAuSeODlxm7grEIRmxZZal2EuhOxjEGR24yNwXqHOe5MQsdtVCq72He+DiIfNQYMxGwJRHhdIzPLs4zwViGw4ypF5MGsiYIBLML/t04D49gja7kz4eyEB6yiQCnhG4zDx/xsa30sUL3RMtgXP5jO9+JApt2L+DZ3C+/o2sbv9l5xsNtYBz7B0HS8qUZSZqAwCSaKMMRS9J3wAAAABJRU5ErkJggg==", // зелёный notUserChoiceImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABDElEQVR4Aa2TK3CEQBBEt6JwdxKJRJ48GRkZiURGxqt4dV5FnkQikSdXIpHIweE6+8KKyf+7Va92qqe770v493MOoUw8JGJizcSslV+Fm3NRWLxrZUMnzaOAGY0dng/DXVnK+kdpGhKXFI4CZjR2ePC+edu0W3eSYieNPQEPGjvhwUuG7FXuuK+b691uX4Sw2obBmkHbwIOXjC+4qY61D+d5Bq89g5eML6hpxvQd8JLxBXk5uxsM3p05vmBcJhfmnrkzbmaHl4wv6KfL5IKuZHbFecZLxhecxiEuiwVX4nBhPHjJvP0j7QtZe5TaWmqqdG8wo7HD8+m/MWHxUMluDym0wYzGDs/fHqb/Pk9WVkDcHStz1AAAAABJRU5ErkJggg==", // красный UserAltImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABAklEQVR4Aa2TKVDEQBREx3sRiUQi8Wpl5MqVSCQyMhIZGYlciVy5cmQkEhk5runHNQf3kapX9ev36w97hX9/xk3ozGCiScDMjuyr8va6D+syd9LdIOkgYGZHhvNhed4FyxdSmswsaQ/M7MiEg9uWO65r6aV1MCOFCnZkOLh0ygPjMgXpvjc7i5f50HORHRkOLp3yQNSR131uYZMPFbAjw8GlUx5IWk5kLJwiGeQMOzIcoFMfiEEFz+IZMHsHOW8PRO0dHMyxIEK9w8FtX8IYBwe3gPQeOcel0377Vt1w/XNwcOm8/SJtLcxI70OG8+m3kevxKihNucjMjgznbz+m/34eAEg4sZItNtjUAAAAAElFTkSuQmCC", // жёлтый regexpRefresh: /^(?:view-source:)?(?:https?|ftp)/, 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 hint = exists ? val : "Эта опция не указана"; if (hint === "") hint = "[ пустая строка ]"; hint += "\n" + pref.pref; if (pref.hint) hint += "\n" + pref.hint; node.tooltipText = hint; var img, alt = "userAlt" in pref && val == pref.userAlt, pro = "userPro" in pref && val == pref.userPro; if (alt) img = this.UserAltImg; if (pro) img = this.UserImg; if ("userChoice" in pref) if (val == pref.userChoice) node.style.removeProperty("color"), img = this.UserChoiceImg; else { node.style.setProperty("color", "#804040", "important"); if (!alt && !pro) img = this.notUserChoiceImg; } node.nextSibling && node.setAttribute("image", img || this.UserImg); // серый значок, если нет userChoice 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 += ` ${"restart" in pref ? "↯-" : "refresh" in pref ? "-⟳" : "—"} ${sfx}`; } lab = exists ? lab : '['+ lab +']'; // имя = [имя] если преф не существует 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, hint] = 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 (hint) tip += "\n" + hint; menuitem.tooltipText = tip; popup.append(menuitem); } }, openPopup(popup) { var btn = popup.parentNode; if (btn.domParent != btn.parentNode) { btn.domParent = btn.parentNode; if (btn.matches(".widget-overflow-list > :scope")) var 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) { if (conf && !Services.prompt.confirm(null, this.label, "Перезапустить браузер?")) return; var cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool); Services.obs.notifyObservers(cancel, "quit-application-requested", "restart"); return cancel.data ? Services.prompt.alert(null, this.label, "Запрос на выход отменён.") : this.restart(); }, async restart() { var meth = Services.appinfo.inSafeMode ? "restartInSafeMode" : "quit"; Services.startup[meth](Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart); }, 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.shiftKey && prefs.getBoolPref(this.closePref, undefined) && trg.parentNode.hidePopup(); }, 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; } } }, click(e) { if (e.button) return; var trg = e.target, {pref} = trg; if (!pref) return; }, command(e) { // нажатия левой кнопки мыши var trg = e.target, win = e.view; if (trg.btn) { // LMB if (e.shiftKey) e.altKey ? win.openDialog("chrome://user_chrome_files/content/options/prefs_win.xhtml", "user_chrome_prefs:window", "centerscreen,resizable,dialog=no") // Alt+Shift : e.view.ZoomManager.toggleZoom(); // Alt Пипетка else if (e.altKey) e.view.PlacesCommandHook.showPlacesOrganizer("BookmarksToolbar"); // Shift Библиотека Панель закладок else { // LMB Click var bar = e.target.ownerDocument.querySelector("#ucf-additional-vertical-bar") if (bar) { win.setToolbarVisibility(bar, bar.collapsed); bar.collapsed ? win.SidebarUI.hide() : win.SidebarUI.show("viewHistorySidebar"); } else win.SidebarUI.toggle("viewHistorySidebar"); } return; } 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); }, auxclick(e) { // CKM if (e.button != 1 || !e.target.btn) return; if (e.altKey) e.shiftKey ? this.switchToTab(e, "ya.ru") // Alt+Shift : e.view.undoCloseTab() else if (e.shiftKey) this.eyedropper(e.target) else this.switchToTab(e, "about:newtab"); }, contextmenu(e) { // RMB var trg = e.target, win = e.view; if (trg.btn) { if (e.ctrlKey || e.shiftKey) return; if (e.detail == 2) return trg.secondaryPopup.hidePopup(); // меню быстрых настроек ! e.altKey ? this.openPopup(trg.secondaryPopup) : this.switchToTab(e, "about:config"); } else if ("pref" in trg) { this.maybeClosePopup(e, trg); if (trg.pref.user) prefs.clearUserPref(trg.pref.pref), this.maybeRe(trg); } e.preventDefault(); }, mousedown(e) { var reset = e => e.target.linkedObject = this; var id, lo = {command: reset, mousedown: reset, auxclick: e => e.button != 1 || reset(e)}; var lin = /macos|linux/.test(e.view.AppConstants.platform); var stop = e => reset(e) && e.preventDefault(); lo.contextmenu = lin ? e => e.ctrlKey || e.shiftKey ? dsp(e) : stop(e) : stop; var context = lin ? e => e.button == 2 && e.type.endsWith("p") && this.contextmenu(e) : () => {}; var dsp = (e, timeout) => { var trg = e.target; trg.onmouseup = trg.onmouseleave = null; if (timeout) return this.londPress(e); e.view.clearTimeout(id); reset(e); context(e); } (this.mousedown = e => { var trg = e.target; if (!trg.btn) return; trg.linkedObject = lo; trg.onmouseup = trg.onmouseleave = dsp; id = e.view.setTimeout(dsp, 500, e, true); })(e); }, londPress(e) { // удержание кнопки мыши. на второй долгий клик при отпускании сработает действие на обычный клик этой кнопки var trg = e.target, win = e.view; if (e.button == 0) this.switchProxy(e, my_vpn); if (e.button == 1) trg.ownerDocument.getElementById("key_browserConsole").doCommand(); // Консоль браузера if (e.button == 2) { // RMB Long var newURI = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry).convertChromeURL(Services.io.newURI(help_ucf[0])); // .spec = file:/// (newURI.QueryInterface(Ci.nsIFileURL).file.exists()) ? this.switchToTab(e, help_ucf[0]) : this.switchToTab(e, help_ucf[1]); } }, switchProxy(e, pac) { if (prefs.getIntPref('network.proxy.type') == 2) { // выключить prefs.setIntPref('network.proxy.type', 0); prefs.setStringPref("network.proxy.autoconfig_url", "127.0.0.1"); e.target.style.removeProperty("filter"); this.showInStatusPanel("\u{1F6A6} Настройки сети - работа без прокси"); // символ Светофор } else { prefs.setIntPref('network.proxy.type', 2); prefs.setStringPref("network.proxy.autoconfig_url", pac); e.target.style.setProperty("filter", icon_vpn, "important"); this.showInStatusPanel("\u{1F6A6} Заблокированные сайты через «АнтиЗапрет»"); // this.Notify('Proxy', 'Работаем через VPN Антизапрет'); } }, showInStatusPanel(info, ms = 5000) { var win = Services.wm.getMostRecentWindow("navigator:browser"); StatusPanel = win.StatusPanel; if (StatusPanel.update.tid) clearTimeout(StatusPanel.update.tid) else { var {update} = StatusPanel; StatusPanel.update = () => {}; StatusPanel.update.ret = () => { StatusPanel.update = update; StatusPanel.update(); } } StatusPanel.update.tid = setTimeout(StatusPanel.update.ret, ms); StatusPanel._label = info; }, eyedropper(trg) { // Пипетка - захват цвета var obj = ChromeUtils.import("resource://devtools/shared/Loader.jsm") .require("devtools/client/menus").menuitems .find(menuitem => menuitem.id == "menu_eyedropper"); (this.eyedropper = target => obj.oncommand({target}))(trg); }, Notify(title, text, ms = 3000){ Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService).showAlertNotification(null, title, text, false, '', null, ms); }, switchToTab(e = this, url) { // открыть вкладку | закрыть, если открыта for(var tab of e.view.gBrowser.tabs) if ( tab.linkedBrowser.currentURI.spec == url ) {e.view.gBrowser.removeTab(tab); return;}; // вкладка найдена, закрыть e.view.switchToTabHavingURI(url, true, {relatedToCurrent: true, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()}); } }; }); // END ToggleAboutConfig
Отредактировано Dobrov (06-11-2021 03:53:55)
Отсутствует
Вместе с правым кликом в MacOS и вероятно Linux открывается контекстное меню панели
Посмотрел на Mint, и точно, так и есть.
Тогда можно попробовать манипуляцию атрибутом "context".
(async (bar, exp, tid, self) => CustomizableUI.createWidget(self = { label: "Панели, Папки", tooltiptext: [ "ЛКМ: ★ Закладки\n…+ Alt Домашняя папка", "ПКМ: ⟳ История\n…+ Alt Папка установки", "СКМ: Папка профиля\n…+ Alt user_chrome_files" ].join("\n"), id: "add-additional-personaltoolbar-button", localized: false, onCreated(btn) { btn.onclick = this.click; btn.toggleAttribute("context"); btn.style.setProperty("list-style-image", "url(chrome://user_chrome_files/content/vertical_top_bottom_bar/svg/bookmark-16.svg)", "important"); }, exec(num, win) { tid = null; self[num](win); }, context(win) { var btn = win.document.getElementById(this.id); btn.removeAttribute("context"); btn.dispatchEvent(new win.MouseEvent("contextmenu", this.a)); btn.toggleAttribute("context"); }, a: {__proto__: null, bubbles: true, screenX: 0, screenY: 0}, click(e) { if (e.detail > 2) return; var n2 = e.button != 2; var dbl = e.detail == 2; var num = 16 * e.button + 8 * e.ctrlKey + 4 * e.shiftKey + 2 * e.altKey + dbl; if (!self[num]) { if (n2) return; num = "context"; for(var p in self.a) self.a[p] = e[p]; } var win = e.view; if (dbl) tid &&= win.clearTimeout(tid), self[num](win); else tid = win.setTimeout(self.exec, 300, num, win); }, 0: w => bar(w, "viewBookmarksSidebar"), // ЛКМ 2: () => exp("Home"), // Alt+ЛКМ 16: () => exp("ProfD"), // СКМ 18: () => exp("UChrm", "user_chrome_files"), // Alt+СКМ 32: w => bar(w, "viewHistorySidebar"), // ПКМ 34: () => exp("GreD"), // Alt+ПКМ 1(win) { // Double Left Click win.alert("DBL Click"); }, 33(win) { // Double Right Click win.alert("DBL Right Click"); }, 29(win) { // Ctrl + Shift + Double Middle Click win.alert("Ctrl + Shift + DBL Middle Click"); }, }))( (win, bar) => win.SidebarUI.toggle(bar), (dir, sub) => { dir = Services.dirsvc.get(dir, Ci.nsIFile); sub && dir.append(sub); dir.exists() && dir.launch(); } );
скрипт перехвата кликов на downloads-button, PanelUI-menu
Там полную раскликовку сделать сложнее,
потому что панельки из них вываливаются по mousedown.
/* listener = e => { var trg = e.target; // Downloads Clicks if (e.button == 1) { if (e.shiftKey) { // СКМ + Shift if ( prefs.getIntPref("permissions.default.image", 1) == 1) prefs.setIntPref("permissions.default.image", 2), trg.style.filter = "hue-rotate(180deg) brightness(95%)" else prefs.setIntPref("permissions.default.image", 1), trg.style.filter = ""; BrowserReload(); } else // СКМ Click saveSelectionToTxt(); // сохранить .txt } else if (e.button == 2) { if (e.shiftKey) Downloads.getSystemDownloadsDirectory().then(path => FileUtils.File(path).launch(), Cu.reportError) // Обзор папки «Загрузки» else // ПКМ Click save(); // Single HTML } }, listener_pui = e => { // PanelUI-menu Clicks if (e.button == 1) { if (e.altKey) window.BrowserFullScreen() else if( window.windowState != window.STATE_MAXIMIZED ) window.maximize() else window.restore(); } else if (e.button == 2) if (e.altKey) return else { e.stopPropagation(); (e.shiftKey) ? window.close() : window.minimize(); } }, // end Clicks */ tid, allowMousedown, listener = { handleEvent(e) { if (e.detail > 2) return; var btn = e.target; var dbl = e.detail == 2; var num = (btn == pui && 100) + 16 * e.button + 8 * e.ctrlKey + 4 * e.shiftKey + 2 * e.altKey + dbl; if (!this[num]) { if (e.button == 1) return; if (e.button) { num = "context"; for(var p in this.a) this.a[p] = e[p]; } else num = "mousedown"; } if (dbl) tid &&= clearTimeout(tid), this[num](btn); else tid = setTimeout(this.exec, 300, num, btn, this); }, exec(num, btn, self) { tid = null; self[num](btn); }, mousedown(btn) { allowMousedown = true; btn.dispatchEvent(new MouseEvent("mousedown", {})); allowMousedown = false; }, context(btn) { btn.removeAttribute("context"); btn.dispatchEvent(new MouseEvent("contextmenu", this.a)); btn.toggleAttribute("context"); }, a: {__proto__: null, bubbles: true, screenX: 0, screenY: 0}, /*** ======= Downloads Clicks ======= ***/ 16: saveSelectionToTxt, // СКМ Click (сохранить .txt) 20(btn) { // СКМ + Shift var pref = "permissions.default.image"; var one = prefs.getIntPref(pref) == 1; prefs.setIntPref(pref, one ? 2 : 1); btn.style.filter = one ? "hue-rotate(180deg) brightness(95%)" : ""; BrowserReload(); }, 32: save, // ПКМ Click (Single HTML) 36() { // Shift + ПКМ Downloads.getSystemDownloadsDirectory() .then(path => FileUtils.File(path).launch(), Cu.reportError) // Обзор папки «Загрузки» }, 1() { // Double Left Click alert("Double Left Click"); }, 41() { // Ctrl + Double Right Click alert("Ctrl + Double Right Click"); }, 4() { // Shift + ЛКМ alert("Shift + ЛКМ"); }, /*** ======= PanelUI-menu Clicks ======= ***/ 118: BrowserFullScreen, // Alt + СКМ 116() { // СКМ windowState != STATE_MAXIMIZED ? maximize() : restore(); }, 132() { // ПКМ minimize(); }, 136: BrowserTryToCloseWindow, // Shift + ПКМ 134() { // Alt + ПКМ gCustomizeMode.enter(); }, 101() { // Double Left Click alert("Double Left Click"); }, 141() { // Ctrl + Double Right Click alert("Ctrl + Double Right Click"); }, 104() { // Shift + ЛКМ alert("Shift + ЛКМ"); }, }, // end Clicks
/* btn.addEventListener("click", listener), pui.addEventListener("click", listener_pui); window.addEventListener("keydown", keydown_win); var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win; ucf[id] = {destructor() { btn.removeEventListener("click", listener), pui.removeEventListener("click", listener_pui); window.removeEventListener("keydown", keydown_win); }}; */ var mouseenter = function(e) { this.parentNode.addEventListener("mousedown", stop, true); this.addEventListener("mouseleave", mouseleave, {once: true}); } var mouseleave = function(e) { this.parentNode.removeEventListener("mousedown", stop, true); } var stop = e => { e.button || allowMousedown || e.stopImmediatePropagation(); } var btns = [btn, pui]; for(var b of btns) { b.toggleAttribute("context"), b.addEventListener("click", listener, true), b.addEventListener("mouseenter", mouseenter); } window.addEventListener("keydown", keydown_win); var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win; ucf[id] = {destructor() { for(var b of btns) { b.removeEventListener("click", listener, true); b.removeEventListener("mouseenter", mouseenter); if (b.matches(":hover")) b.removeEventListener("mouseleave", mouseleave), b.parentNode.removeEventListener("mousedown", stop, true); } window.removeEventListener("keydown", keydown_win); }};
В скрипт Quick Toggle
Уволь.
Отсутствует
Dumby - спасибо, я немного переделал код и обновил профиль-сборку скриптов.
А ещё у меня там не работают альт-клики. Насколько я понял, mousedown занят системой
Не системой, а демоном горячих клавиш, которые можно изменить в Настройках из меню.
перетаскивание/Resize окна вместе с Alt - это стандарт, но мета-клавишу можно в настройках поменять на Ctrl или Alt или Win…
Отсутствует
присоеденяюсь к просьбе
Какой просьбе? Нет там никакой просьбы.
Но индикатор и не должен напрямую реагировать ни на какие фишки.
Пара десятков миллисекунд на получение данных о памяти,
затем delay (две секунды) пауза, и так по кругу, вот и вся деятельность.
Дополнительный пинок только при открытии нового окна браузера.
И код рабочий, так что, если фишка действительно чистит память,
то индикатор это покажет, не прям сразу, но не позднее delay.
И да, если вдруг надо поставить (для теста) второй экземпляр кода,
то следует изменить id (в конце, "ucf-mem-indicator"), а то будут накладки.
И ещё там есть вопрос, можно ли сделать подобный индикатор,
но на другом принципе — использовать nsIMemoryReporterManager.
Когда-то давно я уже отвечал на это, целый трактат написал.
Суть — можно, но тогда результат будет включть только память DOM-процессов,
то есть выпадут процессы gpu, socket, rdd, может ещё какие-то подобные.
Отсутствует
Dumby - Помоги исправить код перехода в "Адаптивный дизайн".
код в сложной кнопке QuickToggle.js работает, но если несколько раз включить/выключить Адаптивный дизайн через кнопку, то это переключение перестаёт работать.
и не работает в простой кнопке, в которую ты мне клики добавил:
responsiveUI(trg) { var obj = ChromeUtils.import("resource://devtools/shared/Loader.jsm").require("devtools/client/menus").menuitems.find(menuitem => menuitem.id == "menu_responsiveUI"); (this.responsiveUI = target => obj.oncommand({target}))(trg); },
(async (id, func) => { // дополнительные клики на downloads-button, PanelUI-menu для custom_script_win.js await window.delayedStartupPromise; var btn = document.getElementById("downloads-button"), pui = document.getElementById("PanelUI-menu-button"); if (!btn) return; btn.tooltipText = GetDynamicShortcutTooltipText(btn.id) +` Двойной клик: открыть [Загрузки] …на картинке: ⧉ найти Похожие\n Правый клик (Alt+S): Сохранить в единый html всё / выделенное …дважды Картинки вкл/выкл\n Ролик: Сохранить как файл .txt Колёсико на рисунке: ➜ Сохранить`, PanelUI_help = `Клик мыши: меню Firefox ${Services.appinfo.platformVersion} …+ дважды ⊠ закрыть браузер …+ Alt Обновить без кэша …+ Shift ⚑ Краткая справка\n Правый клик ⇲ Свернуть …+ Alt Персонализация Колёсико: Развернуть | окно …+ Alt Полный экран`; var addDestructor = nextDestructor => { var {destructor} = ucf[id]; ucf[id].destructor = () => { try {destructor();} catch(ex) {Cu.reportError(ex);} nextDestructor(); } }, showInStatusPanel = (info, time = 5000) => { var win = Services.wm.getMostRecentWindow("navigator:browser"); StatusPanel = win.StatusPanel; if (StatusPanel.update.tid) clearTimeout(StatusPanel.update.tid) else { var {update} = StatusPanel; StatusPanel.update = () => {}; StatusPanel.update.ret = () => { StatusPanel.update = update; StatusPanel.update(); } } StatusPanel.update.tid = setTimeout(StatusPanel.update.ret, time); StatusPanel._label = info; }, saveSelectionToTxt = async () => { // сохранить страницу или выделенный текст как файл .txt var splice = saveURL.length == 10; var msgName = id + ":Save:GetSelection"; var receiver = msg => { var title = document.title || gBrowser.selectedTab.label; var args = [ "data:text/plain," + encodeURIComponent(gBrowser.currentURI.spec + "\n\n" + msg.data), title.replace(/[:\\\/<>?*|"]+/g,'_').replace(/\s+/g,' ').slice(0, 100).trim() + '_' + new Date().toLocaleString('ru').replace(', ','-').replace(/:/g, '։') + '.txt', null, false, true, null, window.document ]; splice && args.splice(5, 0, null); saveURL(...args) && showInStatusPanel("√ текст сохранён: " + title.slice(0, 60)); } messageManager.addMessageListener(msgName, receiver); addDestructor(() => messageManager.removeMessageListener(msgName, receiver)); var func = fm => { var res, fed, win = {}, fe = fm.getFocusedElementForWindow(content, true, win); var sel = (win = win.value).getSelection(); if (sel.isCollapsed) { var ed = fe && fe.editor; if (ed && ed instanceof Ci.nsIEditor) sel = ed.selection, fed = fe; } if (sel.isCollapsed) fed && fed.blur(), docShell.doCommand("cmd_selectAll"), res = win.getSelection().toString(), docShell.doCommand("cmd_selectNone"), fed && fed.focus(); res = res || sel.toString(); /\S/.test(res) && sendAsyncMessage("saveSelectionToTxt", res); } var url = "data:;charset=utf-8," + encodeURIComponent(`(${func})`.replace("saveSelectionToTxt", msgName)) + '(Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager));'; (saveSelectionToTxt = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))(); }, // end save = async () => { // автор: Лекс, правка: Dumby, Dobrov (пути сохранения HTML) var msgName = id + "ucfDwnldsBtnSaveSnapshotToHTML"; if (typeof IOUtils != "object") { // Firefox 78 ESR var {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); var PathUtils = {join: (...args) => OS.Path.join(...args)}; var IOUtils = {writeUTF8: (path, txt) => OS.File.writeAtomic(path, new TextEncoder().encode(txt))}; } var write = IOUtils.writeUTF8 ? "writeUTF8" : "writeAtomicUTF8"; var Title = (type) => { // получить заголовок (без обрезки, если type не указан) или домен (type <0) var title = (document.title || gBrowser.selectedTab.label); if ( !type ) return title; // заголовок if ( type > 0 ) return title.slice(0, type).replace(/ \| Форум Mozilla Россия$| — Mozilla Firefox|[\\\/?*\"'`]+/g,'').replace(/\s+/g,' ').replace(/[|<>]+/g,'_').replace(/:/g,'։').trim(); // ограничить длину имени var host = (/^file:\/\//.test(gURLBar.value)) ? '' : gURLBar.value.replace(/^.*url=|https?:\/\/|www\.|\/.*/g,''); return host.replace(/^ru\.|^m\.|forum\./,'').replace(/^club\.dns/,'dns'); } var msgListener = async msg => { var [fileContent, fileName] = msg.data, dir; try {dir = prefs.getComplexValue("browser.download.dir", Ci.nsIFile);} catch {dir = dirsvc.get("DfltDwnld", Ci.nsIFile);} var arr = prefs.getStringPref("ucf_save.dirs", "_Web||_Images|0").split('|').slice(0, 2); // Dir/subdir: пусто|0 title|1 домен arr[1] = (arr[1] == "0") ? Title(100) : (arr[1] == "1") ? Title(-1) : ""; // имя вкладки или домен arr.forEach(dir.append); // для ucf_save.dirs = "_Web||_Pics|1" HTML сохранится в папку [Загрузки]/_Web/имя вкладки dir.exists() && dir.isDirectory() || dir.create(dir.DIRECTORY_TYPE, 0o777); // создать папку, если не существует… var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); file.initWithPath(dir.path); dir.append(fileName); await IOUtils[write](dir.path, fileContent) && showInStatusPanel("√ страница записана: " + fileName.slice(0, 60)); var d = await Downloads.createDownload({ source: "about:blank", target: FileUtils.File(dir.path)}); // Fake download (await Downloads.getList(Downloads.ALL)).add(d); d.refresh(d.succeeded = true); // кнопка Загрузки мигает } messageManager.addMessageListener(msgName, msgListener); addDestructor(() => messageManager.removeMessageListener(msgName, msgListener)); var svc = 'globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services'; var url = "data:;charset=utf8," + encodeURIComponent(`(${func})(${svc});`.replace("%MSG_NAME%", msgName)); (save = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))(); }, // end save tid, allowMousedown, listener = { handleEvent(e) { if (e.detail > 2) return; var btn = e.target; var dbl = e.detail == 2; var num = (btn == pui && 100) + 16 * e.button + 8 * e.ctrlKey + 4 * e.shiftKey + 2 * e.altKey + dbl; if (!this[num]) { if (e.button == 1) return; if (e.button) { num = "context"; for(var p in this.a) this.a[p] = e[p]; } else num = "mousedown"; } if (dbl) tid &&= clearTimeout(tid), this[num](btn); else tid = setTimeout(this.exec, 300, num, btn, this); }, exec(num, btn, self) { tid = null; self[num](btn); }, mousedown(btn) { allowMousedown = true; btn.dispatchEvent(new MouseEvent("mousedown", {})); allowMousedown = false; }, context(btn) { btn.removeAttribute("context"); btn.dispatchEvent(new MouseEvent("contextmenu", this.a)); btn.toggleAttribute("context"); }, switchToTab(but, url) { // открыть вкладку | закрыть, если открыта for(var tab of but.ownerGlobal.gBrowser.tabs) if ( tab.linkedBrowser.currentURI.spec == url ) {but.ownerGlobal.gBrowser.removeTab(tab); return;}; // вкладка найдена, закрыть but.ownerGlobal.switchToTabHavingURI(url, true, {relatedToCurrent: true, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()}); }, responsiveUI(trg) { var obj = ChromeUtils.import("resource://devtools/shared/Loader.jsm").require("devtools/client/menus").menuitems.find(menuitem => menuitem.id == "menu_responsiveUI"); (this.responsiveUI = target => obj.oncommand({target}))(trg); }, a: {__proto__: null, bubbles: true, screenX: 0, screenY: 0}, /*** ======= Downloads Clicks ======= ***/ 16: saveSelectionToTxt, // СКМ Click (сохранить .txt) 1() { // Double Left Click - Обзор папки «Загрузки» Downloads.getSystemDownloadsDirectory().then(path => FileUtils.File(path).launch(), Cu.reportError) // Обзор папки «Загрузки» }, 32: save, // ПКМ Click (Single HTML) 33(btn) { // Double Right Click var pref = "permissions.default.image"; var one = prefs.getIntPref(pref) == 1; prefs.setIntPref(pref, one ? 2 : 1); btn.style.filter = one ? "hue-rotate(180deg) brightness(95%)" : ""; BrowserReload(); }, 2() { // Alt + ЛКМ }, /*** ======= PanelUI-menu Clicks ======= ***/ 102: BrowserReloadSkipCache, // Alt + Click 104() { // Shift + ЛКМ var help_ucf = ['chrome://user_chrome_files/content/help.html', 'http://forum.puppyrus.org/index.php?topic=22762']; var newURI = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry).convertChromeURL(Services.io.newURI(help_ucf[0])); // .spec = file:/// (newURI.QueryInterface(Ci.nsIFileURL).file.exists()) ? this.switchToTab(pui, help_ucf[0]) : this.switchToTab(pui, help_ucf[1]); }, 118: BrowserFullScreen, // Alt + СКМ 116() { // СКМ windowState != STATE_MAXIMIZED ? maximize() : restore(); }, 132() { // ПКМ minimize(); }, 134() { // Alt + ПКМ gCustomizeMode.enter(); }, 101: BrowserTryToCloseWindow, // Double Left Click 133(pui) { // Double Right Click responsiveUI(pui); }, }, // end Clicks keydown_win = e => { // нажатие клавиш if (e.keyCode == 83 && e.altKey) e.shiftKey // Alt+S [+Shift] ? singlesave ? singlesave.click() : save() : save(); // имитировать клик по кнопке, используя её ID }, {prefs, dirsvc} = Services, linux = /macos|linux/.test(AppConstants.platform), save_ex = "_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action", singlesave; prefs.setBoolPref("browser.download.autohideButton", false); // не скрывать кнопку Загрузки (async () => { setTimeout(()=> { // дополнить подсказки singlesave = document.getElementById(save_ex); singlesave ? btn.tooltipText = btn.tooltipText + '\n\nAlt⇧S ⌨ нажатие SingleSave' : 0; if (!/Закрыть/.test(pui.tooltipText)) pui.tooltipText = PanelUI_help; }, linux ? 3000 : 9000); // ожидание для Windows больше })(); var mouseenter = function(e) { this.parentNode.addEventListener("mousedown", stop, true); this.addEventListener("mouseleave", mouseleave, {once: true}); } var mouseleave = function(e) { this.parentNode.removeEventListener("mousedown", stop, true); } var stop = e => { e.button || allowMousedown || e.stopImmediatePropagation(); } var btns = [btn, pui]; for(var b of btns) { b.toggleAttribute("context"), b.addEventListener("click", listener, true), b.addEventListener("mouseenter", mouseenter); } window.addEventListener("keydown", keydown_win); var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win; ucf[id] = {destructor() { for(var b of btns) { b.removeEventListener("click", listener, true); b.removeEventListener("mouseenter", mouseenter); if (b.matches(":hover")) b.removeEventListener("mouseleave", mouseleave), b.parentNode.removeEventListener("mousedown", stop, true); } window.removeEventListener("keydown", keydown_win); }}; ucf.unloadlisteners.push(id); })("downloads-button-click-listener", ({io, focus}) => { // SingleHTML не сохраняет svg графику var resolveURL = function (url, base) { try { return io.newURI(url, null, io.newURI(base)).spec; } catch {} }, getSelWin = function (w) { if (w.getSelection().toString()) return w; for (var i = 0, f, r; f = w.frames[i]; i++) { try { if (r = getSelWin(f)) return r; } catch(e) {} } }, encodeImg = function (src, obj) { var canvas, img, ret = src; if (/^https?:\/\//.test(src)) { canvas = doc.createElement('canvas'); if (!obj || obj.nodeName.toLowerCase() != 'img') { img = doc.createElement('img'); img.src = src; } else img = obj; if (img.complete) try{ canvas.width = img.width; canvas.height = img.height; canvas.getContext('2d').drawImage(img, 0, 0); ret = canvas.toDataURL((/\.jpe?g/i.test(src) ? 'image/jpeg' : 'image/png')); } catch (e) {}; if (img != obj) img.src = 'about:blank'; }; return ret; }, toSrc = function (obj) { var strToSrc = function (str) { var chr, ret = '', i = 0, meta = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\x22' : '\\\x22', '\\': '\\\\'}; while (chr = str.charAt(i++)) { ret += meta[chr] || chr; }; return '\x22' + ret + '\x22'; }, arrToSrc = function (arr) { var ret = []; for (var i = 0; i < arr.length; i++) { ret[i] = toSrc(arr[i]) || 'null'; }; return '[' + ret.join(',') + ']'; }, objToSrc = function (obj) { var val, ret = []; for (var prop in obj) { if (obj.hasOwnProperty(prop) && (val = toSrc(obj[prop]))) ret.push(strToSrc(prop) + ': ' + val); }; return '{' + ret.join(',') + '}'; }; switch (Object.prototype.toString.call(obj).slice(8, -1)) { case 'Array': return arrToSrc(obj); case 'Boolean': case 'Function': case 'RegExp': return obj.toString(); case 'Date': return 'new Date(' + obj.getTime() + ')'; case 'Math': return 'Math'; case 'Number': return isFinite(obj) ? String(obj) : 'null'; case 'Object': return objToSrc(obj); case 'String': return strToSrc(obj); default: return obj ? (obj.nodeType == 1 && obj.id ? 'document.getElementById(' + strToSrc(obj.id) + ')' : '{}') : 'null'; } }, mainWin = {}; focus.getFocusedElementForWindow(content, true, mainWin); mainWin = mainWin.value; var selWin = getSelWin(mainWin), win = selWin || mainWin, doc = win.document, loc = win.location; var ele, pEle, clone, reUrl = /(url\(\x22)(.+?)(\x22\))/g; if (selWin) { var rng = win.getSelection().getRangeAt(0); pEle = rng.commonAncestorContainer; ele = rng.cloneContents(); } else { pEle = doc.documentElement; ele = (doc.body || doc.getElementsByTagName('body')[0]).cloneNode(true); }; while (pEle) { if (pEle.nodeType == 1) { clone = pEle.cloneNode(false); clone.appendChild(ele); ele = clone; }; pEle = pEle.parentNode }; var sel = doc.createElement('div'); sel.appendChild(ele); for (var el, all = sel.getElementsByTagName('*'), i = all.length; i--;) { el = all[i]; if (el.style && el.style.backgroundImage) el.style.backgroundImage = el.style.backgroundImage.replace(reUrl, function (a, prev, url, next) { if (!/^[a-z]+:/.test(url)) url = resolveURL(url, loc.href); return prev + encodeImg(url) + next; }); switch (el.nodeName.toLowerCase()) { case 'link': case 'style': case 'script': el.parentNode.removeChild(el); break; case 'a': case 'area': if (el.hasAttribute('href') && el.getAttribute('href').charAt(0) != '#') el.href = el.href; break; case 'img': case 'input': if (el.hasAttribute('src')) el.src = encodeImg(el.src, el); break; case 'audio': case 'video': case 'embed': case 'frame': case 'iframe': if (el.hasAttribute('src')) el.src = el.src; break; case 'object': if (el.hasAttribute('data')) el.data = el.data; break; case 'form': if (el.hasAttribute('action')) el.action = el.action; break; } }; var head = ele.insertBefore(doc.createElement('head'), ele.firstChild), meta = doc.createElement('meta'), sheets = doc.styleSheets, title = doc.getElementsByTagName('title')[0]; meta.httpEquiv = 'content-type'; meta.content = 'text/html; charset=utf-8'; head.appendChild(meta); if (title) head.appendChild(title.cloneNode(true)); head.copyScript = function (unsafeWin) { if ('$' in unsafeWin) return; var f = doc.createElement('iframe'); f.src = 'about:blank'; f.setAttribute('style', 'position:fixed;left:0;top:0;visibility:hidden;width:0;height:0;'); doc.documentElement.appendChild(f); var str, script = doc.createElement('script'); script.type = 'text/javascript'; for (var name in unsafeWin) { if (name in f.contentWindow || !/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) continue; try { str = toSrc(unsafeWin[name]); if (!/\{\s*\[native code\]\s*\}/.test(str)) { script.appendChild(doc.createTextNode('var ' + name + ' = ' + str.replace(/<\/(script>)/ig, '<\\/$1') + ';\n')); } } catch (e) {}; }; f.parentNode.removeChild(f); if (script.childNodes.length) this.nextSibling.appendChild(script); }; head.copyScript(win.wrappedJSObject || win); head.copyStyle = function (s) { if (!s) return; var style = doc.createElement('style'); style.type = 'text/css'; if (s.media && s.media.mediaText) style.media = s.media.mediaText; try { for (var i = 0, rule; rule = s.cssRules[i]; i++) { if (rule.type != 3) { if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) { var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) { if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href); if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url); return prev + url + next; }); style.appendChild(doc.createTextNode(css + '\n')); } } else { this.copyStyle(rule.styleSheet); } } } catch(e) { if (s.ownerNode) style = s.ownerNode.cloneNode(false); }; this.appendChild(style); }; for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]); head.appendChild(doc.createTextNode('\n')); var doctype = '', dt = doc.doctype; if (dt && dt.name) { doctype += '<!DOCTYPE ' + dt.name; if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22'; if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22'; doctype += '>\n'; }; var fileName = selWin ? win.getSelection().toString() : (title && title.text ? title.text : loc.pathname.split('/').pop()); fileName = fileName.replace(/[:\\\/<>?*|"]+/g, '_').replace(/\s+/g, ' ').slice(0, 100).trim(); fileName += "_" + new Date().toLocaleDateString('ru', {day: 'numeric', month: 'numeric', year: '2-digit'}) +'-'+ new Date().toLocaleTimeString().replace(/:/g, "։"); if (!/\.html?$/.test(fileName)) fileName += '.html'; sendAsyncMessage("%MSG_NAME%", [doctype + sel.innerHTML +'\n<a href='+ (loc.protocol != 'data:' ? loc.href : 'data:uri') +'><small><blockquote>источник: '+ new Date().toLocaleString("ru") +'</blockquote></small></a>', fileName]); }); // END hookClicks
Ещё вопрос - как имитировать нажатие клавиш, например "послать" переключения в режим "Адаптивный дизайн" - у меня это Option+Command+M (Win+Alt+M)
пробовал, но не пашет: window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).sendKeyEvent("keypress", 0, "j".charCodeAt(0), 0x08)
Отредактировано Dobrov (11-11-2021 18:07:09)
Отсутствует
не работает
responsiveUI(pui);
this.responsiveUI(pui);
Или (для понимания) без промежуточности
..... 133(pui) { var obj = ChromeUtils.import("resource://devtools/shared/Loader.jsm").require("devtools/client/menus").menuitems.find(menuitem => menuitem.id == "menu_responsiveUI"); (this[133] = target => obj.oncommand({target}))(pui); },
не пашет
window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).sendKeyEvent
На FF87 у window нет метода QueryInterface(),
и у nsIDOMWindowUtils нет метода sendKeyEvent().
Отсутствует
Dumby - спасибо, исправил и доработал код.
Вопрос - как сделать перехват кликов на кнопках расширений, которые динамически появляются?
То есть, при старте браузера кнопки Reader View в строке адреса нет, она появляется, когда открывается сайт.
Будет удобнее, если у кнопки режима чтения появится ещё действие - например альтернативный режим просмотра.
То есть, нужно на кнопке Reader View по клику колёсиком включать/выключать режим "Адаптивный дизайн".
win.document.getElementById("pageAction-panel-_2495d258-41e7-4cd5-bc7d-ac15981f064e_").click() trg.ownerDocument.getElementById("key_responsiveDesignMode").doCommand(); // Адаптивный дизайн id="pageAction-panel-_2495d258-41e7-4cd5-bc7d-ac15981f064e_" Reader View в меню Действия на странице id="pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_" в строке адреса actionid="_2495d258-41e7-4cd5-bc7d-ac15981f064e_"
Желательно добавить перехват кликов в тот же UCF-скрипт, который расширяет возможности кнопок Меню и Загрузки:
(async (id, func) => { // дополнительные клики на downloads-button, PanelUI-menu для custom_script_win.js await window.delayedStartupPromise; var btn = document.getElementById("downloads-button"), pui = document.getElementById("PanelUI-menu-button"); if (!btn) return; btn_help =` Двойной клик: открыть [Загрузки] …на картинке: ⧉ найти Похожие\n Правый клик (Alt+S): Сохранить в единый html всё / выделенное …дважды Картинки вкл/выкл\n Ролик: Сохранить как файл .txt Колёсико на рисунке: ➜ Сохранить`, PanelUI_help = `Клик мыши: меню Firefox ${Services.appinfo.platformVersion} …+ Shift ⚑ Краткая справка …+ Alt Персонализация Клик дважды ⊠ закрыть браузер \n Правый клик ⇲ Свернуть …+ дважды ⤾ Вернуть вкладку …+ Alt Диспетчер задач …+ Shift Адаптивный дизайн\n Колёсико: Развернуть | окно …+ Alt Полный экран …+ дважды Обновить без кэша`, singlesave_help = `\nAlt⇧S ⌨ нажатие SingleSave`; var addDestructor = nextDestructor => { var {destructor} = ucf[id]; ucf[id].destructor = () => { try {destructor();} catch(ex) {Cu.reportError(ex);} nextDestructor(); } }, showInStatusPanel = (info, time = 5000) => { var win = Services.wm.getMostRecentWindow("navigator:browser"); StatusPanel = win.StatusPanel; if (StatusPanel.update.tid) clearTimeout(StatusPanel.update.tid) else { var {update} = StatusPanel; StatusPanel.update = () => {}; StatusPanel.update.ret = () => { StatusPanel.update = update; StatusPanel.update(); } } StatusPanel.update.tid = setTimeout(StatusPanel.update.ret, time); StatusPanel._label = info; }, saveSelectionToTxt = async () => { // сохранить страницу или выделенный текст как файл .txt var splice = saveURL.length == 10; var msgName = id + ":Save:GetSelection"; var receiver = msg => { var title = document.title || gBrowser.selectedTab.label; var args = [ "data:text/plain," + encodeURIComponent(gBrowser.currentURI.spec + "\n\n" + msg.data), title.replace(/[:\\\/<>?*|"]+/g,'_').replace(/\s+/g,' ').slice(0, 100).trim() + '_' + new Date().toLocaleString('ru').replace(', ','-').replace(/:/g, '։') + '.txt', null, false, true, null, window.document ]; splice && args.splice(5, 0, null); saveURL(...args) && showInStatusPanel("√ текст сохранён: " + title.slice(0, 60)); } messageManager.addMessageListener(msgName, receiver); addDestructor(() => messageManager.removeMessageListener(msgName, receiver)); var func = fm => { var res, fed, win = {}, fe = fm.getFocusedElementForWindow(content, true, win); var sel = (win = win.value).getSelection(); if (sel.isCollapsed) { var ed = fe && fe.editor; if (ed && ed instanceof Ci.nsIEditor) sel = ed.selection, fed = fe; } if (sel.isCollapsed) fed && fed.blur(), docShell.doCommand("cmd_selectAll"), res = win.getSelection().toString(), docShell.doCommand("cmd_selectNone"), fed && fed.focus(); res = res || sel.toString(); /\S/.test(res) && sendAsyncMessage("saveSelectionToTxt", res); } var url = "data:;charset=utf-8," + encodeURIComponent(`(${func})`.replace("saveSelectionToTxt", msgName)) + '(Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager));'; (saveSelectionToTxt = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))(); }, // end save = async () => { // автор: Лекс, правка: Dumby, Dobrov (пути сохранения HTML) var msgName = id + "ucfDwnldsBtnSaveSnapshotToHTML"; if (typeof IOUtils != "object") { // Firefox 78 ESR var {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); var PathUtils = {join: (...args) => OS.Path.join(...args)}; var IOUtils = {writeUTF8: (path, txt) => OS.File.writeAtomic(path, new TextEncoder().encode(txt))}; } var write = IOUtils.writeUTF8 ? "writeUTF8" : "writeAtomicUTF8"; var Title = (type) => { // получить заголовок (без обрезки, если type не указан) или домен (type <0) var title = (document.title || gBrowser.selectedTab.label); if ( !type ) return title; // заголовок if ( type > 0 ) return title.slice(0, type).replace(/ \| Форум Mozilla Россия$| — Mozilla Firefox|[\\\/?*\"'`]+/g,'').replace(/\s+/g,' ').replace(/[|<>]+/g,'_').replace(/:/g,'։').trim(); // ограничить длину имени var host = (/^file:\/\//.test(gURLBar.value)) ? '' : gURLBar.value.replace(/^.*url=|https?:\/\/|www\.|\/.*/g,''); return host.replace(/^ru\.|^m\.|forum\./,'').replace(/^club\.dns/,'dns'); } var msgListener = async msg => { var [fileContent, fileName] = msg.data, dir; try {dir = prefs.getComplexValue("browser.download.dir", Ci.nsIFile);} catch {dir = dirsvc.get("DfltDwnld", Ci.nsIFile);} var arr = prefs.getStringPref("ucf_save.dirs", "_Web||_Images|0").split('|').slice(0, 2); // Dir/subdir: пусто|0 title|1 домен arr[1] = (arr[1] == "0") ? Title(100) : (arr[1] == "1") ? Title(-1) : ""; // имя вкладки или домен arr.forEach(dir.append); // для ucf_save.dirs = "_Web||_Pics|1" HTML сохранится в папку [Загрузки]/_Web/имя вкладки dir.exists() && dir.isDirectory() || dir.create(dir.DIRECTORY_TYPE, 0o777); // создать папку, если не существует… var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); file.initWithPath(dir.path); dir.append(fileName); await IOUtils[write](dir.path, fileContent) && showInStatusPanel("√ страница записана: " + fileName.slice(0, 60)); var d = await Downloads.createDownload({ source: "about:blank", target: FileUtils.File(dir.path)}); // Fake download (await Downloads.getList(Downloads.ALL)).add(d); d.refresh(d.succeeded = true); // кнопка Загрузки мигает } messageManager.addMessageListener(msgName, msgListener); addDestructor(() => messageManager.removeMessageListener(msgName, msgListener)); var svc = 'globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services'; var url = "data:;charset=utf8," + encodeURIComponent(`(${func})(${svc});`.replace("%MSG_NAME%", msgName)); (save = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))(); }, // end save tid, allowMousedown, listener = { handleEvent(e) { if (e.detail > 2) return; var btn = e.target; var dbl = e.detail == 2; var num = (btn == pui && 100) + 16 * e.button + 8 * e.ctrlKey + 4 * e.shiftKey + 2 * e.altKey + dbl; if (!this[num]) { if (e.button == 1) return; if (e.button) { num = "context"; for(var p in this.a) this.a[p] = e[p]; } else num = "mousedown"; } if (dbl) tid &&= clearTimeout(tid), this[num](btn); else tid = setTimeout(this.exec, 300, num, btn, this); }, exec(num, btn, self) { tid = null; self[num](btn); }, mousedown(btn) { allowMousedown = true; btn.dispatchEvent(new MouseEvent("mousedown", {})); allowMousedown = false; }, context(btn) { btn.removeAttribute("context"); btn.dispatchEvent(new MouseEvent("contextmenu", this.a)); btn.toggleAttribute("context"); }, switchToTab(but, url) { // открыть вкладку | закрыть, если открыта for(var tab of but.ownerGlobal.gBrowser.tabs) if ( tab.linkedBrowser.currentURI.spec == url ) {but.ownerGlobal.gBrowser.removeTab(tab); return;}; // вкладка найдена, закрыть but.ownerGlobal.switchToTabHavingURI(url, true, {relatedToCurrent: true, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()}); }, a: {__proto__: null, bubbles: true, screenX: 0, screenY: 0}, /*** ======= Downloads Clicks ======= ***/ 16: saveSelectionToTxt, // СКМ Click (сохранить .txt) 1() { // Double Left Click - Обзор папки «Загрузки» Downloads.getSystemDownloadsDirectory().then(path => FileUtils.File(path).launch(), Cu.reportError) // Обзор папки «Загрузки» }, 32: save, // ПКМ Click (Single HTML) 33(btn) { // Double Right Click var pref = "permissions.default.image"; var one = prefs.getIntPref(pref) == 1; prefs.setIntPref(pref, one ? 2 : 1); btn.style.filter = one ? "hue-rotate(180deg) brightness(95%)" : ""; BrowserReload(); }, 2() { // Alt + ЛКМ }, /*** ======= PanelUI-menu Clicks ======= ***/ 102() { gCustomizeMode.enter(); // ЛКМ + Alt Персонализация }, 104() { // Shift + ЛКМ var help_ucf = ['chrome://user_chrome_files/content/help.html', 'http://forum.puppyrus.org/index.php?topic=22762']; var newURI = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry).convertChromeURL(Services.io.newURI(help_ucf[0])); // .spec = file:/// (newURI.QueryInterface(Ci.nsIFileURL).file.exists()) ? this.switchToTab(pui, help_ucf[0]) : this.switchToTab(pui, help_ucf[1]); }, 118: BrowserFullScreen, // Alt + СКМ 116() { // СКМ windowState != STATE_MAXIMIZED ? maximize() : restore(); }, 117: BrowserReloadSkipCache, // СКМ Double 132() { // ПКМ minimize(); }, 134(pui) { // Alt + ПКМ this.switchToTab(pui, 'about:performance'); }, 136(pui) { // Shift + ПКМ pui.ownerDocument.getElementById("key_responsiveDesignMode").doCommand(); // запуск пункта меню с HotKey }, 138(pui) { // Shift + Alt + ПКМ var obj = ChromeUtils.import("resource://devtools/shared/Loader.jsm").require("devtools/client/menus").menuitems.find(menuitem => menuitem.id == "menu_devtools_remotedebugging"); (this[136] = target => obj.oncommand({target}))(pui); // запуск пункта меню, у которого нет HotKey }, 101: BrowserTryToCloseWindow, // Double Left Click 133(pui) { // ПКМ Double Right Click pui.ownerGlobal.undoCloseTab(); }, }, // end Clicks keydown_win = e => { // нажатие клавиш if (e.keyCode == 83 && e.altKey) e.shiftKey // Alt+S [+Shift] ? singlesave ? singlesave.click() : save() : save(); // имитировать клик по кнопке, используя её ID }, {prefs, dirsvc} = Services, linux = /macos|linux/.test(AppConstants.platform), singlesave; prefs.setBoolPref("browser.download.autohideButton", false); // не скрывать кнопку Загрузки var mouseenter = function(e) { this.parentNode.addEventListener("mousedown", stop, true); this.addEventListener("mouseleave", mouseleave, {once: true}); if ((e.target == pui) && (!/справка/.test(pui.tooltipText))) pui.tooltipText = PanelUI_help; // обновить подсказки кнопок if (e.target == btn) { var singlesave = document.getElementById("_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action"), dw; try {dw = prefs.getComplexValue("browser.download.dir",Ci.nsIFile)} catch {dw = dirsvc.get("DfltDwnld", Ci.nsIFile)}; // if (!/Двойной/.test(btn.tooltipText)) btn.tooltipText = GetDynamicShortcutTooltipText(btn.id) + btn_help; // обновлять подсказку при наведении мыши if (singlesave){ if (!/SingleSave/.test(btn.tooltipText)) btn.tooltipText = btn.tooltipText + singlesave_help; } else btn.tooltipText = btn.tooltipText.replace(singlesave_help,''); if (!/выбранная/.test(btn.tooltipText)) btn.tooltipText = btn.tooltipText + `${dw ? "\n\n[Загрузки] — выбранная папка:\n"+ dw.path.substring(0,33) + `${dw.path.length > 32 ? `…\n…${dw.path.substring(dw.path.length -31, dw.path.length)}`: ""}` : ""}`; // сократить/разбить длинную строку } } var mouseleave = function(e) { this.parentNode.removeEventListener("mousedown", stop, true); } var stop = e => { e.button || allowMousedown || e.stopImmediatePropagation(); } var btns = [btn, pui]; for(var b of btns) { b.toggleAttribute("context"), b.addEventListener("click", listener, true), b.addEventListener("mouseenter", mouseenter); } window.addEventListener("keydown", keydown_win); var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win; ucf[id] = {destructor() { for(var b of btns) { b.removeEventListener("click", listener, true); b.removeEventListener("mouseenter", mouseenter); if (b.matches(":hover")) b.removeEventListener("mouseleave", mouseleave), b.parentNode.removeEventListener("mousedown", stop, true); } window.removeEventListener("keydown", keydown_win); }}; ucf.unloadlisteners.push(id); })("downloads-button-click-listener", ({io, focus}) => { // SingleHTML не сохраняет svg графику var resolveURL = function (url, base) { try { return io.newURI(url, null, io.newURI(base)).spec; } catch {} }, getSelWin = function (w) { if (w.getSelection().toString()) return w; for (var i = 0, f, r; f = w.frames[i]; i++) { try { if (r = getSelWin(f)) return r; } catch(e) {} } }, encodeImg = function (src, obj) { var canvas, img, ret = src; if (/^https?:\/\//.test(src)) { canvas = doc.createElement('canvas'); if (!obj || obj.nodeName.toLowerCase() != 'img') { img = doc.createElement('img'); img.src = src; } else img = obj; if (img.complete) try{ canvas.width = img.width; canvas.height = img.height; canvas.getContext('2d').drawImage(img, 0, 0); ret = canvas.toDataURL((/\.jpe?g/i.test(src) ? 'image/jpeg' : 'image/png')); } catch (e) {}; if (img != obj) img.src = 'about:blank'; }; return ret; }, toSrc = function (obj) { var strToSrc = function (str) { var chr, ret = '', i = 0, meta = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\x22' : '\\\x22', '\\': '\\\\'}; while (chr = str.charAt(i++)) { ret += meta[chr] || chr; }; return '\x22' + ret + '\x22'; }, arrToSrc = function (arr) { var ret = []; for (var i = 0; i < arr.length; i++) { ret[i] = toSrc(arr[i]) || 'null'; }; return '[' + ret.join(',') + ']'; }, objToSrc = function (obj) { var val, ret = []; for (var prop in obj) { if (obj.hasOwnProperty(prop) && (val = toSrc(obj[prop]))) ret.push(strToSrc(prop) + ': ' + val); }; return '{' + ret.join(',') + '}'; }; switch (Object.prototype.toString.call(obj).slice(8, -1)) { case 'Array': return arrToSrc(obj); case 'Boolean': case 'Function': case 'RegExp': return obj.toString(); case 'Date': return 'new Date(' + obj.getTime() + ')'; case 'Math': return 'Math'; case 'Number': return isFinite(obj) ? String(obj) : 'null'; case 'Object': return objToSrc(obj); case 'String': return strToSrc(obj); default: return obj ? (obj.nodeType == 1 && obj.id ? 'document.getElementById(' + strToSrc(obj.id) + ')' : '{}') : 'null'; } }, mainWin = {}; focus.getFocusedElementForWindow(content, true, mainWin); mainWin = mainWin.value; var selWin = getSelWin(mainWin), win = selWin || mainWin, doc = win.document, loc = win.location; var ele, pEle, clone, reUrl = /(url\(\x22)(.+?)(\x22\))/g; if (selWin) { var rng = win.getSelection().getRangeAt(0); pEle = rng.commonAncestorContainer; ele = rng.cloneContents(); } else { pEle = doc.documentElement; ele = (doc.body || doc.getElementsByTagName('body')[0]).cloneNode(true); }; while (pEle) { if (pEle.nodeType == 1) { clone = pEle.cloneNode(false); clone.appendChild(ele); ele = clone; }; pEle = pEle.parentNode }; var sel = doc.createElement('div'); sel.appendChild(ele); for (var el, all = sel.getElementsByTagName('*'), i = all.length; i--;) { el = all[i]; if (el.style && el.style.backgroundImage) el.style.backgroundImage = el.style.backgroundImage.replace(reUrl, function (a, prev, url, next) { if (!/^[a-z]+:/.test(url)) url = resolveURL(url, loc.href); return prev + encodeImg(url) + next; }); switch (el.nodeName.toLowerCase()) { case 'link': case 'style': case 'script': el.parentNode.removeChild(el); break; case 'a': case 'area': if (el.hasAttribute('href') && el.getAttribute('href').charAt(0) != '#') el.href = el.href; break; case 'img': case 'input': if (el.hasAttribute('src')) el.src = encodeImg(el.src, el); break; case 'audio': case 'video': case 'embed': case 'frame': case 'iframe': if (el.hasAttribute('src')) el.src = el.src; break; case 'object': if (el.hasAttribute('data')) el.data = el.data; break; case 'form': if (el.hasAttribute('action')) el.action = el.action; break; } }; var head = ele.insertBefore(doc.createElement('head'), ele.firstChild), meta = doc.createElement('meta'), sheets = doc.styleSheets, title = doc.getElementsByTagName('title')[0]; meta.httpEquiv = 'content-type'; meta.content = 'text/html; charset=utf-8'; head.appendChild(meta); if (title) head.appendChild(title.cloneNode(true)); head.copyScript = function (unsafeWin) { if ('$' in unsafeWin) return; var f = doc.createElement('iframe'); f.src = 'about:blank'; f.setAttribute('style', 'position:fixed;left:0;top:0;visibility:hidden;width:0;height:0;'); doc.documentElement.appendChild(f); var str, script = doc.createElement('script'); script.type = 'text/javascript'; for (var name in unsafeWin) { if (name in f.contentWindow || !/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) continue; try { str = toSrc(unsafeWin[name]); if (!/\{\s*\[native code\]\s*\}/.test(str)) { script.appendChild(doc.createTextNode('var ' + name + ' = ' + str.replace(/<\/(script>)/ig, '<\\/$1') + ';\n')); } } catch (e) {}; }; f.parentNode.removeChild(f); if (script.childNodes.length) this.nextSibling.appendChild(script); }; head.copyScript(win.wrappedJSObject || win); head.copyStyle = function (s) { if (!s) return; var style = doc.createElement('style'); style.type = 'text/css'; if (s.media && s.media.mediaText) style.media = s.media.mediaText; try { for (var i = 0, rule; rule = s.cssRules[i]; i++) { if (rule.type != 3) { if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) { var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) { if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href); if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url); return prev + url + next; }); style.appendChild(doc.createTextNode(css + '\n')); } } else { this.copyStyle(rule.styleSheet); } } } catch(e) { if (s.ownerNode) style = s.ownerNode.cloneNode(false); }; this.appendChild(style); }; for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]); head.appendChild(doc.createTextNode('\n')); var doctype = '', dt = doc.doctype; if (dt && dt.name) { doctype += '<!DOCTYPE ' + dt.name; if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22'; if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22'; doctype += '>\n'; }; var fileName = selWin ? win.getSelection().toString() : (title && title.text ? title.text : loc.pathname.split('/').pop()); fileName = fileName.replace(/[:\\\/<>?*|"]+/g, '_').replace(/\s+/g, ' ').slice(0, 100).trim(); fileName += "_" + new Date().toLocaleDateString('ru', {day: 'numeric', month: 'numeric', year: '2-digit'}) +'-'+ new Date().toLocaleTimeString().replace(/:/g, "։"); if (!/\.html?$/.test(fileName)) fileName += '.html'; sendAsyncMessage("%MSG_NAME%", [doctype + sel.innerHTML +'\n<a href='+ (loc.protocol != 'data:' ? loc.href : 'data:uri') +'><small><blockquote>источник: '+ new Date().toLocaleString("ru") +'</blockquote></small></a>', fileName]); }); // END hookClicks
Отсутствует
Dumby
Возможно ли сделать отдельную кнопочку для Вкл/Выкл "Адаптивного дизайна"?
«The Truth Is Out There»
Отсутствует
Возможно ли сделать отдельную кнопочку для Вкл/Выкл "Адаптивного дизайна"?
(async (bar, exp, tid, self) => CustomizableUI.createWidget(self = { id: "test-button", localized: false, label: "Test Button", tooltiptext: `ЛКМ: Design View CKM: folder UCF`, onCreated(btn) { btn.onclick = this.click; btn.toggleAttribute("context"); btn.setAttribute("image", "chrome://browser/skin/preferences/application.png"); }, exec(num, win) { tid = null; self[num](win); }, context(win) { var btn = win.document.getElementById(this.id); btn.removeAttribute("context"); btn.dispatchEvent(new win.MouseEvent("contextmenu", this.a)); btn.toggleAttribute("context"); }, a: {__proto__: null, bubbles: true, screenX: 0, screenY: 0}, click(e) { if (e.detail > 2) return; var n2 = e.button != 2; var dbl = e.detail == 2; var num = 16 * e.button + 8 * e.ctrlKey + 4 * e.shiftKey + 2 * e.altKey + dbl; if (!self[num]) { if (n2) return; num = "context"; for(var p in self.a) self.a[p] = e[p]; } var win = e.view; if (dbl) tid &&= win.clearTimeout(tid), self[num](win); else tid = win.setTimeout(self.exec, 300, num, win); }, 0(win) { // ЛКМ var btn = win.document.getElementById(this.id); btn.ownerDocument.getElementById("key_responsiveDesignMode").doCommand(); // запуск пункта меню с HotKey }, 1(win) { // Double Left Click win.alert("DBL Click"); }, 16: () => exp("UChrm", "user_chrome_files"), // СКМ }))( (win, bar) => win.SidebarUI.toggle(bar), (dir, sub) => { dir = Services.dirsvc.get(dir, Ci.nsIFile); sub && dir.append(sub); dir.exists() && dir.launch(); } );
Отсутствует
Dumby - ещё просьба вдобавок к первой:
подскажи код, чтобы выполнять скрипт из файла. То есть, кликом на кнопке выполняем внешний …/user_chrome_files/custom_scripts/user.js, в который должны быть переданы все текущие переменные, функции и т.п. той кнопки, из которой вызван внешний JS.
Может, это пригодиться для отладки скриптов без перезапуска браузера. А может есть более простой способ отладки части кода кнопки?
Наверное, код внешнего JS не должен попадать в startupCache, это верно?
Отсутствует
Dobrov
Как пример вызова функции из другого скрипта можно посмотреть здесь, выше и ниже. Скрипт с функцией тоже должен быть загружен. Не знаю, это ли было нужно.
https://forum.mozilla-russia.org/viewtopic.php?pid=796057#p796057
На форуме
при старте браузера кнопки Reader View в строке адреса нет, она появляется, когда открывается сайт
Значит слушать клики на родительском контейнере и проверять id кликнутого.
кликом на кнопке выполняем внешний …/user_chrome_files/custom_scripts/user.js, в который должны быть переданы все текущие переменные, функции и т.п. той кнопки, из которой вызван внешний JS
Наверное, код внешнего JS не должен попадать в startupCache, это верно?
Если scriptloader'ом по протоколу chrome:, то будет кэшироваться.
Можно использовать loadSubScriptWithOptions(),
но «все текущие переменные, функции» идут лесом,
разве что только в объект пробросить.
Services.scriptloader.loadSubScriptWithOptions( "chrome://user_chrome_files/content/custom_scripts/user.js", {ignoreCache: true, target: {myVariable1, myVariable2, myFunction}} );
То есть, нужно на кнопке Reader View по клику колёсиком включать/выключать режим "Адаптивный дизайн".
Желательно добавить перехват кликов в тот же UCF-скрипт, который расширяет возможности кнопок Меню и Загрузки
Вот, сводный пример. Добавляем после ucf.unloadlisteners.push(id);
..... var box = document.getElementById("page-action-buttons"); var key = document.getElementById("key_responsiveDesignMode"); var uri = Services.io.newURI("chrome://user_chrome_files/content/custom_scripts/user.js"); var boxLst = e => eval(Cu.readUTF8URI(uri)); box.addEventListener("auxclick", boxLst, true); addDestructor(() => box.removeEventListener("auxclick", boxLst, true));
if ( e.button == 1 && e.target.id == "pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_" ) e.stopImmediatePropagation(), key.doCommand();
this[136]
this[138], наверно.
Возможно ли сделать отдельную кнопочку для Вкл/Выкл "Адаптивного дизайна"?
А в чём конкретно затруднение?
Там же просто получаем <key> и вызываем doCommand();
(async id => CustomizableUI.createWidget({ get label() { var l10n = new (ChromeUtils.import("resource://devtools/shared/Loader.jsm") .require("devtools/shared/l10n")).MultiLocalizationHelper( "devtools/client/locales/startup.properties", "devtools/client/locales/menus.properties" ); this.tooltiptext = l10n.getFormatStr( "toolbox.buttons.responsive", Services.appinfo.OS == "Darwin" ? "Cmd+Opt+M" : "Ctrl+Shift+M" ); delete this.label; return this.label = l10n.getStr("responsiveDesignMode.label"); }, id: "ucf-responsiveDesignMode-btn", localized: false, onCreated(btn) { btn._handleClick = this.click; btn.style.cssText = ` fill-opacity: 0 !important; -moz-context-properties: fill, fill-opacity !important; list-style-image: url(chrome://devtools/skin/images/command-responsivemode.svg) !important; `; }, click() { this.ownerDocument.getElementById(id).doCommand(); } }))("key_responsiveDesignMode");
Отсутствует
А в чём конкретно затруднение?
Там же просто получаем <key> и вызываем doCommand();скрытый текстВыделить кодКод:
(async id => CustomizableUI.createWidget({ get label() { var l10n = new (ChromeUtils.import("resource://devtools/shared/Loader.jsm") .require("devtools/shared/l10n")).MultiLocalizationHelper( "devtools/client/locales/startup.properties", "devtools/client/locales/menus.properties" ); this.tooltiptext = l10n.getFormatStr( "toolbox.buttons.responsive", Services.appinfo.OS == "Darwin" ? "Cmd+Opt+M" : "Ctrl+Shift+M" ); delete this.label; return this.label = l10n.getStr("responsiveDesignMode.label"); }, id: "ucf-responsiveDesignMode-btn", localized: false, onCreated(btn) { btn._handleClick = this.click; btn.style.cssText = ` fill-opacity: 0 !important; -moz-context-properties: fill, fill-opacity !important; list-style-image: url(chrome://devtools/skin/images/command-responsivemode.svg) !important; `; }, click() { this.ownerDocument.getElementById(id).doCommand(); } }))("key_responsiveDesignMode");
Для меня это не так просто.
Dumby, большое спасибо.
«The Truth Is Out There»
Отсутствует