Подскажите, как вернуть к жизни add_toolbar_buttons.2021.9.5.xpi на 102 (Final или ESR), очень уж удобный плагин !
Вы же процитировали решение, просто обновите код для отключения... на тот что под спойлером!
Win7
Отсутствует
Извиняюсь, вставлял код на профиль после запуска со старой "антиподпиской", не сработал. Сейчас вытащил из бэкапа профиль от 101 версии, накатил обнову и новый код. Всё отлично, спасибо !
Отсутствует
Dumby
Можете посмотреть расширение Open Link with New Tab? На 91.11 и 102 начался периодический отвал, проявляется в том что иногда ссылки по Ctrl+ЛКМ начинают открываться в новом окне, перезапуск расширения лечит это.
Отредактировано _zt (03-07-2022 09:14:24)
Отсутствует
Dumby
с последним обновлением ff отваливается такой скрипт, не везде срабатывает: в строке адреса, в строке поиска на стартовом экране - не работает совсем, а на большинстве форум в окнах ввода срабатывает. Странно...
// MiddleMouse.Paste с заменой выделенного текста (порт с СВ) try {((id, code, gmon) => { var d = "data:,", ref = "globalThis." + id, dref = d + ref; var psi = `${dref} = ${encodeURIComponent(code)};`; var psd = `${d}delete ${ref};`; var e10s = Services.appinfo.browserTabsRemoteAutostart; if (e10s) var fsi = `${dref}.listen(this, "add");`, fsd = `${dref}.listen(this);`; var g = Cu.getGlobalForObject(Cu), pref = "middlemouse.paste"; var obs = { pref: Services.prefs.getBoolPref.bind(null, pref), startup() { Services.prefs.addObserver(pref, this); Services.obs.addObserver(this, "quit-application-granted", false); this.pref() && this.init(); this.gmon(); }, async gmon() { Cu.importGlobalProperties(["fetch"]); var url = "chrome://custombuttons/content/editExternal.js"; try {var src = await (await fetch(url)).text();} catch(ex) {return;} src = src.replace(/function gmon_edit_mouseclick[^}]+?}/, gmon); var arr = [["override", url, "data:," + encodeURIComponent(src)]]; url = Services.io.getProtocolHandler("resource").getSubstitution("gre"); this.gmonHelper = Cc["@mozilla.org/addons/addon-manager-startup;1"] .getService(Ci.amIAddonManagerStartup).registerChrome(url, arr); }, shutdown() { this.pref() && this.destroy(); e10s && Services.ppmm.removeDelayedProcessScript(psi), Services.ppmm.loadProcessScript(psd, false); Services.prefs.removeObserver(pref, this); Services.obs.removeObserver(this, "quit-application-granted"); this.gmonHelper && this.gmonHelper.destruct(); }, init() { e10s && Services.mm.loadFrameScript(fsi, true); Services.obs.addObserver(this, "widget-first-paint", false); this.wins("add"); }, destroy() { if (e10s) Services.mm.removeDelayedFrameScript(fsi), Services.mm.loadFrameScript(fsd, false); Services.obs.removeObserver(this, "widget-first-paint"); this.wins(); }, observe(subj, topic) { var char = topic[0]; if (char == "w") return this.call(subj, "add"); if (char == "q") return this.shutdown(); this[this.pref() ? "init" : "destroy"](); }, wins(arg) { for(var win of Services.wm.getEnumerator(null)) this.call(win, arg); }, listen() {} }; Services.ppmm.loadProcessScript(psi, e10s); g[id].call = g[id].listen; Object.assign(g[id], obs).startup(); })("ucf_custom_script_js_MiddleMousePaste", `{ listen(trg, prfx = "remove") { var meth = prfx + "EventListener"; trg[meth]("auxclick", this, true); trg[meth]("unload", this); }, handleEvent(e) {this[e.type](e);}, unload(e) {this.listen(e.target);}, sn: Ci.nsISelectionController.SELECTION_NORMAL, inRect: (r, x, y) => y > r.top && y < r.bottom && x < r.right && x > r.left, auxclick(e) { if (e.button != 1) return; var trg = (e.originalTarget || e.target).closest( "input:not([disabled]),textarea:not([disabled])" ); if (!trg) return; var ed = trg.editor; if (!ed || ed.selection.isCollapsed || !ed.canPaste(this.sn)) return; var x = e.clientX, y = e.clientY, rng = ed.selection.getRangeAt(0); if (!this.inRect(rng.getBoundingClientRect(), x, y)) return; var list = rng.getClientRects(); if (list.length == 1 || Array.from(list).some( rect => this.inRect(rect, x, y) )) ed.paste(this.sn, e.preventDefault()); } }`, `\ function gmon_edit_mouseclick(e) { var mmp = Cc["@mozilla.org/preferences-service;1"] .getService(Ci.nsIPrefBranch).getBoolPref.bind(null, "middlemouse.paste"); (gmon_edit_mouseclick = e => e.button != 1 || mmp() || edittarget(e.target))(e); }`); } catch(ex) {Cu.reportError(ex);} ((bu, bm, {star} = bu) => addEventListener("mouseenter", { async handleEvent() { if (!this.starred) return; star.tooltipText = "\u3164"; var result = []; await this.fetch(); for(var guid of this.guids) { var arr = []; while(true) { if (!this.hover) return; var res = await bm.fetch(guid); if ((guid = res.parentGuid) == bm.rootGuid) { arr.unshift(bm.getLocalizedTitle(res)); break; } arr.unshift(res.title || "[Безымянная папка]"); } result.push(arr.join("\\")); } this.hover && this.setTooltip(result); }, get fetch() { addDestructor(() => this.starred && document.l10n.translateElements([star])); var set = this.guids = new Set(); var args = [b => set.add(b.parentGuid), {concurrent: true}]; delete this.fetch; return this.fetch = () => set.clear() || bm.fetch({url: gBrowser.currentURI.spec}, ...args); }, setTooltip(arr) { var m = arr.length > 1; var text = `Адрес${m ? "а" : ""} заклад${m ? "ок" : "ки"}:\n${arr.join("\n")}`; document.tooltipNode == star ? this.tt.label = text : star.tooltipText = text; }, get tt() { var list = InspectorUtils.getChildrenForNode(document.documentElement, true); delete this.tt; return this.tt = list.item(list.length - 1); }, get starred() {return bu._itemGuids.size;}, get hover() {return star.matches(":hover");} }, false, star || 1))(BookmarkingUI, PlacesUtils.bookmarks);
и вопрос по тому же Switch Keyboard Layout button: переключаешь раскладку для слов начинающихся на букву Б, Ю, Ж - код срабатывает некорректно
Отредактировано Inko7 (03-07-2022 16:59:15)
Отсутствует
Dumby
Сделайте пожалуйста, что бы скрипт: Очистить панель адреса или поиска прокруткой колёсиком мыши на панели работал во всех панелях поиска, включая контент!
Win7
Отсутствует
расширение
Это не расширение, а WebExtensions.
иногда
И где же мне взять это «иногда»? Не́где.
Можете посмотреть
Смотреть там особо неначто.
Регистрируется контентский скрипт, который,
запрашивает пользовательскую аддонскую настройку,
и если она не равна нулю (типа, установлена, и как 1 или 2)
тогда идёт перебор всех элементов <a>, которые присутствуют в DOM-дереве документа
(на момент исполнения скрипта, добавленные [как-то] позже идут лесом; и те, которые в Shadow DOM тоже, наверно, в пролёте),
и, если элемент (собственно ссылка) имеет href, тогда ему уставливается атрибут "target" со значением "_blank".
(ну, там в зависимости от 1 или 2, как-бы same-site или нет, неважно).
Вот и всё. Атрибут либо уставливается, либо нет.
Если атрибут должен устанавливаться, но не устанавливается,
тогда не знаю почему. Может storage.sync глючит (?).
В таком случае можно попробовать заменить все browser.storage.sync на browser.storage.local
и заново посетить настройки аддона. Предположение, разумеется, ни на чём не основано.
А так-то, допустим, если уже установлена какая-либо обезьяна,
то скриптов для неё, делающих нечто подобное, должно быть (ну, я так предполагаю) навалом.
И не просто подобное, а гораздо более ультимативное.
Может попробуй смигрировать в эту сторону.
такой скрипт
Это ты мне что-то совсем левое древнее впариваешь.
Ещё и какой-то star-тултипский код в конце прицеплен, непонятно зачем.
Последний вариант вроде как здесь.
Но, железная поступь проекта «JSM-геноцид»,
рано или поздно, сметёт не только это, а вообще всё.
Если нет возможности вникнуть в это сейчас (пока никто не торопит)
то лучше отказаться от всего подобного сразу, нечего не дожидаясь.
для слов начинающихся на букву Б, Ю, Ж - код срабатывает некорректно
Да видел я пост про «Б». Ин-валидно.
Нет никаких проблем с «Б» (как и с «Ю»).
С «Ж», да, есть проблемы.
Так же, как есть проблемы и с «б», «ю», «ж», «Э».
Но код-то не мой, я просто перегонял исходник из пустого в порожнее.
Возможно, чуть лучше будет с такой правкой
/* if(c in this.convTableForward) return true; if(c in this.convTableBackward) return false; */ var primary = c in this.convTableForward; if(primary ^ c in this.convTableBackward) return primary;
включая контент
Увы, делам контентским, вебским, я весьма посторонен.
Могу только извиниться за это.
Отсутствует
Последний вариант вроде как здесь.
Как-то пропустил его, но он все равно не работает в строке адреса и в строке поиска на стартовой странице FF. Может оно и не особо критично...
Возможно, чуть лучше будет с такой правкой
изменений пока не заметил
Отсутствует
Ещё и какой-то star-тултипский код в конце прицеплен, непонятно зачем.
Точно! Думаю, где же он спрятался)))
У меня есть два варианта кода, кто из них новее/лучше не знаю. Но у обоих есть глюк - открываем закладку, с нее переходим по внутр. ссылкам куда-либо, звездочка соответственно теперь пустая в адресной строке, а тултип все равно показывается с путём к изначально открытой закладке. Такое очень часто.
// Показать адрес существующей закладки при наведении на звездочку try {((bu, bm, {star} = bu) => { var listener = { async handleEvent() { if (!bu._itemGuids.size) return; star.tooltipText = "\u3164"; var result = []; await this.fetch(); for(var guid of this.guids) { var arr = []; while(true) { if (!this.hover) return; var res = await bm.fetch(guid); if ((guid = res.parentGuid) == bm.rootGuid) { arr.unshift(bm.getLocalizedTitle(res)); break; } arr.unshift(res.title || "[Безымянная папка]"); } result.push(arr.join("\\")); } this.hover && this.setTooltip(result); }, get fetch() { var set = this.guids = new Set(); var args = [b => set.add(b.parentGuid), {concurrent: true}]; delete this.fetch; return this.fetch = () => set.clear() || bm.fetch({url: gBrowser.currentURI.spec}, ...args); }, setTooltip(arr) { var m = arr.length > 1; var text = `Адрес${m ? "а" : ""} заклад${m ? "ок" : "ки"}:\n${arr.join("\n")}`; document.tooltipNode == star ? this.tt.label = text : star.tooltipText = text; }, get tt() { var list = InspectorUtils.getChildrenForNode(document.documentElement, true); delete this.tt; return this.tt = list.item(list.length - 1); }, get hover() {return star.matches(":hover");} }; star.addEventListener("mouseenter", listener); addEventListener("unload", () => star.removeEventListener("mouseenter", listener) , {once: true}); })(BookmarkingUI, PlacesUtils.bookmarks);} catch(ex) {Cu.reportError(ex);}
// Показать адрес существующей закладки при наведении на звездочку ((bu, bm, {star} = bu) => addEventListener("mouseenter", { async handleEvent() { if (!this.starred) return; star.tooltipText = "\u3164"; var result = []; await this.fetch(); for(var guid of this.guids) { var arr = []; while(true) { if (!this.hover) return; var res = await bm.fetch(guid); if ((guid = res.parentGuid) == bm.rootGuid) { arr.unshift(bm.getLocalizedTitle(res)); break; } arr.unshift(res.title || "[Безымянная папка]"); } result.push(arr.join("\\")); } this.hover && this.setTooltip(result); }, get fetch() { addDestructor(() => this.starred && document.l10n.translateElements([star])); var set = this.guids = new Set(); var args = [b => set.add(b.parentGuid), {concurrent: true}]; delete this.fetch; return this.fetch = () => set.clear() || bm.fetch({url: gBrowser.currentURI.spec}, ...args); }, setTooltip(arr) { var m = arr.length > 1; var text = `Адрес${m ? "а" : ""} заклад${m ? "ок" : "ки"}:\n${arr.join("\n")}`; document.tooltipNode == star ? this.tt.label = text : star.tooltipText = text; }, get tt() { var list = InspectorUtils.getChildrenForNode(document.documentElement, true); delete this.tt; return this.tt = list.item(list.length - 1); }, get starred() {return bu._itemGuids.size;}, get hover() {return star.matches(":hover");} }, false, star || 1))(BookmarkingUI, PlacesUtils.bookmarks);
Добавлено 03-07-2022 21:46:08
Ну, значит у кого-то из нас (двоих) руки кривые.
тут спору нет
о каком конкретно скрипте речь?
Отредактировано Inko7 (03-07-2022 21:46:08)
Отсутствует
а тултип все равно показывается с путём к изначально открытой закладке
/* if (!bu._itemGuids.size) return; */ if (!bu._itemGuids.size) return star.removeAttribute("tooltiptext");
о каком конкретно скрипте речь?
Об обоих двух.
Отсутствует
Inko7
Ну, значит у кого-то из нас (двоих) руки кривые.
Тут бы хорошо услышать мнение третьей стороны,
но вряд-ли таковое нарисуется, сложновато это всё, наверно.
У меня везде всё вставляет, без проблем.
Отсутствует
Dumby
Понял в чем было дело. По инструкции для MMPaste.jsm нужно было:
можно добавив в конфигурационный CustomStylesScripts.jsm
в массив UcfStylesScripts.scriptsbackground объект вида
{ func: 'ChromeUtils.import("chrome://user_chrome_files/content/custom_scripts/MMPaste.jsm");' },
а у меня скрипты загружались уже через сам файл custom_script.js
(() => { var loadscript = name => { try { Services.scriptloader.loadSubScript(`chrome://user_chrome_files/content/custom_scripts/${name}`, globalThis, "UTF-8"); } catch(e) {} }; loadscript("./js/kbd_layout.js"); loadscript("./js/MiddleMouse_Paste.js"); })();
Отсутствует
"./js/kbd_layout.js"
Это что ещё за дот-слэш в начале?
В данном случае — совершенно неуместно.
Работает, видимо, только потому, что где-то стоит защита от подобных выкрутасов.
но так же они тоже подгружались, просто как-то не совсем корректно?
kbd_layout.js — это просто скрипт.
Можно грузить так, как у тебя, можно инлайн,
можно любым другим аналогичным способом, так что здесь всё верно.
А Middle Mouse Paste — это модуль (jsm'ка, пока ещё).
Модули не грузят как скрипт. Их импортируют.
Так что здесь неверно, следует импортировать так, как сказано.
Отсутствует
Dumby
А так-то, допустим, если уже установлена какая-либо обезьяна, то скриптов для неё, делающих нечто подобное, должно быть (ну, я так предполагаю) навалом
Да, есть маленько.
В таком случае можно попробовать заменить все browser.storage.sync на browser.storage.local и заново посетить настройки аддона.
Уже не хочу, так как найденный скрипт работает лучше, например на github внешние ссылки корректно открывает в новой вкладке, ну и т.п.
Только вот, можете этот скрипт переделать под ucf, с настройками в самом файле.
Отсутствует
Middle Mouse Paste — это модуль (jsm'ка, пока ещё).
Раз jsm-ки скоро отвалится, то весь UCF и CustomStylesScripts.jsm и CustomStylesScriptsChild.jsm тоже перестанут работать?
var EXPORTED_SYMBOLS = ["MouseImgSaverChild", "MouseImgSaverParent"]; // by Dumby сохранить картинку колёсиком или перетащив вправо; DBL поиск похожих var u = {get it() { // https://forum.mozilla-russia.org/viewtopic.php?pid=793837#p793837 delete this.it; return this.it = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools); }}; for(let name of ["E10SUtils", "PrivateBrowsingUtils"]) ChromeUtils.defineModuleGetter(u, name, `resource://gre/modules/${name}.jsm`); class MouseImgSaverChild extends JSWindowActorChild { handleEvent(e) { // клики мышью if (e.button > 1) return; // только ЛКМ, СКМ var trg = e.explicitOriginalTarget; // dragstart trg.nodeType == Node.ELEMENT_NODE && trg instanceof Ci.nsIImageLoadingContent && this[e.type](trg, e); } handleDragEvent(e) { this[e.type](e); } dragstart(trg, e) { this.trg = trg; this.x = e.screenX; this.y = e.screenY; this.drag("add"); this.handleEvent = this.handleDragEvent; this.checkTextLinkyTool(trg.ownerDocument); } events = ["dragover", "drop", "dragend"]; drag(meth = (delete this.handleEvent, delete this.trg, "remove")) { meth += "EventListener"; var win = this.contentWindow; for(var type of this.events) win[meth](type, this, true); } drop() { this.drag(); } dragover(e) { var {x, y} = this, cx = e.screenX, cy = e.screenY, dx = cx - x, ax = Math.abs(dx), ay = Math.abs(cy - y); if (ax < 10 && ay < 10) return; if (dx < 0 || ax < ay) return this.drag(); this.x = cx; this.y = cy; } dragend(e) { // перетаскивание рисунка var dt = e.dataTransfer, {trg} = this; this.drag(); dt.mozUserCancelled || this.send(trg, e.screenX); // сохранить // dt.mozUserCancelled || this.sendAsyncMessage("dragend", (trg.currentRequestFinalURI || uri).spec); } auxclick(trg) { // клик СКМ trg.matches(":any-link :scope") || this.send(trg); } dblclick(trg) { // ЛКМ trg.matches(":any-link :scope") || this.sendAsyncMessage("dblclick", (trg.currentRequestFinalURI || uri).spec); } send(trg, sx) { var uri = trg.currentURI; if (!uri) return; var doc = trg.ownerDocument; var cookieJarSettings = u.E10SUtils .serializeCookieJarSettings(doc.cookieJarSettings); var referrerInfo = Cc["@mozilla.org/referrer-info;1"] .createInstance(Ci.nsIReferrerInfo); referrerInfo.initWithElement(trg); referrerInfo = u.E10SUtils.serializeReferrerInfo(referrerInfo); var contentType = null, contentDisposition = null; try { var props = u.it.getImgCacheForDocument(doc).findEntryProperties(uri, doc); var cs = Ci.nsISupportsCString; try {contentType = props.get("type", cs).data;} catch {} try {contentDisposition = props.get("content-disposition", cs).data;} catch {} } catch {} this.sendAsyncMessage("", { title: trg.closest("[title]")?.title, url: (trg.currentRequestFinalURI || uri).spec, contentType, referrerInfo, cookieJarSettings, contentDisposition, sx, isPrivate: u.PrivateBrowsingUtils.isContentWindowPrivate(trg.ownerGlobal) }); } checkTextLinkyTool(doc) { if (doc.title || !doc.documentURI.startsWith("moz-extension:")) return; var lab = doc.querySelector("body > label#lblFrom:first-child")?.textContent; if (lab) doc.title = lab.slice(0, lab.lastIndexOf("(")); } } if (!ChromeUtils.domProcessChild.childID) { ChromeUtils.registerWindowActor("MouseImgSaver", { allFrames: true, parent: {moduleURI: __URI__}, messageManagerGroups: ["browsers"], child: {moduleURI: __URI__, events: {auxclick: {capture: true}, dblclick: {capture: true}, dragstart: {capture: true}}} }); var wref, titles = Object.create(null); var data = Object.assign(Object.create(null), { "browser.download.dir": {type: "String", get set() { var win = wref.get(), {prefs, dirsvc} = win.Services var {DownloadPaths, FileUtils} = win; var map = val => DownloadPaths.sanitize(val); win.Downloads.getList(win.Downloads.ALL).then(list => list.addView({ onDownloadChanged(download) { if (!download.stopped) return; var {url} = download.source, title = titles[url]; if (!title) return; delete titles[url]; if (!download.succeeded) return; var file = FileUtils.File(download.target.path), {leafName} = file; var ext = leafName.slice(leafName.lastIndexOf(".")); var newName = map(title) + ext, {parent} = file; var newFile = parent.clone(); newFile.append(newName); try { newFile.createUnique(file.NORMAL_FILE_TYPE, file.permissions); file.renameTo(parent, newFile.leafName); download.target.path = newFile.path; download.refresh(); } catch {} } })); Object.defineProperty(this, "set", {get() { try {var dir = prefs.getComplexValue("browser.download.dir", Ci.nsIFile);} catch {var dir = dirsvc.get("DfltDwnld", Ci.nsIFile);} var arr = prefs.getStringPref("ucf.savedirs", "_Web||_Images|0").split('|').slice(2, 4); // подпапки в [Загрузках]: нет | папка графики | имя вкладки | домен arr[1] = (arr[1]) ? wref.get().gBrowser.selectedTab.label.slice(0, 64).replace(/ \| — Mozilla Firefox|[\\\/?*\"'`]+/g,'').replace(/\s+/g,' ').replace(/[|<>]+/g,'_').replace(/:/g,'։').trim() : ""; // имя вкладки arr.map(map).forEach(dir.append); dir.exists() && dir.isDirectory() || dir.create(dir.DIRECTORY_TYPE, 0o777); return dir.path; }}); return this.set; }}, "browser.download.folderList": {type: "Int", set: 2}, "browser.download.useDownloadDir": {type: "Bool", set: true} }); var MouseImgSaverParent = class extends JSWindowActorParent { receiveMessage(msg) { var win = msg.target.browsingContext.topChromeWindow, {name} = msg; if (name) return this[name](win, msg.data); var {url, contentType, contentDisposition, sx, title, isPrivate, referrerInfo, cookieJarSettings} = msg.data; if (sx && sx > win.mozInnerScreenX + win.innerWidth) return; if (title) titles[url] = title; wref = Cu.getWeakReference(win); var p = win.Services.prefs; for(var pref in data) { var obj = data[pref], meth = `et${obj.type}Pref`; obj.val = p.prefHasUserValue(pref) ? p["g" + meth](pref) : null; p["s" + meth](pref, obj.set); } try {win.internalSave( url, null, // document null, // file name contentDisposition, contentType, false, // do not bypass the cache null, // filepicker title key null, // chosen data u.E10SUtils.deserializeReferrerInfo(referrerInfo), u.E10SUtils.deserializeCookieJarSettings(cookieJarSettings), win.document, // initiating doc true, // skip prompt for where to save null, // cache key isPrivate, win.document.nodePrincipal );} finally { for(var pref in data) data[pref].val === null ? p.clearUserPref(pref) : p[`set${data[pref].type}Pref`](pref, data[pref].val); } } dblclick(win, imgURL) { var gb = win.gBrowser, index = gb.selectedTab._tPos + 1; gb.selectedTab = gb.addTrustedTab('https://yandex.ru/images/search?rpt=imageview&url=' + imgURL, {index}); } } }
Отсутствует
Раз jsm-ки скоро отвалится, то весь UCF и CustomStylesScripts.jsm и CustomStylesScriptsChild.jsm тоже перестанут работать?
ESM модули вместо них, несложная конвертация модулей jsm --> mjs, у меня уже работает на FF 103
Отредактировано Vitaliy V. (06-07-2022 14:46:22)
Отсутствует
с настройками в самом файле
Что-то мне в голову не влезает то, что там навёрнуто,
не смог понять как это должно работать, сколько ни пытался.
Могу попробовать просто процитировать, без осознания,
но вряд ли из этого что-то выйдет.
var cfg = { rootzone: false, parent: true, neighbor: true, host: true, child: true, background: false, insert: true, setParent: true }; var name = "ExternalLinkNewtaber"; if (ChromeUtils.domProcessChild.childID) { var empty = new RegExp("^$"); var click = function(e) { e.preventDefault(); e.stopImmediatePropagation(); this.ownerGlobal.windowGlobalChild .getActor(name).sendAsyncMessage("", this.href); } var EXPORTED_SYMBOLS = [name + "Child"]; var ExternalLinkNewtaberChild = class extends JSWindowActorChild { actorCreated() { this.pp = this.ph = empty; var host = this.contentWindow.location.hostname; // quot =========================================================================== let parent = host.replace(/^[^.]*\./, '').replace(/\./g, '\\\.'); host = host.replace(/\./g, '\\\.'); if (cfg.parent){this.pp = new RegExp(`^${parent}$`);} // abc.x => ^abc\.x$ if (cfg.neighbor){ const flat = host.replace(/\..*/, ''); if (cfg.parent){ this.pp = new RegExp(`[^(${flat}\.)]?${parent}$`); // abc.x + *.abc.x => [^(w\.)]?abc\.x$ } else {this.pp = new RegExp(`[^(${flat})]?\.${parent}$`);} // *.abc.x => [^(w)]?\.abc\.x$ } if (!cfg.rootzone && parent.search(/\..+\./) == -1){this.pp = empty;} if (cfg.host){this.ph = new RegExp(`^${host}$`);} // w.abc.x => ^w\.abc\.x$ if (cfg.child){ if (cfg.host){ this.ph = new RegExp(`(.+\.)?${host}$`); // w.abc.x + *.w.abc.x => (.+\.)?w\.abc\.x$ } else {this.ph = new RegExp(`.+\.${host}$`);} // *.w.abc.x => .+\.w\.abc\.x$ } // =========================================================================== quot } handleEvent(e) { for(var a of this.document.getElementsByTagName("a")) if (a.hasAttribute("href")) { var {host} = a; !host || empty.test(host) || this.pp.test(host) || this.ph.test(host) || a.addEventListener("click", click); } } } } else { var {background, insert, setParent} = cfg; var arg = insert || setParent, fg = !background; var EXPORTED_SYMBOLS = [name + "Parent"]; var ExternalLinkNewtaberParent = class extends JSWindowActorParent { receiveMessage(msg) { var opts, gb = this.browsingContext.topChromeWindow.gBrowser; if (arg) { opts = {}; var st = gb.selectedTab; if (insert) opts.index = st._tPos + 1; if (setParent) opts.ownerTab = st; } var tab = gb.addTrustedTab(msg.data, opts); if (fg) gb.selectedTab = tab; } } ChromeUtils.registerWindowActor(name, { allFrames: true, matches: ["*://*/*"], messageManagerGroups: ["browsers"], parent: {moduleURI: __URI__}, child: {moduleURI: __URI__, events: {load: {capture: true}}} }); }
просьба переделать в JS модуль сохранения картинок ClickPicSave.jsm
Сейчас пока не очень удобно, поскольку лисьи jsm'ки ещё не сконвертированы.
А вообще это не очень сложно (и, нужен Firefox 103+).
Сам модуль импортируется не ChromeUtils.import() а ChromeUtils.importESModule()
При регистрации ChromeUtils.register{Window, Process}Actor() указываем не moduleURI а esModuleURI
Свойства __URI__ в этих модулях нет, подойдёт Components.stack.filename
Вместо var EXPORTED_SYMBOLS = []; используем инструкцию export
Ну, вобщем, как-то так:
export {MouseImgSaverChild, MouseImgSaverParent}; var u = {get it() { delete this.it; return this.it = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools); }}; ["E10SUtils", "PrivateBrowsingUtils"].forEach(name => Object.defineProperty(u, name, { configurable: true, enumerable: true, get() { var url = `resource://gre/modules/${name}.`; try {var exp = ChromeUtils.importESModule(url + "sys.mjs");} catch {exp = ChromeUtils.import(url + "jsm");} delete this[name]; return this[name] = exp[name]; } })); class MouseImgSaverChild extends JSWindowActorChild { handleEvent(e) { // клики мышью if (e.button > 1) return; // только ЛКМ, СКМ var trg = e.explicitOriginalTarget; // dragstart trg.nodeType == Node.ELEMENT_NODE && trg instanceof Ci.nsIImageLoadingContent && this[e.type](trg, e); } handleDragEvent(e) { this[e.type](e); } dragstart(trg, e) { this.trg = trg; this.x = e.screenX; this.y = e.screenY; this.drag("add"); this.handleEvent = this.handleDragEvent; this.checkTextLinkyTool(trg.ownerDocument); } events = ["dragover", "drop", "dragend"]; drag(meth = (delete this.handleEvent, delete this.trg, "remove")) { meth += "EventListener"; var win = this.contentWindow; for(var type of this.events) win[meth](type, this, true); } drop() { this.drag(); } dragover(e) { var {x, y} = this, cx = e.screenX, cy = e.screenY, dx = cx - x, ax = Math.abs(dx), ay = Math.abs(cy - y); if (ax < 10 && ay < 10) return; if (dx < 0 || ax < ay) return this.drag(); this.x = cx; this.y = cy; } dragend(e) { // перетаскивание рисунка var dt = e.dataTransfer, {trg} = this; this.drag(); dt.mozUserCancelled || this.send(trg, e.screenX); // сохранить // dt.mozUserCancelled || this.sendAsyncMessage("dragend", (trg.currentRequestFinalURI || uri).spec); } auxclick(trg) { // клик СКМ trg.matches(":any-link :scope") || this.send(trg); } dblclick(trg) { // ЛКМ trg.matches(":any-link :scope") || this.sendAsyncMessage("dblclick", (trg.currentRequestFinalURI || uri).spec); } send(trg, sx) { var uri = trg.currentURI; if (!uri) return; var doc = trg.ownerDocument; var cookieJarSettings = u.E10SUtils .serializeCookieJarSettings(doc.cookieJarSettings); var referrerInfo = Cc["@mozilla.org/referrer-info;1"] .createInstance(Ci.nsIReferrerInfo); referrerInfo.initWithElement(trg); referrerInfo = u.E10SUtils.serializeReferrerInfo(referrerInfo); var contentType = null, contentDisposition = null; try { var props = u.it.getImgCacheForDocument(doc).findEntryProperties(uri, doc); var cs = Ci.nsISupportsCString; try {contentType = props.get("type", cs).data;} catch {} try {contentDisposition = props.get("content-disposition", cs).data;} catch {} } catch {} this.sendAsyncMessage("", { title: trg.closest("[title]")?.title, url: (trg.currentRequestFinalURI || uri).spec, contentType, referrerInfo, cookieJarSettings, contentDisposition, sx, isPrivate: u.PrivateBrowsingUtils.isContentWindowPrivate(trg.ownerGlobal) }); } checkTextLinkyTool(doc) { if (doc.title || !doc.documentURI.startsWith("moz-extension:")) return; var lab = doc.querySelector("body > label#lblFrom:first-child")?.textContent; if (lab) doc.title = lab.slice(0, lab.lastIndexOf("(")); } } if (!ChromeUtils.domProcessChild.childID) { var esModuleURI = Components.stack.filename; ChromeUtils.registerWindowActor("MouseImgSaver", { allFrames: true, parent: {esModuleURI}, messageManagerGroups: ["browsers"], child: {esModuleURI, events: {auxclick: {capture: true}, dblclick: {capture: true}, dragstart: {capture: true}}} }); var wref, titles = Object.create(null); var data = Object.assign(Object.create(null), { "browser.download.dir": {type: "String", get set() { var win = wref.get(), {prefs, dirsvc} = win.Services var {DownloadPaths, FileUtils} = win; var map = val => DownloadPaths.sanitize(val); win.Downloads.getList(win.Downloads.ALL).then(list => list.addView({ onDownloadChanged(download) { if (!download.stopped) return; var {url} = download.source, title = titles[url]; if (!title) return; delete titles[url]; if (!download.succeeded) return; var file = FileUtils.File(download.target.path), {leafName} = file; var ext = leafName.slice(leafName.lastIndexOf(".")); var newName = map(title) + ext, {parent} = file; var newFile = parent.clone(); newFile.append(newName); try { newFile.createUnique(file.NORMAL_FILE_TYPE, file.permissions); file.renameTo(parent, newFile.leafName); download.target.path = newFile.path; download.refresh(); } catch {} } })); Object.defineProperty(this, "set", {get() { try {var dir = prefs.getComplexValue("browser.download.dir", Ci.nsIFile);} catch {var dir = dirsvc.get("DfltDwnld", Ci.nsIFile);} var arr = prefs.getStringPref("ucf.savedirs", "_Web||_Images|0").split('|').slice(2, 4); // подпапки в [Загрузках]: нет | папка графики | имя вкладки | домен arr[1] = (arr[1]) ? wref.get().gBrowser.selectedTab.label.slice(0, 64).replace(/ \| — Mozilla Firefox|[\\\/?*\"'`]+/g,'').replace(/\s+/g,' ').replace(/[|<>]+/g,'_').replace(/:/g,'։').trim() : ""; // имя вкладки arr.map(map).forEach(dir.append); dir.exists() && dir.isDirectory() || dir.create(dir.DIRECTORY_TYPE, 0o777); return dir.path; }}); return this.set; }}, "browser.download.folderList": {type: "Int", set: 2}, "browser.download.useDownloadDir": {type: "Bool", set: true} }); var MouseImgSaverParent = class extends JSWindowActorParent { receiveMessage(msg) { var win = msg.target.browsingContext.topChromeWindow, {name} = msg; if (name) return this[name](win, msg.data); var {url, contentType, contentDisposition, sx, title, isPrivate, referrerInfo, cookieJarSettings} = msg.data; if (sx && sx > win.mozInnerScreenX + win.innerWidth) return; if (title) titles[url] = title; wref = Cu.getWeakReference(win); var p = win.Services.prefs; for(var pref in data) { var obj = data[pref], meth = `et${obj.type}Pref`; obj.val = p.prefHasUserValue(pref) ? p["g" + meth](pref) : null; p["s" + meth](pref, obj.set); } try {win.internalSave( url, null, // original url null, // document null, // file name contentDisposition, contentType, false, // do not bypass the cache null, // filepicker title key null, // chosen data u.E10SUtils.deserializeReferrerInfo(referrerInfo), u.E10SUtils.deserializeCookieJarSettings(cookieJarSettings), win.document, // initiating doc true, // skip prompt for where to save null, // cache key isPrivate, win.document.nodePrincipal );} finally { for(var pref in data) data[pref].val === null ? p.clearUserPref(pref) : p[`set${data[pref].type}Pref`](pref, data[pref].val); } } dblclick(win, imgURL) { var gb = win.gBrowser, index = gb.selectedTab._tPos + 1; gb.selectedTab = gb.addTrustedTab('https://yandex.ru/images/search?rpt=imageview&url=' + imgURL, {index}); } } }
Отсутствует
не работает, или я не знаю как его прописать
Да обычная jsm'ка, как и другие. То есть ChromeUtils.import("урл");
Чтоб совсем уж не работало это вряд ли. Откровенно "внешние" ссылки
должны открываться в новой вкладке, во всяком случае те, которые в есть в html сразу.
А вот конфигурация — вообще непонятно, ну кроме background, insert, setParent.
Отсутствует
Dumby
Точно, забыл ее в лоадере проверить. Работает не хуже чем в обезьяне, на первый взгляд. Спасибо.
Я не знаю чего он там учесть пытался, без parent: true host: true она работает плохо, все подряд открывает в новой, в том числе и когда здесь по имени щелкаешь. Возможно последовательно опции добавлял, да так и оставил, у меня все как по умолчанию.
Отредактировано _zt (07-07-2022 07:12:41)
Отсутствует
Привет мастерам!
Ребят, пару кнопок из шапки задействовал, работают прекрасно, спасибо большое создателям. Единственное, что поменял бы на свой вкус - сами иконки кнопок. Подскажите как можно это сделать, пожалуйста!
Отсутствует
ez7pac
Свою иконку конвертируете в формат base64. Онлайн-конвертеров в сети полно.
Ищете в коде кнопки что-то типа такого
Это иконка из , можно взять то, что между двойными кавычками, вставить в адресную строку и посмотреть. Заменяете на свой код.
Или смотрите уже сконвертированные иконки в коде типа
Механизм такой же - заменяете на свой код то, что между двойными кавычками.
Отсутствует
xrun1
Ага, понял, спасибо!
Такого нет:
Т.е. иконка не дефолтная, а своя.
Вот такое есть
С конвертацией и заменой разберусь, думаю. Но тогда другой вопрос возник - а нельзя вместо кода иконки, вот этого "непонятного", воткнуть в код кнопки дефолтную иконку? Я там (chrome://browser/skin/browser.css) глянул - подходящие для меня есть.
Если можно, то как это сделать, чтобы не накосячить?
Отсутствует