unter_officer
Да, вижу. Можно вместо (или вместе с)
// var MozXULElement = {insertFTLIfNeeded() {}}; var document = {l10n: {setAttributes: msg => msg.textContent = "Скопировано в буфер обмена!"}};
Отсутствует
Dumby, большое спасибо!
«The Truth Is Out There»
Отсутствует
Dumby посмотрите пожалуйста эти 2 кнопки что то они не работают в 109.0
// Switch Keyboard Layout try {(keybUtils => CustomizableUI.createWidget({ type: "custom", id: "SwitchKeyboardLayout", onBuild(doc) { var btn = doc.createXULElement("toolbarbutton"); btn.id = this.id; btn.label = btn.tooltipText = "Switch Keyboard Layout"; btn.image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAk1BMVEX///8/Pz8BAQF8fHwJCQkCAgIJCQl8fHx9fX0AAABJSUkBAQENDQ0wMDBVVVUAAABra2t0dHR7e3thYWEBAQEAAAAAAAABAQEAAAAgICABAQEBAQH8/Pzw8PDp6en39/fj4+Pe3t41V9I/YeWKioqDg4N9fX0jRa8wUrVoaGhkhuxWeNx1dXVCZMhvb28kRqsqTL4KidXxAAAAHHRSTlMAAABndwAAAAA0blVZcm1naWhNa6hrcJ8AAKRU4jk/3gAAAHVJREFUeF6FyMUCwjAUBdEbaQupUMOjqMv/fx1dQN6yZ3aDcWnyw6ezoRWNYc15kqKQZCFlgTKQQwgllL/dn5f3+bPb+6P3CpWNw56srdCZOMzDmA61i8O9nKvRaHLVukEryFKIFtnkj7ENYxmNdd5v+5xj1BcJ/w9Kj6K7ZAAAAABJRU5ErkJggg=="; btn.setAttribute("oncommand", "linkedObj.switch(document);"); btn.className = "toolbarbutton-1 chromeclass-toolbar-additional"; btn.linkedObj = this; return btn; }, switch(doc) { var br = doc.activeElement; br && br.localName == "browser" && br.isRemoteBrowser ? br.messageManager.loadFrameScript(this.url, false) : this.keybUtils.switchSelKeybLayout(); }, get url() { delete this.url; return this.url = `data:;charset=utf-8,(${ encodeURIComponent(keybUtils) }).switchSelKeybLayout()`; }, get keybUtils() { delete this.keybUtils; var def = "let{KeyEvent,HTMLInputElement,HTMLTextAreaElement}=Cu.getGlobalForObject(Services);"; var url = `data:;charset=utf-8,${def}%0Athis.keybUtils=${encodeURIComponent(keybUtils)}`; Services.scriptloader.loadSubScript(url, this); var {id} = this; this.keybUtils.getFocusedElement = function(_subCall, _focusFixed) { var window = Services.focus.activeWindow, {document} = window; var button = document.getElementById(id); if( !_focusFixed && "closeMenus" in window && document.commandDispatcher.focusedElement == button ) { window.closeMenus(button); window.setTimeout(function(_this) { _this.switchSelKeybLayout(_subCall, true); }, 0, this); return; } return document.commandDispatcher.focusedElement; } return this.keybUtils; } }))(`{ //== Options noSelBehavior: { // Shift+Home ctrlKey: false, altKey: false, shiftKey: true, metaKey: false, keyCode: KeyEvent.DOM_VK_HOME, charCode: 0 }, // 0 - do nothing // 1 - convert all text // Or use object like following to simulate "keypress" event: convTableForward: { // ru -> en "\\"": "@", ":": "^", ";": "$", "?": "&", ",": "?", "/": "|", ".": "/", "э": "'", "б": ",", "ю": ".", "Ж": ":", "ж": ";", "Б": "<", "Ю": ">", "Э": "\\"", "х": "[", "ъ": "]", "ё": "\`", "Х": "{", "Ъ": "}", "Ё": "~", "№": "#", "Ф": "A", "ф": "a", "И": "B", "и": "b", "С": "C", "с": "c", "В": "D", "в": "d", "У": "E", "у": "e", "А": "F", "а": "f", "П": "G", "п": "g", "Р": "H", "р": "h", "Ш": "I", "ш": "i", "О": "J", "о": "j", "Л": "K", "л": "k", "Д": "L", "д": "l", "Ь": "M", "ь": "m", "Т": "N", "т": "n", "Щ": "O", "щ": "o", "З": "P", "з": "p", "Й": "Q", "й": "q", "К": "R", "к": "r", "Ы": "S", "ы": "s", "Е": "T", "е": "t", "Г": "U", "г": "u", "М": "V", "м": "v", "Ц": "W", "ц": "w", "Ч": "X", "ч": "x", "Н": "Y", "н": "y", "Я": "Z", "я": "z", __proto__: null }, //== End of options get convTableBackward() { var ctb = { __proto__: null }; var ctf = this.convTableForward; for(var c in ctf) ctb[ctf[c]] = c; delete this.convTableBackward; return this.convTableBackward = ctb; }, inPrimaryLayout: function(s) { for(var i = 0, l = s.length; i < l; ++i) { var c = s.charAt(i); var primary = c in this.convTableForward; if(primary ^ c in this.convTableBackward) return primary; } return false; }, switchKeybLayout: function(s, convTable) { var res = ""; for(var i = 0, l = s.length; i < l; ++i) { var c = s.charAt(i); res += c in convTable ? convTable[c] : c; } return res; }, getFocusedElement: function() { return Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager) .getFocusedElementForWindow(content, true, {}); }, switchSelKeybLayout: function(_subCall, _focusFixed) { var fe = this.getFocusedElement(_subCall, _focusFixed); if(!fe) return; if(fe instanceof HTMLInputElement || fe instanceof HTMLTextAreaElement) { var ta = fe; try { var val = ta.value; var sel = val.substring(ta.selectionStart, ta.selectionEnd); } catch(e) { // Non-text HTMLInputElement return; } if(!sel && val && this.noSelBehavior && !_subCall) { if(this.noSelBehavior == 1) { ta.selectionStart = 0; ta.selectionEnd = val.length; sel = val; } else { this.handleNoSel(ta); return; } } if(!sel) return; var res = this.switchKeybLayout( sel, this.inPrimaryLayout(sel) ? this.convTableForward : this.convTableBackward ); if(res != sel) this.insertText(ta, res); } else if(fe.contentEditable == "true") { var doc = fe.ownerDocument; var docURI = doc.documentURI; if( docURI.substr(0, 5) == "data:" && docURI.indexOf("chrome://browser/skin/devtools/") != -1 ) { //~ todo: seems like we only can use paste from clipboard here... return; } var sel = doc.defaultView.getSelection(); var rng = sel.rangeCount && sel.getRangeAt(0); var tmpNode; if(!rng || rng.collapsed) { if(!this.noSelBehavior || _subCall) return; if(this.noSelBehavior == 1) { var r = doc.createRange(); r.selectNodeContents(fe); sel.removeAllRanges(); sel.addRange(r); tmpNode = fe.cloneNode(true); } else { this.handleNoSel(fe); return; } } else { tmpNode = doc.createElementNS("http://www.w3.org/1999/xhtml", "div"); tmpNode.appendChild(rng.cloneContents()); } var orig = tmpNode.innerHTML; var convTable = this.inPrimaryLayout(tmpNode.textContent) ? this.convTableForward : this.convTableBackward; var _this = this; var parseChildNodes = function(node) { if(node instanceof Element.isInstance(x)) { var childNodes = node.childNodes; for(var i = childNodes.length - 1; i >= 0; --i) parseChildNodes(childNodes[i]); } else if(node.nodeType == node.TEXT_NODE) { var text = node.nodeValue; var newText = _this.switchKeybLayout(node.nodeValue, convTable); if(newText != text) node.parentNode.replaceChild(doc.createTextNode(newText), node); } } parseChildNodes(tmpNode); var res = tmpNode.innerHTML; if(res != orig) doc.execCommand("insertHTML", false, res); } }, handleNoSel: function(node) { this.select(node); this.switchSelKeybLayout(true); }, select: function(node) { var e = this.noSelBehavior; if(!e || typeof e != "object") return; if(ChromeUtils.domProcessChild.childID) { var cmd = this.beh2cmd[e.ctrlKey + "_" + e.shiftKey + "_" + e.keyCode]; cmd && docShell.doCommand(cmd); } else node.dispatchEvent(new node.ownerGlobal.KeyboardEvent( "keypress", {bubbles: true, cancelable: true, ...e} )); }, beh2cmd: { // Ctrl_Shift_VK false_true_36: "cmd_selectLinePrevious", // Shift+Home }, insertText: function(ta, text) { //var editor = ta.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).editor var editor = ta.editor .QueryInterface(Components.interfaces.nsIPlaintextEditor || Ci.nsIEditor); if(editor.flags & editor.eEditorReadonlyMask) return; var sTop = ta.scrollTop; var sHeight = ta.scrollHeight; var sLeft = ta.scrollLeft; // var sWidth = ta.scrollWidth; if(text) editor.insertText(text); else editor.deleteSelection(0, 0); ta.scrollTop = sTop + (ta.scrollHeight - sHeight); ta.scrollLeft = sLeft; // + (ta.scrollWidth - sWidth); } }`)} catch(ex) {Cu.reportError(ex);}
//переключение раскладки клавиатуры по F8 try {(id => { var listener = { get obj() { var obj = document.getElementById(id); if (obj) obj = obj.linkedObj; else { obj = Cu.import("resource:///modules/CustomizableUI.jsm", {}) .gPalette.get(id); if (obj) obj = obj.implementation; else { Services.console.logStringMessage(id + " not found"); return this.destroy() || {switch() {}}; } } delete this.obj; return this.obj = obj; }, handleEvent(e) { if (e.key != "F8" || e.ctrlKey || e.shiftKey || e.altKey || e.repeat) return; //e.preventDefault(); //e.stopPropagation(); this.obj.switch(document); }, destroy: function destroy() { removeEventListener("keydown", this, true); removeEventListener("unload", destroy); } }; addEventListener("keydown", listener, true); addEventListener("unload", listener.destroy); })("SwitchKeyboardLayout");} catch(ex) {Cu.reportError(ex);}
Отсутствует
egorsemenov06
x instanceof *Element лучше заменить на *Element.isInstance(x)
Там три вхождения (поиск по «instanceof»).
Сделано не только неполно (только третье), да ещё и неправильно.
/* if(fe instanceof HTMLInputElement || fe instanceof HTMLTextAreaElement) { */ if(HTMLInputElement.isInstance(fe) || HTMLTextAreaElement.isInstance(fe)) { /* if(node instanceof Element.isInstance(x)) { */ if(Element.isInstance(node)) {
Отсутствует
egorsemenov06
Dumby пишетx instanceof *Element лучше заменить на *Element.isInstance(x)
Там три вхождения (поиск по «instanceof»).Сделано не только неполно (только третье), да ещё и неправильно.
скрытый текстВыделить кодКод:
/* if(fe instanceof HTMLInputElement || fe instanceof HTMLTextAreaElement) { */ if(HTMLInputElement.isInstance(fe) || HTMLTextAreaElement.isInstance(fe)) { /* if(node instanceof Element.isInstance(x)) { */ if(Element.isInstance(node)) {
Спасибо большое!!!А что неправильно где не полно я так и не понял заработало и слава Dumby
Отсутствует
Dumby, а вы не можете придумать способ, который позволял бы открывать закладки и историю в новой вкладке, когда открыта одна вкладка about:newtab..? Т.е, если поподробнее, то сейчас, когда запускаю фокс, то открыта только вкладка about:newtab, и , если жмякнуть по закладке, например, в боковой панели, то она откроется в текущей вкладке, а не в новой. То же самое и с историей. Меня почему-то это сильно напрягает... нужно, чтобы about:newtab (она же домашняя с плитками) не "затиралась", а оставалась "нетронутой". Привычка, может и вредная.
Добавлено 20-01-2023 16:14:11
Под способом, естественно, скрипт подразумевается, а не какие-нибудь клавиши и СКМ.
Отредактировано LGS (20-01-2023 16:14:11)
Отсутствует
LGS
https://forum.mozilla-russia.org/viewto … 05#p797605
Отредактировано kokoss (20-01-2023 19:25:18)
Win7
Отсутствует
kokoss
Я это пробовал, и это - у меня не работает. Именно после запуска ФФ, когда еще ни одна закладка не открывалась и ничего не посещалось. В этом случае закладка или история откроются в текущей about:newtab вкладке. Если вернуться обратно на about:newtab, то уже будет открываться в новых вкладках. Насколько я понял - нужна хотя бы одна посещенная вкладка, чтобы фокс начал открывать в новой вкладке. Может, Dumby что-нибудь придумает типа такого как здесь.
Отсутствует
а вы не можете придумать способ, который позволял бы открывать закладки и историю в новой вкладке, когда открыта одна вкладка about:newtab..? Т.е, если поподробнее, то сейчас, когда запускаю фокс, то открыта только вкладка about:newtab, и , если жмякнуть по закладке, например, в боковой панели, то она откроется в текущей вкладке, а не в новой. То же самое и с историей. Меня почему-то это сильно напрягает...
Этот -> https://forum.mozilla-russia.org/viewto … 05#p797605 скрипт так и работает, открывает( кроме дилов, в хотелке про открытие дилов в новой вкладке нет) закладки и историю в новой вкладке + user_pref("browser.tabs.loadBookmarksInTabs", true);
Добавлено 20-01-2023 21:32:15
у меня не работает. Именно после запуска ФФ, когда еще ни одна закладка не открывалась и ничего не посещалось. В этом случае закладка или история откроются в текущей about:newtab вкладке.
есть такое, тоже напрягает...
Отредактировано kokoss (20-01-2023 21:32:15)
Win7
Отсутствует
Эти скрипты так и работают, открывают закладки и историю в новой вкладке + user_pref("browser.tabs.loadBookmarksInTabs", true);
Работают, если открыта хотя-бы одна вкладка. Если открыта только about:newtab (сразу после запуска фокса), то закладка или история откроются в текущей вкладке (в моем случае это about:newtab).
Вообщем, если не лень, то можно воспроизвести:
1. Устанавливаем скрипт.
2. Запускаем ФФ.
3. Устанавливаем домашней страницей about:newtab.
4. Убираем (если включено) галку «Открыть предыдущие окна и вкладки» (или, в более старых версиях, «Восстанавливать предыдущую сессию».
5. Закрываем ФФ, запускаем снова. Фокс откроется с одной вкладкой (about:newtab).
6. Жмем, к примеру, закладку в боковой панели - она откроется в текущей вкладке, а не в новой.
Добавлено 20-01-2023 21:41:56
есть такое, тоже напрягает...
Ага, значит кое-как смог объяснить, что мне нужно...
Отредактировано LGS (21-01-2023 14:28:05)
Отсутствует
когда запускаю фокс, то открыта только вкладка about:newtab
То есть, ты хочешь забрать эту вкладку себе,
чтобы в неё places-добро не грузилось?
Можно так попробовать, вроде не должно грузиться
пока в эту вкладку не будет загружено что-то другим образом.
Код для custom_script_win.js
(async place => { await gBrowserInit.idleTasksFinishedPromise; var tabs = gBrowser.visibleTabs; if (tabs.length > 1) return; var re = /^about:(?:newtab|home)$/; var [tab] = tabs, br = tab.linkedBrowser; if (re.test(br.currentURI.spec)) br.loadURI = function(url, params) { if ( re.test(this.currentURI.spec) && gBrowser.selectedBrowser == this && Components.stack.formattedStack.includes(place) ) { var e = window.event || Services.focus.focusedWindow.event || Services.wm.getMostRecentWindow("Places:Organizer")?.event; if (e) { var node, trg = e.target; if (trg.nodeName == "treechildren") node = trg.parentNode.selectedNode; else if (trg.id == "placesCmd_open") { var popup = trg.ownerDocument.getElementById("placesContext"); node = popup._view.selectedNode || popup.triggerNode._placesNode; } else node = trg._placesNode; if (node) { PlacesUIUtils._openNodeIn(node, "tab", window); //gBrowser.selectedTab = tab; // force in background return; } } } delete this.loadURI; this.loadURI(url, params); } })("_openNodeIn@resource:///modules/PlacesUIUtils.");
можно воспроизвести
Не написано про галку «Открыть предыдущие окна и вкладки»
(или, в более старых версиях, «Восстанавливать предыдущую сессию»).
Кстати, можно прицепить что-нибудь к адресу, типа about:newtab#
тогда, вкладка с таким адресом, наверно, не будет рассматриваться как c «blank page url».
Не то же самое, что скрипт, но, при определённом раскладе, может представлять интерес.
Отсутствует
Кстати, можно прицепить что-нибудь к адресу, типа about:newtab#
тогда, вкладка с таким адресом, наверно, не будет рассматриваться как c «blank page url».
Не то же самое, что скрипт, но, при определённом раскладе, может представлять интерес.
Скрипт почему-то не зашел, а вот ваша мысль про about:newtab# пришлась очень кстати. Назначил домашней about:newtab# - теперь открывает как мне надо в новой вкладке. Единственное, пришлось стили подправить, которые завязаны были на about:newtab, но это мелочи.
Большое спасибо!
Скрипт заработал... из custom_script_all_win.js.
Отредактировано LGS (21-01-2023 16:30:51)
Отсутствует
Dumby
Возможно ли сделать кнопочку - удалить (очистить) сессию.
«The Truth Is Out There»
Отсутствует
unter_officer
(async ss => { ss = ChromeUtils.importESModule(ss).SessionStore; await ss.promiseAllWindowsRestored; CustomizableUI.createWidget({ id: "803529", localized: false, onCreated(btn) { var vals, keys = [, "label", "tooltiptext"]; var disable = () => { keys[0] = "disabled"; vals = [true, "No Last Session", "No last session, nothing to clear"]; } var setState = btn => { for(var ind in keys) btn.setAttribute(keys[ind], vals[ind]); } if (ss.canRestoreLastSession) { keys[0] = "oncommand"; var cmd = `SessionStore.canRestoreLastSession = false;`; vals = [cmd, "Clear Last Session", "Clear last session"]; var qt = "quit-application-granted"; var ct = "sessionstore-last-session-cleared"; var destroy = () => { Services.obs.removeObserver(obs, ct); Services.obs.removeObserver(destroy, qt); } var obs = () => { destroy(); disable(); var widget = CustomizableUI.getWidget(this.id); for(var win of CustomizableUI.windows) { var {node} = widget.forWindow(win); setState(node); node.removeAttribute("oncommand"); } } Services.obs.addObserver(obs, ct); Services.obs.addObserver(destroy, qt); } else disable(); (this.onCreated = btn => { setState(btn); btn.setAttribute("image", "chrome://global/skin/icons/close-fill.svg"); })(btn); } }); })("resource:///modules/sessionstore/SessionStore.sys.mjs");
Отсутствует
Dumby
Большое спасибо!
«The Truth Is Out There»
Отсутствует
Dumby
Подскажите пожалуйста.
Понадобился мне 78 ESR. Стал подключать UCF-кнопки и столкнулся с такой проблемкой.
Не получается подключить кнопки, которые сделаны в виде JSM'ок.
Пытаюсь подключать так:
scriptsbackground: [ // В фоне [System Principal] { func: 'ChromeUtils.import("chrome://user_chrome_files/content/custom_scripts/Script.jsm");' }, ],
Версия UCF крайняя (2021-9-23).
Консоль ничего не говорит.
Это особенность 78 версии или у меня лыжи не едут?
«The Truth Is Out There»
Отсутствует
Не получается подключить кнопки, которые сделаны в виде JSM'ок
У меня тоже лыжи не смазанные... правда, версия UCF старая 2021-2-14 и подключал в custom_script.js, как здесь (спойлеры внизу).
Консоль что-то говорит про:
ChromeUtils.domProcessChild.childID || ({
Это на 78esr. На 91esr, 102esr и последней релизной 109 нормально подхватывается.
Отредактировано LGS (08-02-2023 09:36:41)
Отсутствует
Не получается подключить кнопки, которые сделаны в виде JSM'ок.
Испёк портабл 78.15.0esr + UCF 2021-9-23
Проставил галку «Включить скрипты:»
[✔] В фоне [System Principal]
Создал в папке custom_scripts файл Script.jsm
var EXPORTED_SYMBOLS = []; ChromeUtils.import("resource:///modules/CustomizableUI.jsm").CustomizableUI.createWidget({ id: "is_78esr_special_test", label: "TEST: is 78ESR Special?", tooltiptext: "TEST: is 78ESR Special?", localized: false, onCreated(btn) { btn._handleClick = function() { this.ownerGlobal.Services.prompt.alert(null, null, "Success!"); } btn.setAttribute("image", "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQ=="); } });
Таким образом, ответ на вопрос «Это особенность 78 версии или у меня лыжи не едут?»
будет такой: нет, 78-я версия ничем здесь не особенная.
Консоль что-то говорит про:
ChromeUtils.domProcessChild.childID
Правильно говорит, в 78 у ChromeUtils нет свойства domProcessChild
Наверно, можно заменить ChromeUtils.domProcessChild.childID
на ChromeUtils.contentChild
Отсутствует
Таким образом, ответ на вопрос «Это особенность 78 версии или у меня лыжи не едут?»
будет такой: нет, 78-я версия ничем здесь не особенная.
Оказалось, что дело в самих кнопках.
По вашему совету заменил ChromeUtils.domProcessChild.childID на ChromeUtils.contentChild.
Кнопка LongLeftClick заработала без ошибок.
Кнопка Reload user{Chrome, Content}.css работает, но при нажатии ПКМ все же выдает в консоль TypeError: ChromeUtils.getAllDOMProcesses is not a function.
Кнопка Сохранить страницу или выбранное как HTML появилась, но не работает. Консоль пишет TypeError: cwg.domProcess is undefined.
В Старом about:config я ничего не редактировал. Просто не работает. Консоль пишет: TypeError: L10nRegistry.registerSources is not a function.
Отредактировано unter_officer (08-02-2023 11:39:08)
«The Truth Is Out There»
Отсутствует
Кнопка Reload user{Chrome, Content}.css работает, но при нажатии ПКМ все же выдает в консоль TypeError: ChromeUtils.getAllDOMProcesses is not a function.
Да, метод добавлен только c Firefox 80+
Без него, разве что process script'ом пытаться пнуть.
var name = "UCFUserCReloader", EXPORTED_SYMBOLS = [name + "Parent", name + "Child"]; var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); var find = function(sheet) { return sheet.href == this; } var getSheet = (doc, href) => InspectorUtils.getAllStyleSheets(doc).find(find, href); if (!ChromeUtils.contentChild) { var data, url; var noop = () => {}; var getURI = sub => { var file = Services.dirsvc.get("UChrm", Ci.nsIFile); file.append(`userC${sub}.css`); return Services.io.newFileURI(file).QueryInterface(Ci.nsIFileURL); } var oncontextmenu = e => e.ctrlKey || e.shiftKey || e.detail != 1 || contextmenu(e); var contextmenu = e => { var {file, spec} = getURI("ontent"); var wb = Services.appShell.createWindowlessBrowser(); var contentSheet = getSheet(wb.document, spec); wb.close(); if (!contentSheet) return oncontextmenu = contextmenu = noop; url = spec; var child = {moduleURI: __URI__}; ChromeUtils.registerProcessActor(name, {child, parent: child}); var ps = `data:,ChromeUtils.contentChild?.getActor("${name}").query()`; (contextmenu = async e => { if (!file.exists()) return; e.preventDefault(); data = await reload(contentSheet, Object.create(null)); if (data) for(var p in data) { Services.ppmm.loadProcessScript(ps, false); return e.view.setTimeout(restyle, 150); } })(e); } ChromeUtils.import("resource:///modules/CustomizableUI.jsm").CustomizableUI.createWidget({ label: "Reload user{Chrome, Content}.css", tooltiptext: "L: Reload userChrome.css\nR: Reload userContent.css", id: "798278", localized: false, onCreated(btn) { btn._handleClick = this.click; btn.oncontextmenu = oncontextmenu; btn.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAIpwAACKcBMsYCAwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAMwSURBVEiJ5dbNb5RVFMfxz3mmrYgYE0IN4IaKb4n4UqOwMCYu2JCoQVDiwoUrQ4j0xao7ExITQxRoodEFK1cmRkSE8AeYYKpEFF0YY4SiUSMRQW0sLe0818U8nekwHe3U7vhtnnNOzj3f89znPvderjVFK8npaSWrPSjpElahQzhvyrF4y++t1GqbF7DHOvQLj6Ozrt2EDutYRHAasMK0vXgWWZO0SX/7DlJf6Skp3UWcFeVRV4zG235tCZx6rDPtKLqqAN4XPhROm3DJEiG3LA6aKkZ14jUSKaOd1Gsco6Qz8vRiDDvTFJz63S13AjdVAg7JvBxDzs2RfrE2MP9ijolZijvJXo/h8pmmb5z6LZf7qICWJQNxwP5mM1OnzNdy03V1U0oi2x77y+/Wp16t3CDWgvDKvKGIQZepfO+iWBIpKG9s7HGW0k7dKgsJjsSQffOF1or4srAuS04U9jOp14amYGGgiF2Re6llaEWnMSbPNyl5DtNFQzvnBKdd2oRNhXt4ZvW1rCwfkbInY9jHMeiscBiEJ9Lz2mfSaovgovXC8sI7siAoYsgnMy8JkmPYhhtdbwOV6a9NdVhT69qphYIblPl0FuO2WrimVVVrcu7dZkFqd75q525uBCelqj0tXzRwvSYbwWZ1doOVi4Yad0vVDj81gjPfV+2y9YsGLnlgFrj6p9TA405irPAemwmn/raNqc/D/wO9uXj+bMhXDeDihDledLYt9VmTektb5flxebYgcOpx+yzw0aic3vXgSqY9hdUuOUx6T+WWcX/LUELYh3ZMyqq1G8FxwCl8ULjdVFd6d6tgPQbMfLIwHIPONgVXWs1OFm3Mjt6Rdlg2X2bq0yfsLtzP/OHVq3PqzuPUm/Vj9xz9ZDrcg5F/Bb6gS8mbkq1F6EdlW+IdE03Baae1pEeJb1SuO0vrMvPsPvKRArDaChf8qWRal/BQccBsxnXFiBFTtjS7czW93qYdVurQJZW6SLeK+DaGyofSLh0uGUNHk6F/SfZI3ojh2k41b3DThnrdS+1/nAnjcxzR5mDsdeG/6szrXl2nJX4w4RFJJ3LhF7lzMey3lmtdU/oHaoj4Y/PDRWgAAAAASUVORK5CYII="); }, get click() { var {file, spec} = getURI("hrome"); var chromeSheet = getSheet(Services.wm.getMostRecentWindow(null).document, spec); delete this.click; return this.click = !chromeSheet ? noop : function() { var win = this.ownerGlobal; if (win.event?.detail < 2 && file.exists()) reload(chromeSheet), win.setTimeout(restyle, 50); } } }); var restyle = () => { var subst = "u_css_reloader_restyle_substitution"; var rph = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler); rph.setSubstitution(subst, Services.io.newURI("data:text/css,:root{}")); var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); var args = [Services.io.newURI(`resource://${subst}/`), sss.USER_SHEET]; (restyle = () => { sss.loadAndRegisterSheet(...args); sss.unregisterSheet(...args); })(); } var reload = async (sheet, obj) => { try {var style = await (await fetch(sheet.href)).text();} catch {return obj;} InspectorUtils.parseStyleSheet(sheet, style); if (obj) obj[sheet.href] = style; for(var ind = 0, len = sheet.cssRules.length; ind < len; ind++) { var rule = sheet.cssRules.item(ind); rule.type == rule.IMPORT_RULE && rule.styleSheet.href.startsWith("file:///") && await reload(rule.styleSheet, obj); } return obj; } var UCFUserCReloaderParent = class extends JSProcessActorParent { receiveMessage(msg) { return msg.name ? url : data; } } } else var UCFUserCReloaderChild = class extends JSProcessActorChild { async query() { var {sheet} = this; if (!sheet) { var en = Services.ww.getWindowEnumerator(null); if (en.hasMoreElements()) sheet = this.sheet = getSheet(en.getNext().document, await this.sendQuery("u")); } sheet && this.parse(sheet, await this.sendQuery("")); } parse(sheet, data) { var style = data[sheet.href]; if (!style) return; InspectorUtils.parseStyleSheet(sheet, style); for(var ind = 0, len = sheet.cssRules.length; ind < len; ind++) { var rule = sheet.cssRules.item(ind); rule.type == rule.IMPORT_RULE && rule.styleSheet.href.startsWith("file:///") && this.parse(rule.styleSheet, data); } } }
Кнопка Сохранить страницу или выбранное как HTML появилась, но не работает. Консоль пишет TypeError: cwg.domProcess is undefined.
Если бы только это.
Ещё нет nsIFocusManager.focusedContentBrowsingContext
и напрочь отсутствует IOUtils как таковой.
Ладно, можно попробовать что-нибудь подпаять.
Вот первая часть. Остальное, var snap = mainWin => {…} такое же.
var name = "UCFSaveSnapshotToHTML", EXPORTED_SYMBOLS = [name + "Child"]; var fw = win => { var gfe = Cc["@mozilla.org/focus-manager;1"] .getService(Ci.nsIFocusManager).getFocusedElementForWindow; return (fw = win => { var res = {}; var fe = gfe(win, true, res); return [res.value, fe]; })(win); } if (!ChromeUtils.contentChild) { var click = async function() { var win = this.ownerGlobal; var bc = win.gBrowser.selectedBrowser.browsingContext, cwg = bc.currentWindowGlobal; var fp = picker(win, "", Ci.nsIFilePicker.modeSave); if (cwg.isInProcess) { var [fwin, fe] = fw(bc.window); if (fe?.matches("browser[remote=true]")) cwg = fe.browsingContext.currentWindowGlobal; } var [fileContent, fileName] = cwg.isInProcess ? snap(fwin) : await cwg.contentParent.getActor(name).sendQuery("", cwg.innerWindowId); fp.defaultString = fileName; fp.appendFilters(fp.filterHTML); fp.appendFilters(fp.filterAll); await new Promise(fp.open) != fp.returnCancel && win.OS.File.writeAtomic(fp.file.path, new win.TextEncoder().encode(fileContent)); } ChromeUtils.import("resource:///modules/CustomizableUI.jsm").CustomizableUI.createWidget({ label: "796961", tooltiptext: "796961", id: "796961", localized: false, onCreated(btn) { btn._handleClick = click; btn.setAttribute("image", "chrome://devtools/skin/images/tool-application.svg"); } }); var picker = (...args) => { ChromeUtils.registerProcessActor(name, {child: {moduleURI: __URI__}}); return (picker = Components.Constructor( "@mozilla.org/filepicker;1", "nsIFilePicker", "init" ))(...args); } } else var UCFSaveSnapshotToHTMLChild = class extends JSProcessActorChild { receiveMessage(msg) { return snap(fw(WindowGlobalChild.getByInnerWindowId(msg.data).browsingContext.window)[0]); } }
В Старом about:config я ничего не редактировал. Просто не работает. Консоль пишет: TypeError: L10nRegistry.registerSources is not a function.
Странно, там же есть старый about:config.
chrome://global/content/config.xhtml
Но если, зачем-то, надо, то можно после строки, содержащей
.import("resource://gre/modules/L10nRegistry.jsm"); дописать
// if (!L10nRegistry.registerSources) L10nRegistry = Object.assign( Object.create(L10nRegistry), {registerSources([s]) {this.registerSource(s);}, removeSources([s]) {this.removeSource(s);}} );
Отредактировано Dumby (10-02-2023 09:10:56)
Отсутствует
Dumby
Кнопочки "Reload user{Chrome, Content}.css" и "Сохранить страницу или выбранное как HTML" теперь отлично работают.
Про то, что в 78 в старый about:config можно попасть по адресу chrome://global/content/config.xhtml, я за давностью забыл напрочь.
Огромное спасибо за помощь!
«The Truth Is Out There»
Отсутствует
Dumby
Если не сложно, переделайте под 78 вот этот скриптик:
// // HTTP Request Logger .......... // https://forum.mozilla-russia.org/viewtopic.php?pid=794053#p794053 ..... // (async self => CustomizableUI.createWidget(({ label: "HTTP Request Logger", tooltiptext: "HTTP Request Logger", fileName: "http-request-log.txt", images: { true: "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/AAAA/wAAAP/AwMD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/wMDA/wAAAP8AAAD/wMDA/wAAAP9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/AAAA/8DAwP8AAAD/AAAA/8DAwP8AAAD/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/wAAAP/AwMD/AAAA/wAAAP/AwMD/AAAA/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf8AAAD/wMDA/wAAAP8AAAD/wMDA/wAAAP9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/AAAA/8DAwP8AAAD/AAAA/8DAwP8AAAD/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/wAAAP/AwMD/AAAA/wAAAP/AwMD/AAAA/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf8AAAD/wMDA/wAAAP8AAAD/wMDA/wAAAP9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/AAAA/8DAwP8AAAD/AAAA/8DAwP8AAAD/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/wAAAP/AwMD/AAAA/wAAAP/AwMD/AAAA/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf8AAAD/wMDA/wAAAP8AAAD/wMDA/wAAAP9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/Zv+Z/2b/mf9m/5n/AAAA/8DAwP8AAAD/AAAA/8DAwP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP/AwMD/AAAA/wAAAP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQ==", false: "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/AAAA/wAAAP/AwMD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/wMDA/wAAAP8AAAD/wMDA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8DAwP8AAAD/AAAA/8DAwP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AwMD/AAAA/wAAAP/AwMD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wMDA/wAAAP8AAAD/wMDA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8DAwP8AAAD/AAAA/8DAwP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AwMD/AAAA/wAAAP/AwMD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wMDA/wAAAP8AAAD/wMDA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8DAwP8AAAD/AAAA/8DAwP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AwMD/AAAA/wAAAP/AwMD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wMDA/wAAAP8AAAD/wMDA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8DAwP8AAAD/AAAA/8DAwP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP/AwMD/AAAA/wAAAP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AACsQQAArEEAAKxBH/isQR/4rEEf+KxBH/isQR/4rEEf+KxBH/isQR/4rEEf+KxBH/isQQAArEEAAKxBAACsQQ==" }, id: "ucf-httpRequestLogger", localized: false, init(pref) { var topic = "http-on-modify-request"; this.toggle = () => Services.prefs.setBoolPref(pref, !this.active); var prefObs = () => { var val = Services.prefs.getBoolPref(pref, false); if (this.active ^ (this.active = val)) Services.obs[`${val ? "add" : "remove"}Observer`](this, topic); this.setBtnsState(); } prefObs(); Services.prefs.addObserver(pref, prefObs); Services.obs.addObserver(function quit(s, t) { Services.obs.removeObserver(quit, t); Services.prefs.removeObserver(pref, prefObs); self.active && Services.obs.removeObserver(self, topic); }, "quit-application-granted"); return self = this; }, onCreated(btn) { btn._handleClick = this.toggle; btn.setAttribute("image", this.images[this.active]); }, setBtnsState() {this.setBtnsState = () => { var img = this.images[this.active]; var widget = CustomizableUI.getWidget(this.id); for(var win of CustomizableUI.windows) widget.forWindow(win).node?.setAttribute("image", img); }}, log: "", observe(channel) { if (!(channel instanceof Ci.nsIHttpChannel)) return; this.log += `${ channel.referrerInfo?.originalReferrer?.spec || "(none)" } ${ channel.requestMethod } ${ channel.URI.spec }\r\n`; this.busy || this.write(); }, write() { var file = Services.dirsvc.get("UChrm", Ci.nsIFile); file.append(this.fileName); var {path} = file; var {IOUtils} = Cu.getGlobalForObject(Cu); var modes = [{mode: "create"}, {mode: "append"}]; var unbusy = () => { this.busy = false; this.log && this.write(); } (this.write = () => { this.busy = true; var {log} = this; this.log = ""; IOUtils.writeUTF8(path, log, modes[+file.exists()]) .finally(unbusy); })(); } }).init("ucf.httpRequestLogger.enabled")))();
«The Truth Is Out There»
Отсутствует
unter_officer
Попробуй такой write()
// write() { var file = Services.dirsvc.get("UChrm", Ci.nsIFile); file.append(this.fileName); var flags = 0x02 | 0x08 | 0x10; // MODE_WRONLY | MODE_CREATE | MODE_APPEND var args = ["@mozilla.org/network/file-output-stream;1", "nsIFileOutputStream", "init"]; var fos = Components.Constructor(...args).bind(null, file, flags, 0o644, 0); var sis = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream); var copier = Cc["@mozilla.org/network/async-stream-copier;1"].createInstance(Ci.nsIAsyncStreamCopier2); var ro = {onStartRequest() {}}; ro.onStopRequest = () => { this.busy = false; this.log ? this.write() : sis.setData("", 0); }; (this.write = () => { this.busy = true; sis.setUTF8Data(this.log); this.log = ""; try { copier.init(sis, fos(), null, 0, true, true); copier.asyncCopy(ro, null); } catch(ex) { this.toggle(); ro.onStopRequest(); Services.prompt.alert(null, this.label, ex.message); } })(); }
Отсутствует