Stkvsky пишетПодскажите как поставить Custom Buttons на 781) В папку, куда установлен Firefox, скопируй одноимённую папку из данного архива. (Костыли для FF)2) ставь обычным способом расширение custom_buttons-0.0.7.0.0.17-fx-bootstrap.xpi
На 78.10.1 ESR portable не ставится.
Отредактировано foxboy (13-05-2021 12:37:24)
Отсутствует
На 78.10.1 ESR portable не ставится.
Win7
Отсутствует
Вопрос: как получить текст первого конкретного html-тэга текущей страницы? Так не работает: doc.getElementsByTagName("label")[0];
В коде, вместо статического path, определить геттер.
Расширение Text Linky Tool открывает страницу moz-extension://…/imglist.html, хочу доработать Сохранение картинки перетаскиванием,
чтобы создаваемое имя папки было осмысленным, а не moz-extension.
То есть, в код, где получаю Заголовок текущей вкладки, хочу добавить проверку, что это страница moz-extension:// и тогда брать заголовок из label-тэга текущей страницы.
<body> <label id="lblFrom">Custom Buttons | Форум Mozilla Россия(https://forum.mozilla-russia.org/viewtopic.php?id=9591&p=623/page/2)</label> <label>Images Viewer</label><span id="spnCount"> - 65 pics</span>
Да я понял уже, что вам такой вариант решения неинтересен, надоедать больше не буду.
Не в интересе дело, а в том, что расширение Image Picka не подгружает картинки, по которым не кликали, то есть оно бесполезно!
Отредактировано Dobrov (14-05-2021 02:51:24)
Отсутствует
Dumby
Посмотрите, пожалуйста, кнопкуSave, от 07.03.2017. .............
Идет неправильное сохранение через пункт "Сохранить всю страницу или выбранное как HTML"
Не сохраняются изображения и стили. При просмотре сохраненной страницы в автономном режиме(без инета) получается ерунда,
например здесь.
Отсутствует
voqabuhe
Кнопка с твоей ссылки точно также не сохраняет изображения и стили. При просмотре сохраненной страницы в автономном режиме(без инета) получается ерунда.
Твой код применяю для UCF.
Отсутствует
Кнопка с твоей ссылки точно также не сохраняет изображения и стили. При просмотре сохраненной страницы в автономном режиме(без инета) получается ерунда.
Твой код применяю для UCF.
вот кнопка SaveHTML от Dumby, с моими доработками. Данная ссылка с рецептами без интернета открывается нормально.
(async (id, func) => { // дополнительные клики на downloads-button для custom_script_win.js await window.delayedStartupPromise; var btn = document.getElementById("downloads-button"); if (!btn) return; btn.setAttribute("context", "event.stopPropagation()"); // откл контекстное меню btn.tooltipText = GetDynamicShortcutTooltipText(btn.id) +` ПКМ: Сохранить единый .html …Shift Обзор папки «Загрузки» Ролик: Сохранить как файл .txt всё | выделенный текст …Shift Сайт: графика Вкл/Выкл Alt⇧S нажать SingleSave`; // если такой кнопки нет, то выполнить save() var addDestructor = nextDestructor => { var {destructor} = ucf[id]; ucf[id].destructor = () => { try {destructor();} catch(ex) {Cu.reportError(ex);} nextDestructor(); } } var saveSelectionToTxt = async () => { // сохранить страницу или выделенный текст как файл .txt var splice = saveURL.length == 10; var msgName = id + ":Save:GetSelection"; var receiver = msg => { var title = document.title || gBrowser.selectedTab.label; var args = [ "data:text/plain," + encodeURIComponent(gBrowser.currentURI.spec + "\n\n" + msg.data), title.replace(/[:\\\/<>?*|"]+/g,'_').replace(/\s+/g,' ').slice(0, 100).trim() + '_' + new Date().toLocaleString('ru').replace(', ','-').replace(/:/g, '։') + '.txt', null, false, true, null, window.document ]; splice && args.splice(5, 0, null); saveURL(...args); } messageManager.addMessageListener(msgName, receiver); addDestructor(() => messageManager.removeMessageListener(msgName, receiver)); var func = fm => { var res, fed, win = {}; var fe = fm.getFocusedElementForWindow(content, true, win); var sel = (win = win.value).getSelection(); if (sel.isCollapsed) { var ed = fe && fe.editor; if (ed && ed instanceof Ci.nsIEditor) sel = ed.selection, fed = fe; } if (sel.isCollapsed) fed && fed.blur(), docShell.doCommand("cmd_selectAll"), res = win.getSelection().toString(), docShell.doCommand("cmd_selectNone"), fed && fed.focus(); res = res || sel.toString(); /\S/.test(res) && sendAsyncMessage("saveSelectionToTxt", res); } var url = "data:;charset=utf-8," + encodeURIComponent(`(${func})`.replace("saveSelectionToTxt", msgName)) + '(Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager));'; (saveSelectionToTxt = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))(); } // end var save = async () => { // автор: Лекс, правка: Dumby, Dobrov var msgName = id + "ucfDwnldsBtnSaveSnapshotToHTML"; if (typeof IOUtils != "object") { // Firefox 78 ESR var {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); var PathUtils = {join: (...args) => OS.Path.join(...args)}; var IOUtils = {writeUTF8: (path, txt) => OS.File.writeAtomic(path, new TextEncoder().encode(txt))}; } var write = IOUtils.writeUTF8 ? "writeUTF8" : "writeAtomicUTF8"; var Title = function (type) { // получить заголовок (без обрезки, если type не указан) или домен (type <0) var title = (document.title || gBrowser.selectedTab.label); if ( !type ) return title; // заголовок if ( type > 0 ) return title.substr(0, type).trim(); // ограничить длину имени var host = (/^file:\/\//.test(gURLBar.value)) ? '' : gURLBar.value.replace(/^.*url=/,'').replace(/^https?:\/\//,'').replace(/\/.*/,''); return host.replace(/^www\./,'').replace(/^ru\./,'').replace(/^m\./,'').replace(/^forum\./,'').replace(/^club\.dns/,'dns'); } var FatMs = (str) => {return str.replace(/[:\\\/<>?*|"'`]+/g,'').replace(/\s+/g,' ').replace(/ /g,' ');} var msgListener = async msg => { var [fileContent, fileName] = msg.data; var savedir = PathUtils.join(await Downloads.getPreferredDownloadsDirectory(), "_Web", FatMs(Title(-1))); // каталог Загрузки + домен var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); file.initWithPath(savedir); if ( !file.exists() || !file.isDirectory() ) file.create(Ci.nsIFile.DIRECTORY_TYPE, 0777); // создать папку, если не существует… var path = PathUtils.join(savedir, FatMs(fileName)); await IOUtils[write](path, fileContent); var d = await Downloads.createDownload({ source: "about:blank", target: FileUtils.File(path)}); (await Downloads.getList(Downloads.ALL)).add(d); d.refresh(d.succeeded = true); // кнопка Загрузки мигает } messageManager.addMessageListener(msgName, msgListener); addDestructor(() => messageManager.removeMessageListener(msgName, msgListener)); var svc = 'globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services'; var url = "data:;charset=utf8," + encodeURIComponent(`(${func})(${svc});`.replace("%MSG_NAME%", msgName)); (save = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))(); } // end save var listener = e => { // Clicks var trg = e.target, {prefs} = Services; if (e.button == 1) { if (e.shiftKey) { // СКМ + Shift if ( prefs.getIntPref("permissions.default.image", 1) == 1) prefs.setIntPref("permissions.default.image", 2), trg.style.filter = "hue-rotate(180deg) brightness(95%)" else prefs.setIntPref("permissions.default.image", 1), trg.style.filter = ""; BrowserReload(); } else // СКМ Click saveSelectionToTxt(); // сохранить .txt } else if (e.button == 2) { if (e.shiftKey) Downloads.getSystemDownloadsDirectory().then(path => FileUtils.File(path).launch(), Cu.reportError) // Обзор папки «Загрузки» else // ПКМ Click save(); // Single HTML } } var keydown_win = e => { // нажатие клавиш if (!(e.keyCode == 83 && e.shiftKey && e.altKey)) return; var singlesave = document.getElementById("_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action"); // SingleSave singlesave ? singlesave.click() : save(); // имитировать клик по кнопке, используя её ID } btn.addEventListener("click", listener); window.addEventListener("keydown", keydown_win); var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win; ucf[id] = {destructor() { btn.removeEventListener("click", listener); window.removeEventListener("keydown", keydown_win); }}; ucf.unloadlisteners.push(id); })("downloads-button-click-listener", ({io, focus}) => { 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 mainWin = {}; focus.getFocusedElementForWindow(content, true, mainWin); mainWin = mainWin.value; 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).trim(); fileName += "_" + new Date().toLocaleString("ru").replace(", ","-").replace(/:/g, "։"); if (!/\.html?$/.test(fileName)) fileName += '.html'; sendAsyncMessage("%MSG_NAME%", [doctype + sel.innerHTML +'\n<a href='+ (loc.protocol != 'data:' ? loc.href : 'data:uri') +'><small><blockquote>источник: '+ new Date().toLocaleString("ru") +'</blockquote></small></a>', fileName]); }); // END hookClicks
Отсутствует
Dumby - есть два кода, показывающих при наведении на Звёздочку адрес закладки или последнюю папку, куда добавлялась закладка.
Первый работает в custom_script_win.js , а Второй почему-то только в кнопке CustomButton.
Нужно устранить три недостатка либо первого либо второго скрипта (ещё второй не работает в custom_script_win.js):
1) Оба скрипта зачем-то удаляют стандартную подсказку Звёздочки: у меня это «Добавить страницу в Закладки (⌘D)».
2) Нет строки "Недавняя папка\n:" перед текстом последней папки, куда добавлялась закладка [как в этом же коде "Адрес закладки:\n"]. Я не смог найти строку кода, где нужно добавить этот текст!
3) нет обработки кликов Звёздочки, я их добавил в более старый вариант, но у него нет "Недавней папки":
try {((bu, bm, {star} = bu) => { // показать расположение закладки в Избранном. Клики на Звёздочке: var listener = { // СКМ: Вернуть вкладку, СКМ+Alt страница about:newtab, СКМ+Shift google.ru async handleEvent() { var result = []; await this.fetch(); for(var guid of this.guids) { var arr = []; while(true) { if (!this.hover) return; var res = await bm.fetch(guid); if ((guid = res.parentGuid) == bm.rootGuid) { arr.unshift(bm.getLocalizedTitle(res)); break; } arr.unshift(res.title || "[Безымянная папка]"); } result.push(arr.join("\\")); } this.hover && this.setTooltip(result); }, get fetch() { var set = this.guids = new Set(); var args = [b => set.add(b.parentGuid), {concurrent: true}]; delete this.fetch; return this.fetch = () => set.clear() || bm.fetch({url: gBrowser.currentURI.spec}, ...args); }, setTooltip(arr) { var m = arr.length > 1; var help = '\nРолик: Вернуть вкладку \n…+Alt Быстрый доступ\n…+Shift поиск в Google', text = `Адрес${m ? "а" : ""} заклад${m ? "ок" : "ки"}:\n${arr.join("\n")}\n`+ help; if (bu._itemGuids.size) star.tooltipText = "\u3164" else text = star.tooltipText + help; if (/Ролик/.test(star.tooltipText)) return; document.tooltipNode == star ? this.tt.label = text : star.tooltipText = text; }, get tt() { var list = InspectorUtils.getChildrenForNode(document.documentElement, true); delete this.tt; return this.tt = list.item(list.length - 1); }, get hover() {return star.matches(":hover");} }, loadURI_ex = (url, newtab) => { newtab = newtab || false; // параметры по-умолчанию if (newtab) switchToTabHavingURI(url, true, {relatedToCurrent: true, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()}) else gBrowser.loadURI(url, {triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()}); }, clicks = e => { if (e.button != 1) return; // CKM Click if (e.shiftKey) loadURI_ex('https://www.google.ru', true) else if (e.altKey) loadURI_ex('about:newtab') else document.defaultView.undoCloseTab(); }; star.addEventListener("mouseenter", listener); star.addEventListener("click", clicks); addEventListener("unload", () => { star.removeEventListener("mouseenter", listener); star.removeEventListener("click", clicks) } , {once: true}); })(BookmarkingUI, PlacesUtils.bookmarks);} catch(ex) {Cu.reportError(ex);}
Отсутствует
вот кнопка SaveHTML от Dumby, с моими доработками
Что-то у меня ничего не получилось с этим кодом. Создал файл SaveHTML.js, прописал его в загрузчик custom_script_win.js.
Никаких кнопок, меню ни где не появилось, в коде написано дополнительные клики на downloads-button для custom_script_win.js. А что это такое downloads-button ? у меня вроде нигде нет такого.
Отсутствует
rubel это стандартная кнопка «Загрузки», всё и так ясно по названию downloads-button.
Alt+Shift+S для сохранения страницы или жми на «Загрузки» правой кнопкой мыши, включив постоянный показ:
Персонализация > Правый клик на кнопке «Загрузки» > Снять флажок: Автоматически скрывать на панели инструментов.
Отсутствует
Dobrov
ОК. Спасибо, все работает и сохраняет как надо ! Но вот путь сохранения для меня не удобен, да еще и по домену.
У меня все сохраняется в "D:\Downloads" вот нужно и прописать в ваш скрипт этот путь. Как правильно прописать ?
И еще бы сделать при сохранение открытие диалогового окна, чтобы корректировать имя файла.
Отредактировано rubel (16-05-2021 07:32:26)
Отсутствует
rubel - строка 82:
var savedir = PathUtils.join(await Downloads.getPreferredDownloadsDirectory(), "_Web", FatMs(Title(-1))); // каталог Загрузки + домен
Отсутствует
Dobrov
Исправил -- var savedir = PathUtils.join(await Downloads.getPreferredDownloadsDirectory(), );
Теперь сохраняет просто в "D:\Downloads" . Но вот с именами файлов беда. Например вот с этой страницы сохраняет название файла:
Mozilla Firefox 87.0 08.02.2021 _ Cento8 Название программы_ Firefox Версия программы_ 87.0 Разработ_16.05.2021-09։41։18 Чушь какая-то. Как сделать чтоб было нормально, с выбором названия файла ?
Отсутствует
Как сделать чтоб было нормально, с выбором названия файла ?
Удобство этого скрипта именно в том, что нет навязчивого запроса имени файла! Имя файла равно заголовку вкладки, это задано в последних строках.
Что-то ты не так исправил, у меня с этой ссылки сохраняет как: Mozilla Firefox 87.0 _ effect ∞_16.05.2021-14։42։47.html
Отсутствует
Удобство этого скрипта именно в том, что нет навязчивого запроса имени файла!
Ну кому как, а мне удобно присваивать имена файлов как я хочу.... Все равно спасибо.
Уважаемые гуру Dobrov Andrey_Krropotkin Dumby Vitaliy V.
сделайте, пожалуйста, кнопку Save snapshot to html для UCF.
Отсутствует
Dumby
Как бы на "отмена" код SidebarUI.hide(); сработал ?
/*Initialization Code*/ this.onclick = this.oncontextmenu = function(event) { if (event.button == 1) { SidebarUI.toggle('viewHistorySidebar'); if (custombuttons.confirmBox(null, "Вниманиее ! Очистка Истории!", "Да", "Отмена") ) { PlacesUtils.history.clear(); SidebarUI.hide(); } } if(event.button == 0 && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey){ SidebarUI.toggle('viewHistorySidebar'); } if(event.button == 2 && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey){ Sanitizer.showUI(window); CustomizableUI.setToolbarVisibility("PersonalToolbar", document.querySelector("#PersonalToolbar").closed); var s = "browser.zoom.full"; cbu.setPrefs(s, cbu.getPrefs(s) == true ? true : true); var s = "intl.accept_languages"; cbu.setPrefs(s, cbu.getPrefs(s) == "ru" ? "ru": "ru"); var s = "media.autoplay.default"; cbu.setPrefs(s, cbu.getPrefs(s) == 5 ? 5: 5); SidebarUI.hide(); var s = "extensions.long_left_click.timeContent"; cbu.setPrefs(s, cbu.getPrefs(s) == 350 ? 350: 350); document.querySelector( "#mainPopupSet > tooltip[onpopupshowing*=undoCloseTabsList]" )?.undoCloseTabsList.updUI(); } }; this.oncontextmenu =e=> { e.button && !e.ctrlKey && e.preventDefault() }; this.tooltipText = "ЛКМ: Боковая история\nСКМ: Очистка Истории \nПКМ: Окно очистки всего";
Отсутствует
и тогда брать заголовок из label-тэга текущей страницы
Жаль, что слова «в другом процессе» — пустой звук.
Если title страницы Text Linky Tool не ценность, то можно так попробовать
/* this.drag("add"); }, */ this.drag("add"), this.checkTLT(); }, checkTLT() { var tltHost = WebExtensionPolicy.getByID( "{3efee51a-7d3b-4412-a889-addc6ff6276b}" )?.mozExtensionHostname; tltHost && (this.checkTLT = () => gBrowser.selectedTab.label.startsWith(tltHost) && gBrowser.selectedBrowser.messageManager.loadFrameScript(this.tltFs, false) )(); }, get tltFs() { delete this.tltFs; return this.tltFs = "data:;charset=utf-8,(" + encodeURIComponent(doc => { var tc = doc.getElementById("lblFrom").textContent; doc.title = tc.slice(0, tc.lastIndexOf("(")); }) + ")(content.document)"; },
Первый работает в custom_script_win.js , а Второй почему-то только в кнопке CustomButton.
Нужно устранить три недостатка
Потому что первый сделан под ucf, а второй под CB.
И не «устранить три недостатка», а «добавить три хотелки».
(async (id, sel) => { var g = Cu.getGlobalForObject(Cu), stt = g[id]; if (!stt) { var {obs, prefs} = Services, {bookmarks: bm, observers: pobs} = PlacesUtils; stt = g[id] = { bm, pref: `ucf.${id}Guid`, events: ["bookmark-added"], async init() { this.handleEvent = e => this[e.type](e); if ((this.pbm = typeof PlacesBookmarkMoved == "function")) this.events.push("bookmark-moved"); else this.QueryInterface = g.ChromeUtils.generateQI([Ci.nsINavBookmarkObserver]), bm.addObserver(this); pobs.addListener(this.events, this.added = events => { for(var e of events) e.isTagging || this[e.constructor.name](e); }); obs.addObserver(this, "quit-application-granted"); this.args = [b => this.bguids.add(b.parentGuid), {concurrent: true}]; var guid = prefs.getStringPref(this.pref, ""); if (!guid) try {var [guid] = await PlacesUtils.metadata.get( PlacesUIUtils.LAST_USED_FOLDERS_META_KEY, [] )} catch {} this.guids.push(guid || await PlacesUIUtils.defaultParentGuid || bm.unfiledGuid); }, observe() { this.pbm || bm.removeObserver(this); pobs.removeListener(this.events, this.added); obs.removeObserver(this, "quit-application-granted"); prefs.setStringPref(this.pref, this.guids[0]); }, skipTags: true, bguids: new g.Set(), guids: new g.Array(), PlacesBookmarkAddition(e) { if (e.itemType == bm.TYPE_BOOKMARK && e.source == bm.SOURCES.DEFAULT) this.guids[0] = e.parentGuid; }, PlacesBookmarkMoved(e) { e.parentGuid != e.oldParentGuid && this.PlacesBookmarkAddition(e); }, onItemMoved(a, b, c, d, e, itemType, f, oldParentGuid, parentGuid, source) { this.PlacesBookmarkMoved({itemType, source, oldParentGuid, parentGuid}); }, fetch(win) { this.bguids.clear(); return bm.fetch({url: win.gBrowser.currentURI.spec}, ...this.args); }, tt(win) { var list = win.InspectorUtils .getChildrenForNode(win.document.documentElement, true); return list.item(list.length - 1); }, find: obj => obj.name == "tooltiptext", opts: { relatedToCurrent: true, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal() }, loadURI_ex(win, url, newtab) {newtab ? win.switchToTabHavingURI(url, true, this.opts) : win.gBrowser.loadURI(url, this.opts); }, auxclick(e) { if (e.button != 1) return; var win = e.view; if (e.shiftKey) this.loadURI_ex(win, "https://www.google.ru", true); else if (e.altKey) this.loadURI_ex(win, "about:newtab"); else win.undoCloseTab(); } }; var ps = ["onBeginUpdateBatch", "onEndUpdateBatch", "onItemChanged", "onItemVisited"]; var noop = () => {}; for(var p of ps) stt[p] = noop; stt.init(); var func = id => this[id].mouseenter = async function(e) { var win = e.view; var star = e.target; star.tooltipText = "\u3164"; var starred = win.BookmarkingUI.status == win.BookmarkingUI.STATUS_STARRED; starred && await this.fetch(win); var result = []; for(var guid of (starred ? this.bguids : this.guids)) { var arr = [], num = 50; while(--num) { if (!star.matches(":hover")) return; var res = await this.bm.fetch(guid); if (!res) break; if ((guid = res.parentGuid) == this.bm.rootGuid) { arr.unshift(this.bm.getLocalizedTitle(res)); break; } arr.unshift(res.title || "[Безымянная папка]"); } arr.length && result.push(arr.join("\\")); } if (!star.matches(":hover")) return; var text = (await win.document.l10n.formatMessages([{ id: star.getAttribute("data-l10n-id"), args: JSON.parse(star.getAttribute("data-l10n-args")) }]))[0].attributes.find(this.find).value; if (result.length) { var txt = result.join("\n"); if (starred) { var m = result.length > 1; txt = `Адрес${m ? "а" : ""} заклад${m ? "ок" : "ки"}:\n${txt}`; } else txt = "Недавняя папка:\n" + txt; text += "\n\n" + txt; } win.document.tooltipNode == star ? this.tt(win).label = text : star.tooltipText = text; } var url = "data:;charset=utf-8," + encodeURIComponent(`(${func})("${id}")`); g.ChromeUtils.compileScript(url).then(ps => ps.executeInGlobal(g)); } await delayedStartupPromise; var stars = Array.from(document.querySelectorAll(sel)); for(var star of stars) star.addEventListener("auxclick", stt), star.addEventListener("mouseenter", stt); var destructor = () => { for(var star of stars) star.removeEventListener("auxclick", stt), star.removeEventListener("mouseenter", stt); } var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win; if (ucf) ucf[id] = {destructor}, ucf.unloadlisteners.push(id); else window.addEventListener("unload", destructor, {once: true}); })("ucfBookmarksStarFTooltipHelper", ":is(#star-button, #star-button-box)[role], #context-bookmarkpage");
сделайте, пожалуйста, кнопку Save snapshot to html для UCF.
Попробую JSM'кой. Создать AppMenuTbbSaveHTMLChild.jsm
и подключть в custom_script.js (путь свой).
(async url => ChromeUtils.import(url))( "chrome://user_chrome_files/content/custom_scripts/Actors/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.className = "subviewbutton subviewbutton-iconic"; btn.setAttribute("label", "Сохранить страницу или выбранное как HTML"); btn.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACzElEQVQ4jV2STW8bZRDHf/Psrr11nZhgVKcKaSmUiArRKBRVIMgH4BKJ7xAp5MSFiA+Rc28ckBAoipC4koJQLyAaVFChIlQllDRWmjRev8Qvu14/+wwHx6ZlpNFcZn7zn79GVJW1tbXc6urqijHGqKoAPF3TgcVaq8owXJbphx99fOOnWzcHoqqsr68/t7y83BARVBXnHHraXo3a3HoUU8gFAHRTS2Bg/7C2Zx7vXPIBwjA0p3BU9Zns9i3vvVrhr6MWzlpee+EsRqAbHc3+/Pee7wPkcrkx4P+g0IMvb/5Iv5/iXEaWZQS+By578MaVy9YH8H3fE5FnANZajqMmgcAnH7yN73mICMYMd21sbLy7srKiPkA+n3/qBLhzv8p+EuOfTUjShPbODvOVWa5fnRsvKBaLAcAIMFbw+bc/EBVn8At7SPcQ60LSiVm++P0fGu0e7y++yalvHoABCILAiAj7hzU+vfcVT6zPVGmR3x4/xJoLSH6BVu4cN777nnQwQETI5XL/AYwxRkS4ff8BEk6Q2pBfq3dxUuHMmWt0kgFGStTDY/7YrTLybQwYPU2cpgzsCd1OgmSzWHeOR7VjWicxaT9lxn+HfjoYmWnGHgAiIsydf5HKnUXiThehQDG4Tr3e5KR7hN8XilnGKxfOoyrDgZECwIgIb125xIxxTGVdgjRG4pR2+zbG/sIkD7l2cYJyaYLMOZxzjBV4nueLCI1GnaWFab65t4OXt4gUuFqYJ8gGuPYBCxdLHNciys9PkaapjAHGGM8YQ7lcZv71OaYmC/xZPaJHTN4cUgpDXrr8MtOVaUqTRXzfY3t7u7O0tDR82a2trfkkSTSOY+31etrpdLTZbGoURRpFkdbrTY3qTW00mhrHse7u7t4tl8uhqg4VxHHcPDg4+ExVHeBU1YmIU1WnisucZtamLszn01ar9WRzc/PrWq2WAPwLJ7l2ULfXOAMAAAAASUVORK5CYII="); btn.setAttribute("oncommand", "saveHTML();"); btn.saveHTML = this.saveHTML; popup.querySelector('toolbarbutton[id^="appMenu-print-button"]').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 {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); var IOUtils = {writeUTF8: (path, txt) => OS.File.writeAtomic(path, new TextEncoder().encode(txt))}; } (this.write = IOUtils.writeUTF8 || IOUtils.writeAtomicUTF8)(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]; }
Как бы на "отмена" код SidebarUI.hide(); сработал ?
Скобку «}», которая идёт после SidebarUI.hide();
переставить так, чтобы она шла перед SidebarUI.hide();
Отредактировано Dumby (23-05-2021 17:53:01)
Отсутствует
Dumby Спасибо! Скрипты для Звёздочки и Загрузки картинки отличные! (я лишь добавил обрезку имён вкладок)
Ещё просьба [финальная ]: скрипт Загрузки картинки перетаскивание вправо с изменениями не всегда может сохранить картинку.
Некоторые изображения нельзя тащить, например Cover Гости из прошлого и там же фотки актрис.
Убрал стилем мешающий сохранению div на данном сайте, клик по обложке откроет Слайд-шоу на всё окно, но перетаскивание на картинке не работает.
Dumby - нельзя ли в скрипт "Сохранить картинку перетаскиванием" добавить ещё сохранение картинки по событию двойной click или click+Ctrl или клик колёсиком мыши (это в строке events: ["dragover", "drop", "dragend"],) ???
А лучше сделать отдельный скрипт, который может по кликам сохранить картинку или скрытую некликабельную картинку, которая под курсором.
@-moz-document domain(doramatv.live), domain(mose.live) { /* позволяет сохранять картинки */ .fotorama__fullscreen-icon { max-height: 300px !important; max-width: 300px !important;} }
Все сделал по вашей методе, но меню не появилось.
AppMenuTbbSaveHTMLChild.jsm - Всё работает, строка "Сохранить страницу или выбранное как HTML" есть в меню, которое на кнопке Firefox.
Отредактировано Dobrov (17-05-2021 08:13:59)
Отсутствует
Dobrov, Dumby
Помогите, пожалуйста.
Вот мои действия:
1.Создаю файл AppMenuTbbSaveHTMLChild.jsm
2.помещаю его в папку custom_scripts
3.в файл custom_script.js в самый верх добавляю
(async url => ChromeUtils.import(url))( "chrome://user_chrome_files/content/custom_scripts/AppMenuTbbSaveHTMLChild.jsm" );
Получается вот так:
(async url => ChromeUtils.import(url))( "chrome://user_chrome_files/content/custom_scripts/AppMenuTbbSaveHTMLChild.jsm" ); (() => { var loadscript = name => { try { Services.scriptloader.loadSubScript(`chrome://user_chrome_files/content/custom_scripts/${name}`, globalThis, "UTF-8"); } catch(e) {} }; loadscript("cs/Icons in Sidebar.js"); loadscript("cs/extension_manager_button.js"); loadscript("cs/closeothertabs.uc.js"); loadscript("cs/BBCode-Multi.js"); loadscript("cs/undo_tab.js"); loadscript("cs/download_and_switch_proxy_buttons.js"); loadscript("cs/Ram.js"); loadscript("cs/Nightly.js"); // и т. д. })();
Удаляю полностью папку startupCache, запускаю браузер и ничего не появилось в меню, которое на кнопке Firefox.
Что у меня не так ?
Отредактировано rubel (17-05-2021 13:41:10)
Отсутствует