Можно заменить все (два) « instanceof Ci.nsIDOMChromeWindow» на «.isChromeWindow»
Большое спасибо!
Добавлено 06-07-2023 21:16:32
скриптом для UCF размещения фавиконки сайта в адресной строке
Если ничего не путаю, то вот: https://forum.mozilla-russia.org/viewto … 52#p793152
Отредактировано unter_officer (06-07-2023 21:16:47)
«The Truth Is Out There»
Отсутствует
Если ничего не путаю, то вот: https://forum.mozilla-russia.org/viewto … 52#p793152
Спасибо большое, но... Всё время показывает дефолтную иконку.
А вот этот работает - https://github.com/Aris-t2/CustomJSforFx/blob/master/scripts/favicon_in_urlbar.uc.js
Отсутствует
Viatcheslav
Вот это рабочий, если нет, то проблема у вас.
Иконку дефолтную свою вписать или положить по прописанному пути.
// FavIcon in URL-bar - Иконка сайта в url-баре // https://forum.mozilla-russia.org/viewtopic.php?pid=789469#p789469 (this.faviconinurlbar = { init(that) { var identity = document.querySelector("#identity-icon"); if (!identity) return; var iconDefault = "chrome://user_chrome_files/content/custom_styles/png/globe-16.png"; // или свою иконку var style = "data:text/css;charset=utf-8," + encodeURIComponent(` #identity-faviconinurlbar { --v-faviconinurlbar-default: url("${iconDefault}"); list-style-image: var(--v-faviconinurlbar, none) !important; pointer-events: none !important; height: 16px !important; width: auto !important; margin-inline-start: 4px !important; -moz-context-properties: fill, fill-opacity; fill: currentColor; fill-opacity: var(--urlbar-icon-fill-opacity, 1); } #identity-faviconinurlbar:not([faviconinurlbar="true"]), #identity-faviconinurlbar[favbusy="true"] { --v-faviconinurlbar: var(--v-faviconinurlbar-default) !important; } #identity-faviconinurlbar[faviconchrome="true"], #urlbar[actiontype="extension"] #identity-faviconinurlbar, #identity-box:is(.extensionPage,.chromeUI,.localResource) #identity-faviconinurlbar, #urlbar:not(.searchButton) #identity-box[pageproxystate="invalid"] #identity-faviconinurlbar { display: none !important; } `); windowUtils.loadSheetUsingURIString(style, windowUtils.USER_SHEET); var faviconinurlbar = document.createXULElement("image"); faviconinurlbar.id = "identity-faviconinurlbar"; identity.after(faviconinurlbar); gBrowser.tabContainer.addEventListener("TabAttrModified", this); gBrowser.addProgressListener(this); that.unloadlisteners.push("faviconinurlbar"); var {STATE_START, STATE_STOP, STATE_IS_NETWORK} = Ci.nsIWebProgressListener; var updatefavicon = image => { if (image) { faviconinurlbar.style.setProperty("--v-faviconinurlbar", `url("${image}")`); faviconinurlbar.setAttribute("faviconinurlbar", "true"); faviconinurlbar.setAttribute("faviconchrome", `${image.startsWith("chrome:")}`); } else { faviconinurlbar.setAttribute("faviconinurlbar", "false"); faviconinurlbar.style.setProperty("--v-faviconinurlbar", ""); } }; this.handleEvent = e => { var tab = e.target, changed; if (!tab.selected || !((changed = e.detail.changed).includes("image") || changed.includes("selected"))) return; updatefavicon(tab.image); }; this.onStateChange = (aWebProgress, aRequest, aStateFlags, aStatus) => { if (aStateFlags & STATE_IS_NETWORK && aWebProgress?.isTopLevel) { if (aStateFlags & STATE_START) faviconinurlbar.setAttribute("favbusy", "true"); else if (aStateFlags & STATE_STOP) { faviconinurlbar.setAttribute("favbusy", "false"); updatefavicon(gBrowser.selectedTab.image); } } }; }, destructor() { gBrowser.tabContainer.removeEventListener("TabAttrModified", this); gBrowser.removeProgressListener(this); } }).init(this);
Отсутствует
Вот это рабочий, если нет, то проблема у вас
Наверное...
А каким способом подключали?
У меня вот этот - https://github.com/Aris-t2/CustomJSforFx/blob/master/scripts/favicon_in_urlbar.uc.js
подключен к UCF в custom_script_win.js по событию "DOMContentLoaded".
Только не зря его Виталий назвал "ужасным...
Отсутствует
Viatcheslav Они разные, может и подключать по разному надо, у меня в CustomStylesScripts.jsm
scriptschrome: { // Для докум. окна браузера [ChromeOnly]
load: [ // По событию "load"
Это аналог custom_script_win.js после секции ...
load() { if (this.initialized) return; this.initialized = true; /* ************************************************ */ тут коды или импорт
Импорт раньше у меня такой был ...
// Для скриптов отдельными файлами (см. примеры) // С уточнением в каком "документе" работать // https://forum.mozilla-russia.org/viewtopic.php?pid=788301#p788301 (async () => { var loadscript = (relpath, obj) => { try { Services.scriptloader.loadSubScript(`chrome://user_chrome_files/content/custom_scripts/${relpath}`, obj, "UTF-8"); return true; } catch(e) { } return false; }, load_scripts_by_url = { browser: win => { //>>>>>>>>>>| Блок требуется для боковой панели и т.п. |>>>>>>>>>> var box = document.querySelector("#browser") || window; var listener = e => { var doc = e.target || ({}); load_scripts_by_url[doc.documentURI]?.(doc.defaultView); }; box.addEventListener("pageshow", listener); this.loadscriptswinandsidebar = { destructor() { box.removeEventListener("pageshow", listener); } }; this.unloadlisteners.push("loadscriptswinandsidebar"); /* <<<<<<<<<<<<<<<<<<<< */ //>>>>>>>>>>| Загрузка скриптов для browser.xhtml |>>>>>>>>>> // Здесь скрипты для основного окна loadscript("custom_js_win/ucf_Bookmarks_Star_Tooltip_Helper.uc.js", win); loadscript("custom_js_win/ucf_Context_Menu_Open_With.us.js", this) && this.unloadlisteners.push("contextmenuopenwith"); loadscript("custom_js_win/ucf_FavIcon_In_URL-bar.uc.js", this); loadscript("custom_js_win/ucf_Open_Hisory_Bookmark_In_NewTab.uc.js", win) && win.ucf_where_to_open_link.browser(); loadscript("custom_js_win/ucf_SidebarTabs.us.js", this) && this.unloadlisteners.push("sidebar_tabs"); // и т.д. //<<<<<<<<<<<<<<<<<<<< }, //>>>>>>>>>>| Загрузка скриптов для др. документов |>>>>>>>>>> "chrome://browser/content/places/bookmarksSidebar.xhtml": win => { // Здесь скрипты для боковой панели закладок loadscript("custom_js_win/s_AutoCloseBookMarkFolder_Fx37.uc.js", win); loadscript("custom_js_win/ucf_Open_Hisory_Bookmark_In_NewTab.uc.js", win) && win.ucf_where_to_open_link.bookmarksSidebar(); // и т.д. }, "chrome://browser/content/places/historySidebar.xhtml": win => { // Здесь скрипты для боковой панели истории loadscript("custom_js_win/s_AutoCloseHistoryFolder_Fx37.uc.js", win); loadscript("custom_js_win/ucf_Open_Hisory_Bookmark_In_NewTab.uc.js", win) && win.ucf_where_to_open_link.historySidebar(); // и т.д. }, //<<<<<<<<<<<<<<<<<<<< }; load_scripts_by_url.browser(window); })();
Отредактировано _zt (07-07-2023 20:03:41)
Отсутствует
Импорт раньше у меня такой был ...
Это для старой версии UCF
Спасибо за помощь
Отсутствует
Dumby
Есть ваш скриптик "Восстановление удалённых закладок".
// // Dumby: https://forum.mozilla-russia.org/viewtopic.php?pid=801497#p801497 // (async sep => { if (!sep) return; var key = "hasRemoveTransaction"; var g = Cu.import("resource://gre/modules/PlacesTransactions.jsm", {}); var raws = (g.lazy || g).TransactionsHistory?.proxifiedToRaw; if (raws) g = raws; if (!g[key]) { if (!raws) { Services.scriptloader.loadSubScript( `data:,this.${key}=TransactionsHistory.proxifiedToRaw;`, g ); raws = g[key]; } g[key] = entry => { for(var tr of entry) if (raws.get(tr) instanceof PlacesTransactions.Remove) return true; } } var menuitem = document.createXULElement("menuitem"); for(var args of Object.entries({ closemenu: "single", class: "menuitem-iconic", id: "placesCmd_undoRemove", label: "Восстановить удалённое", oncommand: "PlacesTransactions.undo().catch(Cu.reportError);", image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQEAYAAABPYyMiAAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAAEd0lEQVRIx53Ve2yW5RkG8N/7ft8Hxa/9CgjSSDnMA4xVTUMQWzadhzhnjSCC0y0jSjom+JdGp844ZhSjHLJsowaNZoCCHOWglXGoQbo2fBW3obDNUBfXKpsUVhxn6OHdH8+31GXGmL3/3M913ffzPNed93qeBxvmI8umCNjyPFEDSRJw40qKa9jyHSbdzY77Ar+9FTvZ+nHAb9T7P76YcwlOktlBdJia2SSthfRvaR/Mync5tp85Q2mbEHJ/X0bqRTpOBJyehog3C3j1HV9RQP91xG9T8z2SofyphMELWH4zW5s40s7kQ/T0cnYfXfPD1OgM0TlGzSN1DZkzxG1EdURjaa9HCfddEupfuSkIfHXJ5wVENA8Iw9QcRnbzXj31++g8w+WVZHMhXzaKhu2MGMtd36f5CTrn8WAJyf001KCYpA6dDBtLlOfoYuI6kgp6XuLsbhQRfw39ovDPx7/JgYS1b3NkCxcvoPgTevIULyFVTm4jyinp4uRJiirYt5BMLc15kvE0lnCsgZaE2wdx6LVCo9/ghQn4LhdFxEOonELv8ogVV9Iyjd9fx8T1FE2nq5XSQWQuJbsmrJH9JclMsldhFsW3EU0iuxsb6f9zTA3dHj1J1yPsKaPrIOtnkn6KDY2cvYF/vkfmINGuiPdnUD6Pd/7Mur/x0RCqXqTfj+m5glyO1B8ovR1pijeil6KvBw8V1QaB/QYWzNgSYu+TmMm5GVhKT47OBWR28kgnvxvKS/OjvuMGuTSr72FtBR/WctNe4l+H3GUt7DxB2TKe+CmnF5IZRzSZzFmS4wy9n2QGY2eR3Mx193DqAao+4vh04lZS2/EkQyqo7cWux4Kjwf4gKF3N5hEs+QsLlwVuVRPLP2FeTSh95hZSpSx6OOAkwWCWLSEqYWVz4JtLqd3GiuX0/oS6XKjd/BQbF6SRJynij4eJKpl7WSg8cCdzxjHjH3QuIsaorQx7NCx8QQdxCYM2kzxL423BbGN6SP+I6tmcO86hahqu4MA2To3mX+eTxbA2er6VJjcA/Yl2kOzlrutJxrDraaI1XH09j3fQVk7pcG5sCgIOttLVzejpmMPrnxJvYnIZXelwxGHTCOaX0PorsmUMOC/wpeNofg4fjg9EW3+k6CzcYJ99M7h6fSfxFFJrMZzFm0I+fzXxlTQ1EHf3eSlJyI3mlYGs/yEPx4F7/NkQ11zEymFhnDoY9RnwcHmIZ34Q1CcTkBD9FSM58gu8SmUHbmVuJbYRt2AiE/cwZT/tG3h+Gh29lH3A+VPZ+zMq1rHwcq6tY1U31ReQXPgFt3M+/9+xJRvM9f5S3NnX6btLqfqYt1p44xQrFnH0aX6zmBXIj+Hae0N95qG+ea/PJjrB7tV47csE7CzEJqKXyTcW8CquaibfwTOX0FjPLSfYk+G8XWyb+rlTUcndVUQjWXOK+FiBn/QfQen/FVBVVdhoc4FIkczqM5WBvPMWp4fQMpzFHeEN2NCFCcyNSH2b1AiSl3nhVnrnkjpNkqP9jrBvdzX8G2rIlxvMK3a7AAAAInpUWHRTb2Z0d2FyZQAAeNorLy/Xy8zLLk5OLEjVyy9KBwA22AZYEFPKXAAAAABJRU5ErkJggg==", })) menuitem.setAttribute(...args); var desc = Object.getOwnPropertyDescriptor(XULElement.prototype, "hidden"); var {set} = desc; desc.set = () => { var entry = PlacesTransactions.topUndoEntry; var vis = entry && g[key](entry); vis && menuitem.removeAttribute("disabled"); set.call(menuitem, !vis); } Object.defineProperty(menuitem, "hidden", desc); sep.after(menuitem); })(document.getElementById("placesContext_deleteSeparator"));
«The Truth Is Out There»
Отсутствует
ucf_hookClicks.js некорректно работает в 115.0.1, где-то нет тултипов, отвалилась подсветка и вся система алертов при копирований адресной строки через identity-box, и еще что-то. Все остальное работает, пока не разобрался что еще отвалилось.
Кстати, как в консоли высматривать ошибки? Тот который Ctrl+Shift+J.
Отредактировано b0ttle (10-07-2023 14:13:43)
Отсутствует
В предыдущих версиях всё работает нормально.
Да, вижу. Слегка поменяли код.
Раньше disabled ставился перед hidden,
а теперь получилось наоборот, сначала hidden.
Можно попробовать вообще просто поставить на disabled заглушку
/* var vis = entry && g[key](entry); vis && menuitem.removeAttribute("disabled"); set.call(menuitem, !vis); } */ set.call(menuitem, !entry || !g[key](entry)); } Object.defineProperty(menuitem, "disabled", {});
Bug 1780695 - «Remove Services.jsm» (Firefox 117+)
See also: Bug 1667455 - «Expose a "Services" property on all privileged JS scopes (like Cu/Cc/Ci)» (Firefox 104+)
Отсутствует
Можно попробовать вообще просто поставить на disabled заглушку
Большое спасибо!
«The Truth Is Out There»
Отсутствует
Тут тултипы работают в hookClicks, но при запуске firefox почему-то пишет, что файл не запущен, хотя по виду все работает. Странно.
Проверил. В коде по ссылке, там тултипы работают, а функций нет, при кликах ничего не происходит.
Хотел свою версию сюда(код то не мой, не умею кодить. просто чуть-чуть под себя подогнал), но там какие-то символы мешают, сайт не принимает, а в base64txt, не умею.
Смог сделать в base64txt, но теперь из-за размера не пропустил, что-то про (64 КБ).
В общем, https://pastebin.com/fn2WwQVS Судя по длине кода, наверно никто не захочет в ней возиться.
Отредактировано b0ttle (11-07-2023 17:25:12)
Отсутствует
Тут тултипы работают в hookClicks, но при запуске firefox почему-то пишет, что файл не запущен, хотя по виду все работает.
на FF114 всё работало. На 115 перехват кликов не работает, базовый hookClicks выдаёт много ошибок в консоли.
Dumby - проверьте на Firefox 115 ваш базовый hookClicks, на его основе я делал все доработки для профиля в шапке.
Отсутствует
Dumby - просьба доработать скрипт, чтобы его запускать по перехвату кликов из любых кнопок:
/* для UCF CustomStylesScripts.jsm scriptsbackground: [ // В фоне [System Principal] { func: jsmImport("AppMenuTbbSaveHTMLChild.jsm"), }, */ var self, name = "AppMenuTbbSaveHTML", EXPORTED_SYMBOLS = [name + "Child"]; var {io, focus, obs} = globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services; class AppMenuTbbSaveHTMLChild extends JSWindowActorChild { receiveMessage() { return htmlAndName(this.contentWindow); } } ChromeUtils.domProcessChild.childID || ({ init(topic) { ChromeUtils.registerWindowActor(name, { allFrames: true, child: {moduleURI: __URI__}, messageManagerGroups: ["browsers"] }); obs.addObserver(self = this, topic); obs.addObserver(function quit(s, t) { obs.removeObserver(quit, t); obs.removeObserver(self, topic); }, "quit-application-granted"); this.handleEvent = e => this[e.type](e); }, observe(win) { win.document.getElementById("appMenu-popup") .addEventListener("popupshowing", this); win.addEventListener("unload", this); }, popupshowing(e) { this.unload(e); var popup = e.target; var btn = popup.ownerDocument.createXULElement("toolbarbutton"); btn.id = "appMenu-ucf-save-html-button"; btn.setAttribute("label", "Страница | выбранное в единый HTML"); var before = "appMenu-save-file-button2", subviewbutton = "subviewbutton"; if ( parseInt(popup.ownerGlobal.Services.appinfo.version) < 89 ) { subviewbutton = "subviewbutton subviewbutton-iconic", before = "appMenu-print-button"; btn.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAAAAAClZ7nPAAAAAXRSTlMAQObYZgAAACNJREFUCNdjYH/AgBX9/89Q/4/B/g+D/A8G/g8gEeYDDIwNAIB7EDCcKCcMAAAAAElFTkSuQmCC"); } btn.className = subviewbutton; btn.setAttribute("oncommand", "saveHTML();"); btn.saveHTML = this.saveHTML; popup.querySelector('toolbarbutton[id^="'+ before +'"]').before(btn); }, unload(e) { var win = e.target.ownerGlobal; win.removeEventListener("unload", this); win.document.getElementById("appMenu-popup").removeEventListener("popupshowing", this); }, async saveHTML() { var win = this.ownerGlobal; var br = win.gBrowser.selectedBrowser; var bc = focus.focusedContentBrowsingContext; if (bc?.top.embedderElement != br) bc = br.browsingContext; var actor = bc?.currentWindowGlobal?.getActor(name); actor && self.save(win, ...await actor.sendQuery("")); }, async save(win, fileContent, fileName) { var fp = Cc['@mozilla.org/filepicker;1'].createInstance(Ci.nsIFilePicker); fp.init(win, "", fp.modeSave); fp.defaultString = fileName; fp.appendFilters(fp.filterHTML); fp.appendFilters(fp.filterAll); var res = await new Promise(fp.open); if (res == fp.returnOK || res == fp.returnReplace) this.write(fp.file.path, fileContent); }, write(path, html) { if (typeof IOUtils == "object") var write = IOUtils.writeUTF8 || IOUtils.writeAtomicUTF8; // Fx 85+ || 82-84 if (!write) { // Fx 79-81 var {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); write = (path, txt) => OS.File.writeAtomic(path, new TextEncoder().encode(txt)); } (this.write = write)(path, html); } }).init("browser-delayed-startup-finished"); var htmlAndName = async mainWin => { var resolveURL = function (url, base) { try { return io.newURI(url, null, io.newURI(base)).spec; } catch {} }; var getSelWin = function (w) { if (w.getSelection().toString()) return w; for (var i = 0, f, r; f = w.frames[i]; i++) { try { if (r = getSelWin(f)) return r; } catch(e) {} } }; var encodeImg = function (src, obj) { var canvas, img, ret = src; if (/^https?:\/\//.test(src)) { canvas = doc.createElement('canvas'); if (!obj || obj.nodeName.toLowerCase() != 'img') { img = doc.createElement('img'); img.src = src; } else { img = obj; }; if (img.complete) try{ canvas.width = img.width; canvas.height = img.height; canvas.getContext('2d').drawImage(img, 0, 0); ret = canvas.toDataURL((/\.jpe?g/i.test(src) ? 'image/jpeg' : 'image/png')); } catch (e) {}; if (img != obj) img.src = 'about:blank'; }; return ret; }; var toSrc = function (obj) { var strToSrc = function (str) { var chr, ret = '', i = 0, meta = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\x22' : '\\\x22', '\\': '\\\\'}; while (chr = str.charAt(i++)) { ret += meta[chr] || chr; }; return '\x22' + ret + '\x22'; }, arrToSrc = function (arr) { var ret = []; for (var i = 0; i < arr.length; i++) { ret[i] = toSrc(arr[i]) || 'null'; }; return '[' + ret.join(',') + ']'; }, objToSrc = function (obj) { var val, ret = []; for (var prop in obj) { if (obj.hasOwnProperty(prop) && (val = toSrc(obj[prop]))) ret.push(strToSrc(prop) + ': ' + val); }; return '{' + ret.join(',') + '}'; }; switch (Object.prototype.toString.call(obj).slice(8, -1)) { case 'Array': return arrToSrc(obj); case 'Boolean': case 'Function': case 'RegExp': return obj.toString(); case 'Date': return 'new Date(' + obj.getTime() + ')'; case 'Math': return 'Math'; case 'Number': return isFinite(obj) ? String(obj) : 'null'; case 'Object': return objToSrc(obj); case 'String': return strToSrc(obj); default: return obj ? (obj.nodeType == 1 && obj.id ? 'document.getElementById(' + strToSrc(obj.id) + ')' : '{}') : 'null'; } }; var selWin = getSelWin(mainWin), win = selWin || mainWin, doc = win.document, loc = win.location; var ele, pEle, clone, reUrl = /(url\(\x22)(.+?)(\x22\))/g; if (selWin) { var rng = win.getSelection().getRangeAt(0); pEle = rng.commonAncestorContainer; ele = rng.cloneContents(); } else { pEle = doc.documentElement; ele = (doc.body || doc.getElementsByTagName('body')[0]).cloneNode(true); }; while (pEle) { if (pEle.nodeType == 1) { clone = pEle.cloneNode(false); clone.appendChild(ele); ele = clone; }; pEle = pEle.parentNode }; var sel = doc.createElement('div'); sel.appendChild(ele); for (var el, all = sel.getElementsByTagName('*'), i = all.length; i--;) { el = all[i]; if (el.style && el.style.backgroundImage) el.style.backgroundImage = el.style.backgroundImage.replace(reUrl, function (a, prev, url, next) { if (!/^[a-z]+:/.test(url)) url = resolveURL(url, loc.href); return prev + encodeImg(url) + next; }); switch (el.nodeName.toLowerCase()) { case 'link': case 'style': case 'script': el.parentNode.removeChild(el); break; case 'a': case 'area': if (el.hasAttribute('href') && el.getAttribute('href').charAt(0) != '#') el.href = el.href; break; case 'img': case 'input': if (el.hasAttribute('src')) el.src = encodeImg(el.src, el); break; case 'audio': case 'video': case 'embed': case 'frame': case 'iframe': if (el.hasAttribute('src')) el.src = el.src; break; case 'object': if (el.hasAttribute('data')) el.data = el.data; break; case 'form': if (el.hasAttribute('action')) el.action = el.action; break; } }; var head = ele.insertBefore(doc.createElement('head'), ele.firstChild); var meta = doc.createElement('meta'); meta.httpEquiv = 'content-type'; meta.content = 'text/html; charset=utf-8'; head.appendChild(meta); var title = doc.getElementsByTagName('title')[0]; if (title) head.appendChild(title.cloneNode(true)); head.copyScript = function (unsafeWin) { if ('$' in unsafeWin) return; var f = doc.createElement('iframe'); f.src = 'about:blank'; f.setAttribute('style', 'position:fixed;left:0;top:0;visibility:hidden;width:0;height:0;'); doc.documentElement.appendChild(f); var str, script = doc.createElement('script'); script.type = 'text/javascript'; for (var name in unsafeWin) { if (name in f.contentWindow || !/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) continue; try { str = toSrc(unsafeWin[name]); if (!/\{\s*\[native code\]\s*\}/.test(str)) { script.appendChild(doc.createTextNode('var ' + name + ' = ' + str.replace(/<\/(script>)/ig, '<\\/$1') + ';\n')); } } catch (e) {}; }; f.parentNode.removeChild(f); if (script.childNodes.length) this.nextSibling.appendChild(script); }; head.copyScript(win.wrappedJSObject || win); head.copyStyle = function (s) { if (!s) return; var style = doc.createElement('style'); style.type = 'text/css'; if (s.media && s.media.mediaText) style.media = s.media.mediaText; try { for (var i = 0, rule; rule = s.cssRules[i]; i++) { if (rule.type != 3) { if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) { var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) { if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href); if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url); return prev + url + next; }); style.appendChild(doc.createTextNode(css + '\n')); } } else { this.copyStyle(rule.styleSheet); } } } catch(e) { if (s.ownerNode) style = s.ownerNode.cloneNode(false); }; this.appendChild(style); }; var sheets = doc.styleSheets; for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]); head.appendChild(doc.createTextNode('\n')); var doctype = '', dt = doc.doctype; if (dt && dt.name) { doctype += '<!DOCTYPE ' + dt.name; if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22'; if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22'; doctype += '>\n'; }; var fileName = selWin ? win.getSelection().toString() : (title && title.text ? title.text : loc.pathname.split('/').pop()); fileName = fileName.replace(/[:\\\/<>?*|"]+/g, '_').replace(/\s+/g, ' ').slice(0, 100).replace(/^\s+|\s+$/g, ''); fileName += (function () { var d = new Date(), z = function(n){return '_' + (n < 10 ? '0' : '') + n}; return z(d.getHours()) + z(d.getMinutes()) + z(d.getSeconds()); })(); if(!/\.html?$/.test(fileName))fileName += '.html'; return [doctype + sel.innerHTML + '\n<!-- This document saved from ' + (loc.protocol != 'data:' ? loc.href : 'data:uri') + ' -->', fileName]; }
Просьба такая - сделать единый скрипт, который работает в зависимости от переданных опций, то есть либо сохраняет в единый HTML с запросом "Куда?", либо сохраняет сразу без запроса в "Загрузки".
То есть, чтобы скрипт можно было вызывать из разных кнопок (например, по перехвату кликов из ucf_hookClicks) с разными опциями – например "Спросить", куда сохранять или "Не спрашивать".
Отсутствует
Не знаю в какую тему написать... В FX115 отвалилась кнопка восстановления вкладок после закрытия (не показывает список закрытых вкладок), вроде она относится к расширению add_toolbar_buttons@vitaliy.ru. Можно как-то ее починить?
https://dropmefiles.com/XaeKh - расширение
Отсутствует
Northtech
https://forum.mozilla-russia.org/viewtopic.php?pid=804061#p804061
Add, надеюсь оно, я просто эту кнопку не использую.
Отредактировано kokoss (12-07-2023 11:38:06)
Win7
Отсутствует
Возможно ли запускать перевод горячими клавишами (двойнм Ctrl) в этом скрипте?
Это как-то неудобно. Скрипт завязан на контекстное меню,
и берёт выделенный текст из его машинерии. А если клавишей, то взять негде.
Разве что через буфер обмена. Ну попробуй дописать после строки
contextMenu.insertBefore(document.createXULElement("menuseparator"), nextEleMenu);
// var translate = async () => { var br = gBrowser.selectedBrowser; var fw = Services.focus.focusedWindow; if (fw == window) { if (document.activeElement != br) return; } else if (fw.browsingContext.top != br.browsingContext) return; var cb = navigator.clipboard; var was = await cb.readText(); if (was) await cb.writeText(""); docShell.doCommand("cmd_copy"); await new Promise(r => setTimeout(r, 100)); var txt = await cb.readText(); if (txt || was) cb.writeText(was); if (!txt && !br.currentURI.scheme.startsWith("http")) return; window.gContextMenu = {selectionInfo: { get fullText() { window.gContextMenu = null; return txt; } }}; ujs_google_translate("auto|ru"); } var ts = 0, destr = this.destructor, args = ["keyup", e => e.key == "Control" && ts - (ts = Cu.now()) > -300 && !e.shiftKey && !e.altKey && translate(ts = 0) ]; addEventListener(...args); this.destructor = () => destr(removeEventListener(...args));
ваш базовый hookClicks
Нет у меня никакого hookClicks, не сочиняй.
Мы там что-то когда-то обсуждали, и ты его родил.
проверьте на Firefox 115
Ну я убрал кусок кода if (typeof IOUtils != "object") {…};
и, на первый взгляд, вроде нормализовалось.
Так, потыкал немного, там же невозможно всё проверить,
нужно что-то поконкретнее.
В этом куске всё тот же косяк с непониманием работы var.
Вчера вот Services.jsm удалили, так у меня всё рухнуло в основном из-за этого.
Вобщем, тоже удали, или перепиши кусок правильно.
Да, кстати, потерялся var перед str_cut = …
Без него, в окно добавятся ненужные там
str_cut, url_color, switchToTab, showInStatusPanel, Title,
saveSelectionToTxt, save, bright, help, GetSelection, data,
и gClipboard конечно, который может перезаписать
тот, что от Custom Buttons, а это уже совсем нехорошо.
чтобы скрипт можно было вызывать
Скрипт нельзя «вызвать», только загрузить. Вызвать можно функцию.
Это надо что-то в SystemGlobal добавить, чтобы с других мест вызывать.
Попробую расписать, чисто для примера. Следи за мыслью
Затем, из saveHTML() убираем var win = this.ownerGlobal;
а в саму функцию добавляем наш аргумент, и вторым аргументом окно
async saveHTML(arg, win = this.ownerGlobal) {
и, в последней строке функции, наш аргумент пробрасываем
actor && self.save(win, ...await actor.sendQuery(""), arg);
Далее вписываем его и в save()
async save(win, fileContent, fileName, arg) {
Таким образом, внутри save() теперь можно его использовать
if (arg) {
win.alert(arg); // test
// Здесь делаем что-то одно, типа вычисляем путь для файла
} else {
// Здесь делаем что-то другое, типа открываем файл-пикер и забираем путь с него
}
// Здесь записываем файл
Всё. Теперь можно вызывать снаружи, например, с консоли браузера:
(() => {
var save = Cu.getGlobalForObject(Cu)[Symbol.for("AppMenuTbbSaveHTML")];
save("TesT", window);
})();
dropmefiles.com
javascript:void(0); — нет уж, разрешите отказаться.
Но наверняка дело в getClosedTabCount
Можно заменить в parent.js все два на getClosedTabCountForWindow
Если нужна обратная совместимость, то два
sessionStore.getClosedTabCount
заменить на
(sessionStore.getClosedTabCountForWindow || sessionStore.getClosedTabCount)
Отсутствует
После какого-то из недавних обновлений перестал работать скрипт (contextsearch.uc.js), вот он: https://forum.mozilla-russia.org/viewto … 83#p780283 , переключающий поисковые системы в контекстном меню выделенного текста.
В данный момент стоит 115.02 (Windows 7).
В скриптах я, к сожалению, совсем не разбираюсь. Подскажите пожалуйста, как теперь его снова заставить работать?
Отсутствует
Попробую расписать, чисто для примера. Следи за мыслью…
Спасибо за подсказки! Доработал скрипт AppMenuTbbSaveHTMLChild, проверь, может я накосячил где-то…
1) теперь запускается так: Cu.getGlobalForObject(Cu)[Symbol.for("SingleHTML")](true, window);
2) можно сохранять страницу автоматически или с запросом "Куда"
3) может сохранять в разные папки в зависимости от опции ucf.savedirs: Загрузки[домен]имя вкладки
или указать любой путь сохранения, например: Загрузки/Web/домен/имя …for("SingleHTML")]("Web|1", window)
/* SingleHtml by Лекс, правка: Dumby, mod Dobrov для UCF CustomStylesScripts.jsm scriptsbackground: [ // В фоне [System Principal] { func: jsmImport("SingleHTMLChild.jsm"), }, вызов: Cu.getGlobalForObject(Cu)[Symbol.for("SingleHTML")](arg, window) если arg False, то диалог выбора пути сохранения */ var self, name = "SingleHTML", EXPORTED_SYMBOLS = [name + "Child"]; var {io, focus, obs, prefs, dirsvc} = globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services; class SingleHTMLChild extends JSWindowActorChild { //класс = name + Child receiveMessage() { return htmlAndName(this.contentWindow);} } ChromeUtils.domProcessChild.childID || ({ init(topic) { ChromeUtils.registerWindowActor(name, { allFrames: true, child: {moduleURI: __URI__}, messageManagerGroups: ["browsers"] }); obs.addObserver(self = this, topic); obs.addObserver(function quit(s, t) { obs.removeObserver(quit, t); obs.removeObserver(self, topic); }, "quit-application-granted"); this.handleEvent = e => this[e.type](e); globalThis[Symbol.for(name)] = this.saveHTML; }, observe(win) { win.document.getElementById("appMenu-popup") .addEventListener("popupshowing", this); win.addEventListener("unload", this); }, popupshowing(e) { this.unload(e); var popup = e.target; var btn = popup.ownerDocument.createXULElement("toolbarbutton"); btn.id = "appMenu-ucf-save-html-button"; btn.setAttribute("label", "Страница | выбранное в единый HTML"); var before = "appMenu-save-file-button2", subviewbutton = "subviewbutton"; btn.className = subviewbutton; btn.setAttribute("oncommand", "saveHTML();"); btn.saveHTML = this.saveHTML; popup.querySelector('toolbarbutton[id^="'+ before +'"]').before(btn); }, unload(e) { var win = e.target.ownerGlobal; win.removeEventListener("unload", this); win.document.getElementById("appMenu-popup").removeEventListener("popupshowing", this); }, async saveHTML(arg, win = this.ownerGlobal) { var br = win.gBrowser.selectedBrowser; var bc = focus.focusedContentBrowsingContext; if (bc?.top.embedderElement != br) bc = br.browsingContext; var actor = bc?.currentWindowGlobal?.getActor(name); actor && self.save(win, ...await actor.sendQuery(""), arg); // htmlAndName }, async save(win, data, fname, host, arg, d = prefs.getStringPref("ucf.savedirs","_Web||_Pic|0")) { if (/.*\|/.test(arg)) d = arg; //Dir/Subdir|[пусто|0 title|1 host] if (!/.*\|/.test(d)) d += '|'; d = d.split('|').slice(0,2); //Загрузки[домен]имя fname = fname.replace(/\s+/g,' ').replace(/[\\\/?*\"'`]+/g,'').replace(/[|<>]+/g,'_').replace(/:/g,'։').slice(0,100).trim(); d[1] = (d[1] == "0") ? fname.slice(0,48).trim() : (d[1] == "1") ? host.replace(/\/.*/,'') : ""; try {var dir = prefs.getComplexValue("browser.download.dir", Ci.nsIFile);} catch {var dir = dirsvc.get("DfltDwnld", Ci.nsIFile);} d.forEach(dir.append); dir.exists() && dir.isDirectory() || dir.create(dir.DIRECTORY_TYPE, 0o777); fname += (function() {var d = new Date(), z = function(n){return '։' + (n < 10 ? '0' : '') + n}; return '_'+ d.getHours() + z(d.getMinutes()) + z(d.getSeconds());})(); dir.append(fname +'.html'); var path = dir.path; //назначить путь сохранения if (!arg) { // диалог выбора папки var fp = Cc['@mozilla.org/filepicker;1'].createInstance(Ci.nsIFilePicker); fp.init(win, "", fp.modeSave); fp.defaultString = path.split(/.*[\/|\\]/)[1]; fp.appendFilters(fp.filterHTML); fp.appendFilters(fp.filterAll); var res = await new Promise(fp.open); if (res == fp.returnOK || res == fp.returnReplace) path = fp.file.path else return; } this.write(path, data); d = await win.Downloads.createDownload({source: "about:blank",target: win.FileUtils.File(path)}); (await win.Downloads.getList(win.Downloads.ALL)).add(d); await d.refresh(d.succeeded = true); //flash DWButton }, write(path, html) { if (typeof IOUtils == "object") var write = IOUtils.writeUTF8 || IOUtils.writeAtomicUTF8; // Fx 85+ || 82-84 if (!write) { // Fx 79-81 var {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); write = (path, txt) => OS.File.writeAtomic(path, new TextEncoder().encode(txt)); } (this.write = write)(path, html); } }).init("browser-delayed-startup-finished"); var htmlAndName = async mainWin => { var resolveURL = function (url, base) { try { return io.newURI(url, null, io.newURI(base)).spec;} catch {} }, getSelWin = function (w) { if (w.getSelection().toString()) return w; for (var i = 0, f, r; f = w.frames[i]; i++) { try { if (r = getSelWin(f)) return r;} catch(e) {} } }, encodeImg = function (src, obj) { var canvas, img, ret = src; if (/^https?:\/\//.test(src)) { canvas = doc.createElement('canvas'); if (!obj || obj.nodeName.toLowerCase() != 'img') { img = doc.createElement('img'); img.src = src; } else img = obj; if (img.complete) try { canvas.width = img.width; canvas.height = img.height; canvas.getContext('2d').drawImage(img, 0, 0); ret = canvas.toDataURL((/\.jpe?g/i.test(src) ? 'image/jpeg' : 'image/png')); } catch (e) {}; if (img != obj) img.src = 'about:blank'; }; return ret; }, toSrc = function (obj) { var strToSrc = function (str) { var chr, ret = '', i = 0, meta = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\x22' : '\\\x22', '\\': '\\\\'}; while (chr = str.charAt(i++)) { ret += meta[chr] || chr; }; return '\x22' + ret + '\x22'; }, arrToSrc = function (arr) { var ret = []; for (var i = 0; i < arr.length; i++) { ret[i] = toSrc(arr[i]) || 'null'; }; return '[' + ret.join(',') + ']'; }, objToSrc = function (obj) { var val, ret = []; for (var prop in obj) { if (obj.hasOwnProperty(prop) && (val = toSrc(obj[prop]))) ret.push(strToSrc(prop) + ': ' + val); }; return '{' + ret.join(',') + '}'; }; switch (Object.prototype.toString.call(obj).slice(8, -1)) { case 'Array': return arrToSrc(obj); case 'Boolean': case 'Function': case 'RegExp': return obj.toString(); case 'Date': return 'new Date(' + obj.getTime() + ')'; case 'Math': return 'Math'; case 'Number': return isFinite(obj) ? String(obj) : 'null'; case 'Object': return objToSrc(obj); case 'String': return strToSrc(obj); default: return obj ? (obj.nodeType == 1 && obj.id ? 'document.getElementById(' + strToSrc(obj.id) + ')' : '{}') : 'null'; } }, selWin = getSelWin(mainWin), win = selWin || mainWin, doc = win.document, loc = win.location, ele, pEle, clone, reUrl = /(url\(\x22)(.+?)(\x22\))/g; if (selWin) { var rng = win.getSelection().getRangeAt(0); pEle = rng.commonAncestorContainer; ele = rng.cloneContents(); } else { pEle = doc.documentElement; ele = (doc.body || doc.getElementsByTagName('body')[0]).cloneNode(true); }; while (pEle) { if (pEle.nodeType == 1) { clone = pEle.cloneNode(false); clone.appendChild(ele); ele = clone; }; pEle = pEle.parentNode }; var sel = doc.createElement('div'); sel.appendChild(ele); for (var el, all = sel.getElementsByTagName('*'), i = all.length; i--;) { el = all[i]; if (el.style && el.style.backgroundImage) el.style.backgroundImage = el.style.backgroundImage.replace(reUrl, function (a, prev, url, next) { if (!/^[a-z]+:/.test(url)) url = resolveURL(url, loc.href); return prev + encodeImg(url) + next; }); switch (el.nodeName.toLowerCase()) { case 'link': case 'style': case 'script': el.parentNode.removeChild(el); break; case 'a': case 'area': if (el.hasAttribute('href') && el.getAttribute('href').charAt(0) != '#') el.href = el.href; break; case 'img': case 'input': if (el.hasAttribute('src')) el.src = encodeImg(el.src, el); break; case 'audio': case 'video': case 'embed': case 'frame': case 'iframe': if (el.hasAttribute('src')) el.src = el.src; break; case 'object': if (el.hasAttribute('data')) el.data = el.data; break; case 'form': if (el.hasAttribute('action')) el.action = el.action; break; } }; var head = ele.insertBefore(doc.createElement('head'), ele.firstChild), meta = doc.createElement('meta'), sheets = doc.styleSheets; meta.httpEquiv = 'content-type'; meta.content = 'text/html; charset=utf-8'; head.appendChild(meta); var title = doc.getElementsByTagName('title')[0]; if (title) head.appendChild(title.cloneNode(true)); head.copyScript = function (unsafeWin) { if ('$' in unsafeWin) return; var f = doc.createElement('iframe'); f.src = 'about:blank'; f.setAttribute('style', 'position:fixed;left:0;top:0;visibility:hidden;width:0;height:0;'); doc.documentElement.appendChild(f); var str, script = doc.createElement('script'); script.type = 'text/javascript'; for (var name in unsafeWin) { if (name in f.contentWindow || !/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) continue; try { str = toSrc(unsafeWin[name]); if (!/\{\s*\[native code\]\s*\}/.test(str)) { script.appendChild(doc.createTextNode('var ' + name + ' = ' + str.replace(/<\/(script>)/ig, '<\\/$1') + ';\n')); } } catch (e) {}; }; f.parentNode.removeChild(f); if (script.childNodes.length) this.nextSibling.appendChild(script); }; head.copyScript(win.wrappedJSObject || win); head.copyStyle = function (s) { if (!s) return; var style = doc.createElement('style'); style.type = 'text/css'; if (s.media && s.media.mediaText) style.media = s.media.mediaText; try { for (var i = 0, rule; rule = s.cssRules[i]; i++) { if (rule.type != 3) { if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) { var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) { if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href); if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url); return prev + url + next; }); style.appendChild(doc.createTextNode(css + '\n')); } } else { this.copyStyle(rule.styleSheet);} } } catch(e) { if (s.ownerNode) style = s.ownerNode.cloneNode(false); }; this.appendChild(style); }; for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]); head.appendChild(doc.createTextNode('\n')); var doctype = '', dt = doc.doctype; if (dt && dt.name) { doctype += '<!DOCTYPE ' + dt.name; if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22'; if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22'; doctype += '>\n'; }; var onlyName = selWin ? win.getSelection().toString() : (title && title.text ? title.text : loc.pathname.split('/').pop()); return [doctype + sel.innerHTML +'\n<a href='+ (loc.protocol != 'data:' ? loc.href : 'data:uri') +'><small><blockquote>источник: '+ new Date().toLocaleString("ru") +'</blockquote></small></a>', onlyName, loc.hostname]; }
Отредактировано Dobrov (15-07-2023 18:36:11)
Отсутствует
Dumby - ещё нужна помощь!
хочу добавить в SystemGlobal вторую функцию, в ней нужны адрес и имя текущей вкладки.
gURLBar и gBrowser не работают, а win.location.hostname и doc.getElementsByTagName('title')[0] работают только в var htmlAndName = async mainWin => {
не знаю, как получить адрес и имя текущей вкладки без receiveMessage()
как в JSM-ке SingleHTMLChild получить адрес и имя текущей вкладки ?
Отсутствует
стоит 115.02
Нет такой версии.
Но есть 115.0.2 и на ней скрипт работает.
А вот в 116, да, отвалится:
Move handling of search engine one-off hidden from preferences into the search settings.
Можно будет так поправить
/* var pref = Services.prefs.getStringPref("browser.search.hiddenOneOffs"); var hiddenList = pref ? pref.split(",") : []; var engines = await Services.search.getVisibleEngines(); for (let engine of engines.filter(e => !hiddenList.includes(e.name))) { */ var engines = await Services.search.getVisibleEngines(); for(let engine of engines.filter(e => !e.hideOneOffButton)) {
/* async rebuild(menu) { var de = Services.search.defaultEngine; de = de.wrappedJSObject || de; this.setAttrs(menu, de, `Искать в ${de.name} или в ...`); menu.ePopup.textContent = ""; var pref = Services.prefs.getStringPref("browser.search.hiddenOneOffs"); var hiddenList = pref ? pref.split(",") : []; var engines = await Services.search.getVisibleEngines(); for (let engine of engines.filter(e => !hiddenList.includes(e.name))) { */ getEngines() { var args = "hideOneOffButton" in Services.search.defaultEngine ? [e => !e.hideOneOffButton] : Object.defineProperty( [function(e) {return !this.includes(e.name);}], "1", { get: () => Services.prefs.getStringPref(this.hide)?.split(",") || [] } ); return (this.getEngines = async () => (await Services.search.getVisibleEngines()).filter(...args) )(); }, async rebuild(menu) { var de = Services.search.defaultEngine; de = de.wrappedJSObject || de; this.setAttrs(menu, de, `Искать в ${de.name} или в ...`); menu.ePopup.textContent = ""; for(let engine of await this.getEngines()) {
gURLBar и gBrowser не работают
Что-то я не понимаю твоего затруднения.
gURLBar и gBrowser — это свойства окна браузера, а не свойства SystemGlobal.
Есть ссылка на окно — есть и его свойства,
через оператор доступа к свойству объекта «.» (точка),
то есть: окно.gURLBar и окно.gBrowser
У тебя же самого, например, написано win.Downloads и win.FileUtils
Эти, конечно, можно получить и импортом модулей, но зачем, когда они уже есть в окне.
И gBrowser в модуле используется, смотри первую строку в saveHTML()
Отсутствует
Что-то я не понимаю твоего затруднения.
Я тоже! Накосячил - разные функции с одним именем прописал в globalThis[Symbol.for(…
В итоге доработал 3 скрипта, в них сокращён код, используются 2 общие функции:
ucf_hookClicks.js ClickPicSave.jsm SingleHTMLChild.jsm
Ещё не получилось добавить setTimeout(… в скрипты scriptsbackground: [ // В фоне [System Principal]
Отредактировано Dobrov (16-07-2023 15:49:12)
Отсутствует