Dumby спасибо!
ещё проблемку со скриптом ClickPicSave.jsm не смог исправить…
Сохраняет только в папку Загрузки по-умолчанию, хотя в настройках выбран другой путь, который запоминается в data["browser.download.dir"].set
// by Dumby сохранить картинку колёсиком или перетащив вправо; DBL поиск похожих export {MouseImgSaverChild, MouseImgSaverParent}; // forum.mozilla-russia.org/viewtopic.php?pid=800469#p800469 var u = {get it() { delete this.it; return this.it = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools); }}; ["E10SUtils", "PrivateBrowsingUtils"].forEach(name => Object.defineProperty(u, name, { configurable: true, enumerable: true, get() { var url = `resource://gre/modules/${name}.`; try {var exp = ChromeUtils.importESModule(url + "sys.mjs");} catch {exp = ChromeUtils.import(url + "jsm");} delete this[name]; return this[name] = exp[name]; } })); class MouseImgSaverChild extends JSWindowActorChild { handleEvent(e) { //клики мыши if (e.button > 1) return; //ЛКМ+СКМ var trg = e.explicitOriginalTarget; // dragstart trg.nodeType == Node.ELEMENT_NODE && trg instanceof Ci.nsIImageLoadingContent && this[e.type](trg, e); } handleDragEvent(e) { this[e.type](e); } dragstart(trg, e) { this.trg = trg; this.x = e.screenX; this.y = e.screenY; this.drag("add"); this.handleEvent = this.handleDragEvent; this.checkTextLinkyTool(trg.ownerDocument); } events = ["dragover", "drop", "dragend"]; drag(meth = (delete this.handleEvent, delete this.trg, "remove")) { meth += "EventListener"; var win = this.contentWindow; for(var type of this.events) win[meth](type, this, true); } drop() { this.drag(); } dragover(e) { var {x, y} = this, cx = e.screenX, cy = e.screenY, dx = cx - x, ax = Math.abs(dx), ay = Math.abs(cy - y); if (ax < 10 && ay < 10) return; if (dx < 0 || ax < ay) return this.drag(); this.x = cx; this.y = cy; } dragend(e) { // перетаскивание рисунка var dt = e.dataTransfer, {trg} = this; this.drag(); dt.mozUserCancelled || this.send(trg, e.screenX); // сохранить // dt.mozUserCancelled || this.sendAsyncMessage("dragend", (trg.currentRequestFinalURI || uri).spec); } auxclick(trg) { //СКМ trg.matches(":any-link :scope") || this.send(trg); } dblclick(trg) { // ЛКМ trg.matches(":any-link :scope") || this.sendAsyncMessage("dblclick", (trg.currentRequestFinalURI || uri).spec); } send(trg, sx) { var uri = trg.currentURI; if (!uri) return; var doc = trg.ownerDocument; var cookieJarSettings = u.E10SUtils .serializeCookieJarSettings(doc.cookieJarSettings); var referrerInfo = Cc["@mozilla.org/referrer-info;1"] .createInstance(Ci.nsIReferrerInfo); referrerInfo.initWithElement(trg); referrerInfo = u.E10SUtils.serializeReferrerInfo(referrerInfo); var contentType = null, contentDisposition = null; try { var props = u.it.getImgCacheForDocument(doc).findEntryProperties(uri, doc); var cs = Ci.nsISupportsCString; try {contentType = props.get("type", cs).data;} catch {} try {contentDisposition = props.get("content-disposition", cs).data;} catch {} } catch {} this.sendAsyncMessage("", { title: trg.closest("[title]")?.title, url: (trg.currentRequestFinalURI || uri).spec, contentType, referrerInfo, cookieJarSettings, contentDisposition, sx, isPrivate: u.PrivateBrowsingUtils.isContentWindowPrivate(trg.ownerGlobal) }); } checkTextLinkyTool(doc) { if (doc.title || !doc.documentURI.startsWith("moz-extension:")) return; var lab = doc.querySelector("body > label#lblFrom:first-child")?.textContent; if (lab) doc.title = lab.slice(0, lab.lastIndexOf("(")); } } if (!ChromeUtils.domProcessChild.childID) { var esModuleURI = Components.stack.filename; ChromeUtils.registerWindowActor("MouseImgSaver", { allFrames: true, parent: {esModuleURI}, messageManagerGroups: ["browsers"], child: {esModuleURI, events: {auxclick: {capture: true}, dblclick: {capture: true}, dragstart: {capture: true}}} }); var wref, titles = Object.create(null); var data = Object.assign(Object.create(null), { "browser.download.dir": {type: "String", get set() { var win = wref.get(), {prefs, dirsvc} = win.Services var {DownloadPaths, FileUtils} = win; var map = val => DownloadPaths.sanitize(val); win.Downloads.getList(win.Downloads.ALL).then(list => list.addView({ onDownloadChanged(download) { if (!download.stopped) return; var {url} = download.source, title = titles[url]; if (!title) return; delete titles[url]; if (!download.succeeded) return; var file = FileUtils.File(download.target.path), {leafName} = file; var ext = leafName.slice(leafName.lastIndexOf(".")); var newName = map(title) + ext, {parent} = file; var newFile = parent.clone(); newFile.append(newName); try { newFile.createUnique(file.NORMAL_FILE_TYPE, file.permissions); file.renameTo(parent, newFile.leafName); download.target.path = newFile.path; download.refresh(); } catch {} } })); Object.defineProperty(this, "set", {get() { try {var dir = prefs.getComplexValue("browser.download.dir", Ci.nsIFile);} catch {var dir = dirsvc.get("DfltDwnld", Ci.nsIFile);} var arr = prefs.getStringPref("extensions.user_chrome_files.savedirs", "_Web||_Pics|0").split('|').slice(2, 4); // подпапки в [Загрузках]: нет | папка графики | имя вкладки | домен arr[1] = (arr[1]) ? wref.get().gBrowser.selectedTab.label.slice(0, 64) .replace(/\s+/g,' ').replace(/:/g,'։').replace(/[|<>]+/g,'_').replace(/([\\\/?*\"'`]+| ։։ .*)/g,'').trim() : ""; arr.map(map).forEach(dir.append); try {dir.exists() && dir.isDirectory() || dir.create(dir.DIRECTORY_TYPE, 0o777);} catch{console.error(dir.path)} return dir.path; }}); return this.set; }}, "browser.download.folderList": {type: "Int", set: 2}, "browser.download.useDownloadDir": {type: "Bool", set: true} }); var MouseImgSaverParent = class extends JSWindowActorParent { receiveMessage(msg) { var win = msg.target.browsingContext.topChromeWindow, {name} = msg; if (name) return this[name](win, msg.data); var {url, contentType, contentDisposition, sx, title, isPrivate, referrerInfo, cookieJarSettings} = msg.data; if (sx && sx > win.mozInnerScreenX + win.innerWidth) return; if (title) titles[url] = title; wref = Cu.getWeakReference(win); var p = win.Services.prefs; for(var pref in data) { var obj = data[pref], meth = `et${obj.type}Pref`; obj.val = p.prefHasUserValue(pref) ? p["g" + meth](pref) : null; p["s" + meth](pref, obj.set); } try { var args = [url, null, // document null, // file name contentDisposition, contentType, false, // no cache null, // filepicker title key null, // chosen data u.E10SUtils.deserializeReferrerInfo(referrerInfo), u.E10SUtils.deserializeCookieJarSettings(cookieJarSettings), win.document, // initiating doc true, // skip prompt for where to save null, // cache key isPrivate, win.document.nodePrincipal], {length} = win.internalSave, lfix = length >15; lfix && args.splice(1, 0, null); //FIX FF113+ win.internalSave(...args); } finally { for(var pref in data) data[pref].val === null ? p.clearUserPref(pref) : p[`set${data[pref].type}Pref`](pref, data[pref].val); } } dblclick(win, imgURL) { var gb = win.gBrowser, index = gb.selectedTab._tPos + 1; gb.selectedTab = gb.addTrustedTab('https://yandex.ru/images/search?rpt=imageview&url=' + imgURL, {index}); } } }
Отсутствует
Сохраняет только в папку Загрузки по-умолчанию, хотя в настройках выбран другой путь
Попробовал (на 124) воспроизвести — не получилось.
который запоминается в data["browser.download.dir"].set
В data["browser.download.dir"].set ничего не запоминается.
Это геттер, который каждый раз вычисляет путь заново.
Отсутствует
Попробовал (на 124) воспроизвести — не получилось.
Отбой, картинка запишется в путь Загрузок по-умолчанию, если запись в другую папку не удалась, например, прав на запись не хватило.
Отсутствует
Оптимизировал скрипты ucf_hookClicks SingleHTML.mjs ClickPicSave.mjs в части глобальных функций.
Клики мыши работают на кнопке "Новая вкладка" и пустой панели (Закрыть вкладки слева/справа от активной), при ошибках сохранения страниц/картинок urlbar мигает красным.
В меню пользователя (правый клик на кнопке Дополнения) «Заметки» запускает свой софт для каждой системы (для Linux не вписал, т.к. нет стандарта да и пользователей только 2%)
Отсутствует
Dumby – исчезающая панель не пашет в UCF scriptsbackground [System Principal] (custom_script.js)
но код без win. работает нормально в режиме scriptschrome: document [ChromeOnly]
// ChromeUtils.domProcessChild.childID || ({………………………… getwin(){ //self = Services.obs.addObserver(self = this, topic); //в custom_script.js return this.ownerGlobal || Services.wm.getMostRecentWindow("navigator:browser"); }, ask(head, run, info = "", sec = 3, x, y = 58, win = self.getwin()){ // x < 0 отсчёт смещения справа var doc = win.document, wary = doc.createXULElement("panel"), popupset = doc.getElementById("mainPopupSet"); wary.setAttribute("onpopupshown", "move()"); wary.setAttribute("onpopuphidden", "this.remove()"); var div = wary.appendChild(doc.createElement("div")); var header = div.appendChild(doc.createElement("div")).appendChild(new Text()); var txt = div.appendChild(header.parentNode.cloneNode(true)); var s = run ? [250, 20, 8] : [0, 14, 5]; //без команды вывод сведений: аналог tooltip wary.style.cssText = `filter: sepia(100%) hue-rotate(${s[0]}deg)`; div.style.cssText = `font-size: ${s[1]}px; ${run ? "font-weight: bold;" : ""} margin: 0.${s[2]}em; max-width: 680px; white-space: pre-wrap`; txt.style.cssText = `font-size: 14px; font-style: italic; margin-top: ${info.length > 0 ? "1" : "0"}em`; txt = txt.firstChild; wary.move = (pr = wary.getOuterScreenRect(), x = -win.outerWidth) => { if (x < 0) x = Math.abs(x) - pr.width; wary.moveTo(pr.x + x, pr.y + y); wary.style.opacity = "1"; } header.data = head, txt.data = info, wary.style.opacity = "0"; wary.onclick =()=>{ run(); wary.hidePopup(); }; popupset.append(wary); wary.openPopup(); win.setTimeout(() => { wary.hidePopup(); wary.onclick = null; }, (sec + (head + info).length*0.04)*1000); // время показа зависит от кол-ва букв }
Отредактировано Dobrov (06-04-2024 03:52:52)
Отсутствует
Ошибка на строке: var header = div.appendChild(doc.createElement("div")).appendChild(new Text());
new win.Text()
Но, если панель создаётся каждый раз новая,
то иметь ссылки на текстовые ноды большого смысла нет.
То есть, можно создать header просто как div, и написать header.append(head);
Отсутствует
Dumby =>
Я переделал код, но не получается вставить второй блок текста с другим стилем.
второй текст получается сразу слитно за первым, с тем же размером шрифта и без переноса…
var header = wary.appendChild(document.createElement("div")); header.append(head); var txt = header.appendChild(new Text());
Отредактировано Dobrov (06-04-2024 08:33:52)
Отсутствует
второй текст получается сразу слитно за первым, с тем же размером шрифта и без переноса…
Ну, переносу-то с чего не работать, должен работать.
А то, что с тем же размером шрифта — так ничего удивительного.
Ты в элемент header добавил вторую текстовую ноду,
откуда для неё другой размер шрифта возьмётся?
Это вот header ещё можно не создавать, а просто написать div.append(head);
Но txt должен быть элементом, чтобы на него другой стиль прицепить.
Отсутствует
Dumby спасибо, сделал! Вот ещё хотелка для любителей ярлыков любых прог:
В кнопке «Меню пользователя» создавать последний пункт меню из опции, загружаемой из about:config.
т.е. для последней строки должно быть изменяемое свойство объекта, которое можно править каким либо образом.
Нужно по правому клику открыть диалог правки последней строки меню с её свойствами – т.е. данными в MenuItem{………}.
имя MenuItem не менять (для обращения из другой части кода), а имя строки меню и всё содержимое сделать изменяемым.
Если сложно, то можно не включать функционал upd() – автообновляемая строка меню с renderedOnce.
Но в идеале перед открытием меню из about:config лучше брать весь объект MyMenu, но не представляю, как это сделать…
Пригодиться многим: возможность вбить код, делающий то, что нужно юзеру. После правки строка меню должна измениться.
(async id => { // UserMenu, последний пункт меню брать из extensions.user_chrome_files.MenuItem MyMenu = { //имя курсивом: есть подсказка, обводка: изменяемые строки, alt() клик правой кнопкой Pics: { // Графика сайтов Вкл/Выкл permissions.default.image upd() { // обновлять сроку перед показом меню var s = G.pref(G.v) == 1, i = "chrome://browser/skin/canvas-blocked.svg"; this.label = `Графика страниц ${s ? "загружается" : G.pref(G.v) == 3 ? "кроме сторонних" : "отключена"}`; this.image = s ? i.replace("-blocked","") : i; this.tooltipText = `${G.v} = ${G.pref(G.v)}\nRClick – кроме сторонних`; }, cmd(){ G.pref(G.v, G.pref(G.v) == 2 ? 1 : 2); BrowserReload(); }, }, "SubMenu": { men: 1, //подменю "SubItem": { cmd(){console.log(this.label)}, }, }, MenuItem: { sep: 1, //сперва разделитель lab: "User MenuItem", inf: `Правый клик: изменить данное меню Эту строку и все её значения брать из extensions.user_chrome_files.MenuItem`, cmd(){ console.log("User MenuItem:\n"+ G.pref("extensions.user_chrome_files.MenuItem")) }, }, } CustomizableUI.createWidget({ id: id, label: id, tooltiptext: id, localized: false, defaultArea: CustomizableUI.AREA_NAVBAR, onCreated(btn) { btn.style.setProperty("list-style-image", "url(chrome://branding/content/icon32.png)"); btn.type = "menu"; var doc = btn.ownerDocument, m = nn => doc.createXULElement(nn); var popup = m("menupopup"), menu = m("menuitem"); menu.m = m; menu.fill = this.fill; menu.render = this.render; popup.append(menu); btn.prepend(popup); }, render(){ var popup = this.parentNode; this.remove(); this.fill(MyMenu, popup); }, fill(o, popup) { for (key in o) { if (typeof o[key] != "object") continue; var {lab, inf, img, cmd, alt, sep, men, upd} = o[key]; sep && popup.append(this.m("menuseparator")); var name = men ? "menu" : "menuitem"; var item = this.m(name); item.setAttribute("label", lab || key); // item.alt = alt; //RClick в ucf_hookClicks.js {Mouse… if (inf) item.tooltipText = inf, item.style.setProperty("font-style", "italic", "important"); if(img || /this\.image.*=/.test(upd)) item.className = name + "-iconic", item.setAttribute("image", img || F.nul); men || cmd && item.setAttribute("oncommand", cmd.toString().replace( /cmd\(.*?\){/, "{var trg = event.target || event;")); popup.append(item); if(upd){ //выделить обновляемый пункт меню item.style.filter = "drop-shadow(0.1px 1px 0.1px #c99)"; if(item.renderedOnce) (item.render = upd).call(item); else item.upd = upd, item.render = self.renderSub; } men && this.fill(o[key], item.appendChild(this.m("menupopup"))); } } }); G = { v: "permissions.default.image", pref(key,set){ //или key = [key,default] if (!Array.isArray(key)) key = [key]; var t = Services.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) Services.prefs[`set${t}Pref`](key[0],set) else set = Services.prefs[`get${t}Pref`](...key); return set; } } })("ucf_test_menu");
Отредактировано Dobrov (07-04-2024 03:53:33)
Отсутствует
Здравствуйте. Можно как-то переделать код, убрать лишнее сделав его из папки, а не полного пути?
Примерно, чтобы был такой путь, где можно назад по папкам. Может сделать по другому? Есть что-то подобное как GreD, но чтобы открывал на папку ниже?
var p=Services.dirsvc.get('GreD',Ci.nsIFile);p.initWithPath(p.path+"\\..\\..\\ShareX\\ShareX.exe");p.launch();
Обычно запускаю через батник с такими параметрами:
::@echo off|firefox -profile p1
::firefox -no-remote -p ""
::firefox -no-remote -profile .\p1
Кстати, когда добавили перезапуск из-под браузера? Ctrl+Alt+R, похоже перезапускает без кэша. Круто)
upd: dobrov, ок спасибо, посмотрю.
Немного не то, что хотелось, ну сойдет наверно) Из под js, хоткей, как-то удобнее. Файл можно подвязать, но это отдельно торчащий файл, выглядит костыльно. Наверно оставлю код js, просто из-за удобства. Профили проверяю новые, версия особо не имеет значение.
Отредактировано b0ttle (08-04-2024 19:52:45)
Отсутствует
Ну и может совет, как лучше запускать для теста другие профили?
Профили могут требовать и разные версии браузеров.
Set WshShell = CreateObject("WScript.Shell") CurrPath = CreateObject("Scripting.FileSystemObject").GetFile(WScript.ScriptFullName).ParentFolder ProfileDir = CurrPath & "\ProfileDobrov" ProfileUser = "C:\UserTarget\MozillaFirefox\ProfileDobrovRAM" ProfileCD = CurrPath & "\ProfileDobrov" RamDir = "R:\UserTarget\MozillaFirefox\ProfileDobrov" If CreateObject("Scripting.FileSystemObject").FolderExists(RamDir) Then ' CurrPath = FirefoxDir WshShell.Run "cmd /c @echo " & chr(007), 0, false End If If CreateObject("Scripting.FileSystemObject").FolderExists(ProfileUser) Then ProfileDir = ProfileUser End If If CreateObject("Scripting.FileSystemObject").FolderExists(ProfileCD) Then ProfileDir = ProfileCD End If ' result = WshShell.Popup(ProfileDir, 3, "FireFox", vbQuestion) WshShell.Run(Quote(CurrPath & "\firefox.exe") & " -no-remote -profile " & Quote(ProfileDir)) Function Quote(PathFile) 'заключить в кавычки, если путь содержит пробелы If InstrRev(PathFile," ") = 0 Then Quote = PathFile Else Quote = Chr(34) & PathFile & Chr(34) End Function
Отсутствует
заготовка
Да, я понимаю, ты одноокошечник. И я одноокошечник.
Но раз заявлено стремление в сторону «Пригодиться многим»,
то в таких вопросах неплохо, хотя бы, отдавать себе отчёт.
И даже если проверку делать, то виджет, рождённый в каком-то окне,
зависит от существования этого окна. Если его закрыть, то в другом окне
виджет может перестать работать. Прежде всего, всякий promise async await,
но не только, бывает, что и синхронный код перестаёт работать.
Поэтому, создавать виджет в окне, в общем случае, не рекомендуется.
Лучше, чтобы он рождался в чём-то стабильном, существующем всегда
(но, тогда уже без выкрутасов типа F.nul).
Здесь, проще всего, в SystemGlobal, но там CustomizableUI надо импортировать.
Хорошо бы, конечно, в сандбоксе UCF, но в окне нет туда прямых ссылок.
И, если внутренний сандбокс ещё можно достать, например, так
Cu.getGlobalForObject(Cc["@mozilla.org/network/protocol/about;1?what=user-chrome-files"].getService().wrappedJSObject);
то пользовательский сандбокс, разве что только дебаггером всё перебирать.
Кстати, если Виталий это читает, и если будет обновление UCF, то заодно,
возможно, стоит рассмотреть добавить.
Вот есть scope.UcfPrefs = UcfPrefs;
а рядом, наоборот, что-то типа UcfPrefs.userbox = scope;
Но в идеале перед открытием меню из about:config лучше брать весь объект MyMenu
А мне кажется, так чуть проще, чем отдельный MenuItem.
Но, опять же, следует понимать, что если в настройку писать
больше четырёх килобайт — получим Warning в консоль.
А если больше одного мегабайта — будет отказ с ошибкой.
Столько набрать, конечно, нереально, даже с base64 иконками, но мало ли.
И, прикинь как расколбасит строку этой настройки на странице about:config
А если там ткнуть кнопку редактирования (или двойной ЛКМ),
и не одуматься (нажав Esc), а, даже ничего не трогая, сохранить,
то пропадут все переводы строк.
не представляю, как это сделать…
Direct eval() — как же ещё, eval-like стафф всё ещё позволен тем,
у кого заявлено использование конфигурационного файла.
Может дебаггером возможно, но не уверен, не пробовал, и пока не требуется.
BrowserReload();
Кстати, тебе (и всем заинтересованным) здесь рекомендую обратить внимание на
Bug 1880914 - Move Browser* helper functions used from global menubar and similar commands to a single object in a separate file, loaded as-needed
То есть, в 126, вместо BrowserReload(); уже нужен BrowserCommands.reload();
открыть диалог правки
Это ты предлагаешь написать такой диалог мне?
Занятие весьма утомительное и бесконечное,
а главное — всё равно ничего хорошего не выйдет.
И всё только ради того, чтобы редактировать без перезапуска?
Слегка сомнительная полезность.
Нет, ну можно что-то такое подзапилить, чисто для прикола,
может что-нибудь понравится или пригодится.
Вот, вызов — СКМ по самой кнопке.
Примечание: код eval'уатится в круглых скобках (),
а не в точности таким, какой есть.
(async id => { var MyMenuFunc = () => ({ //имя курсивом: есть подсказка, обводка: изменяемые строки, alt() клик правой кнопкой Pics: { // Графика сайтов Вкл/Выкл permissions.default.image upd() { // обновлять сроку перед показом меню var s = G.pref(G.v) == 1, i = "chrome://browser/skin/canvas-blocked.svg"; this.label = `Графика страниц ${s ? "загружается" : G.pref(G.v) == 3 ? "кроме сторонних" : "отключена"}`; this.image = s ? i.replace("-blocked","") : i; this.tooltipText = `${G.v} = ${G.pref(G.v)}\nRClick – кроме сторонних`; }, cmd(){ G.pref(G.v, G.pref(G.v) == 2 ? 1 : 2); BrowserReload(); }, }, "SubMenu": { men: 1, //подменю "SubItem": { cmd(){console.log(this.label)}, }, }, MenuItem: { sep: 1, //сперва разделитель lab: "User MenuItem", inf: `Правый клик: изменить данное меню Эту строку и все её значения брать из extensions.user_chrome_files.MenuItem`, cmd(){ console.log("User MenuItem:\n"+ G.pref("extensions.user_chrome_files.MenuItem")) }, }, }); var widget = CustomizableUI.getWidget(id); if (!widget?.label) { var func = (id, sym, self, widget) => widget = CustomizableUI.createWidget(self = { id, label: id, tooltiptext: id, localized: false, defaultArea: CustomizableUI.AREA_NAVBAR, get disallowSubView() { return (this.f = !this.f) || delete this.f && delete this.disallowSubView && this; }, get ut() { return Services.wm.getMostRecentBrowserWindow().MyMenu[sym]; }, setupMyMenu(data) { var {prefs} = Services, pref = "extensions.user_chrome_files.MyMenuSource"; var utils = class { constructor(data) { Object.assign(this, data); } get pref() { return prefs.getStringPref(pref, ""); } get code() { return this.pref || this.src; } get src() { var proto = this.constructor.prototype; delete proto.src; return proto.src = String(this.mmf).slice(7, -1); } changePref(val) { val ? prefs.setStringPref(pref, val) : prefs.clearUserPref(pref); } reinit() { var {pref} = this; if (pref) try { var mm = this.eval(`(${pref})`); } catch { self.error = true; } (this.win.MyMenu = typeof mm == "object" ? mm : this.mmf())[sym] = this; } }; (this.setupMyMenu = data => (new utils(data)).reinit())(data); }, onCreated(btn) { btn.type = "menu"; btn.style.setProperty("list-style-image", "url(chrome://branding/content/icon32.png)"); var doc = btn.ownerDocument, m = nn => doc.createXULElement(nn); var tmp = btn.tmp = m("menuitem"); var popup = btn.popup = m("menupopup"); popup.toggleAttribute("context"); //popup.setAttribute("oncontextmenu", 'if (event.target.nodeName == "menuitem") this.activateItem(event.target, event);'); tmp.m = m; tmp.fill = this.fill; tmp.render = this.render; popup.append(tmp); btn.prepend(popup); btn.reinit = this.reinit; btn.onauxclick = this.auxclick; }, reinit() { var {popup, tmp} = this; if (popup.firstChild == tmp) return; popup.removeAttribute("hasbeenopened"); popup.textContent = ""; popup.append(tmp); }, auxclick(e) { e.button == 1 && e.target == this && self.edit(e.view); }, render(){ var popup = this.parentNode; this.remove(); this.fill(this.ownerGlobal.MyMenu, popup); }, wt: "UCF:EditMyMenuObj", edit(win) { var w = Services.wm.getMostRecentWindow(this.wt); if (w) return w.focus(); var features = "chrome,centerscreen,resizable,dependent,width=1200,height=750"; if (Services.appinfo.widgetToolkit == "windows") features += ",dialog=no"; var w = win.openDialog("about:blank", "", features, null); var lss = Services.scriptloader.loadSubScript; lss("chrome://global/content/customElements.js", w); lss("chrome://global/content/globalOverlay.js", w); try {lss("chrome://global/content/editMenuOverlay.js", w);} catch {} w.onpageshow = this.editorShown; }, editorShown(e) { var doc = e.target, win = doc.ownerGlobal; doc.title = "Edit MyMenu Object"; doc.documentElement.setAttribute("windowtype", self.wt); var wu = win.windowUtils; for(var sub of ["menu", "popup", "global-shared", "in-content/common-shared"]) wu.loadSheetUsingURIString(`chrome://global/skin/${sub}.css`, wu.AUTHOR_SHEET); var style = doc.head.appendChild(doc.createElement("style")); style.append(` * {border-radius: 0 !important; outline-width: 1px !important;} :root, body {margin: 0; height: 100vh; overflow: hidden;} body {display: grid; grid-template-rows: 1fr auto;} body > * {margin: 8px !important;} textarea {resize: none; margin-bottom: 0 !important; white-space: pre; font-family: monospace !important;} div {display: grid; grid-template-columns: 1fr auto auto; column-gap: 1em; align-items: center;} span {display: flex; align-items: center; justify-content: center; color: light-dark(crimson, tomato); font-family: monospace;} button {border: 1px solid gray !important; margin: 0 !important;} `); var ta = win.ta = doc.body.appendChild(doc.createElement("textarea")); ta.value = self.ut.code; ta.onchange = self.change; ta.onkeypress = self.keypress; var btns = doc.body.appendChild(doc.createElement("div")); win.err = btns.appendChild(doc.createElement("span")).appendChild(new win.Text()); for(var lab of ["Применить", "Готово"]) { var btn = btns.appendChild(doc.createElement("button")); btn.onclick = self.btnClick; btn.append(lab); } doc.getElementById("cmd_selectAll")?.setAttribute( "oncommand", "ta.blur(); Services.focus.setFocus(ta, Services.focus.FLAG_NOSCROLL);" ); if (self.error) return delete self.error, self.btnClick.call(btn.previousSibling); ta.editor.beginningOfDocument(); ta.focus(); }, change() { this.ownerGlobal.newCode = true; }, keypress(e) { if (e.shiftKey || e.ctrlKey || e.altKey || e.metaKey) return; if (e.key == "Tab") return e.preventDefault(), this.editor.insertText("\t"); if (e.key != "Enter") return; e.preventDefault(); var ss = this.selectionStart; var beg = this.value.slice(0, ss); var ind = beg.lastIndexOf("\n") + 1; var indent = beg.slice(ind).match(/^(?:[ \t]*)?/); this.editor.insertText("\n" + indent); }, btnClick() { var wnd = this.ownerGlobal; var {ta, err, newCode} = wnd, code = ta.value; wnd.newCode = false; var done = this.matches(":last-child"); if (newCode || err.ex) { var some = /\S/.test(code), {ut} = self; if (newCode) err.data = ""; if (some) try { if (newCode) ut.eval(`(${code})`); else throw err.ex; } catch(ex) { var num = ex.lineNumber; var ed = ta.editor, sc = ed.selectionController; ed.beginningOfDocument(); while(num--) sc.lineMove(true, !num); var div = ed.rootElement; var dr = div.getBoundingClientRect(); var dp = dr.top + div.clientHeight / 2.6; var sr = ed.selection.getRangeAt(0).getBoundingClientRect(); var sc = sr.top + sr.height / 2 div.scrollBy(0, sc - dp); if (newCode) err.data = err.ex = ex; return ta.focus(); } err.ex = null; ut.changePref(some && code); if (!some && !done) ta.focus(), ta.value = ut.src; for(var win of Services.wm.getEnumerator("navigator:browser")) if (!win.closed) win.MyMenu?.[sym]?.reinit(), widget.forWindow(win)?.node?.reinit(); } done && wnd.close(); }, renderSub() { delete this.render; this.render(); this.render = self.updSub; this.upd(); }, updSub() { this.parentNode.state.startsWith("c") || this.upd(); }, fill(o, popup) { for(var key in o) { if (typeof o[key] != "object") continue; var {lab, inf, img, cmd, alt, sep, men, upd} = o[key]; sep && popup.append(this.m("menuseparator")); var name = men ? "menu" : "menuitem"; var item = this.m(name); item.setAttribute("label", lab || key); // item.alt = alt; //RClick в ucf_hookClicks.js {Mouse… if (inf) item.tooltipText = inf, item.style.setProperty("font-style", "italic", "important"); if (img || /this\.image.*=/.test(upd)) item.className = name + "-iconic", item.setAttribute("image", img || "chrome://browser/content/robot.ico"); men || cmd && item.setAttribute("oncommand", cmd.toString().replace( /cmd\(.*?\){/, "{var trg = event.target || event;")); popup.append(item); if (upd) { //выделить обновляемый пункт меню item.style.filter = "drop-shadow(0.1px 1px 0.1px #c99)"; if (item.renderedOnce) (item.render = upd).call(item); else item.upd = upd, item.render = self.renderSub; } men && this.fill(o[key], item.appendChild(this.m("menupopup"))); }} }); widget = Cu.evalInSandbox(`(${func})("${id}", Symbol());`, Cu.getGlobalForObject( Cc["@mozilla.org/network/protocol/about;1?what=user-chrome-files"].getService().wrappedJSObject )); } widget.disallowSubView.setupMyMenu({win: window, eval: code => eval(code), mmf: MyMenuFunc}); G = { v: "permissions.default.image", pref(key,set){ //или key = [key,default] if (!Array.isArray(key)) key = [key]; var t = Services.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) Services.prefs[`set${t}Pref`](key[0],set) else set = Services.prefs[`get${t}Pref`](...key); return set; } } })("ucf_test_menu");
Отсутствует
следует понимать, что если в настройку писать больше четырёх килобайт — получим Warning в консоль.
Dumby – спасибо за изменяемое пользователем меню, потестирую!
Наверное, код станет проще без диалога настройки, если объект меню хранить в опции в виде base64.
Для изменения меню создавать временный файл через atob(MyMenuSource) и править его в редакторе по-умолчанию.
Только непонятно, как отследить, что редактор сохранил и закрыл файл ??? Затем файл надо перевести в btoa(……) и запомнить новое содержимое в опции.
Т.е когда редактор по-умолчанию является многовкладочным типа SublimeText и при закрытии файла сам не закрывается…
раз заявлено стремление в сторону «Пригодиться многим», то в таких вопросах неплохо, хотя бы, отдавать себе отчёт.
java API браузеров сложна для меня, только чужие примеры переделываю. Не нашёл статей, где можно последовательно изучить API браузеров с нуля, от developer.mozilla.org толку мало.
Отсутствует
Затем файл надо перевести в btoa(……) и запомнить новое содержимое в опции.
То есть, содержимое файла как бинарную строку, а не как текст,
ведь btoa() его есть не будет, попробуй с консоли btoa("меню");
Тогда надо ещё делать метод конвертирования настройки в текст,
в смысле не для создания файла,
и метод перегона текста в бинарную строку для для создания файла,
если настройка не существует.
объект меню хранить в опции в виде base64
А зачем? Он от этого только больше станет.
Если имеется в виду, что он будет одной длинной строкой,
то проще заменять переводы строк на что-нибудь другое, и обратно.
Или JSON.stringify() <—> JSON.parse(), правда тогда ненужных слэшей насыпет.
В base64, возможно, лучше если только в gzip, но не всегда, и это заморочно.
Только непонятно, как отследить, что редактор сохранил и закрыл файл ???
Я не знаю что такое «закрыл файл».
Это типа он берёт его в оборот монопольно,
и других к нему даже не подпустит, пока не «закроет», так что ли?
Или только не даст удалить?
А если сохранил, значит у файла изменится lastModifiedTime
Поэтому, запоминаем его сразу, вешаем в окна листенер на событие "activate".
И обсёрвер на топик "quit-application-granted".
И там сравниваем lastModifiedTime на момент события или топика
с тем, который запомнили.
Можно предусмотреть ручной выход из режима редактирования,
типа когда заказали редактирование, кнопка начинает назойливо мигать,
намекая, что её нужно нажать ещё раз,
чтобы удалить все листенеры, обсёрвер, и временный файл.
Вобщем, можешь пофантазировать на эту тему.
Отсутствует
если будет обновление UCF, то заодно,
возможно, стоит рассмотреть добавить.Вот есть scope.UcfPrefs = UcfPrefs;
а рядом, наоборот, что-то типа UcfPrefs.userbox = scope;
Обновил, добавил UcfPrefs.customSandbox, в случае если отключены в настройках фоновые скрипты
вызов UcfPrefs.customSandbox создает песочницу но при этом скрипты если подключены в CustomStylesScripts.mjs не загружаются.
Для всех:
В этом обновлении CustomStylesScriptsChild.mjs удалён, настройки из него перемещены в CustomStylesScripts.mjs см. Сontent Settings
и подчистил этот файл оставил там только то что нужно для редактирования.
Отредактировано Vitaliy V. (14-04-2024 15:05:19)
Отсутствует
Обновил, добавил UcfPrefs.customSandbox, в случае если отключены в настройках фоновые скрипты
вызов UcfPrefs.customSandbox создает песочницу но при этом скрипты если подключены в CustomStylesScripts.mjs не загружаются.
О, замечательно!
Я-то разогнался, словно сандбокс-скриптинг всегда enabled,
а это, конечно же, может быть и не так.
оставил там только то что нужно для редактирования
Кстати, был, когда-то, вообще ультимативный проект.
Обновлять UCF — это тот ещё головняк, поэтому,
идея была в том, чтобы вырезать весь интерналс в отдельную папку.
То есть, в папке user_chrome_files — только пользовательский стафф.
Включая там сугубый пользовательский user_chrome.manifest, для всяких override директив.
UCF'ские иконки, вроде, тоже рассматривались как пользовательские,
поскольку есть любители ещё старых, тёплых, ламповых svg'шек.
А рядом с этой пользовательской папкой user_chrome_files
другая — (условно) user_chrome_files_internal
Там — весь остальной обеспечительный код, считай почти весь UCF.
Собственно, идея в том, чтобы последний раз переломаться обновить,
но затем,
если какое-то обновление, улучшение, исправление, рефлексия на отвал,
то просто заменяем папку user_chrome_files_internal, ни о чём даже не задумываясь.
Скачал, заменил, перезапустился с очисткой кэша — всё, свободен.
Ну, это некая маниловщина, если бы, да кабы.
Мне такое, скорее всего, не по зубам, но как замысел, возможно, представляет интерес.
И, внезапно меняя тему, я смотрю ATB обновился. Это хорошо.
Но торчат BrowserOpenTab() и BrowserOpenFileWindow()
которых в 126 уже нет.
BrowserOpenAddonsMgr() пока ещё есть, но уже не жилец.
рекомендую обратить внимание на
Bug 1880914 - Move Browser* helper functions used from global menubar and similar commands to a single object in a separate file, loaded as-needed
Отсутствует
Dumby посмотрите пожалуйста кнопку Save в ней не работают все пункты сохранить .... как PNG и Сохранить ярлык страницы как Кодировать изображение в base64 в 125.0
try {CustomizableUI.createWidget({ id: "ucf-cbbtn-Save", tooltiptext: "Сохранить", localized: false, get initCode() { delete this.initCode; return this.initCode = Cu.readUTF8URI(Services.io.newURI( "chrome://user_chrome_files/content/custom_scripts/custom_script/Save.js" )); }, cbu: { types: { 128: "Bool", boolean: "Bool", 64: "Int", number: "Int", 32: "String", string: "String" }, getPrefs(pref) { try { return Services.prefs[`get${ this.types[Services.prefs.getPrefType(pref)] }Pref`](pref); } catch {return null;} }, setPrefs(pref, val) { Services.prefs[`set${this.types[typeof val]}Pref`](pref, val); } }, gClipboard: { get ch() { delete this.ch; return this.ch = Cc["@mozilla.org/widget/clipboardhelper;1"] .getService(Ci.nsIClipboardHelper); }, write(str) { this.ch.copyStringToClipboard(str, Services.clipboard.kGlobalClipboard); } }, custombuttonsUtils: { writeFile(path, data) { try { if (path.includes(":\\")) path = path.replace(/\//g, "\\"); var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); file.initWithPath(path); file.exists() && file.remove(false); var strm = Cc["@mozilla.org/network/file-output-stream;1"] .createInstance(Ci.nsIFileOutputStream); strm.init(file, 0x04 | 0x08, 420, 0); strm.write(data, data.length); strm.flush(); strm.close(); } catch(ex) { Cu.reportError("Custom Buttons: " + [path, "---", ex, ex.stack].join("\n")); } } }, addDestructor(destructor, context) { this._destructors.push({destructor, context}); }, addEventListener(...args) { var trg = args[3]; if (!trg) trg = args[3] = this.ownerGlobal; trg.addEventListener(...args); this._handlers.push(args); }, onCreated(btn) { var win = btn.ownerGlobal; btn._handlers = new win.Array(); btn._destructors = new win.Array(); win.addEventListener("unload", this, {once: true}); new win.Function( "self,_id,cbu,xhtmlns,addDestructor,addEventListener,gClipboard,custombuttonsUtils", this.initCode ).call( btn, btn, this.id, this.cbu, "http://www.w3.org/1999/xhtml", this.addDestructor.bind(btn), this.addEventListener.bind(btn), this.gClipboard, this.custombuttonsUtils ); }, handleEvent(e) { var btn = e.target.getElementById(this.id); for(var args of btn._handlers) args.pop().removeEventListener(...args); delete btn._handlers; for(var {destructor, context} of btn._destructors) try {destructor.call(context, "destructor");} catch(ex) {Cu.reportError(ex);} delete btn._destructors; } });} catch(ex) {Cu.reportError(ex);}
Отредактировано egorsemenov06 (15-04-2024 19:48:18)
Отсутствует
Dumby вот убрал все опиания (все равно не соображаю)
self.label = "Save"; self._handleClick =()=> menuPopup.openPopup(this, "after_start"); self.image = "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAADAgBEDRIXnwxQjKQNWp6pDFWXqAxXm6gMV5moDFeaqAxXmqgMV5qoDFebqAxVlqgNW5+pCkyIogwSFqgDAgBHDQoFhyszOv8hheP+IJH7/x+L8v8fjfb/H433/x+N9v8fjfb/H432/x+N9/8fi/L/IJH7/yGF5P0kLTTvDAcDgwgICIQ8Ojf/0czA+Oji1fzh18r85NzO/OTbz/zj287849vO/OPbzvzk3M/84dfK++ji1f3Sy8D5NDIvywYGB3kKCgqFQ0A8/+XXw/v979f/9uTO//rp0f/66NH/+ujR//rn0f/66NH/+ujR//bkzv/979f/5tfD/UZBPv8KCwqEDQwMhUVDQP/f08X7+OrZ/+zf0P/v5NP/8OPT/+/j0//v4tP/8OPT/+/j0//s39D/+OrZ/+DTxfxEQj//DAwMhA8PD4VKR0T/4dXG+/rr2v/v4tH/9OXU//Ll1P/z5dT/8+XU//Pl1P/05NT/7+DR//rr2v/i1cX7SkhE/w8PD4USEhKFT0xI/+XXxfv97tr/9ePR//no1P/459T/+OfU//jn1P/459T/+OfU//Xk0f/97tr/5dfF+09MSf8SEhGFFRQUhVNQTv/j2cv7+u/g//Hm2P/169v/9Orb//Tq2//06tv/9erb//br3P/x5tf/+e/g/+PZzPtTUU7/FBQUhRgXF4VXU1D/2828+/Lk0f/q2sf/7d3K/+3dyv/t3cr/7N3K/+rayP/r28n/69vI//Ll0v/azbv7VlNP/xgXF4UfHh6FTktJ/1JOTPtZVFL/Uk5L/1FNSv9RTUr/UU1K/1JPTP9YVVD/VVJP/09NSv9WUk//UU1L+05LSf8fHh2FIR8fhVVTUP9FQkD7UlBM/6Wlj/+4uJ7/sLCX/7S0mv+xsJn/oKCQ/6+vmv+hoYv/TEtH/0NCQPtVUk//IR8fhSMhIIVcWVb/SEVF+19dVv/f3sP////e//X10v///93/2di8/1lYWP+eno//5+fG/19dV/9JRkb7W1hV/yMhIYUkJCOFXltZ/0tJSPtdW1f/0NC4/+/u1P/h4cj/8PDV/7++q/8vLC7/e3lw/9fWv/9eXVf/TElJ+15bWf8lJCKEJSQjhF9cWf9LSUf5XVtX/tbVwf/5+OL/6enV//j54v/GxrX/QD0+/42Kgv/d3cr/YF5a/k5LSvlhXlv/JSUjhCkoKIZpZWT/VVJR/WNhXP/V1cT//f3s/+3t3v/8/Or/zc2//01LSf+VlIz/4eDS/2hmYv9YVVT8aWVj/ycmJoIaGRlYSEVE1DYzM8NKSUfP0dHG9/X16P/n59v+7e3g/+jo3f/X2M3+6uve/9bWzPdOTUvNOjg3y0RBQLwPDw8lAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; var folderpath="C:\\Users\\Firepox\\Desktop"; var array = [ { label: "Сохранить значок веб-сайта", func: "saveFavicon()", image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACPVBMVEX09ff////C3L+Uq8+Vq8+Uqs+Zr9CZrtCZr9Gfu+ear8+mt9JRf8ORxl3t8vfF06+Twojs8/d9otl8o9s+aquZrs/X9KLp8Pft8fZhisf//+DBzN2hveihv+pii8hti9pgicl6oNlojs1zncNsi836/P2duebx8/eYyWqBp+Gn0IKBvlKHsm9qmaVuk8zt7/FEbauEv1Tp7/JdhL9oi9Pl8e2LwlmdsdD7/P76+/3H7ofo8+peh8eHwFaSteZ0pkp2gl7q8/Ohy5OApt2by2eZuOqbuOWaezWuvtd7nN2HvWxul9Ty9feQxV5ljcqBp+JEcLCVtOOo0nR7odx5n9suX6Z1mtBzmtSXyGPv9PewzfOzx+O6zu/s8fd9o95Xfrthi8lYhMN5oNnw9ffw9Pjw9Pf8/f6ewO/m8O9zmdE6aapsjdyUwouPxWPDzd6XteOSs9B5nNVpnpqHt7h/s6F6n9d7ntSTttGHwVh4qp+Ev1HH7ox6qk5wj+Hm8e3t9fOm0IKAtqOBpNrx+P9ljcyhs9FpkM2hv+/u8/fF0eOLu4N+vFKgzX3p9OSFqN13qExekIl4n9j7/P3x9PhxmNDm8e9Vg8Zfkozr8veq0YTX9qL//92AtamOwnHFz96Fot1diMh+pd13ntmatu+YyW/3+/+Tqs5UgcShzJNbhsdTf8GHs7bo8PaXtuqMr+Ty8/SZt+SUqs7r7Ox3ndb9/f7t8feZyXGYyWWCpNbz9PRuiteNtNDn7/V4ntjx8fGo3JqNAAAAv3RSTlP/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AEVuhDkAAAD+SURBVBhXY5jHzcUMAqxAICq9bx8D96adDFAgaGQOFOBaH7h7zoqZDTlFyptncAAFWBjyi52CXCI0unRLxcECPhsatbbzmlXMnS60hg0kkOxW0uNrq93tNaFpD1ggUm21QK532ZQdSm1hmXKdDCwdnOWVOi1RjNGMQCCrwMDMJ8NZ4LAynVGPkXFp8zpJBubYmn579wXtqhZb0iwn9a1iWLaViYmJ3891obOwYtLEvcYMGyWAAkwJdv6accEhi8LjGVr11SenpC5f61g3NcO0vjCAIc+DjZ2dnWexddWSbYa9nlkM+8BgWsxsK7FZ1VLzRaACNokmtdnyu1QMQgF7Rlh4zWWTAwAAAABJRU5ErkJggg=="}, { label: "Запомнить значок веб-сайта как base64", func: "copyFaviconData()", image: "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAI2bv/9RVpf/AAAAAAAAAAAAAAAAAAAA/wbwAf8G8AH/BvAB/wbwAf8G8AH/BvAB/wbwAf8G8AH/AAAAAAAAAACIkvD/Jia6/ywpq/8AAAAAAAAAAAAAAAAAAAD/AAAA/wbwAf90qpv/Ymic/1RWqP9OUKr/W2Ch/2dumf9YYKT/Ly/B/xQP3/8MB9P/JCGb/wAAAAAAAAAAAAAAAAAAAP8G8AH/U5ea/ycr8f8VIP3/HiP4/ywo8v8sIvb/LCL2/ywi9v8KBOj/BQDe/wQAtv8tK4P/AAAAAAAAAAAAAAD/BvAB/3Sqm/9iaJz/Tim3/0UuuP9GPrT/R0ex/zk8uf8gIMz/FRDe/xEMzv8jIJz/AAAAAAAAAAAAAAAAAAAA/wbwAf8G8AH/BvAB/wAAAAAAAAAAAAAAAAAAAP8AAAD/SqOR/yImvP8sLKj/AAAAAAAAAAAAAAAAAAAAAAAAAP8G8AH/BvAB/wbwAf8AAAD/AAAA/wAAAP8AAAD/BvAB/3Sqm/9KW5r/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/BvAB/wbwAf8G8AH/BvAB/wbwAf8G8AH/BvAB/wbwAf8G8AH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wbwAf8G8AH/BvAB/wbwAf8G8AH/BvAB/wbwAf8G8AH/BvAB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8G8AH/BvAB/wbwAf8AAAAAAAAAAAAAAAAAAAAABvAB/wbwAf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/BvAB/wbwAf8G8AH/AAAAAAAAAAAAAAAAAAAAAAAAAAAG8AH/AAAAAAAAAP8G8AH/AAAAAAAAAAAAAAAAAAAA/wbwAf8G8AH/BvAB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8G8AH/BvAB/wAAAAAAAAAAAAAAAAAAAP8G8AH/BvAB/wbwAf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/BvAB/wbwAf8AAAAAAAAA/wAAAP8G8AH/BvAB/wbwAf8G8AH/BvAB/wbwAf8G8AH/BvAB/wbwAf8G8AH/BvAB/wbwAf8G8AH/AAAAAAAAAAAG8AH/BvAB/wbwAf8G8AH/BvAB/wbwAf8G8AH/BvAB/wbwAf8G8AH/BvAB/wbwAf8G8AH/BvAB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOesQQBjrEGAAaxBwACsQcABrEHDg6xBwAesQcAPrEHAD6xBw8+sQcPprEHD8axBwAGsQQABrEGAAaxB//+sQQ=="}, { separator: ''}, { label: "Сохранить ярлык страницы как…", func: "saveShortcuts()", image: "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADzqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA/5XLDv/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA/5XLDv8E/yT/lcsO//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA/5XLDv8E/yT/BP8k/wT/JP+Vyw7/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA/5XLDv8E/yT/BP8k/wT/JP8E/yT/BP8k/5XLDv/zqgD/86oA//I1///yNf//86oA//OqAP/zqgD/86oA//OqAP+Vyw7/lcsO/wT/JP8E/yT/BP8k/5XLDv+Vyw7/86oA//OqAP/yNf//8jX///OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP+Vyw7/BP8k/5XLDv/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/lcsO/wT/JP+Vyw7/86oA//OqAP/zqgD/86oA//02AP/9NgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA/5XLDv8E/yT/lcsO//OqAP/zqgD/86oA//OqAP/9NgD//TYA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP+Vyw7/BP8k/5XLDv/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/lcsO/wT/JP+Vyw7/86oA//OqAP/zqgD/86oA/wA31v8AN9b/86oA//9If///SH//86oA//OqAP/zqgD/86oA/5XLDv8E/yT/lcsO//OqAP/zqgD/86oA//OqAP8AN9b/ADfW//OqAP//SH///0h///OqAP/zqgD/86oA//OqAP+Vyw7/BP8k/5XLDv/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/lcsO/5XLDv+Vyw7/86oA//OqAP/zqgD/86oA/0CA//9AgP//86oA/07+9f9O/vX/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP9AgP//QID///OqAP9O/vX/Tv71//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/86oA//OqAP/zqgD/AACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQ=="}, { separator: ''}, { label: "Кодировать изображение(текст.файл) в base64", func: "copyFaviconbase()", image: "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AIAQ/wCAEf8AgA//AIAR/wCAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AgBX/AIAVAAAAAAAAAAD/AIAo/wCA//8AgP//AID//wCA//8AgP//AIAoAAAAAAAAAAAAAAAAAAAAAP8AgBL/AID//wCA//8AgA3/AIAL/wCA//8AgP//AID//wCA//8AgP//AID//wCA//8AgBAAAAAAAAAAAAAAAAD/AIAR/wCA//8AgP//AIAK/wCACv8AgP//AID//wCAIf8AgAX/AIAh/wCA//8AgP//AIAQAAAAAAAAAAAAAAAA/wCACv8AgP//AID//wCAB/8AgAf/AID//wCA//8AgAUAAAAA/wCABf8AgP//AID//wCACgAAAAD/AIAQ/wCADP8AgCH/AID//wCA//8AgAf/AIAH/wCA//8AgP//AIAh/wCABf8AgCH/AID//wCA//8AgAv/AIAh/wCA//8AgP//AID//wCA//8AgP//AIAH/wCAB/8AgP//AID//wCA//8AgP//AID//wCA//8AgP//AIAg/wCA//8AgP//AID//wCA//8AgP//AID//wCAB/8AgAf/AID//wCA//8AgP//AID//wCA//8AgP//AIAh/wCAC/8AgP//AID//wCAHP8AgBz/AID//wCA//8AgAf/AIAH/wCA//8AgP//AIAh/wCACf8AgA7/AIAMAAAAAP8AgAj/AID//wCA//8AgAP/AIAD/wCA//8AgP//AIAH/wCAB/8AgP//AID//wCABQAAAAAAAAAA/wCADf8AgAr/AIAL/wCA//8AgP//AIAH/wCAB/8AgP//AID//wCAB/8AgAr/AID//wCA//8AgCH/AIAH/wCAJf8AgP//AID//wCAI/8AgP//AID//wCAB/8AgAf/AID//wCA//8AgAf/AIAL/wCA//8AgP//AID//wCA//8AgP//AID//wCA//8AgCT/AID//wCA//8AgAr/AIAK/wCA//8AgP//AIAKAAAAAP8AgCj/AID//wCA//8AgP//AID//wCA//8AgCP/AIAM/wCA//8AgP//AIAN/wCADf8AgP//AID//wCADQAAAAAAAAAA/wCAEP8AgBH/AIAP/wCAEf8AgBAAAAAAAAAAAP8AgBT/AIAVAAAAAAAAAAD/AIAV/wCAFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//+sQcH5rEGA8KxBAHCsQQBwrEEIQKxBAACsQQAArEEAAKxBAQCsQQwArEEAAKxBAACsQYAArEHBmaxB//+sQQ=="}, { separator: ''}, { label: "Сохранить всю страницу как PDF", func: "savePageToPDF()", image: "data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYUw4pJt3V/+Rb1D8lnFP/55zTf+VcVH/lXJS/5VyUv+VclL/lXJS/5VyUv+VclL/k3BR/J56Wv9cRzSkAAAAAJNvUKTto2L/4ppe/uehZf/Pmmr/noZv/9Scav/Wl17/1plh/9eZYf/XmWH/15lh/9eZYf/WmGD/2Jlg/suRXP9mRiuk8rWA/397dP1akKn/rqqi/3LF3f8Mntj/4dLJ///+9f/48u3/9e7n//bt5v/47+f/+O/n//jv5//rvZP/1ZJX/a9/VP9+lrD8AIvz/xOt+f8Douv/ALb6/wC28/9tmar/z8jJ//Lq5/////7//v////n9///6/P3//////+Ta0P/PjVP/pnpT/IWds/+aiXj/5efl/8Px//951/3/LMz//wCx8/8GltL/NIu3/4ycqf/l29L////+//n6+//8/v//3tXM/8+OVP+oe1P/6K57/86QWP/r6Ob////////++v/r9/z/oOb9/zDL//8Arf//AI/r/ydysv+hpqr//PTr///////d1Mz/0I5U/6h7U//osH//wo5g/+fm5P/7/f//9vf5//z7+////vv/9/r8/5Dc/P8Oqv7/AJf//wF02v9ffZ7/8Ojh/+Ha1P/NjFL/qHtT/+ewf//Ej1//7O3r///////+/v7//v7+//f5+v/6+vv////8/8Tq/f8hp/7/AJH//wB18/8/bqj/1MGu/9mXXv+leVH/569+/8iSYv+/tKn/wLew/8O5sf/P0M////////7+/v/3+fv////7/9Hv/v8hoP3/AIn//wB4/v84ZqL/w4NH/619VP/nsYD/x45c/9W5of/bv6j/0Jxt/6J/YP+spqD/2N3i//7////6+/3///76/8vr/v8Slv7/AIb+/wBz//83VH7/nW1B/+ewfv/Fjl7/7Ozr///////9+/r/9d7K/9Ghdv+jd1D/pJ6Y/+jt8f/9///////7/6fb/v8Ahv7/AYD//wRp6f95YlT/57B//8SOXv/n5uT//v7///r7/P/8/v////////XRsv/DhEv/loBu/9DX3P/9/v/////7/2O6/f8Afv//FnTU/5JtTf/nsH//xY9e/+jn5f/+/f//+fj5//n4+P/5+Pn/+/////Xbxf/Wj1D/nX1h/+Ll6P////7/3+/3/w+V//8tcbP/qHJB/+WuffzCjV7/5efn///////+/v7//////////////v7///////XRsP/TnW3/8fT3//////////z/ddD//0Nxl/+zdkH88LmH/9CRWP2+qJT/0M7N/8/Jxv/Pysf/z8rH/8/Kxv/Py8n/zsO6/7+pmP/PzMv/zsnG/9bNyP+nsK7/h4R3/b2BT/+Sb1Ck7qxw/9GSW/69hlb/wYhX/8CIV//AiFf/wIhX/8CIVv/BiVj/xI1d/8CIVv/BiFf/vYZW/9STW/7ppmv/bE80pAAAAACUd16k+sui/+7AmPzwwpr/8MKa//DCmv/wwpr/8MKa//DCmf/vwZj/8MKa//DCmv/uwJj8+cui/5N3XaQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="}, { label: "Сохранить всю страницу или выбранное как HTML", func: "savePageToHTML()", 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="}, { label: "Сохранить выделенный текст как txt файл", func: "saveSelectionToTxt()", image: "data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAAAAAQE6AAAAZAAAAGgAAAJmAAACZgAAAGYAAABmAAAAZgAAAGYAAABmAAAAZgAAAGYAAABlAAAAaQABAmYAAQEjAAAAADlVkOdVcKHxVXKi8kdklPJLZpfyU3Cg8lJvn/JRbZ7yUW+g8lFun/JRbp/yUG6e8lVyofFVdKjzLkV45wAAAFABAQEAaIzF/3y34v9wsuL/cJe0/0lpgv9bjLP/dLLh/2+v3v9sq9v/cK3d/3Gv3v9sqtv/b7Df/4G77P9VcqT2AAAAVAMDAQBnir/+ZqfU/pDB4/7a3uD+j46N/kxYXv6To6/+1er4/tXp+P7J3/D+1ej4/svg8v6Gut/9aqzd/lhxnvAAAABSAwIBAGaIvv9pptX/ocfj//f4/P/P0tX/g4CA/1xZWf+Woqr/2uz8/9Hl+f/W5fT/2Of3/5fC4v5tq93/Vm+e8QAAAFIDAgEAaYm+/3mw2/+iyeX/9Pn8/+z0+//IzNL/d3h5/0tMTv+Mkpn/xdvs/9Hp/f/O4PL/msXk/nmz4/9XcJ/xAAAAUgMDAQBti7//k7/h/6fL5v/v9fn/4u73/9Dk9P+8wMT/YGpx/zJJWv94iJf/ztzo/9Pp/P+ZwuD+gLfk/1dwnvEAAABSAwMBAHOPwf+myub/sNHp//j7/P/6/P3/8fr///r39P+sxdP/IXWq/xJJcv+NjZD/0+Lu/6TN7f6Ft+L/WXGf8QAAAFIDAwEAd5LD/7PR6/+ZxOP/0ePx/97r9f/Y5/L/3e32/8Tc7f9gseT/CHK3/zBYdv+HiY7/lL/f/pLE7/9bcJ3xAAAAUgMDAQB4k8P/xNvx/5/F5f+kyOX/qMrn/6TH5f+kyOX/sM/q/5e51P9Mm83/GHm3/xxIav9fdYf+pMvs/1x1pfIAAABTAwMBAHmSxf/O4/T/y9/y/8Hb9P/C3PX/wNv0/7vW7/+93ff/utDm/42fsf9Gjbn/EXS2/ytSbv6Fj5r/WnGc8gAAAFICAwEBepPE/tHk9f/S5PX/vMjV/7fCzP+3w8//uMPP/7XBzP+6ytf/qa+4/3h/hv9Ghaz/JoO+/jNXdP82PVnyAAAAVgACAgCBmcb/2+r3/dHh8fyPkpX/kI6N/5yam/+dnJ3/paWk/6enpf+sr6//mpSR/3Bubf9SjbD8H4C+/QsrSvcCAAB/AAAAA3yVx//j8///3u/7/52gpf6pqKf+uLm5/rq7u/7Ly8v+ycnI/paWlf6LjY/+np2f/Xh+g/5gnL7/MX+y/xcgJ80BAgNNN1OUs6W84fDA1O73mJyj/ainpv+2trb/t7e4/8fHyP/Fxsb/kZGQ/4eGhP+vucT/j6G+/W53k/NlkbnwNoOv/AgiNb8CCBsQDRo/YwsaO3B0d33arKyp9q2trfWvr6/2u7u79ru7vPawr7H1sbCt9nJ2gOQIGD6bFCFEYB0qPE1Bf6SpEz9cggAAAAMCAQEBAQAAADIyMmlDQ0ONQUFBhUFBQYVCQkGFQkJBhUhISIRNTU2OKysrZAEAAAUBAQAAAgEAAAkEAAEDAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="}, { separator: ''}, { label: "Запомнить изображение как base64, в контекстном меню", value: "Save.WebScreenShotOnImage"}, { label: "Сохранить выделенный текст в файл, в контекстном меню", value: "Save.SelectionToFile" }, { label: "Открыть выделенный текст в внешнем редакторе, в контекстном меню", value: "Save.TextToEditor"}, ]; var menuPopup = self.appendChild(document.createXULElement("menupopup")); array.forEach((m,i)=> { if ("separator" in m) { menuPopup.appendChild(document.createXULElement("menuseparator")); return }; var mItem = menuPopup.appendChild(document.createXULElement("menuitem")); mItem.setAttribute("label", m.label); mItem.setAttribute("class", "menuitem-iconic"); if ("image" in m) mItem.setAttribute("image", m.image || array[i-1].image); if ("value" in m) { mItem.setAttribute('type', 'checkbox'); mItem.setAttribute('checked', cbu.getPrefs(m.value) ); mItem.onclick =()=> cbu.setPrefs(m.value, !cbu.getPrefs(m.value)); } if ("func" in m) mItem.addEventListener("command", ()=> eval(m.func.toString())); }); menuPopup.setAttribute("onclick", "event.stopPropagation()"); function aDate() { var t=new Date(); var y=1900+t.getYear(); var min=t.getMinutes(); if (min<10){min="0"+min}; var h=t.getHours(); var m=t.getMonth();switch(m){case 0: m="января";break;case 1: m="февраля";break;case 2: m="марта";break;case 3: m="апреля";break;case 4: m="мая";break;case 5: m="июня";break;case 6: m="июля";break;case 7: m="августа";break;case 8: m="сентября";break;case 9: m="октября";break;case 10: m="ноября";break;default: m="декабря";} var d=t.getDate(); var curdate=d+" "+m+" "+y+" "+"г"; var myfilename=curdate; return myfilename; } function WebScreenShotonImage(image) { var canvas = document.createElementNS(xhtmlns, 'canvas'); canvas.width = image.naturalWidth; canvas.height = image.naturalHeight; var ctx = canvas.getContext('2d'); ctx.drawImage(image, 0, 0); var base64 = canvas.toDataURL(); gClipboard.write(base64); var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); var uri = makeURI('data:text/css,'+ encodeURIComponent('#alertImage { height: 25px !important; width: 25px !important; }')); sss.loadAndRegisterSheet(uri, 0); // alertsService.showAlertNotification(base64, self.label, "Запомнил изображение как base64", false, "", (s, t)=> { Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService).showAlertNotification(base64, self.label, "Изображение копировано как base64", false, "", (s, t)=> { if (t == 'alertfinished') sss.unregisterSheet(uri, 0); }, ""); }; var saveToFile = function (fileContent, fileName) { var uc = Components.classes['@mozilla.org/intl/scriptableunicodeconverter'].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); uc.charset = 'utf-8'; fileContent = uc.ConvertFromUnicode(fileContent); var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker); fp.init(window, '', fp.modeSave); fp.defaultString = fileName; fp.appendFilters(fp.filterHTML); fp.appendFilters(fp.filterAll); fp.open(function (rv) { if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) { var stream = Components.classes['@mozilla.org/network/file-output-stream;1'].createInstance(Components.interfaces.nsIFileOutputStream); stream.init(fp.file, 0x02|0x20|0x08, 0666, 0); stream.write(fileContent, fileContent.length); stream.close(); } }); }; function savePageToHTML() { var vert = String.raw`javascript:(function(){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 selWin=getSelWin(window),win=selWin||window,doc=win.document,loc=win.location;var qualifyURL=function(url,base){if(!url||/^([a-z]+:|%23)/.test(url))return url;var a=doc.createElement('a');if(base){a.href=base;a.href=a.protocol+(url.charAt(0)=='/'%3F(url.charAt(1)=='/'%3F'':'//'+a.host):'//'+a.host+a.pathname.slice(0,(url.charAt(0)!='%3F'&&a.pathname.lastIndexOf('/')+1)||a.pathname.length))+url}else{a.href=url};return a.href};var encodeImg=function(src,obj){var canvas,img,ret=src;if(/^https%3F:%5C/%5C//.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((/%5C.jpe%3Fg/i.test(src)%3F'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={'%5Cb':'%5C%5Cb','%5Ct':'%5C%5Ct','%5Cn':'%5C%5Cn','%5Cf':'%5C%5Cf','%5Cr':'%5C%5Cr','%5Cx22':'%5C%5C%5Cx22','%5C%5C':'%5C%5C%5C%5C'};while(chr=str.charAt(i++)){ret+=meta[chr]||chr};return'%5Cx22'+ret+'%5Cx22'},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(Object.prototype.hasOwnProperty.call(obj,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)%3FString(obj):'null';case'Object':return objToSrc(obj);case'String':return strToSrc(obj);default:return obj%3F(obj.nodeType==1&&obj.id%3F'document.getElementById('+strToSrc(obj.id)+')':'{}'):'null'}};var ele,pEle,clone,reUrl=/(url%5C(%5Cx22%3F)(.+%3F)(%5Cx22%3F%5C))/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,b,c,d){return b+encodeImg(qualifyURL(c))+d});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)!='%23')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(){if('$'in win)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 win){if(name in f.contentWindow||!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name))continue;try{str=toSrc(win[name]);if(!/%5C{%5Cs*%5C[native code%5C]%5Cs*%5C}/.test(str)){script.appendChild(doc.createTextNode('var '+name+' = '+str.replace(/<%5C/(script>)/ig,'<%5C%5C/$1')+';%5Cn'))}}catch(e){}};f.parentNode.removeChild(f);if(script.childNodes.length)this.nextSibling.appendChild(script)};head.copyScript();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))){style.appendChild(doc.createTextNode(rule.cssText.replace(reUrl,function(a,b,c,d){var url=qualifyURL(c,s.href);if(rule.type==1&&rule.style&&rule.style.backgroundImage)url=encodeImg(url);return b+url+d})+'%5Cn'))}}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('%5Cn'));var doctype='',dt=doc.doctype;if(dt&&dt.name){doctype+='<!DOCTYPE '+dt.name;if(dt.publicId)doctype+=' PUBLIC %5Cx22'+dt.publicId+'%5Cx22';if(dt.systemId)doctype+=' %5Cx22'+dt.systemId+'%5Cx22';doctype+='>%5Cn'};var href = 'data:text/html;charset=utf-8,' + encodeURIComponent(doctype + sel.innerHTML + '\n<!-- This document saved from ' + (loc.protocol != 'data:' ? loc.href : 'data:uri') + ' -->');var a = document.documentElement.appendChild(document.createElement("a"));a.setAttribute("href", href);var name = selWin ? win.getSelection().toString() : (title && title.text ? title.text : loc.pathname.split('/').pop());name=name.replace(/[:\\\/<>?*|"]+/g, '_').replace(/\s+/g, ' ').slice(0, 100).replace(/^\s+|\s+$/g, '');name += (function () {var d = new Date(), z=function(n){return '_' + (n < 10 ? '0' : '') + n};return z(d.getHours()) + z(d.getMinutes()) + z(d.getSeconds());})();a.setAttribute("download", name + ".html");a.click();a.remove();})();`; gBrowser.fixupAndLoadURIString(vert, {triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()}); }; function saveShortcuts() { var file = Components.classes["@mozilla.org/file/local;1"]. createInstance(Components.interfaces.nsIFile); file.initWithPath(folderpath); if( !file.exists() || !file.isDirectory() ) { file.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0x1B6);} var savetodir=folderpath+"\\"; var urllink=gBrowser.currentURI.spec; var out=getTabLabel(); var filename=savetodir+out+'.url'; var data="[InternetShortcut]\r\nURL="+urllink+"\r\n"; saveToFile(data, filename); var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); var uri = makeURI('data:text/css,'+ encodeURIComponent('#alertImage { height: 25px !important; width: 25px !important; }')); sss.loadAndRegisterSheet(uri, 0); var notific = 'Сохранил в: ' + folderpath; var image = gBrowser.selectedBrowser.mIconURL; Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService).showAlertNotification(image, filename, notific); }; function copyFaviconbase(){ var fp = window.makeFilePicker(); fp.init(window, "Открыть файл", fp.modeOpen); fp.appendFilter("Text and images", "*.txt; *.text; *.css; *.js; *.ini; *.rdf; *.xml; *.html; *.htm; *.shtml; *.xhtml; *.jpe; *.jpg; *.jpeg;\ *.gif; *.png; *.bmp; *.ico; *.svg; *.svgz; *.tif; *.tiff; *.ai; *.drw; *.pct; *.psp; *.xcf; *.psd; *.raw"); fp.open(re=> { if ( re != fp.returnOK ) return; var file = fp.file; var inputStream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); inputStream.init(file, 0x01, 0600, 0); var stream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream); stream.setInputStream(inputStream); var encoded = btoa(stream.readBytes(stream.available())); var contentType = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService).getTypeFromFile(file); var dataURI = "data:" + contentType + ";charset=utf-8;base64," + encoded; gClipboard.write(dataURI); //Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService).showAlertNotification(dataURI, self.label, "Текст скопирован как base64"); var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); var uri = makeURI('data:text/css,'+ encodeURIComponent('#alertImage { height: 25px !important; width: 25px !important; }')); sss.loadAndRegisterSheet(uri, 0); // alertsService.showAlertNotification(base64, self.label, "Изображение скопировано как base64", false, "", (s, t)=> { Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService).showAlertNotification(dataURI, self.label, "Изображение скопировано как base64", false, "", (s, t)=> { if (t == 'alertfinished') sss.unregisterSheet(uri, 0); }, ""); }); }; function savePageToPDF() { var loc = gBrowser.currentURI.spec; var vert = "http://pdfmyurl.com?url=" + loc; gBrowser.fixupAndLoadURIString(vert, { triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal() }); }; if (typeof window.saveImageURL != "function") var saveImageURL = internalSave.length == 16 ? (url, name, a3, a4, a5, a6, a7, type, a9, priv, prin) => internalSave(url, null, null, name, a9, type, a4, a3, null, a6, null, a7, a5, null, priv, prin) : internalSave.length == 15 ? (url, name, a3, a4, a5, a6, a7, type, a9, priv, prin) => internalSave(url, null, name, a9, type, a4, a3, null, a6, null, a7, a5, null, priv, prin) : (url, name, a3, a4, a5, a6, a7, type, a9, priv, prin) => internalSave(url, null, name, a9, type, a4, a3, null, a6, a7, a5, null, priv, prin); function saveFavicon() { var uri = gBrowser.currentURI; function getSiteName() { try { var domain = uri.host.split('.') } catch(e) { return "" }; domain = (domain.length == 2) ? domain[0] : domain[1] return domain.charAt(0).toUpperCase() + domain.slice(1).split('.')[0] + " "; }; var url = gBrowser.selectedTab.image; url && saveImageURL( url, getSiteName(), null, false, false, null, null, /^data:(image\/[^;,]+)/i.test(url) ? RegExp.$1.toLowerCase() : Cc["@mozilla.org/mime;1"] .getService(Ci.nsIMIMEService).getTypeFromURI(Services.io.newURI(url)), null, PrivateBrowsingUtils.isContentWindowPrivate(content || window), document.nodePrincipal ); }; function copyFaviconData() { var img = new Image(); img.src = gBrowser.selectedTab.image; WebScreenShotonImage(img); }; (popup => addEventListener("popupshowing", { handleEvent(e) { if (this.shouldHide) return; var menuitem = document.createXULElement("menuitem"); menuitem.id = "content-baseItem"; menuitem.className = "menuitem-iconic"; menuitem.setAttribute("oncommand", "copyImageAsBase64()"); menuitem.setAttribute("label", "Запомнить изображение как base64"); menuitem.setAttribute("image", "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AIAQ/wCAEf8AgA//AIAR/wCAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AgBX/AIAVAAAAAAAAAAD/AIAo/wCA//8AgP//AID//wCA//8AgP//AIAoAAAAAAAAAAAAAAAAAAAAAP8AgBL/AID//wCA//8AgA3/AIAL/wCA//8AgP//AID//wCA//8AgP//AID//wCA//8AgBAAAAAAAAAAAAAAAAD/AIAR/wCA//8AgP//AIAK/wCACv8AgP//AID//wCAIf8AgAX/AIAh/wCA//8AgP//AIAQAAAAAAAAAAAAAAAA/wCACv8AgP//AID//wCAB/8AgAf/AID//wCA//8AgAUAAAAA/wCABf8AgP//AID//wCACgAAAAD/AIAQ/wCADP8AgCH/AID//wCA//8AgAf/AIAH/wCA//8AgP//AIAh/wCABf8AgCH/AID//wCA//8AgAv/AIAh/wCA//8AgP//AID//wCA//8AgP//AIAH/wCAB/8AgP//AID//wCA//8AgP//AID//wCA//8AgP//AIAg/wCA//8AgP//AID//wCA//8AgP//AID//wCAB/8AgAf/AID//wCA//8AgP//AID//wCA//8AgP//AIAh/wCAC/8AgP//AID//wCAHP8AgBz/AID//wCA//8AgAf/AIAH/wCA//8AgP//AIAh/wCACf8AgA7/AIAMAAAAAP8AgAj/AID//wCA//8AgAP/AIAD/wCA//8AgP//AIAH/wCAB/8AgP//AID//wCABQAAAAAAAAAA/wCADf8AgAr/AIAL/wCA//8AgP//AIAH/wCAB/8AgP//AID//wCAB/8AgAr/AID//wCA//8AgCH/AIAH/wCAJf8AgP//AID//wCAI/8AgP//AID//wCAB/8AgAf/AID//wCA//8AgAf/AIAL/wCA//8AgP//AID//wCA//8AgP//AID//wCA//8AgCT/AID//wCA//8AgAr/AIAK/wCA//8AgP//AIAKAAAAAP8AgCj/AID//wCA//8AgP//AID//wCA//8AgCP/AIAM/wCA//8AgP//AIAN/wCADf8AgP//AID//wCADQAAAAAAAAAA/wCAEP8AgBH/AIAP/wCAEf8AgBAAAAAAAAAAAP8AgBT/AIAVAAAAAAAAAAD/AIAV/wCAFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//+sQcH5rEGA8KxBAHCsQQBwrEEIQKxBAACsQQAArEEAAKxBAQCsQQwArEEAAKxBAACsQYAArEHBmaxB//+sQQ=="); popup.append(menuitem); addDestructor(() => menuitem.remove()); menuitem.copyImageAsBase64 = () => { var {osPid} = gContextMenu.actor.manager.browsingContext.currentWindowGlobal; if (osPid == -1) osPid = Services.appinfo.processID; for(var ind = 0, len = Services.ppmm.childCount; ind < len; ind++) { var pmm = Services.ppmm.getChildAt(ind); if (pmm.osPid == osPid) break; } pmm.loadProcessScript("data:;charset=utf-8," + encodeURIComponent(this.code()), false); } this.handleEvent = () => menuitem.hidden = this.shouldHide; }, get shouldHide() { return !(gContextMenu.onImage && Services.prefs.getBoolPref("Save.WebScreenShotOnImage", false)); }, code: () => `(targetIdentifier => { var image = ChromeUtils.import("resource://gre/modules/ContentDOMReference.jsm") .ContentDOMReference.resolve(targetIdentifier); var canvas = image.ownerDocument.createElementNS("${xhtmlns}", "canvas"); canvas.width = image.naturalWidth; canvas.height = image.naturalHeight; var ctx = canvas.getContext("2d"); ctx.drawImage(image, 0, 0); var base64 = canvas.toDataURL(); Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper) .copyStringToClipboard(base64, Ci.nsIClipboard.kGlobalClipboard); Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService) .showAlertNotification(base64, "${self.label}", "Запомнил изображение как base64"); })(${ JSON.stringify(gContextMenu.targetIdentifier) })` }, false, popup || 1))(document.getElementById("contentAreaContextMenu")); function saveSelectionToTxt() { var {length} = saveURL, splice = length > 9, l11 = length == 11; var msgName = _id + ":Save:GetSelection"; var receiver = msg => { var args = [ "data:text/plain," + encodeURIComponent(gBrowser.currentURI.spec + "\r\n\r\n" + msg.data), getTabLabel() + ' ' + aDate().replace(/:/g, ".") + ".txt", null, false, false, null, window.document ]; splice && args.splice(5, 0, null) && l11 && args.splice(1, 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("NAME", res); } var url = "data:charset=utf-8," + encodeURIComponent(`(${func})`.replace("NAME", msgName)) + '(Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager));'; (saveSelectionToTxt = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))(); } ((contextMenu, el)=> { var saveItem = contextMenu.insertBefore(document.createXULElement("menuitem"), el); saveItem.id = "content-saveItem"; saveItem.setAttribute("label", "Сохр./добавить выбранный текст в файл"); saveItem.setAttribute("class", "menuitem-iconic"); saveItem.setAttribute("image", "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAADAgBEDRIXnwxQjKQNWp6pDFWXqAxXm6gMV5moDFeaqAxXmqgMV5qoDFebqAxVlqgNW5+pCkyIogwSFqgDAgBHDQoFhyszOv8hheP+IJH7/x+L8v8fjfb/H433/x+N9v8fjfb/H432/x+N9/8fi/L/IJH7/yGF5P0kLTTvDAcDgwgICIQ8Ojf/0czA+Oji1fzh18r85NzO/OTbz/zj287849vO/OPbzvzk3M/84dfK++ji1f3Sy8D5NDIvywYGB3kKCgqFQ0A8/+XXw/v979f/9uTO//rp0f/66NH/+ujR//rn0f/66NH/+ujR//bkzv/979f/5tfD/UZBPv8KCwqEDQwMhUVDQP/f08X7+OrZ/+zf0P/v5NP/8OPT/+/j0//v4tP/8OPT/+/j0//s39D/+OrZ/+DTxfxEQj//DAwMhA8PD4VKR0T/4dXG+/rr2v/v4tH/9OXU//Ll1P/z5dT/8+XU//Pl1P/05NT/7+DR//rr2v/i1cX7SkhE/w8PD4USEhKFT0xI/+XXxfv97tr/9ePR//no1P/459T/+OfU//jn1P/459T/+OfU//Xk0f/97tr/5dfF+09MSf8SEhGFFRQUhVNQTv/j2cv7+u/g//Hm2P/169v/9Orb//Tq2//06tv/9erb//br3P/x5tf/+e/g/+PZzPtTUU7/FBQUhRgXF4VXU1D/2828+/Lk0f/q2sf/7d3K/+3dyv/t3cr/7N3K/+rayP/r28n/69vI//Ll0v/azbv7VlNP/xgXF4UfHh6FTktJ/1JOTPtZVFL/Uk5L/1FNSv9RTUr/UU1K/1JPTP9YVVD/VVJP/09NSv9WUk//UU1L+05LSf8fHh2FIR8fhVVTUP9FQkD7UlBM/6Wlj/+4uJ7/sLCX/7S0mv+xsJn/oKCQ/6+vmv+hoYv/TEtH/0NCQPtVUk//IR8fhSMhIIVcWVb/SEVF+19dVv/f3sP////e//X10v///93/2di8/1lYWP+eno//5+fG/19dV/9JRkb7W1hV/yMhIYUkJCOFXltZ/0tJSPtdW1f/0NC4/+/u1P/h4cj/8PDV/7++q/8vLC7/e3lw/9fWv/9eXVf/TElJ+15bWf8lJCKEJSQjhF9cWf9LSUf5XVtX/tbVwf/5+OL/6enV//j54v/GxrX/QD0+/42Kgv/d3cr/YF5a/k5LSvlhXlv/JSUjhCkoKIZpZWT/VVJR/WNhXP/V1cT//f3s/+3t3v/8/Or/zc2//01LSf+VlIz/4eDS/2hmYv9YVVT8aWVj/ycmJoIaGRlYSEVE1DYzM8NKSUfP0dHG9/X16P/n59v+7e3g/+jo3f/X2M3+6uve/9bWzPdOTUvNOjg3y0RBQLwPDw8lAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="); saveItem.onclick =()=> saveSelectionToFile(); var editorItem = contextMenu.insertBefore(document.createXULElement("menuitem"), el); editorItem.id = "content-editorItem"; editorItem.setAttribute("label", "Открыть выбранный текст в редакторе"); editorItem.setAttribute("class", "menuitem-iconic"); editorItem.setAttribute("image", "data:image/x-icon;base64,AAABAAEAEBAAAAEACABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAQAEAAAAAAAAAAAAAAAEAAAAAAAAAAAAA////AIiafwC85K4AS1ZGANLsyABKU0UAy+m+AL/lsQC14aQAn9WMAJ/QjQCsrKwAqNyXAOPz3ADe8dcA2e/QANPtyQDM68EAxei4AL7lrwC14aUArt6dAJfOhACdz4sAgICAALThpQDg8doA3vHVANjuzgDR7MYAyum+AMLmtQC7460AsuCjAK3dmgCUy4AArdedANDsxQDL6sAAz+PIAMviwwDH4L4Awd62ALvbrwC02KcArdafAKbTlgCEu3EAtNWoANPqywDa8NIA1u7NANHtxwDK6cAAw+e3ALzkrwC14aYAr9+dAKXbkQCJwnMA1+3QAKncmADd8dQAyuLBAMbgvAC6264AttmoAK/XoACn1JYAotKPAJbNgwB9tWgA4+zfANju0ADT7coAz+vFAMPntgC95K8Art6eAKndlQCa1IYAi8R3AP3+/QDD37kAvt2yALjarACz2KYArdaeAKHRjwCXzoUAj8V6AI6/ewDu8e4Awea2AMrqwQDG6LoAweazALnjqwCz4KQAr9+cAKbbkwCd2IkAlc1/AKbTlQC73K8At9qqALDXowCp1ZsApdOVAKDRjQCYzoUAksx7AIi+cwCu0aEAp9yUAMXougDC5rYAveSuALfipwCw4J8AqdyXAKLajwCd2IcAlNR9AI3FdwDU6ssAqdWZAKPSkgCe0YsAmc6GAJDLfQB/tmoA3enZAJfWhACc2IkApNuRAKTbkACj2pAAodqOAKHZjgCl25IAotmOAIzHdgAPAAAA2JIKAAAA9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOzARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACcrkUA9CUMAAAAAAAAAAAAAAAAAAAAAAAAAA8AAQAAAAEAAAAAAAAAVCIMAAAAAAABAAAAuwP/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAACZDSMAAQAAAAAAAAAAAAAAAAAAAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAABAEAABHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGRkZGRkZGRkZAAAAAAAZAQEBAQEBAQEBARkAAIeHiImKi4yNjY5+AQEZAD4mJlZXRH+AgYKDhIVdGQBzJnR1dnd4eXp7fH1+ARkAGiYnaWprbG1ub3Bxcl0ZACdeJl9gYWJjZGVmZ2gBGQAAAyZUVVZXWEVZWltcXRkAAA1KS0wfTU45T1BRUlMZAAA+P0BBK0JDREVGR0hJGQAAAzIzNDU2Nzg5Ojs8PRkAACYnKCkqKywtLi8YMDEZAAAAGhscHR4fICEiIyQlGQAAAA0ODxAREhMUFRYXGBkAAAADBAUGBwYIBgkGChkAAAAAAAACAAIAAgACAAIAAPgBAADwAAAAwAAAAIAAAACAAAAAgAAAAIAAAADAAAAAwAAAAMAAAADAAAAAwAAAAOAAAADgAAAA4AEAAPqrAAA="); editorItem.onclick =()=> textToEditor(); addEventListener('popupshowing', e=> { if (e.target != e.currentTarget) return; var sel = gContextMenu.isTextSelected; saveItem.hidden = !sel || !cbu.getPrefs("Save.SelectionToFile"); editorItem.hidden = !sel || !cbu.getPrefs("Save.TextToEditor"); }, false, contextMenu); addDestructor(()=> { saveItem.remove(); editorItem.remove(); }); })(document.getElementById("contentAreaContextMenu"), document.getElementById("context-sep-open")); function saveSelectionToFile() { var line = ".".repeat(62) + "\n"; var hint = "Нажмите чтобы открыть файл"; var prfx = "Выделенный текст сохранен в файл "; var img = self.getAttribute("image"); var desk = Services.dirsvc.get("Desk", Ci.nsIFile); var as = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService); (saveSelectionToFile = async () => { var time = aDate(), url = gBrowser.currentURI.displaySpec; var text = `${line}${getTabLabel()} - ${time}\n${url}\n\n${ gContextMenu.contentData.selectionInfo.fullText }\n\n\n`; try { var file = Services.prefs.getComplexValue("browser.download.dir", Ci.nsIFile); var msg = prfx + "в папку " + file.leafName; await IOUtils.makeDirectory(file.path); } catch(ex) { file && Cu.reportError(ex); file = desk.clone(); var msg = prfx + "на рабочий стол"; } file.append(`Save - ${time}.txt`); await IOUtils.writeUTF8(file.path, text, {mode: file.exists() ? "append" : "create"}); var name = "sstf-" + Cu.now(); as.showAlertNotification( gBrowser.selectedTab.image || img, msg, hint, true, "", (s, t) => t == "alertclickcallback" && file.launch(), name ); setTimeout(as.closeAlert, 8e3, name); })(); }; function textToEditor() { let browserMM = gBrowser.selectedBrowser.messageManager; browserMM.addMessageListener('getSelect', function listener(message) { var text = convertFromUnicode("UTF-8", message.data); try {var file = Services.prefs.getComplexValue("browser.download.dir", Ci.nsIFile);} catch {file = Services.dirsvc.get("Desk", Ci.nsIFile);} file.append("TextToEditor.txt"); custombuttonsUtils.writeFile(file.path, text); file.launch(); browserMM.removeMessageListener('getSelect', listener, true); }); browserMM.loadFrameScript('data:,sendAsyncMessage("getSelect", content.document.getSelection().toString())', false); }; function convertFromUnicode(charset, str) { var converter = Cc['@mozilla.org/intl/scriptableunicodeconverter'].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); converter.charset = charset; str = converter.ConvertFromUnicode(str); return str + converter.Finish(); }; function getTabLabel() { var label = gBrowser.selectedTab.label; var label = label.replace(/[:+.\\\/<>?*|"]+/g, " ").replace(/\s\s+/g, " "); return label.substring(0, 50); }; ((main, parts) => this.onmousedown = e => { if (e.button) return; this.onmousedown = null; var df = MozXULElement.parseXULToFragment(` <menugroup orient="vertical"> <menuseparator/> <menuitem class="menuitem-iconic" image="data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAzAAAAiAcFBa4KCQmvCgkJrwoJCa8KCQmvCgkJrwoJCa8KCQmvCgkJrwoJCa8KCQmvCgkJrwsJCaECAQE/BQMDAAAAAJUgICD4V1ZW/2FhYf5hYWH/YmFh/2BgYP9fX1//X19f/19fX/9gYGD/YmFh/2FhYf9gYGD+ZmVl/1RSUuIVFBQtCgkJy1paWv+Li4v9h4eH/oiIiP6FhYX+i4uL/pKSkv6Sk5P+kpKS/ouLi/6FhYX+iIiI/oiIiP6Hh4f7lZaW/25tbYQNDQ3OcHBw/5KSkv6Li4v/i4uL/5mZmf+EhIT/ZGRk/1tbWv9kZGT/hISE/5mZmf+Li4v/jY2N/4yMjPyWl5f/iomJjQ4NDc13d3f/m5ub/pWVlf+goKD/XFxc/ygoKP8fHyD/GBsb/yAhIv8pKSn/W1tb/6CgoP+Wlpb/lpaW/J6env+Jh4eMDg4OzX1+fv+ioqL+qqqq/1hYWP8ZGRn/Ghwb/x4dHP8mIh//FhQR/xUWF/8aGhr/WFhY/6urq/+cnJz8pKSk/4qJiYwPDg7Ng4OD/7W1tf6MjIz/Ghoa/xYYGP8uKCb/ZEAo/5xyOP++saL/RD45/xISE/8bGxv/jY2N/6+vr/ypqan/ioiIjA8PD82IiIj/xMTE/l1cXP8LDAz/JiId/1o3LP9ADgD/mGog//Dt6P/VysX/Ih4Z/wsMDf9eXl7/v7+//K6urv+KiYmMEA8PzY+Pj//Kysr+SEhH/wEDBv9MPi7/hlES/3dCAP+VZAn/tJVO/7eVXf9OQTL/AAIE/0pJSf/FxcX8tLS0/4qJiYwQEBDNm5ub/9/e3/5SUlL/AAAA/0M7Mf/aya7/ybiO/5RmEf9aIAD/cjkX/z80KP8AAAD/U1JS/9nZ2fzAwMD/i4qKjBEREc2oqKn/8O/w/oeGhv8AAAD/DAsK/6qkof/17uj/nW8l/14eCf9hPTr/ExUU/wAAAP+Hh4f/6urq/MzMzf+Mi4uMERERzbCwsv/r6uz+3Nzd/yoqKv8AAAD/ExEP/2heU/9yWjv/UD0u/xcXFv8AAAD/Kioq/93d3v/l5eb81NTV/4yLi4wSERHNuLm5/+/v8P7z8/P/xsbG/yAgIP8AAAD/AQEB/wAAAP8BAQH/AAAA/yAgIP/Gxsb/9PT0/+np6vzb29v/jIuLjBIREc2+vb7/+Pj5/uvr7P/7+/v/4ODg/3Nyc/8uLi7/Hh4d/y0sLP9zc3P/4ODg//v7+//s7O3/8/P0/OHg4f+Mi4uLFBMTyMPDw//////7+Pj4/ff29v38/Pz9/////fr6+v3u7u79+vr6/f////38/Pz99/b2/fn5+f37+/v53t7e/5KSko4GBgZ7m5yc//j4+P/w8fH/8fLy//Dw8P/u7u7/8vLy//X19f/y8vL/7u7u//Dw8P/x8vL/8vLy/uXl5f/BwcH+k5GRUAAAAAQeHR1yb25uxn59fcZ9fHzGfXx8xn18fMZ9e3vGfHt7xn17e8Z9fHzGfXx8xn18fMZ9fHzGgH9/xYmIiGVaV1cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" label="Сохранить всю страницу как PNG" value="all"/> <menuitem class="menuitem-iconic" image="data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAzAAAAiAcFBa4KCQmvCgkJrwoJCa8KCQmvCgkJrwoJCa8KCQmvCgkJrwoJCa8KCQmvCgkJrwsJCaECAQE/BQMDAAAAAJUgICD4V1ZW/2FhYf5hYWH/YmFh/2BgYP9fX1//X19f/19fX/9gYGD/YmFh/2FhYf9gYGD+ZmVl/1RSUuIVFBQtCgkJy1paWv+Li4v9h4eH/oiIiP6FhYX+i4uL/pKSkv6Sk5P+kpKS/ouLi/6FhYX+iIiI/oiIiP6Hh4f7lZaW/25tbYQNDQ3OcHBw/5KSkv6Li4v/i4uL/5mZmf+EhIT/ZGRk/1tbWv9kZGT/hISE/5mZmf+Li4v/jY2N/4yMjPyWl5f/iomJjQ4NDc13d3f/m5ub/pWVlf+goKD/XFxc/ygoKP8fHyD/GBsb/yAhIv8pKSn/W1tb/6CgoP+Wlpb/lpaW/J6env+Jh4eMDg4OzX1+fv+ioqL+qqqq/1hYWP8ZGRn/Ghwb/x4dHP8mIh//FhQR/xUWF/8aGhr/WFhY/6urq/+cnJz8pKSk/4qJiYwPDg7Ng4OD/7W1tf6MjIz/Ghoa/xYYGP8uKCb/ZEAo/5xyOP++saL/RD45/xISE/8bGxv/jY2N/6+vr/ypqan/ioiIjA8PD82IiIj/xMTE/l1cXP8LDAz/JiId/1o3LP9ADgD/mGog//Dt6P/VysX/Ih4Z/wsMDf9eXl7/v7+//K6urv+KiYmMEA8PzY+Pj//Kysr+SEhH/wEDBv9MPi7/hlES/3dCAP+VZAn/tJVO/7eVXf9OQTL/AAIE/0pJSf/FxcX8tLS0/4qJiYwQEBDNm5ub/9/e3/5SUlL/AAAA/0M7Mf/aya7/ybiO/5RmEf9aIAD/cjkX/z80KP8AAAD/U1JS/9nZ2fzAwMD/i4qKjBEREc2oqKn/8O/w/oeGhv8AAAD/DAsK/6qkof/17uj/nW8l/14eCf9hPTr/ExUU/wAAAP+Hh4f/6urq/MzMzf+Mi4uMERERzbCwsv/r6uz+3Nzd/yoqKv8AAAD/ExEP/2heU/9yWjv/UD0u/xcXFv8AAAD/Kioq/93d3v/l5eb81NTV/4yLi4wSERHNuLm5/+/v8P7z8/P/xsbG/yAgIP8AAAD/AQEB/wAAAP8BAQH/AAAA/yAgIP/Gxsb/9PT0/+np6vzb29v/jIuLjBIREc2+vb7/+Pj5/uvr7P/7+/v/4ODg/3Nyc/8uLi7/Hh4d/y0sLP9zc3P/4ODg//v7+//s7O3/8/P0/OHg4f+Mi4uLFBMTyMPDw//////7+Pj4/ff29v38/Pz9/////fr6+v3u7u79+vr6/f////38/Pz99/b2/fn5+f37+/v53t7e/5KSko4GBgZ7m5yc//j4+P/w8fH/8fLy//Dw8P/u7u7/8vLy//X19f/y8vL/7u7u//Dw8P/x8vL/8vLy/uXl5f/BwcH+k5GRUAAAAAQeHR1yb25uxn59fcZ9fHzGfXx8xn18fMZ9e3vGfHt7xn17e8Z9fHzGfXx8xn18fMZ9fHzGgH9/xYmIiGVaV1cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" label="Сохранить видимую часть страницы как PNG" value="page"/> <menuitem class="menuitem-iconic" image="data:image/x-icon;base64,AAABAAEAIBkAAAEAIAAMDQAAFgAAACgAAAAgAAAAMgAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29fT/2tra/8jIyP/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8jIyP/a2tr/9vX0/+zs7P/ak0b/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/9qTRv/s7Oz/7Ozs/+J9Dv/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+/6SdmP/8+/r//Pv6//z7+v/8+/r//Pv6//z7+v/8+/r//Pv6//z7+v/8+/r/+vn4//z7+v/6+fj/4n0O/+zs7P/s7Oz/4n0O//z7+v/8+/r//Pv6//z7+v/8+/r//Pv6//z7+v/8+/r//Pv6//z7+v/8+/r//Pv6//z7+v/8+/r/aFtT//Lw7//y8O//8vDv//Lw7//y8O//8vDv//Lw7//y8O//8vDv//Lw7//y8O//8vDv//j39v/ifQ7/7Ozs/+zs7P/ifQ7/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P9oW1P/7+zq/+/s6v/v7Or/8O3r//Dt6//w7ev/8O3r//Dt6//w7ev/8O3r/+/s6v/w7ev/9fTy/+J9Dv/s7Oz/7Ozs/+J9Dv/49/b/+Pf2//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4/2hbU//q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/y8O//4n0O/+zs7P/s7Oz/4n0O//j39v/49/b/+Pf2//j39v/49/b/+Pf2//j39v/49/b/+Pf2//j39v/49/b/+Pf2//j39v/49/b/aFtT/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe//Dt6//ifQ7/7Ozs/+zs7P/ifQ7/9vX0//b19P/29fT/9vX0//b19P/29fT/9vX0//b19P/29fT/9vX0//b19P/29fT/9vX0//b19P9oW1P/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/7uro/+J9Dv/s7Oz/7Ozs/+J9Dv/08vH/9PLx//Ty8f/08vH/9PLx//Ty8f/08vH/9PLx//Ty8f/08vH/9PLx//Ty8f/08vH/9PLx/2hbU//x7+3/8vDv//Hv7f/x7+3/8e/t//Lw7//x7+3/8e/t//Lw7//x7+3/8vDv//Hv7f/29fT/4n0O/+zs7P/s7Oz/4n0O//Lw7//y8O//8vDv//Lw7//y8O//8vDv//Lw7//y8O//8vDv//Lw7//y8O//8vDv//Lw7//y8O//aFtT/6igmP+ooJj/qKCY/6igmP+ooJj/qKCY/6igmP+ooJj/qKCY/6igmP+ooJj/qKCY/8vGwf/ifQ7/7Ozs/+zs7P/ifQ7/8e/t//Hv7f/x7+3/8e/t//Hv7f/x7+3/8e/t//Hv7f/x7+3/8e/t//Hv7f/x7+3/8e/t//Hv7f9nWlL/aFtT/2hbU/9nWlL/Z1pS/2hbU/9oW1P/Z1pS/2daUv9oW1P/aFtT/2hbU/9nWlL/pJyX/+J9Dv/s7Oz/7Ozs/+J9Dv/w7ev/8O3r//Dt6//w7ev/8O3r//Dt6//x7+3/8O3r//Dt6//w7ev/8e/t//Dt6//w7ev/8O3r//Hv7f/w7ev/8O3r//Dt6//x7+3/8O3r//Dt6//w7ev/8e/t//Dt6//w7ev/8O3r//Dt6//w7ev/4n0O/+zs7P/s7Oz/4n0O/+/s6v/v7Or/7uro/+/s6v/v7Or/7+zq/+/s6v/v7Or/7+zq/+/s6v/v7Or/7+zq/+/s6v/v7Or/7+zq/+/s6v/v7Or/7+zq/+/s6v/v7Or/7+zq/+/s6v/v7Or/7+zq/+/s6v/u6uj/7+zq/+/s6v/ifQ7/7Ozs/+zs7P/ifQ7/7uro/+7q6P/u6uj/7uro/+zo5v/u6uj/7uro/+7q6P/s6Ob/7uro/+7q6P/u6uj/7Ojm/+7q6P/u6uj/7uro/+zo5v/u6uj/7uro/+7q6P/s6Ob/7uro/+7q6P/u6uj/7Ojm/+7q6P/u6uj/7Ojm/+J9Dv/s7Oz/7Ozs/+J9Dv/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/4n0O/+zs7P/s7Oz/4n0O/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/ifQ7/7Ozs/+zs7P/ifQ7/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+J9Dv/s7Oz/7Ozs/+J9Dv/m4d7/5uHe/+bh3v/p5eL/5uHe/+bh3v/m4d7/6eXi/+bh3v/m4d7/5uHe/+nl4v/m4d7/5uHe/+bh3v/p5eL/5uHe/+bh3v/m4d7/6eXi/+bh3v/m4d7/5uHe/+nl4v/m4d7/5uHe/+bh3v/p5eL/4n0O/+zs7P/s7Oz/4n0O/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/ifQ7/7Ozs/+zs7P/ifQ7/5uHe/+Tf3P/m4d7/5N/c/+bh3v/k39z/5uHe/+Tf3P/m4d7/5N/c/+bh3v/k39z/5uHe/+Tf3P/m4d7/5N/c/+bh3v/k39z/5uHe/+Tf3P/m4d7/5N/c/+bh3v/k39z/5uHe/+Tf3P/m4d7/5N/c/+J9Dv/s7Oz/7Ozs/+J9Dv/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/k39z/4n0O/+zs7P/s7Oz/4n0O/+Lc2f/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/ifQ7/7Ozs/+zs7P/ifQ7/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+J9Dv/s7Oz/9fTy/+J9Dv/8+/r/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/4n0O//X08v/8+/r/6KFU/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ooVT//Pv6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" label="Сохранить выбранный элемент страницы как PNG" value="click"/> <menuitem class="menuitem-iconic" image="data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAADDn2Hfz5pE/8eVQP7IlkH/yJZB/8iWQf/IlUH/yJVA/8iVQP/IlED/yJQ//8iUP//IlD//yJM+/8iTPv/Hkj3/nI1w//bDbP//8OH//+zW///s1///69b//+rV///p1P//59L//+XQ///izf//38n//9vG///ZxP//1b///dG////Prf/KlkX/88N4/v37///99Pj//fT6//vy9v/68fT/+u/y//rt8P/66u3/+ufq//rl6P/64eT/+93h//3a3//71d7//9LK/86XR//0xHb//vv////18///9fT///f5///4////9f7///P8///v+f//7Pb//+nz///m8f//4eb//9vZ//3Y2v//1Mb/zphH//TGd//+/////Pj1///7///Q58r/m9aV/6TZnv+i15r/otWY/6LTlv+j0pb/mc6M/9DXuf//3+P//Nnc///Wyf/OmUf/9MZ3//7////8+/j//////53WnP+Y5pn/rvGv/6PvpP+e7p//me6b/5nvm/95533/mM+L///j7f/629z//9jL/86ZR//0xnf//v////z9+v//////qtup/8Xzxf/a/tn/z/vO/8n7yf/D+sL/xPvD/6Hzo/+j05b//+Tu//re3///2cz/zplI//XGeP/+/////P36//////+n26f/uvC6/9T71P/K+Mr/xvjG/8D3wP+/+L//nfCf/6LTlf//5u//+t/g///cz//OmUj/9MZ3//7////8/fr//////6rcqv/G9MX/3//f/9n92f/V/NX/0PzQ/9H+0P+s9a7/pdSY///o8f/64OL//9zP/86aSP/0xnf//v////z9+f//////ndid/5TjlP+v7q//qeyp/6jsqf+k7KX/p+6n/4Tlh/+Z0Y7//+r0//rh4v//3tH/zppI//TGd//+/////v77///////Y8Nj/p9+n/6/jr/+t4a3/rd2p/67bpv+u2ab/p9Wc/9jgx///6Oz//OPl///e0f/Omkj/9MV1//7//////fr///78///+/f///////////////////P////j////0+///8fn//+vu///m4v/94+P//97P/86ZSP/zx3v//v/////+/f///////f////v////7////+/////v+///7+///+/f///vz/P/98Pr//+33//3p9///5OL/zppL//a1Sv/0xoL/9cR7//XEfP/1xHz/9cR8//XEfP/1xH3/9cR8//XCev/1wXr/9b94//W9d//1u3X/87l0//y6bP/Llj7/+pMA/vWBAP/1gwD/9YMA//WDAP/1gwD/9YMA//WDAP/1gwD/9YQA//WEAP/1hAD/9YQA//WEAP/zhAH//okA/8qLIv3xpzP/4ptV/+OdU//jnVP/451T/+OdU//jnVP/451T/+OdU//jnVL/451S/+OdUv/jnVL/451S/+GdVf/qnUf/2aRJ/9q0c9/8yn7/98V5/vjGev/4xnr/+MZ6//jGev/4xnr/+MZ6//jGev/4xnr/+MZ6//jGev/4xnr/+MZ6/vrIe/+jj2y4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" label="Сохранить выбранную область страницы как PNG" value="clipping"/> </menugroup> `); var menugroup = df.firstChild; menugroup.setAttribute("context", ""); menugroup.setAttribute("oncommand", "handleCommand(event);"); menugroup.handleCommand = e => { var name = _id + ":DataURLReady"; main = main.replace("%MESSAGE_NAME%", name); var urls = {}, configurable = true, enumerable = true; Object.entries(parts).forEach(([key, part]) => Object.defineProperty(urls, key, { configurable, enumerable, get() { var value = `data:;charset=utf-8,({${ encodeURIComponent(main + part) }%0A}).init("${key}")`; Object.defineProperty(urls, key, {configurable, enumerable, value}); return value; }})); var getTabLabel = () => { var label = gBrowser.selectedTab.label; var label = label.replace(/[:+.\\\/<>?*|"]+/g, " ").replace(/\s\s+/g, " "); return label.substring(0, 50); } var listener = msg => { var fp = makeFilePicker(); fp.init(window, "Сохранить как…", fp.modeSave); fp.appendFilter("", "*.png"); fp.defaultString = getTabLabel() + ".png"; fp.open(res => { if (res == fp.returnCancel || !fp.file) return; var wbp = makeWebBrowserPersist(), args = [ Services.io.newURI(msg.data), document.nodePrincipal, null, null, null, null, fp.file, null ]; var {length} = wbp.saveURI; length >= 9 && splice(args); length == 10 && args.splice(3, 0, null); wbp.saveURI(...args); setTimeout(async lp => { var d = await Downloads.createDownload({ source: "about:blank", target: fp.file }); (await lp).add(d); d.refresh(d.succeeded = true); }, 777, Downloads.getList(Downloads.ALL)); }); } var splice = arr => { var fox74 = parseInt(Services.appinfo.platformVersion) >= 74; var args = [fox74 ? 7 : 2, 0, fox74 ? Ci.nsIContentPolicy.TYPE_IMAGE : null]; (splice = arr => arr.splice(...args))(arr); } messageManager.addMessageListener(name, listener); addDestructor(() => messageManager.removeMessageListener(name, listener)); (menugroup.handleCommand = e => gBrowser.selectedBrowser.messageManager .loadFrameScript(urls[e.target.value], false) )(e); } menuPopup.querySelector('menuitem[label*="ярлык"]').after(df); })(` init(cmd) { cmd.startsWith("c") ? this[cmd].init(this[cmd].parent = this) : this[cmd](); }, capture(win, x, y, width, height) { var canvas = win.document.createElementNS("${xhtmlns}", "canvas"); canvas.width = width; canvas.height = height; var ctx = canvas.getContext("2d"); var tryDraw = ind => { try {ctx.drawWindow(win, x, y, canvas.width, canvas.height, "white")} catch(ex) {canvas.height = ind * canvas.width; tryDraw(--ind);} } tryDraw(17); sendAsyncMessage("%MESSAGE_NAME%", canvas.toDataURL("image/png")); }, `, { all: `all() { var win = content; this.capture(win, 0, 0, win.innerWidth + win.scrollMaxX, win.innerHeight + win.scrollMaxY); }`, page: `page() { var win = content, doc = win.document, body = doc.body, html = doc.documentElement; var scrX = (body.scrollLeft || html.scrollLeft) - html.clientLeft; var scrY = (body.scrollTop || html.scrollTop) - html.clientTop; this.capture(win, scrX, scrY, win.innerWidth, win.innerHeight); }`, clipping: `clipping: { handleEvent(e) { if (e.button) return false; e.preventDefault(); e.stopPropagation(); switch(e.type) { case "mousedown": this.downX = e.pageX; this.downY = e.pageY; this.bs.left = this.downX + "px"; this.bs.top = this.downY + "px"; this.body.appendChild(this.box); this.flag = true; break; case "mousemove": if (!this.flag) return; this.moveX = e.pageX; this.moveY = e.pageY; if (this.downX > this.moveX) this.bs.left = this.moveX + "px"; if (this.downY > this.moveY) this.bs.top = this.moveY + "px"; this.bs.width = Math.abs(this.moveX - this.downX) + "px"; this.bs.height = Math.abs(this.moveY - this.downY) + "px"; break; case "mouseup": this.uninit(); break; } }, init() { var win = {}; Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager) .getFocusedElementForWindow(content, true, win); this.win = win.value; this.doc = this.win.document; this.body = this.doc.body; if (!HTMLBodyElement.isInstance(this.body)) { Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService) .showAlertNotification("${self.image}", ${JSON.stringify(self.label)}, "Не удается захватить!"); return false; } this.flag = null; this.box = this.doc.createElement("div"); this.bs = this.box.style; this.bs.border = "#0f0 dashed 2px"; this.bs.position = "absolute"; this.bs.zIndex = "2147483647"; this.defaultCursor = this.win.getComputedStyle(this.body, "").cursor; this.body.style.cursor = "crosshair"; ["click", "mouseup", "mousemove", "mousedown"].forEach(type=> this.doc.addEventListener(type, this, true)); }, uninit() { var pos = [this.win, parseInt(this.bs.left), parseInt(this.bs.top), parseInt(this.bs.width), parseInt(this.bs.height)]; this.body.style.cursor = this.defaultCursor; this.body.removeChild(this.box); this.parent.capture.apply(this, pos); ["click", "mouseup", "mousemove", "mousedown"].forEach(type=> this.doc.removeEventListener(type, this, true)); } }`, click: `click: { getPosition() { var html = this.doc.documentElement; var body = this.doc.body; var rect = this.target.getBoundingClientRect(); return [ this.win, Math.round(rect.left) + (body.scrollLeft || html.scrollLeft) - html.clientLeft, Math.round(rect.top) + (body.scrollTop || html.scrollTop) - html.clientTop, parseInt(rect.width), parseInt(rect.height) ]; }, highlight() { this.orgStyle = this.target.hasAttribute("style") ? this.target.style.cssText : false; this.target.style.cssText += "outline: red 2px solid; outline-offset: 2px; -moz-outline-radius: 2px;"; }, lowlight() { if (this.orgStyle) this.target.style.cssText = this.orgStyle; else this.target.removeAttribute("style"); }, handleEvent(e) { switch(e.type){ case "click": if (e.button) return; e.preventDefault(); e.stopPropagation(); this.lowlight(); this.parent.capture.apply(this, this.getPosition()); this.uninit(); break; case "mouseover": if (this.target) this.lowlight(); this.target = e.target; this.highlight(); break; } }, init() { this.win = content; this.doc = content.document; ["click", "mouseover"].forEach(type=> this.doc.addEventListener(type, this, true)); }, uninit() { this.target = false; ["click", "mouseover"].forEach(type=> this.doc.removeEventListener(type, this, true)); } }` });
try {CustomizableUI.createWidget({ id: "ucf-cbbtn-Save", tooltiptext: "Сохранить", localized: false, get initCode() { delete this.initCode; return this.initCode = Cu.readUTF8URI(Services.io.newURI( "chrome://user_chrome_files/content/custom_scripts/custom_script/Save.js" )); }, cbu: { types: { 128: "Bool", boolean: "Bool", 64: "Int", number: "Int", 32: "String", string: "String" }, getPrefs(pref) { try { return Services.prefs[`get${ this.types[Services.prefs.getPrefType(pref)] }Pref`](pref); } catch {return null;} }, setPrefs(pref, val) { Services.prefs[`set${this.types[typeof val]}Pref`](pref, val); } }, gClipboard: { get ch() { delete this.ch; return this.ch = Cc["@mozilla.org/widget/clipboardhelper;1"] .getService(Ci.nsIClipboardHelper); }, write(str) { this.ch.copyStringToClipboard(str, Services.clipboard.kGlobalClipboard); } }, custombuttonsUtils: { writeFile(path, data) { try { if (path.includes(":\\")) path = path.replace(/\//g, "\\"); var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); file.initWithPath(path); file.exists() && file.remove(false); var strm = Cc["@mozilla.org/network/file-output-stream;1"] .createInstance(Ci.nsIFileOutputStream); strm.init(file, 0x04 | 0x08, 420, 0); strm.write(data, data.length); strm.flush(); strm.close(); } catch(ex) { Cu.reportError("Custom Buttons: " + [path, "---", ex, ex.stack].join("\n")); } } }, addDestructor(destructor, context) { this._destructors.push({destructor, context}); }, addEventListener(...args) { var trg = args[3]; if (!trg) trg = args[3] = this.ownerGlobal; trg.addEventListener(...args); this._handlers.push(args); }, onCreated(btn) { var win = btn.ownerGlobal; btn._handlers = new win.Array(); btn._destructors = new win.Array(); win.addEventListener("unload", this, {once: true}); new win.Function( "self,_id,cbu,xhtmlns,addDestructor,addEventListener,gClipboard,custombuttonsUtils", this.initCode ).call( btn, btn, this.id, this.cbu, "http://www.w3.org/1999/xhtml", this.addDestructor.bind(btn), this.addEventListener.bind(btn), this.gClipboard, this.custombuttonsUtils ); }, handleEvent(e) { var btn = e.target.getElementById(this.id); for(var args of btn._handlers) args.pop().removeEventListener(...args); delete btn._handlers; for(var {destructor, context} of btn._destructors) try {destructor.call(context, "destructor");} catch(ex) {Cu.reportError(ex);} delete btn._destructors; } });} catch(ex) {Cu.reportError(ex);}
Отредактировано egorsemenov06 (16-04-2024 10:02:50)
Отсутствует
Поэтому, создавать виджет в окне, в общем случае, не рекомендуется.
……проще всего, в SystemGlobal, но там CustomizableUI надо импортировать.
Хорошо бы, конечно, в сандбоксе UCF, но в окне нет туда прямых ссылок.
Vitaliy V.
В новой версии можно проще общие объекты подключать к UCF вместо браузера?
У меня пока так: в скрипте scriptsbackground: общий объект для вызова из scriptschrome: кода
globalThis[Symbol.for('UcfGlob')] = this.UcfGlob; //общие функции
И почему CustomStylesScripts.mjs расположен отдельно? Ведь после добавления скриптов его надо править (пока не будет GUI-менеджера подключенных скриптов/стилей)
Вообще, в ReadMe не хватает описания функций UserChromeFiles, т.е. нет авторской рекламы!
И если убраны файлы стилей, то хотя бы сохранить их закомментированными в stylesall: [ // For all documents
{ path: "custom_styles_all_agent.css", type: "AGENT_SHEET"},
Отсутствует
вот убрал 1 иконку
Другое дело.
Но, fp.init(window, в трёх местах торчат,
хотя было сказано, что в 125, уже нужно
fp.init(window.browsingContext,
так что нет, не принимается.
Отсутствует
egorsemenov06 пишетвот убрал 1 иконку
Другое дело.
Но, fp.init(window, в трёх местах торчат,
хотя было сказано, что в 125, уже нужно
fp.init(window.browsingContext,так что нет, не принимается.
ОГРОМНЕЙШЕЕЕ СПАСИБО!!!!!!!!я значит пропустил.виноват.несудите строго
Отсутствует