Но тогда, да, действительно, мы получим вообще всё и сразу
Что ж пусть так и будет. Модули только нужно подгружать по необходимости
https://github.com/VitaliyVstyle/Vitali … me.js#L177
Отсутствует
Что ж пусть так и будет.
Сунул в custom_script.js
некий рандомно-тестовый код, и всё работает так, как ожидалось.
var bla = "bla"; var test = { "globalThis.bla": globalThis.bla, // user box, expected string "SystemGlobal.bla": Cu.getGlobalForObject(Cu).bla, // SystemGlobal, expected undefined // expected all exsists // dom idl PathUtils: PathUtils, AbortController: AbortController, HTMLAnchorElement: HTMLAnchorElement, // global properties FileReader: FileReader, XMLSerializer: XMLSerializer, URLSearchParams: URLSearchParams, // modules PlacesUtils: PlacesUtils, AppConstants: AppConstants, CustomizableUI: CustomizableUI, // internal stuff UcfPrefs: UcfPrefs, user_chrome: user_chrome, user_chrome_files_sandbox: user_chrome_files_sandbox, }; for(let key in test) test[key] = typeof test[key]; console.log(JSON.stringify(test, null, "\t"));
Отсутствует
Есть вот такой скрипт: "Переключить текущий поисковик" (первый спойлер)
Кто-нибудь на FF123 пользуется этим скриптом?
Дело в том, что на Windows 7, по понятным причинам, крайнюю версию оригинального FF я поставить не могу.
Но нашлись "умельцы", которые делают сборки крайних FF, которые работают на Win7.
Так вот, на такой сборке сам скрипт работает, поисковики переключает, но вот иконки поисковиков почему-то не подгружает.
Пытаюсь разобраться, это проблема скрипта в FF123 или "умельцы" что-то накрутил в своей сборке.
Кому не сложно, проверьте пожалуйста этот скрипт в оригинальном FF123.
Отредактировано unter_officer (14-03-2024 00:20:52)
«The Truth Is Out There»
Отсутствует
Пытаюсь разобраться
Это Bug 1870644 - Provide a single function for obtaining icon URLs from search engines
Farby предложил такую конструкцию:
engine._iconURI ? engine._iconURI.spec : engine.iconURI ? engine.iconURI.spec : this.defaultImg
что слегка замудро. Надеюсь, чуть лучше так:
(engine._iconURI || engine.iconURI)?.spec || this.defaultImg
Затем getIconURL() сделали асинхронной,
но пока ещё работает, то есть
img: e => (e._iconURI || e.iconURI)?.spec || "chrome://browser/skin/search-engine-placeholder.png",
А когда приземлится это, надо будет смотреть,
не слетят ли иконки встроенных лисьих поисковиков.
Ну, и на самой кнопке иконка не подхватывается, нужно прицепить wrappedJSObject.
/* var engine = popup.getDefaultEngine(); */ var engine = popup.getDefaultEngine().wrappedJSObject;
Отсутствует
Dumby
egorsemenov06
Большое вам спасибо за помощь!
«The Truth Is Out There»
Отсутствует
img: e => (e._iconURI || e.iconURI)?.spec || "chrome://browser/skin/search-engine-placeholder.png",
Спасибо, забрал.
Там ещё не работает скрытие неиспользуемых поисковиков, при excludeHiddenOneOffs: true, но полазил по форуму и нашел решение от Vitaliy V.
// excludeHiddenOneOffs: false, excludeHiddenOneOffs: true, // скрыть не нужные поисковики .. // if (this.excludeHiddenOneOffs) // var ex = Services.prefs.getStringPref(this.pref, "").split(","); var visibleEngines = await Services.search.getVisibleEngines(); if (this.excludeHiddenOneOffs) { var args = "hideOneOffButton" in Services.search.defaultEngine ? [e => !e.hideOneOffButton] : Object.defineProperty( [function(e) {return !this.includes(e.name);}], "1", { get: () => Services.prefs.getStringPref("browser.search.hiddenOneOffs")?.split(",") || [] }); visibleEngines = visibleEngines.filter(...args); } .. // for(var engine of await Services.search.getVisibleEngines()) { for(var engine of visibleEngines) { .. // if (this.excludeHiddenOneOffs && ex.includes(engine.name)) continue;
Жизнь иногда такое выкидывает, что хочется подобрать...
На форуме
Vitaliy V.
Вы делали кнопку
// Ссылка у курсора в тултипе, кнопка https://forum.mozilla-russia.org/viewtopic.php?pid=783755#p783755 (async () => { var id = "ucf-toggle-tooltip-url", label = "Тултипы с URL", tooltiptext = "Переключить тултипы", img = "data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' style='fill:context-fill rgb(142, 142, 152);'><path d='M9.618 6.721a2.483 2.483 0 0 0-.39-.317l-.735.734A1.486 1.486 0 0 1 8.91 9.55l-2.12 2.122a1.486 1.486 0 0 1-2.122 0 1.486 1.486 0 0 1 0-2.121l.605-.605a3.53 3.53 0 0 1-.206-1.209L3.961 8.843a2.506 2.506 0 0 0 0 3.535 2.506 2.506 0 0 0 3.535 0l2.122-2.121a2.506 2.506 0 0 0 0-3.536z'/><path d='M6.79 9.55c.12.121.25.226.389.317l.734-.734a1.486 1.486 0 0 1-.417-2.411L9.618 4.6a1.486 1.486 0 0 1 2.121 0 1.486 1.486 0 0 1 0 2.121l-.605.605c.137.391.211.798.206 1.209l1.106-1.107a2.506 2.506 0 0 0 0-3.535 2.506 2.506 0 0 0-3.535 0L6.789 6.014a2.506 2.506 0 0 0 0 3.536z'/><circle style='fill:none;stroke:context-fill rgb(142, 142, 152);stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round' cx='8' cy='8' r='7.4'/></svg>", imgcolordisable = "color-mix(in srgb, currentColor 20%, #e31b5d)"; var branch = "extensions.ucf.", pref = "tooltip_url_enable"; var tpurl = { initialised: false, tooltip_url_enable: true, get ext_branch() { delete this.ext_branch; return this.ext_branch = Services.prefs.getBranch(branch); }, init() { if (this.initialised) return; Services.prefs.getDefaultBranch(branch).setBoolPref(pref, true); Services.prefs.addObserver(`${branch}${pref}`, this); if (this.tooltip_url_enable = this.ext_branch.getBoolPref(pref)) this.registerActor(); this.initialised = true; }, observe(subject, topic, data) { var fill = ""; if ((this.tooltip_url_enable = this.ext_branch.getBoolPref(pref)) === true) this.registerActor(); else { fill = imgcolordisable; this.unregisterActor(); } this.callWithEachWindow(id, {fill: fill}); }, callWithEachWindow(buttonID, atr) { var getW = CustomizableUI.getWidget(buttonID); if (getW.instances.length) for (let {node} of getW.instances) { if (!node) continue; for (let a in atr) node.style.setProperty(a, atr[a]); } else for (let win of CustomizableUI.windows) { let node = getW.forWindow(win).node; if (!node) continue; for (let a in atr) node.style.setProperty(a, atr[a]); } }, registerActor() { ChromeUtils.registerWindowActor("UcfTooltipUrl", { child: { moduleURI: "chrome://user_chrome_files/content/custom_scripts/cs/UcfTooltipUrlChild.jsm", events: { mouseover: { capture: true }, }, }, allFrames: true, matches: ["<all_urls>"], messageManagerGroups: ["browsers"], }); }, unregisterActor() { ChromeUtils.unregisterWindowActor("UcfTooltipUrl"); }, }; CustomizableUI.createWidget({ id: id, label: label, tooltiptext: tooltiptext, localized: false, defaultArea: CustomizableUI.AREA_NAVBAR, onCreated(btn) { tpurl.init(); btn.style.setProperty("list-style-image", `url("${img}")`, "important"); if (!tpurl.tooltip_url_enable) btn.style.setProperty("fill", imgcolordisable); }, onCommand(e) { tpurl.ext_branch.setBoolPref(pref, !tpurl.ext_branch.getBoolPref(pref)); }, }); })();
var EXPORTED_SYMBOLS = ["UcfTooltipUrlChild"]; ChromeUtils.defineModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); class UcfTooltipUrlChild extends JSWindowActorChild { handleEvent(e) { timer.cancel(); timer.initWithCallback(() => { var elm = e.isTrusted && e.composedTarget, el, titl; if (!elm) return; do { if (!elm.matches) continue; if (elm.matches(":any-link")) { if (elm.matches("[href='#'], [href^='javascript']")) return; el = elm; if (elm.matches("[title]")) titl = elm; else while (elm = elm.flattenedTreeParentNode) { if (!elm.matches) continue; if (elm.matches("[title]")) { titl = elm; break; } } break; } if (elm.matches("[title]")) { titl = elm; while (elm = elm.flattenedTreeParentNode) { if (!elm.matches) continue; if (elm.matches(":any-link")) { if (elm.matches("[href='#'], [href^='javascript']")) return; el = elm; break; } } break; } } while (elm = elm.flattenedTreeParentNode); if (!el) return; var href = el.href; if (titl) el = titl; titl = (el.title || ""); var title = titl.trim(), pre = "", path = ""; try { href = Services.io.newURI(href); pre = href.displayPrePath; path = `\n${href.pathQueryRef}`; if (path === "\n/") path = ""; href = `${pre}${path}`; } catch (e) {} try { href = decodeURIComponent(href); } catch (e) {} el.title = title = `${href}${title === "" ? "" : `\nTitle: ${title}`}`; this.contentWindow.addEventListener("mouseout", () => { try { if (!el || title !== el.title) return; if (titl !== "") el.title = titl; else el.removeAttribute("title"); } catch (e) {} }, { once: true }); }, 100, Ci.nsITimer.TYPE_ONE_SHOT); /* было 400 */ } didDestroy() { timer.cancel(); } }
Отсутствует
нашел решение от Vitaliy V
Не, Виталий такую шляпу не пишет, у него всё как-то более академично.
Это моё, наверно. Кстати, ошибку свою заметил.
Настройка "browser.search.hiddenOneOffs" дефолтно существовала (до 116),
а значит, если там ничего не было, то значением возвращалась пустая строка.
А выражение ""?.split(",") возвращает массив с пустой строкой, и это совсем не то, что нужно.
А когда приземлится это, надо будет смотреть,
не слетят ли иконки встроенных лисьих поисковиков.
Ха, оказывается они уже слетели (причём, во всём браузере),
если руками включить настройку browser.search.newSearchConfig.enabled
Впрочем, теперь не важно, баг приземлился, настройку включили,
иконки встроенных лисьих поисковиков в брузере в порядке,
а в кнопке пропали (ну, или не появились, смотря от какого состояния настройки считать).
Но ничего, теперь хотя бы понятно, что engine._iconURI для них больше не подходит.
Вобщем вот, небольшая модификация обсуждавшегося кода
try {CustomizableUI.createWidget({ label: "Переключить текущий поисковик", id: "ucf-cbbtn-ToggleCurrentSearchEngine", image: "data:image/png;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA", excludeHiddenOneOffs: true, gn: () => Services.search.defaultEngine, gp: () => Services.search.defaultPrivateEngine, sn: val => Services.search.defaultEngine = val, sp: val => Services.search.defaultPrivateEngine = val, onCreated(btn) { btn.type = "menu"; btn.owner = this; btn.setAttribute("image", this.image); var win = btn.ownerGlobal; var popup = btn.appendChild(win.document.createXULElement("menupopup")); var pr = win.PrivateBrowsingUtils.isWindowPrivate(win); popup.getDefaultEngine = pr ? this.gp : this.gn; popup.setDefaultEngine = pr ? this.sp : this.sn; popup.setAttribute("oncommand", "setDefaultEngine(event.target.engine)"); popup.setAttribute("onpopupshowing", "this.shouldRebuild && owner.rebuild(this, document)"); this.autoOpenCloseFeature(win, btn); this.updButton(btn, win); }, getEngines() { var ve = Services.search.getVisibleEngines; if (!this.excludeHiddenOneOffs) return (this.getEngines = ve)(); var arr = []; var args = this.fx116 ? [e => !e.hideOneOffButton] : Object.defineProperty( [function(e) {return !this.includes(e.name);}], "1", {get: () => { var str = Services.prefs.getStringPref(this.pref); return str ? str.split(",") : arr; }} ); return (this.getEngines = async () => (await ve()).filter(...args))(); }, async rebuild(popup, doc) { popup.textContent = ""; var df = doc.createDocumentFragment(); var de = popup.getDefaultEngine().wrappedJSObject, jsde = this.json(de); var check = true; for(var engine of await this.getEngines()) { if (check && engine.name == de.name && this.json(engine) == jsde) { check = false; continue; } var menuitem = df.appendChild(doc.createXULElement("menuitem")); menuitem.engine = engine; menuitem.label = engine.name; menuitem.className = "menuitem-iconic"; menuitem.image = await this.img(engine); } popup.append(df); delete popup.shouldRebuild; }, async updButton(btn, win) { this.updButton = () => {}; Services.search.isInitialized || await Services.search.init(); this.fx116 = "hideOneOffButton" in Services.search.defaultEngine; var topics = ["browser-search-engine-modified", "quit-application-granted"]; for(var topic of topics) Services.obs.addObserver(this, topic, false); this.observe = (s, topic) => this[topic[0]](); var remove = () => topics.forEach( topic => Services.obs.removeObserver(this, topic) ); var {id} = this; var wins = callback => { for(var win of CustomizableUI.windows) { var btn = win.document.getElementById(id); btn && callback(btn, win); } } if (this.excludeHiddenOneOffs && !this.fx116) { var setRebuild = btn => btn.firstChild.shouldRebuild = true; var {pref} = this, obs = () => wins(setRebuild); Services.prefs.addObserver(pref, obs); this.q = () => remove(Services.prefs.removeObserver(pref, obs)); } else this.q = remove; var updButton = (btn, win) => { var popup = btn.firstChild; var engine = popup.getDefaultEngine(); /*btn.label =*/ btn.tooltipText = engine.name; popup.shouldRebuild = true; win.requestAnimationFrame(async () => btn.icon.src = await this.img(engine)); } (this.b = () => wins(updButton))(); this.updButton = updButton; btn.tooltipText || updButton(btn, win); }, pref: "browser.search.hiddenOneOffs", json: e => JSON.stringify(e.toJSON()), img: async e => await e.getIconURL?.() || e.iconURI?.spec || "chrome://browser/skin/search-engine-placeholder.png", // https://github.com/Infocatcher/Custom_Buttons/blob/master/code_snippets/autoOpenCloseMenu.js // Automatically open menu on mouse over (and hide it on mouse out) autoOpenCloseFeature(win, btn, openDelay = 200, closeDelay = 350) { var _openTimer = 0; var _closeTimer = 0; btn.onmouseover = function(e) { win.clearTimeout(_closeTimer); if(e.target == btn && closeOtherMenus()) { btn.open = true; return; } _openTimer = win.setTimeout(function() { btn.open = true; }, openDelay); }; btn.onmouseout = function(e) { win.clearTimeout(_openTimer); _closeTimer = win.setTimeout(function() { btn.open = false; }, closeDelay); }; function closeOtherMenus() { return win.Array.prototype.some.call( btn.parentNode.getElementsByTagName("*"), function(node) { if( node != btn && win.XULElement.isInstance(node) // See https://github.com/Infocatcher/Custom_Buttons/issues/28 //&& node.boxObject //&& node.boxObject instanceof Components.interfaces.nsIMenuBoxObject && "open" in node && node.open && node.getElementsByTagName("menupopup").length ) { node.open = false; return true; } return false; } ); } } });} catch(ex) {Cu.reportError(ex);}
Отсутствует
Вобщем вот, небольшая модификация обсуждавшегося кода
Dumby, в консоль пишет: CustomizableUI: Could not localize property 'ucf-cbbtn-ToggleCurrentSearchEngine.tooltiptext'.
Если в код добавить что-то типа:
tooltiptext: "Переключить текущий поисковик",
то тогда в консоли чисто.
«The Truth Is Out There»
Отсутствует
Получаеться что и эта кнпка не будет работать
Ну, что значит не будет работать?
В данном случае речь о том, что перестанут подхватываться иконки
встроенных поисковиков (не поисковиков, которые поставил пользователь),
когда включат search-config-v2 (пока что, только в Nightly).
А правка там простая
/* node.setAttribute("image", engine._iconURI ? engine._iconURI.spec : engine.iconURI ? engine.iconURI.spec : this.defaultImg); */ node.setAttribute("image", await engine.getIconURL?.() || engine.iconURI?.spec || this.defaultImg);
в консоль пишет: CustomizableUI: Could not localize property 'ucf-cbbtn-ToggleCurrentSearchEngine.tooltiptext'.
Да, есть такое, за всем не уследишь.
Можно добавить, например, второй строкой
localized: false,
переделать на mjs?
Что-то я не вижу там ничего такого,
что могло бы помешать сделать это самому.
Никаких выкрутасов, никаких __URI__ (которого в ESM нет),
никакого использования top-level this (который в ESM undefined),
разве что для Services, но он всё равно уже давно везде определён.
В скрипте меняем
/* moduleURI: "chrome://user_chrome_files/content/custom_scripts/cs/UcfTooltipUrlChild.jsm", */ esModuleURI: "chrome://user_chrome_files/content/custom_scripts/cs/UcfTooltipUrlChild.mjs",
/* var EXPORTED_SYMBOLS = ["UcfTooltipUrlChild"]; ChromeUtils.defineModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); class UcfTooltipUrlChild extends JSWindowActorChild { */ var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); export class UcfTooltipUrlChild extends JSWindowActorChild {
Отсутствует
Да, есть такое, за всем не уследишь.
Можно добавить, например, второй строкой
localized: false,
Спасибо, теперь всё нормально.
«The Truth Is Out There»
Отсутствует
Не, Виталий такую шляпу не пишет, у него всё как-то более академично.
Каюсь, простите великодушно, уже крыша едет где что взял... К сожалению я не умею писать, но зато умею читать и чуть чуть переставлять слова...
Жизнь иногда такое выкидывает, что хочется подобрать...
На форуме
Вобщем вот, небольшая модификация обсуждавшегося кода
ой а без директивы localized: false вы сразу отшибаете таких пользователей как например я..
Жизнь иногда такое выкидывает, что хочется подобрать...
На форуме
Dumby
Вы когда-то помогли мне переделать кнопку CB в UCF:
(async initCode => CustomizableUI.createWidget({ id: "ucf_UpDownCenterPage", label: "Up/Down/Center Page", // defaultArea: CustomizableUI.AREA_NAVBAR, localized: false, onCreated(btn) { btn.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAACXBIWXMAAAAAAAAAAAHqZRakAAACvElEQVQ4y3VTX0jTURT+rrsqmm3gwm02dZOZOk3RFCTMp4ggEQIT9GUD7VV8mDNF2NaD4qY2X8PBBpGkDwX64EP6YILGilzl3B/dnI5UMHSUWHO/3+1h/pva93S595zvfN8551IcgyYcZMYbHhpV17MU4xShABBV17MU9xR5xjSMAsCIe34ZAKb7F86S00aJ77CN3aJNUpVbnpYhX2pNvj7b5gQVJaceEEJWZ4mzEgBolHGrHPicwg5FxGtdF51ydCjKI9Z1lwgXQAGgr7CWJQkEGKh+yLqc00Tdlb+TdCTA92G/hAJAj3eenGQUmPKYsDsNAKBKzY3r1sgLJ+wlDxr1vg+TFsMS8RsulDiPfE3OWKg0fLvgh3Lf8yJQeykg4NhsBgAPAmcMnP0t48w2pLiniFIjn7hrL238rPdOeizBBjpYXMcslhHwACw1j9ioyO1y6da2wRMFAFDdyhxheffZoUqB9JlRgsUr+kBC7wlC8YuaaAkDgHZBJ1oE2vi8RiH1hcXXeOPPtaLFlGXymrOzFoGWnDK0VtUVoKQCRkc3AODk8co+XAWlRj6htMsaZRAjBxK8089NeizBhksEHYryyJDRKBzoM6PHt3BahYDEFmyf/NE9RLMOxFQUE2YmKDDllbFekwmc2QbObIOOiqFT1zPD7xD6N76RgGOzGY54whZ2sYXdxC4ZQl+JQfv4vxZUT3Od6S9JVfpRBm5yUrh7g19WhgKVCRbaFWVLaYTKjijhwZDE87Eda8BVVj2oZnyUAzVT8AwI89uQZIkrsi1ZbKZzkZwSRGJ//SPSonKIJYA0G/q5Nx8BwKlzk9wmmTv7VWYxOZ7f807TL89wUJigwBH2PnGEvVda2BjfUm+Mb6GwQxFpsWpFlzYlvvNFY/fC+3f28Cd6IBbTfVHGrjXgqj0f7LWuX/py/wDHfA2DzTMorQAAAABJRU5ErkJggg=="); new btn.ownerGlobal.Function(initCode).call(btn); } }))(`(u => { var id, lfs = url => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false); var max = () => { var url = u([ "var args = [scroller.scrollHeight, 0];", "scroller.scrollTop != 0 || args.reverse();", "content.scrollTo(...args);" ].join("\\n\\t")); (max = () => lfs(url))(); } var mid = () => { var url = u("content.scrollTo(0, (scroller.scrollHeight - scroller.clientHeight) / 2);"); (mid = () => id = lfs(url))(); } var obj = { mousedown: () => id = setTimeout(mid, 500), mouseup: () => id && max(id = clearTimeout(id)) }; this.onmousedown = this.onmouseup = e => e.button || obj[e.type](); this.tooltipText = "ЛКМ: Вверх/Вниз по странице \\nдЛКМ: Центрирование страницы"; }) (code => "data:," + encodeURIComponent(\`(doc => { var root = doc.documentElement; var body = doc.body || root; var scroller = body.scrollHeight > root.scrollHeight ? body : root; \${code} })(content.document)\`));`);
«The Truth Is Out There»
Отсутствует
Dumby - поправь код менюшки! Не работает upd(){… для подменю!
Одинаковый код обновления не пашет в подменю, но работает в первой и последней строках меню.
(async id => { // forum.mozilla-russia.org/viewtopic.php?pid=808738#p808738 MyMenu = { //массив команд пользователя, alt() клик правой кнопкой Pics: { // Графика сайтов Вкл/Выкл permissions.default.image upd() { // обновлять сроку перед показом меню // var {G} = this.ownerGlobal; var val = G.pref(G.v), s = val == 1, i = G.pdi; s ? i = i.replace("-blocked","") : 0; this.label = `Графика сайтов ${s ? "загружается" : val == 3 ? "кроме сторонних" : "отключена"}`; this.image = i || G.chk; this.tooltipText = G.v +" "+ val +"\nRClick – кроме сторонних"; }, cmd(){ G.pref(G.v, G.pref(G.v) == 2 ? 1 : 2); BrowserReload(); }, // alt(){ //для RClick нужен ucf_hookClicks.js // G.pref(G.v, 3); BrowserReload(); // }, }, "SubMenu": { men: 1, //подменю "SubItem": { lab: "SubItem Mod", // img: G.opt, upd() { // обновлять сроку перед показом меню var val = G.pref(G.v), s = val == 1, i = G.pdi; s ? i = i.replace("-blocked","") : 0; this.label = `SubItem: Графика ${s ? "загружается" : val == 3 ? "кроме сторонних" : "отключена"}`; this.image = i || G.chk; this.tooltipText = G.v +" "+ val +"\nRClick – кроме сторонних"; }, cmd(){console.log(this.label)}, }, }, "End Menu": { sep: 1, //сперва разделитель upd() { //обновить иконку var val = G.pref(G.v), s = val == 1, i = G.pdi; s ? i = i.replace("-blocked","") : 0; this.image = i; }, }, } CustomizableUI.createWidget({ id: id, label: id, tooltiptext: id, localized: false, defaultArea: CustomizableUI.AREA_NAVBAR, onCreated(btn) { btn.style.setProperty("list-style-image", "url(chrome://branding/content/icon32.png)"); btn.type = "menu"; var doc = btn.ownerDocument, m = nn => doc.createXULElement(nn); var popup = m("menupopup"), menu = m("menuitem"); menu.m = m; menu.fill = this.fill; menu.render = this.render; popup.append(menu); btn.prepend(popup); }, render(){ var popup = this.parentNode; this.remove(); this.fill(MyMenu, popup); }, fill(o, popup) { for (key in o) { var val = o[key]; if (typeof val != "object") continue; var {lab, inf, img, cmd, alt, sep, men, upd} = val; sep && popup.append(this.m("menuseparator")); var name = men ? "menu" : "menuitem"; var item = this.m(name); item.setAttribute("label", lab || key); // item.alt = alt; //RClick в ucf_hookClicks.js {Mouse… if (inf) item.tooltipText = inf; if (img || /this\.image.*=/.test(upd)) item.className = name + "-iconic", item.setAttribute("image", img || G.nul); men || cmd && item.setAttribute("oncommand", cmd.toString().replace( /cmd\(.*?\){/, "{var trg = event.target || event;" )); popup.append(item); upd && (item.render = upd).call(item); men && this.fill(val, item.appendChild(this.m("menupopup"))); } }, }); var {prefs} = Services; G = { pref(key,set){ //или key = [key,default] if (!Array.isArray(key)) key = [key]; var t = prefs.getPrefType(key[0]), m = {b:"Bool",n:"Int",s:"String"}; t = m[t == 128 ? "b" : t == 64 ? "n" : t == 32 ? "s" : ""]; if (set == "get") return t; //тип опции if (!t) t = m[set != undefined ? (typeof set)[0] : (typeof key[1])[0]]; if (t) if (set != undefined) prefs[`set${t}Pref`](key[0],set) else set = prefs[`get${t}Pref`](...key); return set; }, v: "permissions.default.image", pdi: "chrome://browser/skin/canvas-blocked.svg", chk: "chrome://devtools/skin/images/check.svg", nul: "chrome://devtools/skin/images/blocked.svg", } })("ucf_test_menu");
Отсутствует
Это возможно как-то поправить?
Даже не знаю, может так попробовать
/* var root = doc.documentElement; var body = doc.body || root; var scroller = body.scrollHeight > root.scrollHeight ? body : root; */ var scroller = doc.scrollingElement;
код обновления не пашет в подменю
Разве? Код-то как раз пашет, но пункт не render'ится.
Когда добавляешь пункт в основное меню он render'ится сразу,
но когда в субменю, тогда нет. А когда будет следующий вызов render()
метод уже переопределён и ничего не render'ит.
Можно сразу принудительно отрендерить, но лучше, наверно, отложить.
Плюс, upd() вызывается для пунктов субменю даже просто при открытии основного меню,
а это слегка нехорошо. Возможно, стоит проверять, что субменю открыто.
Вобщем, так поменял фрагмент кода создания виджета
CustomizableUI.getWidget(id)?.label || (self => CustomizableUI.createWidget(self = { id, label: id, tooltiptext: id, localized: false, defaultArea: CustomizableUI.AREA_NAVBAR, onCreated(btn) { btn.style.setProperty("list-style-image", "url(chrome://branding/content/icon32.png)"); btn.type = "menu"; var doc = btn.ownerDocument, m = nn => doc.createXULElement(nn); var popup = m("menupopup"), menu = m("menuitem"); menu.m = m; menu.fill = this.fill; menu.render = this.render; popup.append(menu); btn.prepend(popup); }, render(){ var popup = this.parentNode; this.remove(); this.fill(MyMenu, popup); }, fill(o, popup) { for (key in o) { var val = o[key]; if (typeof val != "object") continue; var {lab, inf, img, cmd, alt, sep, men, upd} = val; sep && popup.append(this.m("menuseparator")); var name = men ? "menu" : "menuitem"; var item = this.m(name); item.setAttribute("label", lab || key); // item.alt = alt; //RClick в ucf_hookClicks.js {Mouse… if (inf) item.tooltipText = inf; if (img || /this\.image.*=/.test(upd)) item.className = name + "-iconic", item.setAttribute("image", img || G.nul); men || cmd && item.setAttribute("oncommand", cmd.toString().replace( /cmd\(.*?\){/, "{var trg = event.target || event;" )); popup.append(item); if (upd) if (item.renderedOnce) (item.render = upd).call(item); else item.upd = upd, item.render = self.renderSub; men && this.fill(val, item.appendChild(this.m("menupopup"))); } }, renderSub() { delete this.render; this.render(); this.render = self.updSub; this.upd(); }, updSub() { this.parentNode.state.startsWith("c") || this.upd(); } }))();
Отсутствует
Даже не знаю, может так попробовать
Dumby, большое спасибо. Как всегда всё супер!
«The Truth Is Out There»
Отсутствует
Dumby - спасибо, добавил примеры в пользовательское меню, где меняются иконки, текст и подсказки в зависимости от настроек.
Изменяемые по клику строки меню отличаются выделенным шрифтом.
Обновил меню в ucf_hookClicks.js и исправил совместимость с UCF 2024.
Firefox/config.js может грузить старую и новую версию UCF.
Отсутствует
исправил совместимость с UCF 2024.
Firefox/config.js может грузить старую и новую версию UCF
Немного запоздало я как раз недавно обновил несколько файлов config.js user_chrome.js vertical_top_bottom_bar.css
https://github.com/VitaliyVstyle/Vitali … /config.js
Отсутствует
Dobrov
Спасибо за обновы, особенно за ucf_hookClicks.js) Удобная штука. Все что хотел раньше от скриптов, все в одном флаконе, под любые хотелки. Кстати, а что за сборка 116? esr?
Отсутствует
Vitaliy V.
Спасибо за обновления. Рад вас видеть.
Dumby
Приветствую.
Лоадер применительно к mjs не изменился?
Предполагаю что нет, так как один конвертированный скрипт в нем уже работает.
И, пожалуйста, переделайте в mjs jsm-ки:
1. TST Reload Tab Interval
2. TST TabPreview
TST
Отредактировано _zt (16-03-2024 23:42:36)
Отсутствует
Dumby такой глупый вопрос: JS скрипты будут дóльше поддерживаться в Firefox, чем JSM-ки?
Если это так, то возможно переделать в JS скрипт сохранения страниц SingleHTML.JSM (в custom_scripts UCF 2024 тоже JS-скрипты)
Его функции используют два скрипта (а могут и другие): ClickPicSave.jsm и ucf_hookClicks.js
ucf_hookClicks.js Удобная штука. Все что хотел раньше от скриптов, все в одном флаконе
а что за сборка 116? esr?
в ucf_hookClicks.js код слишком компактный, чтоб легко подстроить «под себя» строки меню/нажатия клавиш/клики мыши в первых блоках. Позже отформатирую по правилам, разграничив блоки разных назначений.
А браузер обычный LibreWolf 116 arm64 на Apple Silicon Mac M3, не вижу смысла постоянно обновлять (поставил в игнор для менеджера пакетов brew)
Отсутствует
Vitaliy V. - пожелание:
добавить подключение стилей по имени в зависимости от OS – иногда нужно использовать один профиль на разных системах, для которых CSS не совпадают.
вот так работает в CustomStylesScripts.mjs (на MacOS подключается custom_styles_all_user_macosx.css):
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); var os = name => `${name.replace(/\.[^.$]+$/,'')}_${AppConstants.platform}${name.lastIndexOf('.') > 0 ? "."+ name.split('.').pop() : ""}`; ………… stylesall: [ // Для всех документов { path: "custom_styles_all_user.css", type: "USER_SHEET", sheet() { registerSheet(this); }, }, // стиль для вашей операционной системы: *_macosx.css, *_linux.css, *_win.css { path: os("custom_styles_all_user.css"), type: "USER_SHEET", sheet() { registerSheet(this); }, }, ],
Отредактировано Dobrov (17-03-2024 07:15:48)
Отсутствует