Нельзя тут как-то добавить PanelUI-menu-button, чтобы он тоже мог переноситься? Пробовал, что-то не выходит. И что за кнопка alltabs-button, все время забываю?
// https://forum.mozilla-russia.org/viewtopic.php?pid=806232#p806232 806233#p806233 // установить для кнопок #alltabs-button и #unified-extensions-button атрибут "removable" как "true" (async topic => { var obs = doc => { doc.getElementById("alltabs-button")?.setAttribute("removable", true); doc.getElementById("unified-extensions-button")?.setAttribute("removable", true); doc.getElementById("PanelUI-menu-button")?.setAttribute("removable", true); } Services.obs.addObserver(obs, topic); Services.obs.addObserver(function quit(s, t) { Services.obs.removeObserver(quit, t); Services.obs.removeObserver(obs, topic); }, "quit-application-granted"); })("chrome-document-interactive");
Отредактировано b0ttle (26-11-2023 21:11:23)
Отсутствует
Скрипт перехвата кликов-нажатий ucf_hookClicks.js — небольшие добработки и устранение ошибок:
1) Вернул сочетания кнопок мыши на вкладках и кнопке «Новая вкладка» — описание во всплывающих подсказках.
2) разблокировка перемещения #unified-extensions-button
3) добавлена команда alt в Меню пользователя. На строке «Закладка первая/последняя» клик правой кнопкой откроет последнюю ссылку.
В блоке «Menu = [{…» cmd имеет приоритет и сработает на клик колёсика или левой кнопки.
для alt возможны любые клики + управляющие клавиши (cmd при этом лучше убрать), пример есть в Mouse = {…B[6]…256 … btn.alt(btn)
4) Меню пользователя открывается колёсиком по кнопке «Быстрые опции» и правым кликом мыши на кнопке «Расширения» unified-extensions-button
В ucf_hookClicks треть объёма занимают блоки данных, которые можно менять «под себя»
Keys: нажатия клавиш, Menu: команды пользователя, Mouse: клики мыши, Setup быстрые опции.
Отредактировано Dobrov (28-11-2023 10:40:05)
Отсутствует
Прошу прощения, я тут отсутствовал какое-то время.
Dumby посмотрите пожалуйста код кнопки в ней тусклая иконка если svg.context-properties.content.enabled стоит в false
Конкретный цвет можно прямо в SVG'шке указать, там, где stroke
А если надо чтобы context-properties подхватывались,
то можно сменить протокол
/* bt.image = img; */ var subst = this.id + "-svg-image"; Services.io.getProtocolHandler("resource") .QueryInterface(Ci.nsIResProtocolHandler) .setSubstitution(subst, Services.io.newURI(img)); var url = `resource://${subst}/`; (this.onCreated = btn => btn.image = url)(bt);
Нельзя тут как-то добавить PanelUI-menu-button, чтобы он тоже мог переноситься?
Эта кнопка не сама по себе, а в составе родительского <toolbaritem>'а,
наверно лучше их не разлучать.
А сам toolbaritem находится за пределами кастомизационных зон,
поэтому только просто устанавливать ему атрибут "removable" бесполезно.
Можно попробовать регистрировать его как "custom" виджет,
а вместо создания подсовывать существующий.
Типа в custom_script.js
(async id => CustomizableUI.createWidget({ id, type: "custom", localized: false, defaultArea: CustomizableUI.AREA_NAVBAR, onBuild(doc) { var item = doc.getElementById(id); item.setAttribute("removable", true); return item; } }))("PanelUI-button");
Отсутствует
Скрипт ucf_hookClicks.js — изменил меню пользователя, чтобы проще подключать команды, устранил пару ошибок.
Справка по жестам мыши создаётся автоматически в ucf_mousedrag.js, и добавленные вами жесты тоже видны:
Меню пользователя > Правый клик по строке "Краткая справка | Жесты мыши"
обновлены скрипты: ucf_hookClicks.js ucf_mousedrag.js SingleHTML.jsm ClickPicSave.jsm и файлы профиля: prefs.js custom_styles_all_user.css userChrome.css userChrome_macosx.css
Dumby - с возвращением!
Отредактировано Dobrov (30-11-2023 18:35:29)
Отсутствует
Dobrov
И еще один вопрос.
Подскажите, от чего зависит стиль начертания шрифта (обычный, наклонный) и его цвет в быстрых настройках ucf_hookClicks.js?
Например, я добавил свой пункт "Unblock addons.mozilla.org"
pref: ["privacy.resistFingerprinting.block_mozAddonManager","Unblock addons.mozilla.org",,"Enables scripts & addons to run on the addons.mozilla.org page"], Def3el: true, refresh: true, keys: [[true, "Unblock"], [false, "Block (default)"]]
он один в один повторяет "Выполнять скрипты Java"
pref: ["javascript.enabled", "Выполнять скрипты Java",,"Поддержка интерактивных сайтов, рекламы\nтакже разрешает действия горячих клавиш"], Def3el: true, refresh: true, keys: [[true, "Да"], [false, "Нет"]]
но у моего пункта, почему-то, стиль шрифта наклонный, в отличие пункта с обычным шрифтом у "Выполнять скрипты Java".
Отсутствует
iG0R
Отсутствует
b0ttle
Спасибо.
Я это уже сделал через userChrome.css
Просто хотелось бы, чтобы скрипты работали без всяких лишних дополнительных движений.
Отсутствует
iG0R. Так не бывает) Как это, без лишних движений?
У меня обычный шрифт, может не так вписали?
Setup = [ { pref: ["privacy.resistFingerprinting.block_mozAddonManager","Unblock addons.mozilla.org",,"Enables scripts & addons to run on the addons.mozilla.org page"], Def3el: true, refresh: true, keys: [[true, "Unblock"], [false, "Block (default)"]] },null, { // быстрые настройки. есть Def3el: несовпадения выделяются pref: ["dom.disable_open_during_load", "Всплывающие окна"], Def3el: true, Yellow: false, keys: [[true, "Блокировать"], [false, "Разрешить"]],
Отредактировано b0ttle (02-12-2023 13:44:09)
Отсутствует
Подскажите, от чего зависит стиль начертания шрифта (обычный, наклонный) и его цвет в быстрых настройках ucf_hookClicks.js?
Иконка зелёная или серая и шрифт обычный - значит опция в значении по-умолчанию, для вашей настройки это false.
Цвет других иконок задаётся для каждой строки подменю, например Blue ставлю, если опция изменена, но не критично. Пример всех цветов в строке: "Режим прокси"
если в pref:…… прописано значение для "Def3el", то текст будет красным, если опция не равна Def3el и не по-умолчанию. В новой версии скрипта вместо красного шрифта будет красный ореол текста.
По двойному разделителю в менюшке поиска не знаю, у меня на разных профилях этого нет.
Отредактировано Dobrov (02-12-2023 19:29:43)
Отсутствует
Dumby, здравствуйте.
Может есть у Вас мысли, которые можно записать в виде скрипта. Но с начала немного о прошлом, есть три расширения в которых есть такой функционал это DownThemAll, Download Manager (S3) и совсем старинное Preserve Download Modification Timestamp. Все они умеют сохранять дату создания (брать дату с сервера) у скачиваемых файлов и присваивать конечному (скаченному). Даже существует по этому поводу Bug 733954, ему уже 12 лет. Так вот есть ли такая возможность реализовать для UCF?
-
Real UA: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0
Жизнь иногда такое выкидывает, что хочется подобрать...
На форуме
умеют сохранять дату создания (брать дату с сервера) у скачиваемых файлов и присваивать конечному (скаченному)
В смысле присваивать как дату изменения?
Вроде как лиса не умееет присваивать файлам дату (именно) создания.
Я посмотрел как это сделано в S3, и, если правильно понял,
то там что-то типа такого (весьма упрощённый набросок),
но тестировать это мне особо негде.
В custom_script.js
(async (url, ...cc) => { var re = /^.*\//; var f = Components.Constructor(...cc); var setLastModified = (file, date) => { if (file.exists()) file.lastModifiedTime = date; } var {Downloads} = ChromeUtils.importESModule(url); (await Downloads.getList(Downloads.ALL)).addView({ onDownloadChanged(download) { if (download.succeeded) try { var date = new Date(download.saver.entityID.replace(re, "")); +date && setTimeout(setLastModified, 2e3, f(download.target.path), date); } //catch(ex) {console.error(ex);} catch {} } }); })( "resource://gre/modules/Downloads.sys.mjs", "@mozilla.org/file/local;1", "nsIFile", "initWithPath" );
Отсутствует
Сделал отдельный скрипт на основе кнопки от Dumby «Быстрые опции about:config»: (меньше оригинала + некоторые улучшения)
Dumby, раз ты на связи, вот мои Хотелки и Проблемы к скрипту Быстрые опции:
1) сделать ввод значения текущей опции вручную через диалог ввода. Например в UserAgent > при клике по строке: "ваши данные…" нужно открыть диалог, где вводим нужные данные аналогично уже вшитым в другие строки этого подменю. После ввода или перезапуска браузера при открытии этого подменю строка "ваши данные…" должна быть выбрана флажком. Такой ввод данных пользователя нужен не для одной опции, а для многих: например в строке «Загрузки» нужна строка своих настроек…
2) надо, чтобы radio-строка подменю была выбрана (с флажком), если опция сброшена и отсутствует.
сделал костыль: pref.undef = [val,str] для pref: pref,lab,key,hint,[val,str],code
костыль делает строку меню такой: "Заголовок - str", но radio-строка подменю остаётся не выбранной.
3) при клике по родительской строке меню открывать эту опцию в about:config – функция about_config прилагается.
Это работает в ucf_hookClicks.js, но не пашет в этом коде, т.к. e.target определяется как кнопка, а не как текущая строка меню.
4) оригинальная кнопка "Быстрое переключение опций about:config" содержала два контекстных меню.
Прошу убрать код для нескольких меню: popups, popupshowing… (может попроще код станет).
Второе UserMenu другого формата и должно быть независимым, чтобы вызываться над разными кнопками.
0) странноcти кода – добавлял функцию switchTab через запятую в разной последовательности, но не
работает: ua = …}, switchTab = … Без запятой пашет: строка UserMenu не выдаст ошибку: no switchTab…
/* Быстрые настройки меню опций about:config. Колёсико, Лев+Shift не закрывать Опция изменена: курсив; Цвет = ключ, по-умолчанию серый, иначе Red есть Def3el: несовпадения выделяются красной обводкой текста refresh=true ⟳ перечитать без кэша, restart=false ↯ без запроса pref: pref,lab,key,hint,[val,str],code | keys:val,lab,dat,+hint,code | icon:значок предыдущее значение: menu.pref.val Новое: newVal и trg.val данные trg.label метка keys: */ (async id =>{ var {prefs} = Services, db = prefs.getDefaultBranch(""); 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; } Icon = (c = '0c0')=>"data:image/svg+xml;charset=utf-8,<svg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'><defs><linearGradient id='a' x1='16' x2='16' y1='32' gradientUnits='userSpaceOnUse'><stop stop-color='%23"+ c +"'/><stop stop-color='%23fff' offset='.8'/></linearGradient><linearGradient id='b' x2='32' y1='16' gradientTransform='matrix(1 0 0 1 2 2)'><stop stop-opacity='.5'/></linearGradient></defs><circle cx='16' cy='16' r='15' fill='url(%23a)' stroke='url(%23b)' stroke-width='2'/></svg>"; about_config = (filter) => { //на опцию if (gURLBar.value.startsWith("about:config")) switchTab(gURLBar.value); var setFilter = (e,input = (e?.target || window.content.document).getElementById("about-config-search")) => { try { if (e || input.value != filter) input.setUserInput(filter);} catch{} }, found = window.switchToTabHavingURI("about:config",true, {relatedToCurrent: true, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()}); if (found) setFilter(null,window); else gBrowser.selectedBrowser.addEventListener("pageshow",setFilter, {once: true}); }; ua = (real = false, ua_my = "general.useragent.override")=>{ //текущий или вшитый ЮзерАгент ttt = Pref(ua_my); prefs.clearUserPref(ua_my); ua = Cc["@mozilla.org/network/protocol;1?name=http"].getService(Ci.nsIHttpProtocolHandler).userAgent; //костыль ttt && Pref(ua_my, ttt); ttt ||= ua; if (real) ttt = ua; return ttt; } switchTab = (url = 'about:config', go)=>{ //открыть вкладку | закрыть её | выбрать for(var tab of gBrowser.visibleTabs) if (tab.linkedBrowser.currentURI.spec == url) {go ? gBrowser.selectedTab = tab : gBrowser.removeTab(tab); return;} gBrowser.addTrustedTab(url); gBrowser.selectedTab = gBrowser.visibleTabs[gBrowser.visibleTabs.length -1]; } var uar = ua(true), //real ЮзерАгент fonts = arr => arr.map(n => [(n == arr[arr.length-1] ? null : n), n]), //array с вложениями serif = fonts("Arial|Roboto|Cantarell|Segoe UI|Cambria|Calibri".split('|')), sans = [["Times","Times"], ...serif], hints = new Map([ //опция отсутствует ? вернуть строку ["general.useragent.override", "UserAgent"]]); UserMenu = { //массив команд пользователя, alt() клик правой кнопкой "Настройки профайлера": { cmd(){switchTab('about:profiling')} }, DwDir: {lab: `папка Загрузки`, cmd(){ Downloads.getSystemDownloadsDirectory().then(path => FileUtils.File(path).launch(),Cu.reportError)}, img: "chrome://devtools/skin/images/folder.svg" }, } AboutCfg = [{ pref: ["dom.disable_open_during_load", "Всплывающие окна"], Def3el: true, Yellow: false, keys: [[true, "Блокировать"], [false, "Разрешить"]], },null,{ pref: ["extensions.user_chrome_files.savedirs", "Загрузки",,'Пути сохранения Страниц и Графики\nСинтаксис «_Html/subdir|_Pics/subdir»\nsubdir: пусто | 0 заголовок | 1 домен', ["", "всё в общей папке"]], Blue: "_Web|1|_Images|0", Gray: "", keys: [ ["_Сайты||_Фото|0", "_Сайты|_Фото/имя…"], ["_Web|1|_Images|0", "_Web/сайт|_Images/имя"], ["Сайт||Фото|", "ваши данные…",,"ключ в about:config", `console.log("введите ваши данные…")`]] },{ pref: ["general.useragent.override", "User Agent",,"Изменяет вид сайта", [uar,"встроенный"]], refresh: true, Def3el: uar, keys: [ ["Windows", "ваши данные…",,,`console.log("введите ваши данные…")`], ["Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36", "Chrome 118 Win10"], ["Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12 Version/12.16", "Opera12 W8"], ["Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", "GoogleBot"], [uar, "по-умолчанию"]] //родной ЮзерАгент }]; CustomizableUI.createWidget({ defaultArea: CustomizableUI.AREA_NAVBAR, label: "Журнал, Меню опций", localized: false, id: id, onCreated(btn) { btn.setAttribute("image", "chrome://devtools/skin/images/settings.svg"); var doc = btn.ownerDocument, m = nn => doc.createXULElement(nn); btn.domParent = null; btn.popups = new btn.ownerGlobal.Array(); this.createPopup(doc, btn, "config", AboutCfg); btn.linkedObject = this; for(var type of ["contextmenu", "command"]) btn.setAttribute("on"+ type, `linkedObject.${type}(event)`); 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(UserMenu, popup); }, fill(o, popup){if (typeof o == "object") for (key in o){ var {lab, sep, sub, cmd, alt, inf, img} = o[key]; var name = sub ? "menu" : "menuitem"; sep && popup.append(this.m("menuseparator")); var item = this.m(name); item.setAttribute("label", lab || key); if (img) item.className = name +"-iconic", item.setAttribute("image",img); if (inf) item.tooltipText = inf; item.alt = alt; //cmd2 sub || cmd && item.setAttribute("oncommand", cmd.toString().replace(/cmd\(.*?\)/,'')); /^(sub|sep|inf|lab|img)$/.test(key) || popup.append(item); sub && this.fill(o[key], item.appendChild(this.m("menupopup"))); }}, createPopup(doc, btn, prop, data) { var popup = doc.createXULElement("menupopup"); btn.popups.push(btn[prop] = popup); popup.id = this.id +"-"+ prop; for (var type of ["popupshowing"]) popup.setAttribute("on"+ type, `parentNode.linkedObject.${type}(event)`); for(var obj of data) popup.append(this.createElement(doc, obj)); btn.append(popup); }, createElement(doc, obj) { //pref if (!obj) return doc.createXULElement("menuseparator"); var pref = doc.ownerGlobal.Object.create(null), node, bool, img; for(var [key, val] of Object.entries(obj)) { if (key == "pref") { var [apref, lab, akey, hint, undef, code] = val; //строка меню pref.pref = apref; pref.lab = lab || apref; if (hint) { if (RegExp(/\p{L}/,'u').test(hint[0]) && (hint[0] === hint[0].toUpperCase())) hint = '\n'+ hint; pref.hint = hint; } if (undef) pref.undef = undef; //если не массив: undef || undef == "" if (code) pref.code = code; } else if (key == "icon") img = val, pref.img = true; else if (key != "keys") pref[key] = val; else pref.hasVals = true; } var t = prefs.getPrefType(pref.pref), m = {b: "Bool", n: "Int", s: "String"}; var str = m[t == prefs.PREF_INVALID ? obj.keys ? (typeof obj.keys[0][0])[0] : "b" : t == prefs.PREF_BOOL ? "b" : t == prefs.PREF_INT ? "n" : "s"]; //String по-умолчанию pref.get = prefs[`get${str}Pref`]; var map, set = prefs[`set${str}Pref`]; if (pref.hasVals) { for(var [val,,,,code] of obj.keys) code && (map || (map = new Map())).set(val, code); if (map) pref.set = (key, val) => { set(key, val); map.has(val) && eval(map.get(val)); //код2 если pref изменён } } if (!map) pref.set = set; node = doc.createXULElement("menu"); node.className = "menu-iconic"; img && node.setAttribute("image", img); akey && node.setAttribute("accesskey", akey); (node.pref = pref).vals = doc.ownerGlobal.Object.create(null); this.createRadios(doc, str.startsWith("B") && !pref.hasVals ? [[true, "true"], [false, "false"]] : obj.keys, node.appendChild(doc.createXULElement("menupopup")) ); if ("Def3el" in obj) pref.noAlt = !("Yellow" in obj); return node; }, createRadios(doc, vals, popup) { for(var arr of vals) { var [val, lab, key, hint] = arr; var menuitem = doc.createXULElement("menuitem"); with (menuitem) setAttribute("type","radio"), setAttribute("closemenu","none"), setAttribute("label", popup.parentNode.pref.vals[val] = lab), key && setAttribute("accesskey", key); var tip = menuitem.val = val === "" ? "[ пустая строка ]" : val; if (hint) tip += "\n" + hint; menuitem.tooltipText = `${tip != undefined ? tip + "\n\n" : ""}клик с Shift блокирует авто-закрытие`; popup.append(menuitem); } }, regexpRefresh: /^(?:view-source:)?(?:https?|ftp)/, upd(node) { var {pref} = node, def = false, user = false, val; //если опция не найдена if (prefs.getPrefType(pref.pref) != prefs.PREF_INVALID) { try { val = pref.defVal = db[pref.get.name](pref.pref); def = true; //опция по-умолчанию получена } catch {def = false} user = prefs.prefHasUserValue(pref.pref); if (user) try {val = pref.get(pref.pref, undefined);} catch {} } if (val == pref.val && def == pref.def && user == pref.user) return; pref.val = val; pref.def = def; pref.user = user; var exists = def || user; if (!exists && pref.undef) //опции нет ? вернуть default val = pref.undef[0]; var hint = hints.get(pref.pref); hint ||= val != undefined ? val : "Эта опция не указана"; if (hint === "") hint = "[ пустая строка ]"; hint += "\n" + pref.pref; if (pref.hint) hint += "\n"+ pref.hint; node.tooltipText = hint; //+ текст var img = Icon("999"), alt = "Yellow" in pref && val == pref.Yellow, clr = "Gray" in pref && val == pref.Gray, blu = "Blue" in pref && val == pref.Blue; if (blu) img = Icon("a0f"); if (alt) img = Icon("f80"); if ("Def3el" in pref) if (val == pref.Def3el) img = Icon(), node.style.removeProperty('filter'); else if (val != pref.defVal) { if (!alt && !clr && !blu) img = Icon("f26"); // Red node.style.filter = "drop-shadow(1px 1px 1px #B8F)"; } pref.img || node.setAttribute("image", img); //нет Def3el ? серый user ? node.style.setProperty("font-style", "italic", "important") : node.style.removeProperty("font-style"); var {lab} = pref; if (exists && pref.hasVals) { if (val in pref.vals) var sfx = pref.vals[val] || val; else var sfx = user ? "другое" : "по-умолчанию"; lab += ` ${"restart" in pref ? "↯-" : "refresh" in pref ? "-⟳" : "—"} ${sfx}`; } lab = exists ? lab : '['+ lab + `${"restart" in pref ? " ↯" : "refresh" in pref ? " ⟳" : ""}` +']'+ `${pref.undef ? " - "+ pref.undef[1] : ""}`; node.setAttribute("label", lab); //имя = [имя] если преф не существует }, openPopup(popup) { var btn = popup.parentNode; if (btn.domParent != btn.parentNode) { btn.domParent = btn.parentNode; if (btn.matches(".widget-overflow-list > :scope")) var pos = "after_start"; else var win = btn.ownerGlobal, {width, height, top, bottom, left, right} = btn.closest("toolbar").getBoundingClientRect(), pos = width > height ? `${win.innerHeight - bottom > top ? "after" : "before"}_start` : `${win.innerWidth - right > left ? "end" : "start"}_before`; for(var p of btn.popups) p.setAttribute("position", pos); } popup.openPopup(btn); }, maybeRestart(node, conf) { if (conf && !Services.prompt.confirm(null, this.label, "Перезапустить браузер?")) return; var cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool); Services.obs.notifyObservers(cancel, "quit-application-requested", "restart"); return cancel.data ? Services.prompt.alert(null, this.label, "Запрос на выход отменён.") : this.restart(); }, async restart() { var meth = Services.appinfo.inSafeMode ? "restartInSafeMode" : "quit"; Services.startup[meth](Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart); }, maybeRe(node, fe) { var {pref} = node; if ("restart" in pref) { if (this.maybeRestart(node, pref.restart)) return; } else this.popupshowing(fe, node.parentNode); if ("refresh" in pref) { var win = node.ownerGlobal; if (this.regexpRefresh.test(win.gBrowser.currentURI.spec)) pref.refresh ? win.BrowserReloadSkipCache() : win.BrowserReload();} }, maybeClosePopup(e, trg) { (e.shiftKey || e.button == 1) || trg.parentNode.hidePopup(); }, popupshowing(e, trg = e.target) { if (trg.state == "closed") return; if (trg.id) { for(var node of trg.children) { if (node.nodeName.endsWith("r")) continue; this.upd(node); !e && node.open && this.popupshowing(null, node.querySelector("menupopup")); } return; } var {pref} = trg.closest("menu"), findChecked = true; var findDef = "defVal" in pref; var checked = trg.querySelector("[checked]"); if (checked) { if (checked.val == pref.val) { if (findDef) findChecked = false; else return; } else checked.removeAttribute("checked"); } if (findDef) { var def = trg.querySelector("menuitem:not([style*=font-style]"); if (def) if (def.val == pref.defVal) { if (findChecked) findDef = false; else return; } else def.style.setProperty("font-style","italic","important"); } for(var node of trg.children) if ("val" in node) { if (!pref.val && pref.val != "" && pref.undef) pref.val = pref.undef[0]; //опции нет ? вернуть default if (findChecked && node.val == pref.val) { node.setAttribute("checked", true); if (findDef) findChecked = false; else break; } if (findDef && node.val == pref.defVal) { node.style.removeProperty("font-style"); if (findChecked) findDef = false; else break; } } }, command(e, trg = e.target) { //LMB if (trg.id == id) { if (trg.config.state != "open") trg.menupopup.openPopup(trg, "after_start") else console.log("Здесь нужен переход на опцию about:config"); return; } var menu = trg.closest("menu"), newVal = trg.val; if (!menu || !menu.pref) return; this.maybeClosePopup(e, menu); menu.pref.code && eval(menu.pref.code); //run1 if (newVal != menu.pref.val) menu.pref.set(menu.pref.pref, newVal), this.maybeRe(menu, true); }, contextmenu(e, trg = e.target) { //RMB if ((trg.id == id) && (!e.ctrlKey && !e.altKey && !e.shiftKey)) if (trg.config.state != "open") this.openPopup(trg.config); else trg.config.hidePopup(); else if ("pref" in trg) { this.maybeClosePopup(e, trg); if (trg.pref.user) prefs.clearUserPref(trg.pref.pref), this.maybeRe(trg); trg.pref.code && eval(trg.pref.code); //run } e.preventDefault(); } }); })("ucf_AboutConfig");
Отсутствует
1) сделать ввод значения текущей опции вручную через диалог ввода. Например в UserAgent > при клике по строке: "ваши данные…" нужно открыть диалог, где вводим нужные данные аналогично уже вшитым в другие строки этого подменю. После ввода или перезапуска браузера при открытии этого подменю строка "ваши данные…" должна быть выбрана флажком.
Попробовал это записать, но как-бы слегка снаружи.
Задержка, и, если ничего не выбрано и преф имеет пользовательское значение,
тогда выбираем строку "ваши данные…".
Врезка в createRadios() перед строкой popup.append(menuitem);
добавляем lab == "ваши данные…" && this.asInput(menuitem, val);
дополнительный стафф в объект
// asInput(menuitem, val) { menuitem.ttsfx = (menuitem.ittt = menuitem.tooltipText) .slice(String(menuitem.ival = val).length); menuitem.linkedObject = this; menuitem.setAttribute("oncommand", "linkedObject.input(event)"); menuitem.render = this.renderInputOnce; }, input(e) { e.stopImmediatePropagation(); var trg = e.target, {pref} = trg.parentNode.parentNode; var res = {value: trg.tt ? pref.val : trg.ival}; if (Services.prompt.prompt( null, `Введите значение (${pref.isInt ? "целое" : "строка"})`, pref.pref, res, null, {} )) { if (pref.isInt) { // from old about:config var val = res.value | 0; if (val != res.value - 0) return Services.prompt.alert( null, "Недействительное значение", "Введённый вами текст не является числом." ); } else val = res.value; pref.set(pref.pref, val); } }, renderInputOnce() { delete this.render; this.render(); var {pref} = this.parentNode.parentNode; pref.isInt = pref.get.name[3] == "I"; if (!("val" in pref)) try {pref.val = pref.get(pref.pref);} catch {} this.linkedObject.hookUncheck(this); // for Shif+Click outside (this.render = this.linkedObject.renderInput).call(this); }, hookUncheck(menuitem) { var rtt = function() { this.tt = false; this.tooltipText = this.ittt; } var desc = {configurable: true, enumerable: true, value(attr) { this.ownerGlobal.Element.prototype.removeAttribute.call(this, attr); attr.startsWith("c") && this.popup.state.startsWith("o") && this.parentNode.rtt(); }}; (this.hookUncheck = menuitem => { menuitem.rtt = rtt; var box = menuitem.firstChild; box.popup = menuitem.parentNode; menuitem.ownerGlobal.Object.defineProperty(box, "removeAttribute", desc); })(menuitem); }, get renderInput() { delete this.renderInput; return this.renderInput = Cu.getGlobalForObject(Cu).eval(`(${async function() { await new Promise(this.ownerGlobal.requestAnimationFrame); var popup = this.parentNode, menu = popup.parentNode; menu.hasAttribute("_moz-menuactive") || this.linkedObject.popupshowing(null, popup, false); // force var checked = popup.querySelector("[checked]"); var {pref} = menu, checkedThis = checked == this; if (checked && !checkedThis || !pref.user) return this.tt && this.rtt(); this.tt = true; this.tooltipText = pref.val + this.ttsfx; if (checkedThis) return; menu.label = menu.label.replace(/другое$/, this.label); this.setAttribute("checked", true); }})`); },
/* popupshowing(e, trg = e.target) { if (trg.state == "closed") return; */ popupshowing(e, trg = e.target, checkstate = true) { if (checkstate && trg.state == "closed") return;
2) надо, чтобы radio-строка подменю была выбрана (с флажком), если опция сброшена и отсутствует.
сделал костыль: pref.undef = [val,str] для pref: pref,lab,key,hint,[val,str],code
костыль делает строку меню такой: "Заголовок - str", но radio-строка подменю остаётся не выбранной.
Не понял. Какая radio-строка остаётся не выбранной?
Вот для extensions.user_chrome_files.savedirs есть pref.undef
и есть три radio-строки, но ни одна из них
не подходит быть выбранной если преф отсутствует.
И, даже если бы подходящая radio-строка была,
то что должно было бы происходить при её активации кликом?
3) при клике по родительской строке меню открывать эту опцию в about:config – функция about_config прилагается.
Это работает в ucf_hookClicks.js, но не пашет в этом коде, т.к. e.target определяется как кнопка, а не как текущая строка меню.
У себя вижу, что на кликнутое ссылается e.explicitOriginalTarget
4) оригинальная кнопка "Быстрое переключение опций about:config" содержала два контекстных меню.
Прошу убрать код для нескольких меню: popups, popupshowing… (может попроще код станет).
Да нет, особо попроще код не станет. В popupshowing здесь менять нечего,
а popups — да, не используется, можно почистить
.... //btn.popups = new btn.ownerGlobal.Array(); .... //btn.popups.push(btn[prop] = popup); btn[prop] = popup; .... //for(var p of btn.popups) p.setAttribute("position", pos); btn.config.setAttribute("position", pos);
0) странноcти кода – добавлял функцию switchTab через запятую в разной последовательности, но не
работает: ua = …}, switchTab = … Без запятой пашет: строка UserMenu не выдаст ошибку: no switchTab…
Я добавил запятую как написано, и у меня всё работает.
Запятая, в данном случае, это оператор множественного вычисления,
она что есть, что нет.
А вот если перед ua добавить var
то запятая станет частью var-синтаксиса
и switchTab перестанет быть глобальной переменной.
То есть, из атрибута "oncommand" его видно не будет.
Отсутствует
Можно в ucf_aom-button.js как-то добавить функцию, как у unified_extensions_button, чтобы при клике вылазило окно, не настройки? Можно эти дополнения с меню, отдельно выделять используя тот шарик с цветом. Во, или на ПКМ посадить unified_extensions_button, а саму кнопку скрыть.
Отредактировано b0ttle (15-12-2023 17:55:26)
Отсутствует
Можно эти дополнения с меню, отдельно выделять используя тот шарик с цветом.
Не понял, нужен скриншот или подробные разьяснения.
Сделал, но пока не публиковал (ucf_hookClicks.js в процессе отладки):
Дополнения к меню опций от Dumby (работает, но переделываю по-своему, ещё изменю формат Setup = [{…)
Меню пользователя и прочие клики для unified_extensions_button работают и на старой кнопке Расширений "add-ons-button"
Можно в ucf_aom-button.js как-то добавить функцию, как у unified_extensions_button, чтобы при клике вылазило окно, не настройки?
Вообще-то удобнее иконку скрипта ucf_aom-button.js убрать, а на правый клик unified_extensions_button назначить меню управления расширениями от ucf_aom-button (но не разбирался, как в этом скрипте привязать клики по меню, открытому из другой кнопки).
Отредактировано Dobrov (16-12-2023 06:30:12)
Отсутствует
попап таких расширений как ublock, tampermonkey, про это меню имелось ввиду, чтобы вместо двух кнопок была одна.
Нет, менюшки расширений не рассматриваются, и я не проверял их открытие над другой кнопкой, если кнопка расширения не закреплена на панели инструментов.
Правым кликом на unified-extensions-button открывается меню пользовательских команд (отлажу скрипт и для "add-ons-button" это меню добавлю)
Отсутствует
Обновил скрипта перехвата кликов-нажатий ucf_hookClicks.js — исправил ошибки несрабатывания некоторых команд пользовательского меню по клику из кнопок.
Cкрипт сохранения страниц SingleHTML.jsm исправлена связка Путь сохранения <-> установка пути из Опций быстрых настроек.
Всех с наступающим праздником!
Отсутствует