А как правильней\экономней\быстрее делать: мне нужно проверять, есть ли у вкладки(из массива всех вкладок) опред.аттрибут. Делать так
function close() { .......... // делать все в самом цикле tabs.forEach( tab => { q++; if(force && tab.hasAttribute("tabProtect")) tab.removeAttribute("tabProtect"); closeTabTimer(tab, 100*(q+1)); // интервал закрытия 100ms }); } ............
или сделать отдельную ф-цию ↓
function close() { .......... let prot = t => t.hasAttribute("tabProtect") ? true : false; ........ tabs.forEach( tab => { q++; if(force && prot(tab)) tab.removeAttribute("tabProtect"); closeTabTimer(tab, 100*(q+1)); // интервал закрытия 100ms }); } ............
...программисты словно войну какую-то ведут за свои обновления. Блин, почему сейчас повсюду мания ухудшать интерфейсы и делать их максимально неудобными?! Radiation
Отсутствует
как правильней\экономней\быстрее делать
На теоретические разговоры потянуло?
Создание отдельной функции, в данном случае,
выглядит совершенно ненужным.
Тем более такой дикой, ведь hasAttribute() уже́
возвращает true или false
Возможно, «мне нужно проверять» — имеется в виду,
что эта функция будет использоваться где-то ещё,
но в коде это нигде не указано.
Не нужно, здесь, и создавать функцию для forEach()
вполне можно обойтись перечислением for of
Избыточно и прибавлять единицу в цикле дважды.
Можно прибавить к q единицу до цикла, а в цикле написать 100 * ++q
Если значение в q используется в дальнейшем, то вычесть единицу после цикла.
Однако, самый интересный вопрос — сто́ит ли
здесь делать проверку hasAttribute() вообще?
Метод removeAttribute() не образует ошибку,
если скормить ему имя атрибута, которого нет.
В этом случае, метод просто не делает ничего (видимого).
То есть, вопрос в том, что если сразу использовать removeAttribute()
то не дешевле ли то, что при этом происходит внутри, в недрах движка,
чем вытаскивать существование атрибута наружу-в -JS
Отсутствует
ну, задавая вопрос, я руководствовался чисто практич. мотивами: полегше да правильней.
Это кнопка которую я, в попытках подтянуть шушуть JS (в череде других) переписал. Закрывает вкладки справа-ВСЕ-слева, что лет пять тому, здесь и слепили с твоей помощью.
Мне захотелось чтоб закрытие было плавненьким по-очереди. Сочинилось такое вот(это в PM):
this.setAttribute("context", ""); this.onclick =(e)=> { const mod = ( e.ctrlKey || e.altKey ) ? true : false, pinned = gBrowser.selectedTab.pinned ? true : false, force = e.shiftKey, // чтоб закрыть вкладки на которые др. кнопка вешает аттрибут и иконку, вроде bunda1 делал prot = t => t.hasAttribute("tabProtect") ? true : false; switch(e.button) { case 0: pinned ? '' : tabsindex(0); break; case 1: mod ? custombuttons.editButton(this) : tabsindex(1); break; case 2: mod ? gShowPopup(this) : tabsindex(2); break; default: return; } function tabsindex(btn) { let tabs = Array.from(gBrowser.visibleTabs), index = tabs.indexOf(gBrowser.selectedTab), q=0; switch (btn) { case 0: tabs = tabs.slice(0, index); break; case 1: pinned ? '' : tabs.splice(index, 1); break; case 2: tabs = tabs.slice(index + 1); break; default: return; } tabs.forEach( tab => { q++; // когда делал, помню что без этого не работал интервал закрытия. закрывалось сразу. if(force && prot(tab)) tab.removeAttribute("tabProtect"); // с зажатым SHIFT закрывает всё closeTabTimer(tab, 100*(q+1)); // интервал закрытия 100ms или 200 или др. }); } function closeTabTimer(tab, timer) { // ради чего все и затевалось - поочередное закрытие if (tab.pinned || prot(tab)) return; setTimeout( ()=> gBrowser.removeTab(tab, {animate: true, byMouse: false}), timer) }; }; this.tooltipText = " ЛКМ - Закрыть вкладки СЛЕВА от активной\n\ СКМ - Закрыть ВСЕ кроме активной\n\ ПКМ - Закрыть вкладки СПРАВА от активной\n\ с SHIFT - закроет и защищённые\n\ ---------------------------------------------\n\ CTRL или ALT + ПКМ \| СКМ - вызов меню \| edit_Button\n\ id: " + this.id;
Тем более такой дикой, ведь hasAttribute() уже́
возвращает true или false
Да я, блин, уже перестраховываюсь. Как-то не мог понять, почему у меня не работает скриптег; долго не мог. А оказалось, что то, что я присваивал, не всегда тру\фалсе а еще и андефайнед или вообще nan/ бывает. Счас не вспомню что и как, но как нашел, теперь перебдеваю.
Избыточно и прибавлять единицу в цикле дважды.
Можно прибавить к q единицу до цикла, а в цикле написать 100 * ++q
Первое что я проверил и да, работает. Мне-то главное было именно последоват. закрытие сделать. А в таком как у меня виде, без этого вначале q++ последоват. закрытия небыло. А додуматься до ++q я не смог. Пасиба.
Метод removeAttribute() не образует ошибку,
Не знал. запомню.
сто́ит ли здесь делать проверку hasAttribute() вообще?
Да. Как видишь, другая кнопка этот аттрибут вешает и я не хочу закрывать эти вкладки. Но иногда, с SHIFT - хочу. Для этого и нужно.
Буду править. Благодарю.
...программисты словно войну какую-то ведут за свои обновления. Блин, почему сейчас повсюду мания ухудшать интерфейсы и делать их максимально неудобными?! Radiation
Отсутствует
то, что я присваивал, не всегда тру\фалсе
В данном коде всё это используется только в логическом контексте,
так что, даже если бы нарисовалось «андефайнед или вообще nan»,
то всё равно должно было бы работать.
чтоб закрытие было плавненьким по-очереди
Тогда странно, что счётчик накручивается для всех вкладок,
а не только для подлежащих закрытию.
То есть, если на пути есть блок из десятка закреплённых или защищённых вкладок,
то закрытие следующей подлежащей закрытию вкладки тормознётся на секунду.
Буду править.
Взгляд со стороны.
this.setAttribute("context", ""); var params = {animate: true, byMouse: false}; var removeTab = tab => gBrowser.removeTab(tab, params); this.onclick = e => { var btn = e.button; // if (btn > 2) return; // ??? if (btn && (e.ctrlKey || e.altKey)) return btn == 1 ? custombuttons.editButton(this) : gShowPopup(this); var tab = gBrowser.selectedTab; if (tab.pinned) if (btn) btn = 2; else return; var tabs = Array.from(gBrowser.visibleTabs); var index = tabs.indexOf(tab); switch (btn) { case 0: tabs = tabs.slice(0, index); break; case 1: tabs.splice(index, 1); break; case 2: tabs = tabs.slice(index + 1); } while (tabs[0].pinned) tabs.shift(); var num = 0, force = e.shiftKey; for(tab of tabs) { if (force) tab.removeAttribute("tabProtect"); else if (tab.hasAttribute("tabProtect")) continue; setTimeout(removeTab, ++num * 100, tab); } } this.tooltipText = `\ ЛКМ - Закрыть вкладки СЛЕВА от активной СКМ - Закрыть ВСЕ кроме активной ПКМ - Закрыть вкладки СПРАВА от активной с SHIFT - закроет и защищённые --------------------------------------------- CTRL или ALT + ПКМ | СКМ - вызов меню | edit_Button id: ${_id}`;
Отредактировано Dumby (01-07-2024 13:04:21)
Отсутствует
Когда-то была кнопка переключаться на вкладку слева при закрытии активной. Может есть такая для 115.
Поведение при закрытии вкладки:
browser.tabs.selectOwnerOnClose = true (по умолчанию): переместить фокус обратно на вкладку, которая ее открыла.
browser.tabs.selectOwnerOnClose = false: переместить фокус на соседнюю правую вкладку, если она существует; в противном случае - на соседнюю левую вкладку.
Для перемещения фокуса всегда на левую вкладку расширение "Focus On Left Tab After Closing" или "Focus left tab on close".
Отсутствует
Dumby здравствуйте.
Вы написали скрипт для включения / разблокировке поисковых движков, Всё было бы хорошо, но в 129 выпилили иконки поисковиков, выглядит как то не комильфо в режиме search-config. Посмотрите пожалуйста можно адаптировать этот скрипт для режима search-config-v2?
PS: Скорее всего выпилят в тихую и из ESR...
Жизнь иногда такое выкидывает, что хочется подобрать...
На форуме
В r3dfox 129 (в FF 129 проверить не могу) сломалась кнопка "Меню".
/*Initialization Code*/ // https://forum.mozilla-russia.org/viewtopic.php?pid=774905#p774905 ..... (this.type != "menu" && (this.type = "menu") && !this.hasAttribute("is")) || (move => { if (this.parentNode.nodeName == "toolbarpaletteitem") return; var bar = document.getElementById("main-menubar"); var menupopup = document.createXULElement("menupopup"); this.prepend(menupopup); move(bar, menupopup); addDestructor(() => move(menupopup, bar)); })((from, to) => Array.from(from.children).forEach(child => { var popup = child.querySelector(":scope > menupopup"); popup.remove(); child.textContent = child.renderedOnce = ""; to.append(child); child.render(); child.append(popup); }));
Сможете помочь? Хоть ты не обновляйся.
Отредактировано manuk (06-08-2024 11:07:52)
Отсутствует
manuk
Проверял на 129, но обнаружил что не все подменю в History и Bookmarks работают, если устроит пользуйтесь...
/*Initialization Code*/ (this.type != "menu" && (this.type = "menu") && !this.hasAttribute("is")) || (move => { if (this.parentNode.nodeName == "toolbarpaletteitem") return; var bar = document.getElementById("main-menubar"); var menupopup = document.createXULElement("menupopup"); this.prepend(menupopup); move(bar, menupopup); addDestructor(() => move(menupopup, bar)); })((from, to) => Array.from(from.children).forEach(child => { var popup = child.querySelector(":scope > menupopup"); if (popup) popup.remove(); child.textContent = child.renderedOnce = ""; to.append(child); child.render?.(); child.append(popup); }));
Жизнь иногда такое выкидывает, что хочется подобрать...
На форуме
Т.е. полного функционала у кнопки не будет? Может аналог в UCF есть?
К сожалению я не обладаю достаточной магией, чтобы квалифицированно поправить скрипт. Так что вам придётся спросить ещё кого...
Жизнь иногда такое выкидывает, что хочется подобрать...
На форуме
для режима search-config-v2
Совсем разблокировать search-config-v2 ?
Ужаснись тогда что получится.
Только бэкап сначала сделать не забудь.
async cso => { var defaultEngine = "vatera"; var order = ["rakuten", "google", "bing", "eudict", "readmoo", "ddg",]; var chrome = [], push = (url, mime, src, rep) => { var code = Cu.readUTF8URI(Services.io.newURI(url)).replace(src, rep); var newURL = `data:${mime};charset=utf-8,` + encodeURIComponent(code); chrome.push(["override", url, newURL]); } push(cso, "application/json", /https(?!\?)/g, "$&?"); push( "chrome://browser/content/parent/ext-search.js", "application/x-javascript", "await Services.search.getVisibleEngines()", "($&).filter(e => !e._metaData?.hideOneOffButton)" ); var uri = Services.io.getProtocolHandler("resource") .QueryInterface(Ci.nsIResProtocolHandler).getSubstitution(""); var ams = Cc["@mozilla.org/addons/addon-manager-startup;1"].getService(Ci.amIAddonManagerStartup); globalThis[Symbol("chrome search patches")] = ams.registerChrome(uri, chrome); var environment = {allRegionsAndLocales: true}; var variants = [{environment}]; order = [{environment, order, default: defaultEngine}]; var types = {engineOrders: "orders", defaultEngines: "specificDefaults"}; var m = "resource://gre/modules/SearchEngineSelector.sys.mjs"; var proto = ChromeUtils.importESModule(m).SearchEngineSelector.prototype; var {getEngineConfiguration} = proto; Object.assign(proto, { async getEngineConfiguration() { if (!this.unlimited) { this.unlimited = true; Object.defineProperty(this, "_configuration", { get() {return this.config;}, set(cfg) {this.modConfig(cfg);} }); } this.config || await getEngineConfiguration.call(this); return this.config; }, modConfig(foxConfig) { var names = new Map(); for(var record of foxConfig) { var type = record.recordType; if (type == "engine") { var {name} = record.base; var arr = names.get(name); arr?.push(record) || names.set(name, [record]); record.variants = variants; } else { var prop = types[type]; if (prop) record[prop] = order; } } for(var arr of names.values()) if (arr.length > 1) for(var record of arr) record.base.name = record.identifier; this.config = foxConfig; } }); })("chrome://browser/content/schemas/chrome_settings_overrides.json");
Ещё просьба, может вы собирали обновлённый DOMi
Ой, не помню уже. Вот, набросил цифру и скормил сборщику.
Но сам он становится всё только хуже.
if (popup)
Увы, не только <script> вкорячен,
но и слушатель на <menubar> повешен.
Чисто формально, возможно, лучше как-то так
(this.type != "menu" && (this.type = "menu") && !this.hasAttribute("is")) || (move => { if (this.parentNode.nodeName == "toolbarpaletteitem") return; var bar = document.getElementById("main-menubar"); var menupopup = document.createXULElement("menupopup"); menupopup.id = "main-menubar-popup"; menupopup.setAttribute("position", "after_start"); bar.append(menupopup); move(bar, menupopup); this.setAttribute("popup", menupopup.id); addDestructor(() => { move(menupopup, bar); menupopup.remove(); }); })((from, to) => Array.from(from.querySelectorAll(":scope > menu")).forEach(menu => { var popup = menu.querySelector(":scope > menupopup"); popup.remove(); menu.textContent = menu.renderedOnce = ""; to.append(menu); menu.render(); menu.append(popup); }));
Отсутствует
Ужаснись тогда что получится.
Только бэкап сначала сделать не забудь.
Спасибо! Все 154 у меня получилось. Я себе делал мод предыдущего скрипта, вот тогда-то я и ужаснулся от количества eBay`ев и Vikipedia`ев
Жизнь иногда такое выкидывает, что хочется подобрать...
На форуме
Подскажите пожалуйста в кнопке
// Двойным левым кликом на папке закладок добавлять закладку в папку закладок addEventListener("dblclick", async e => { if (e.button) return; var trg = e.target, node = trg._placesNode || trg._placesView?._resultNode; if (!node || !PlacesUtils.nodeIsFolder(node)) return; var parentGuid = PlacesUtils.getConcreteItemGuid(node); try { await PlacesTransactions.NewBookmark({ //index: 0, parentGuid, url: gBrowser.currentURI.spec, title: gBrowser.selectedTab.label.substr(3, 50) }).transact(); var msg = `Добавил в папку ${ PlacesUtils.bookmarks.getLocalizedTitle({guid: parentGuid, title: node.title}) }:`; var popupIconURL = gBrowser.selectedTab.image || "chrome://global/skin/icons/Portrait.png" } catch(ex) { msg = "ERROR! " + ex.message; popupIconURL = "chrome://global/skin/icons/warning.svg"; } var n = PopupNotifications.show( gBrowser.selectedBrowser, "PDES-popup", msg, null, null, null, {popupIconURL, hideClose: true} ); setTimeout(() => n.remove(), 2e3); });
Отсутствует
PlacesUtils.nodeIsFolder
Bug 1904909PlacesUtils.nodeIsFolder
PlacesUtils.nodeIsFolderOrShortcut
Отсутствует
Dumby
Подскажите пожалуйста, это сейчас актуальная версия антиподписячего кода или уже таки есть новая?
Отсутствует
Есть две (уверен важные для многих) кнопки
Дополнительные пункты в контекстном меню кнопки
/*Initialization Code*/ ///////////////////////////////////////////////////////////////////////////// /////////////////////////////// Создание меню /////////////////////////////// ///////////////////////////////////////////////////////////////////////////// function $(aId) { return document.getElementById(aId); }; function addMenuItem(aNewIDs, aNodeIDs, aLabel, aIcon, aCommand) { for (var i = 0; i < aNewIDs.length; i++) { if ($(aNewIDs[i])) $(aNewIDs[i]).parentNode.removeChild($(aNewIDs[i])); var mi = document.createXULElement("menuitem"); mi.setAttribute("id", aNewIDs[i]); mi.setAttribute("class", "menuitem-iconic"); mi.setAttribute("image", aIcon); mi.setAttribute("label", aLabel); mi.setAttribute("oncommand", aCommand); if (i == 0) mi.setAttribute("observes", "custombuttons-contextbroadcaster-primary"); if ($(aNodeIDs[i])) { if ($(aNodeIDs[i]).nextSibling) { $(aNodeIDs[i]).parentNode.insertBefore(mi, $(aNodeIDs[i]).nextSibling); } else { $(aNodeIDs[i]).parentNode.appendChild(mi); } } } }; var saveImg1 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAnUlEQVQ4jc3RPQ4BURTF8Z+PgrAPtUJnIxZgBZagkolVqDWWIliARCFR6GSq0Twyw2SemcpJTnPzzv/edy//ohOymj7mARl6NRoOQ6YAiGmNFAm6TQBpePdAJwYYYIF+rpaE8CoGaGEbarsw7qfaVYCl4rY3mOOGaQwwU326O8Zhyi/AJPwxdv8rRmWAyw/hl89lgCZ+69AgvPcXegKfOWlGgoA/rgAAAABJRU5ErkJggg=="; var saveImg2 = "data:application/file;base64,AAABAAEAEBACAAEAAQCwAAAAFgAAACgAAAAQAAAAIAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAADbAAADpcAAA//AAANVwAAD/8AAAKsAAAD/AAAP//AAAP8AAAD/AAAD/8AAAwDAAAP/wAAA/wAAAP8AAA"; var saveImg3 = "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAAAAAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAAAAAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAAAAAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//+sQf//rEH4j6xB8IesQeHDrEHD4axBh/CsQYf4rEGH8KxBw+GsQeHDrEHwh6xB+I+sQf//rEH//6xB//+sQQ=="; var saveImg4 = "data:application/file;base64,AAABAAEAEBACAAEAAQCwAAAAFgAAACgAAAAQAAAAIAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAD/8AAA//AAAP/wAAD/8AAA//AAAP/wAAD/8AAA//AAAP/wAAD/8AAA//AAAP/wAAA/wAAAP8AAA"; var saveImg5 = "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU1FQr1FRT7BRUU+wUVFPsFFRT7BRUU+wUVFPsFFRT7BRUU+wUVFPsFFRT7BRUU+wU1FQrwAAAAAAAAAAAAAAAHd0cpz//////////////////////////////////////////////////////////3d0cpwAAAAAAAAAAAAAAAB4d3Sc/////+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg//////94d3ScAAAAAAAAAAAAAAAAenh3nP/////i4uL/4uLi/5yiz/9HYcT/PWrR/1qQ3P+nuNr/4uLi/+Li4v//////enh3nAAAAAAAAAAAAAAAAH18eJz/////5OTk/2FluP8IJ6r/D1TU/wli4v8FZeb/D3He/4y+5f/k5OT/+/v7/318eJwAAAAAAAAAAAAAAACBfXyc/////5Wc0v8JKq//E2Pd/yFTrv9EKTn/LjVZ/xaF2/8OdNP/zNnm//z8/P+BfXycAAAAAAAAAAAAAAAAhIGBnP////89Xc7/Dk7N/wpQ0/8zVp//TGCK/4U2Cf9DW2b/Eqj7/5C+5//8/Pz/hIGBnAAAAAAAAAAAAAAAAIaEgZz/////Kmnf/wlFzf8gPZ7/uXcl/8OAK/+UTBL/b1Az/zfG9f9srdX/+fn5/4aEgZwAAAAAAAAAAAAAAACJhoac/////0iN6P8HQtH/EVzd/2mCqf/dqkz/0pY6/6FnKv9Nvt7/kMfs//X19f+JhoacAAAAAAAAAAAAAAAAiomJnP////+Mr+r/FFnU/xVRyv+LorL/8Oqh//nXbP+5omH/Urvf/8bj7v/s7Oz/iomJnAAAAAAAAAAAAAAAAI6Kipz/////2+n3/5aSm/+hcEn/4uXC////2P/25KD/rqSD/7HR5//o6Oj/4eHh/46KipwAAAAAAAAAAAAAAACPjo6c//////j4+P/4+Pj/3s/F/9i/n//p27n/5NG0/+7r6f/r6+v/3t7e/9LS0v+Pjo6cAAAAAAAAAAAAAAAAk4+PnP/////6+vr/+vr6//r6+v/6+vr/+vr6//j4+P/19fX/r66t/62sq/ObmprrkI2NpgAAAAAAAAAAAAAAAJOTk5z//////Pz8//z8/P/8/Pz/+/v7//r6+v/4+Pj/9fX1/66trfHs7Ozrp6emp4aGhhMAAAAAAAAAAAAAAACWlpOc/////////////////v7+//39/f/6+vr/9/f3//Pz8/+bmprrp6enp3NzcxYAAAAAAAAAAAAAAAAAAAAAmJiWnJiYlpyYmJacmJiWnJeTk52SkZGemJiWnJeTk52SkZGej4+LpIaGhhMAAAAAAAAAAAAAAAAAAAAAgAMAAIADAACAAwAAgAMAAIADAACAAwAAgAMAAIADAACAAwAAgAMAAIADAACAAwAAgAMAAIADAACABwAAgA8AAA=="; var saveImg6 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABKklEQVR42mNkQAMNDAxCQMoTiB2BWAEq/ACI9wPxdqD8O2T1jGiao4HUEgb8IAaobimGAUDBGiDVzEAcqAWqb4EbQKTNWF3CCPXzW5ho/f//YDqHkZFhCpQNA7lAMV4gzY4QEmZEtx1mgCtQ8W4o2xLIPg5lJwDZUghDYkAGzAEyktENMAQqPA9l6wDZEkB6D6Yhc0EG7AGynfEZYAxkawHpxVC+A5CvC6RFGBj2Em2AIZCeg8Q3BtLSUAMIegGkwQBIz8U0YC7OQEQ2wAjIPoekGRQTUC/E4IxGkMKzaNEI8jso4chDbGdgA0UjekJ6A8S3gRikFWQyKOF/higGR50UFLPBEhLM9AZoUv4F1cAA1QTi/2SAJFkQnxdCoyZlJEPIz0xIhpCUnQFx83abgfUZOQAAAABJRU5ErkJggg=="; var saveImg7 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAASUlEQVR42mNkoBAw0s6ABob/aHxGkg1I8zEGM2dtOTskDED3MxCgGIBpASOGATANhACyi6hrAGVeoDgQB6UB2PxMvAFEAooNAAC7izYR2pQ0nAAAAABJRU5ErkJggg=="; var saveImg8 = "data:application/file;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///8A////AESqAABHpgAASKAAAEukAQxMpQMYR6MAAEepAQ9MpgOLRKgACUenAABHpgAARKoAAP///wD///8A////AP///wBEqgAARaIAAFS2FVBj0jS3Y9AzyVG0EUROrwt8TKcDs0ikAANInwAAR6YAAESqAAD///8A////AP///wD///8ARKQAAVvJKJtj0jX/SaAJ/0abCv9UtSH/U7QX8lW5IMddwyfQW8Iii0mqBQ1DqQAA////AP///wD///8A////AEWlAAFYwB6YXsYc5F7GFt9bwA+vVbgWvU6rAKBRrgf0RZgA/02oDP9ezCzJR6UBA////wD///8A////AP///wBFrAAASKIAADiGNQAeYIIpF1iJHVa4GKEve0tFLHl1Pla7J51exRnUWL8VjEetAAP///8A////AP///wD///8AC0WuAAk/tAAANdpIAFD6/wA+7f8gd6jqBlPX+QBE9PIGS8uDLnZLADqNJwAzjDMA////AP///wD///8A////AAAw0QAALc0AAEPdegBI4f8AK8P/ADHX/wAwzf8AL8b/AEno/gAz2zYALtEQAC3VAP///wD///8A////AP///wAAMssAADjSMwBA2pIATen/ADG9/wBe1v8ATcz/ADHK/wBN5/4ASeH/AEvl6wA10DP///8A////AP///wD///8AADnTSQBO5/8ANc7/ADnR/xC+9/8C0f//AMj//wCP8P8ALcX/ACrC/wBE3f8ASeOf////AP///wD///8A////AABI4Z4ARN3/ACvG/wJAxP8Z5v//AMT//wDE//8Axv7/AETM/wA51P8AUervADjSPP///wD///8A////AP///wAAOdRiAFry+QBS6/QATOP/H+P8/xDe//8J1///E9H4/wFE2f8AReC6ADTOEwAyywD///8A////AP///wD///8AADDNAAAyzCcARN7WACvG/wVfzf8d0vf/HM30/whf0/8AI7n/ADzV+AA40kUAMswA////AP///wD///8A////AAAwywAAPNdTAEfg/wAsw/8AOdb/ADLP/wAswv8AReP/AC7H/wA40f8AR+GfADDKAP///wD///8A////AP///wAAMswAADfRQgBY8f8AT+j/AE7o7AA+1/8AK8T/AE7o/wBN5f8AVe7/AD/ZbAAwywD///8A////AP///wD///8AADPMAAAyywAANM4vADjSUQA0zikAU+z3AEff/wBJ4sMAN9EtADjROQAyywAAM8wA////AP///wD///8A////AAAzzAAAM8wAADHLAAAwywAAMcsAAD/YXQBK4pYAN9AxAC/KAAAwygAAM8wAADPMAP///wD///8A+R8AAPAfAADABwAAwAMAAPgDAADwHwAA8AcAAOADAADAAwAAwAMAAMAHAADgBwAA4AcAAOAHAADwDwAA/j8AAA=="; var saveImg9 = "data:application/file;base64,AAABAAEAEBAAAAAAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAD///8BAAAAFwAAAGkAAABzAAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAADkAAAAP////AQAAAIdgZmj/YWlt/2FobP9haGz/YGhr/2Boa/9fZ2v/X2dr/15mav9dZWn/XGRo/0ZNUP8AAACdAAAAFf///wEAAACr2tzc/9ve4P/a3t//1dnZ/7S2tf+foJz/m5ya/6apqP/O0tP/09fZ/9DV1v+hqq//AAAAuQAAABX///8BAAAAq+3u7//e4eL/ub29/2hnXv9oVUX/U0As/zgxGf83Lx3/YWBX/7a5uv/S1tj/o6yx/wAAALkAAAAV////AQAAAKv29/f/19na/1dUQf9jXDv/dmtJ/4FoSP9VQiL/V0Ek/008Iv9HQTP/yc3P/6Wus/8AAAC5AAAAFf///wEAAACr+Pj4/5uamP9tY0L/g31b/6GLa/+McVH/eFY5/4xwUv9yXkD/RTki/4uMiv+nsLT/AAAAuQAAABX///8BAAAAq/n6+v+FfXL/waSM/8qznf/DrZP/ooFi/7WfhP+qh2//blk9/1A+Iv9aWlH/pK2x/wAAALkAAAAV////AQAAAKv6+/v/d3Rr/9zCsP/RxbH/z8Wu/9fJt//Qvab/qItv/5iOb/9tYUH/VVJK/6Wtsf8AAAC5AAAAFf///wEAAACr+/z8/4mHff+3pI//3NK//+HXxf/m3Mz/5trJ/9rMuf+bgWT/d14//2hnYP+osbX/AAAAuQAAABX///8BAAAAq/z9/f/FxL7/j4l+//Xw5f/29ez/8/Dl/+DMuv/VuaP/poZn/2dFKv+srav/oamt/wAAALkAAAAV////AQAAAKv+/v7/+/z8/5iZjf+5uqr/6+PW/+3i1P/kzL3/vZR+/4NhSf+Qh3z/z9HS/4qQkv8AAAC1AAAAFf///wEAAACr/v7+//7+/v/u7u3/tbiv/5WSgP+DfGj/e25Z/29gTv+sppz/vr6+/5aYmP90eHr/AAAApwAAABP///8BAAAAq/////////////////7+/v/9/f3//f39//v8/P/5+fn/1dXV/2pqav9TU1P/QUFB/wEBAYkAAAAJ////AQAAAKv7+/v//////////////////v7+//7+/v/+/v7/+vr6/9fY2P/V1tb/7Ozs/4KCgv8EBAQrAAAAA////wEAAACFlJSU/6ioqP+qqqr/qqqq/6qqqv+qqqr/qKio/6anp/2kpaX9o6Oj/4qKitUZGRk9////Af///wH///8BAAAAFQAAAFUAAABVAAAAVQAAAFUAAABVAAAAVQAAAFUAAABTBAQEUx8fH1dfX18z////Af///wH///8BAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//w=="; var loadImg = "data:image/x-icon;base64,AAABAAEAEBAAAAAAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAD///8B////Af///wH///8B////AQAAAB+yg2l71ZRt+daTa//Wk2v/1pNr/9aTa//Wk2v/v4NlywYEAycAAAAX////Af///wH///8B////Af///wHdo4M53Zx3/+Sgef/innb/4p52/+Kedv/lo3r/5aR6/+mqgfvPj27N////Af///wH///8B////Af///wH///8B4KSD8+mmff/opH3/56N6/+Whef/no3r/66qB/8KBXf/Fg1//0Y5s78+Pbqn///8B////Af///wH///8B////AeGlg//trIX/7ayE/+6thP/urIX/9bWL/8eFYf/GhF//yYZh/9SPa/nkn3j/////Af///wH///8B////Af///wHkn3j/76+G/+6uh//vrob/76+G//W3jP/GhF//y4di/9ONZ//XkWr/5J94/////wH///8B////Af///wH///8B5J94/++wif/wsIj/8LGJ//CxiP/0toz/y4di/8+KZf/vroP/766D/+SfeP////8B////Af///wH///8B////AeSfeP/xs4v/8bOL//Cziv/ws4v/87WL/9CNa+3QjWvt3p96/96fev/en3r/////Af///wH///8B////Af///wHkn3j/8rWN//K2jf/ytY3/8rWN//O2jvfdo4Lj0I5sJdCObCXQjmwl0I5sJf///wH///8B////Af///wH///8B5J94//O3j//zuI//87iP//O4j//zuZDx3aOD7////wH///8B////Af///wHdo4M/5J94/+SfeP/kn3j/5J94/++2j//zupH/9LqR//O6kv/0upL/87qR/+SfeP/kn3j/5J94/+SfeP////8B////Af///wHkoXr/9cCY//W8k//0vJT/9L2T//S8lP/0vZT/9LyU//S8lP/1vJT/9cCY/+Shev////8B////Af///wH///8B9b+WC+SjfP/2yqP/9b+W//a/lf/2v5X/9b6V//W+lv/1vpX/9sqj/+SjfP////8B////Af///wH///8B////Af///wH2wZgX5aZ+//fTrP/2wJj/9sCY//bAmP/2wZj/99Os/+Smf/////8B////Af///wH///8B////Af///wH///8B////Af///wHkqYH/99ax//fCmv/3wpn/99aw/+Sogf////8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AeWrhP/317L/99ey/+WrhP////8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B5a2F/+Wthf////8B////Af///wH///8B////Af///wH///8BAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//w=="; var moveToMenu = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABKElEQVR42o3TMUvDQBQH8P+7tLlEwaW4ugl+iU6CCA4i0tbdqavgZ/ErCE79DsVBkYpKLR2kuApOatG297zLJWkqXnIPwrsk937cveQIJXHZBZt8cgFyzaEqYGuTvl7feM2FVAIHR8Bj341UAu1T4PPdjXgBJgzyPKDFy4SDIkJZo1yRASZ+FDB5Itzfct7YBGjuBBBh6oT6ed2OazGjsV3wQ2Cu64bXUKM7FgZJgPaufinTSVFhrDPFheVIe01nwLgfq9HNVCRAaw8Q6USWS4B05mgVIH2/qG+ABh+46im7heP9EELOLRDZpVqAQev8ZwUS/DBLivMtlDWxc7Ycs6yBhyov9vqMGcBBDB5/rxT7/Qfntjn/FXsDrmIvoHUonMVegMllx/kXlvSRMQ0GPE4AAAAASUVORK5CYII="; var removeFromToolbar = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACMElEQVR42p3Sz2/SUBwA8G9pgQJd6QYZQQkOjUFdXMCLMn9B4l3myRgXhydPZgcTY2KyLfGiF/wT9GTmhfIXjMQ4NP5YD5qZTGdVdEx+9FVKSwttrTV4QD3AN3mH9837fr7v+/Kww1e4ic2HiSYMRGxufcHjxs87nQ5GN0zodnXQNLVomvCAL6ZR/xxmAS9VsX1umz1pJ/dfKGeD4+58OERNYQQO7Y4BWs8E3XCAqvRAEkWkdpTcNptm+4DpMVUOtboZl4tY2reXWmTGvbDTVKFnALicTrvYsFqbpgEOBw6tpgiigOb4Yoa1gTMzY1B+XUexKM1gLid8a3QgQHtBklQQBJm3RuAxDBiPl0z4aMq+eu1rFYmiFLOBowd8QJEEiLIBlbpV7PdArdZCApJX3j9O3e/Pe/Di0zTpJgvB8CSjSG1o7O7mbCA04QIHjoGsGuAfI6FRk0D8ISe3VlPc4OPGL61nab+/QDE0VD9/+T1CKOCCtqoDQRBAe0n4yH/nZUVLVtjTCP4R8cvPN8LRSKL6qVKygUjIC0rXAAMw6+EI6GkmoGaDM0DP8KuzfyHx+WfLe6KRpdpOlbMB+E9oWof78OhEcjB/5OqLbHAyUEB1oYTBCDFz7VWaYZg11BTYkYBj17lFyu3Lo5aYGwk4fuNNHgd8QVHk2EjA7K3NDVM3iuV708tDA2dXtqb0rr5mrWT57jQaGjh1+13eKio+uXOo9Gs/NJC6+TZhdf7zQ38Ceg0HgF1MCP0AAAAASUVORK5CYII="; var iconADD = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACDUlEQVR42nWT30sUURTHz91Zd9FkVBRrX0oScTMI8weSIYSU/QMFbb5oGAn+AQo9B/UH9BAF+lIr+OLrSETQQ4GhEVRrUFkP/SLRNcvUnXv8nrmz7XVcB86cy7nn+5kz556ryHrueKxIYcFkPMmbxXHgzA6NDyguatQewBzHkKMMQDnWPgDsIwYh8/hATP8HQCRJEFIc5iA1DpljZIGogJU/9WXp39DR1pj99QBwe45dZb6UhCXE2Hx6m4xtQZQ/8SDni+DdSNopVYtysUiFpVbDqp4vPL4uCWc6zt+H+wvbAOBrCBCRFgh0AtIA6BboBVADc6eeZLMCGOq/kkF8Hcs8AO8tgDwav5M0AI/bw87Xw9dml+bvSUamtfsGYmuIrQDwKgIoQirkF3pR9uCbz28vx+tTMWo6VRdsL79eLax80yePtc3MTlwYKwMIT8HTvYufFkc+bq4NOjWN9Kf6cIVsHNr4sePnf9LxytqH06Od1w6oICGA9uZGOnvEpb7tgkrefLl8UXZvdTV5CYe3vv9Wzy6dVnfL9KAKfkcALeihaSKT+yj3Imji1XRPBvFyTTSn4LHMi5Y5SCnrGFc3c5MCqKtMD5c5RnsOisfILlmD1NxA5yThwy96GhkkRtlxrP3oIO0d5ZKXfSSbUYaJ1/tGef9lovAyUeQyAaKCO4nLpPRBABWJlwCWt6vYBccZ9A793wmLAAAAAElFTkSuQmCC"; var customBtn = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjVJREFUeNqcUkuIUmEUPl4fML6bBsFRacRF2EaCcRO48bFLEIJcBIJLxb2b2UWLkIEgQQjauVFaKmgYuclUTMUHKoaKE4GPxnxh5r3ezh0QHJFmmA/OPZfDfx7fdw7AfojQ7qGx4QawdgMymeyRyWR6IZVKucFg8N10Ov0Ot4VGozmNRCLx5XL5F/HHbrefYZh7m1yWWq0+TafTn2kEdqXr9TrtcDje3JR4xRHH1QYCgXOz2Wzs9/sQj8dBIpEATtGrVqu9yWSywmdLNGq3AAeNsFgsz202mxk7QzKZBK1WCzqdjtHjKUmSx41Go4L+slQqpYvF4keKoibXpnA6nWfY+VehUKBSqRTJ0Oh2u3Qul6MHgwE9Ho9pLMD4H16v95zD4RxuU6BbrdYlPh5g8tfFYvET9XiIiRylUsnQgPl8DtgVhsOheL1eS6LRaGy1Wg02FAA5VmKxWB1/yUQioWOxWHKXy2XEYsDQEggEgKJCJpOBcrnMbOliW4MNSOaDCbVKpVISCoVGHBnQQygUgnK1AkeH9z+Ew+HX2xoQezZDjUaj3ygDiMViaLfbV8kK+TGw2WysJzzafry3QK1W+9Lr9RpIDbLZLEhE4vedTsdvMBieuN3ulwRBPLh2B7uYzWYXzWZzjBoc5PP5MJ70K1xfEsVc4cpNeDcnuLFvzM3978gILpcrRy/w+XybGE+v1z/z+/2frFarG9d5AHeBSqUyeDyetwqF4jHcFXw+/4TH44n+CTAA3Ccog288LRAAAAAASUVORK5CYII="; var saveAll = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACOElEQVR42mNkwAJ+7xf7//3tKwZeIUELRqf3JxnwAEZkzrtlwnv/MzE6/WfkWCwS/iTu7RLO/wzMPAwc/z4Lc0f/eIfTgP/7BM0PXDY5ofB9N8M/EB8k+BcoyQw1mEWd4SurLIO97lkUFzX9b/oPNmBznc7/////MbAzfIdoBoI/P77Abfnzn4XhH9A0kOLA7icQV88HKn0EdcH6Ss3/yM76/f0jg2vTXYZ/f39j9fdUgQkMdTp1DNFXoiEGrCzFNMCj6SrD/79/MDQzsbAzCEfyMTBwADkbGBjBBiwrRDXgF9AAz6ZLWF1QIlHCsFRnKdj2pYxLIQYsytPAMMC75SLYBVMkpzDkPM+By0lFSTEwCDAwvJ79eouoqKgv2IB5WWgGfPvI4N95kUEyQQwcJVXbq8CGeEp6MlzUuQi2fcKbCQgDZqWhG/CJIaDrLIPMf0kGBjeggAoDw5YNWxh8rHwYGMQZGB5PfszAysq6RUJCAmLAtCR1DAMCu08zzJSZxtDm0cbA8AQoyAxJGyDbWx+2MrCwsGyRkZGBGDApDpsBx8FhME95HkObfhtYM4MqA8OdnjtgNSAXyMvLQwzoi8JmwGF4NGoc12Bg6IHYXnuzFm6AsrIyxIAJ+UHXfj27oomIhc9AA/ajpAOdPToMV1yuwPnMzMxbNDU14QaEAqnGH28fqYGywt/fP5i8q5czYUtIMABygY6ODsSAJUuWOKMrUFHT2PPvzy90YZhX/79//36dt7d3KACPfPJHOU7GxAAAAABJRU5ErkJggg=="; let cIDs = ["custombuttons-contextpopup-exportXML", "custombuttons-contextpopup-exportXML-sub"]; let bIDs = ["custombuttons-contextpopup-bookmarkButton", "custombuttons-contextpopup-bookmarkButton-sub"]; addMenuItem(cIDs, bIDs, "Сохранить код кнопки в XML файл", saveImg9, "document.getElementById('" + this.id + "').saveXML(('triggerNode' in this.parentNode) " + "? this.parentNode.triggerNode.URI " + ": document.popupNode.URI);", "X"); let xIDs = ["custombuttons-contextpopup-importnewbutton", "custombuttons-contextpopup-importnewbutton-sub"]; let aIDs = ["custombuttons-contextpopup-addnewbutton", "custombuttons-contextpopup-addnewbutton-sub"]; addMenuItem(xIDs, aIDs, "Добавить кнопку из XML файла\u2026", loadImg, "document.getElementById('" + this.id + "').loadXML();"); let fIDs = ["custombuttons-contextpopup-copyImageURI", "custombuttons-contextpopup-copyImageURI-sub"]; let b2IDs = ["custombuttons-contextpopup-copyURI", "custombuttons-contextpopup-copyURI-sub"]; addMenuItem(fIDs, b2IDs, "Копировать изображение кнопки в формате base64", saveImg1, "document.getElementById('" + this.id + "').copyImageURI();"); let f1IDs = ["custombuttons-contextpopup-saveButtonImage", "custombuttons-contextpopup-saveButtonImage-sub"]; addMenuItem(f1IDs, cIDs, "Сохранить изображение кнопки", saveImg8, "document.getElementById('" + this.id + "').saveImageURI();"); let f2IDs = ["custombuttons-contextpopup-copyButtonsCodeText", "custombuttons-contextpopup-copyButtonsCodeText-sub"]; addMenuItem(f2IDs, b2IDs, "Копировать код кнопки как текст", saveImg2, "document.getElementById('" + this.id + "').copyButtonsCodeText();"); let f3IDs = ["custombuttons-contextpopup-copyAsHTML", "custombuttons-contextpopup-copyAsHTML-sub"]; addMenuItem(f3IDs, b2IDs, "Копировать код кнопки как HTML ссылку", saveImg3, "document.getElementById('" + this.id + "').copyToHTMLCode();"); let f4Ds = ["custombuttons-contextpopup-copyToBBCode", "custombuttons-contextpopup-copyToBBCode-sub"]; addMenuItem(f4Ds, b2IDs, "Копировать код кнопки как BBcode сылку", saveImg4, "document.getElementById('" + this.id + "').copyToBBCode();"); let f5Ds = ["custombuttons-contextpopup-saveAsHTML", "custombuttons-contextpopup-saveAsHTML-sub"]; addMenuItem(f5Ds, bIDs, "Сохранить код кнопки в HTML файл", saveImg5, "document.getElementById('" + this.id + "').saveToHTMLCode();"); let f8Ds = ["custombuttons-contextpopup-saveAsHTMLAll", "custombuttons-contextpopup-AsHTMLAll-sub"]; addMenuItem(f8Ds, f5Ds, "Сохранить все кнопки в HTML файл", saveAll, "document.getElementById('" + this.id + "').saveToHTMLALLCode()"); let f6Ds = ["custombuttons-contextpopup-getButtonId", "custombuttons-contextpopup-getButtonId-sub"]; let b1IDs = ["custombuttons-contextpopup-remove", "custombuttons-contextpopup-remove-sub"]; addMenuItem(f6Ds, b1IDs, "Показать Id кнопки", saveImg6, "document.getElementById('" + this.id + "').idMIonclick(content.document);"); let f7Ds = ["custombuttons-contextpopup-addNextButton", "custombuttons-contextpopup-addNextButton-sub"]; var addMI = document.getElementById('custombuttons-contextpopup-addnewbutton'); addMI.setAttribute('image', iconADD); var addMI1 = document.getElementById('custombuttons-contextpopup-addnewbutton-sub'); addMI1.setAttribute('image', iconADD); var addMI2 = document.getElementById('custombuttons-contextpopup-move-moveToPanel'); addMI2.setAttribute('image', moveToMenu); var addMI3 = document.getElementById('custombuttons-contextpopup-move-removeFromToolbar'); addMI3.setAttribute('image', removeFromToolbar); var addMI4 = document.getElementById('custombuttons-contextpopup-customize'); addMI4.setAttribute('image', customBtn); ///////////////////////////////////////////////////////////////////////////// /////////////////////////////// Общие функци //////////////////////////////// ///////////////////////////////////////////////////////////////////////////// var options1 = {year: "numeric"}; var options2 = {day: "numeric", month: "long"}; var cDate = new Date().toLocaleDateString("ru-RU", options1); var dDate = new Date().toLocaleDateString("ru-RU", options2); var aDate = cDate + "г" + " " + dDate; var options3 = {weekday: "long", year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric", hour12: false}; var bDate = new Date().toLocaleDateString("ru-RU", options3); 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(); } }); }; ///////////////////////////////////////////////////////////////////////////// ////////////////////////////Остальные функци //////////////////////////////// ///////////////////////////////////////////////////////////////////////////// /////////////////////////////// Показать Id кнопки /////////////////////////////// this.idMIonclick = function idMIonclick() { var btn = document.popupNode.id; var box = custombuttons.confirmBox("Копировать в буфер", btn, "Да", "Нет"); if (box) { custombuttons.cbService.writeToClipboard(btn); custombuttons.alertSlide(btn, "Скопирована в буфер"); } } function mostRecentWindow(windowType) { return Components.classes['@mozilla.org/appshell/window-mediator;1'].getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow(windowType); } /////////////////////////////// Копировать изображение кнопки в формате base64 /////////////////////////////// this.copyImageURI = function copyImageURI() { var btn = document.popupNode; if (!btn) return; cbu.gClipboard.write(btn.image); var as = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService); as.showAlertNotification(btn.image, "Кнопка: " + btn.name, "Изображение кнопки скопировано в буфер", false, "", null); } /////////////////////////////// Копировать код кнопки как текст /////////////////////////////// this.copyButtonsCodeText = function copyButtonsCodeText() { var btn = document.popupNode; if (!btn) return; var code = ((btn.cbCommand == "") || (btn.Command == "/*CODE*/")) ? "" : ("\n/*CODE*/\n" + btn.cbCommand + "\n"); var init = ((btn.cbInitCode == "") || (btn.cbInitCode == "/*Initialization Code*/")) ? "" : ("\n/*Initialization Code*/\n" + btn.cbInitCode); cbu.gClipboard.write(code + init); //custombuttons.alertSlide(btn.name, "Код скопирван в буфер"); var as = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService); as.showAlertNotification(btn.image, "Кнопка: " + btn.name, "Код скопирван в буфер", false, "", null); } /////////////////////////////// Копировать код кнопки как HTML ссылку /////////////////////////////// this.copyToHTMLCode = function copyToHTMLCode() { var btn = document.popupNode; if (!btn) return; var code = "<p><div id=\"install\" style=\"background: transparent -moz-linear-gradient(center top , rgb(224, 102, 255) 30%, rgb(125, 38, 205) 55%); text-shadow: 0pt -1px 0pt rgb(122, 55, 139); border: 1px outset rgb(85, 26, 139); border-radius: 1em; padding: 0; width: 240px; text-align: center;\"><a href=\"" + btn.URI + "\" style=\"display: block; padding: 1em; color: #ffffff; text-decoration: none;\" title=\"Click here to install " + btn.name + "\" rel=\"nofollow\"><img src=\"" + btn.image + "\" alt=\"" + btn.name + "\" style=\"vertical-align: middle; float: left;\"/>" + btn.name + "</a></div></p>"; cbu.gClipboard.write(code); var as = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService); as.showAlertNotification(btn.image, "Кнопка: " + btn.name, "HTML кнопки скопирован в буфер", false, "", null); } /////////////////////////////// Копировать код кнопки как BBcode сылку /////////////////////////////// this.copyToBBCode = function copyToBBCode() { var btn = document.popupNode; if (!btn) return; var code = "[url=" + btn.URI + "][B]" + btn.name + "[/B][/url]"; cbu.gClipboard.write(code); //.toXMLString()); var as = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService); as.showAlertNotification(btn.image, "Кнопка: " + btn.name, "BBCode кнопки скопирован в буфер", false, "", null); } /////////////////////////////// Сохранить изображение кнопки /////////////////////////////// this.saveImageURI = function saveImageURI(btn) { var remove = gBrowser.removeCurrentTab.bind(gBrowser); var promiseTargetFile = async (...args) => { var res = await window.promiseTargetFile(...args); setTimeout(remove, 0); return res; } var internalSave = eval(`(${window.internalSave})`); var save = eval(`(${window.saveDocument})`); var btn = document.popupNode; if (!btn) return; (saveButtonImage = btn => { if (btn.image != "") { var tab = gBrowser.selectedTab; gBrowser.selectedTab = gBrowser.addTab(btn.image, { triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal() }); setTimeout(function() { window.content.document.title = btn.name; save(window.content.document); }, 2000); } else custombuttons.alertBox("Эта кнопка не имееет изображения!"); })(btn); } /////////////////////////////// Сохранить кнопку в XML файл /////////////////////////////// this.saveXML = function saveXML(aStrURI) { var cbURI = (aStrURI != undefined) ? aStrURI : readFromClipboard(); if (!cbURI || !/^custombutton\:\/\//.test(cbURI)) { custombuttons.uChelpButton(this); return; } var topicURL = "http://forum.mozilla-russia.org/viewforum.php?id=34" var cbXML = cbURI.replace(/^custombutton\:\/\//, ""); var decodeXML = unescape(cbXML); var btnName = decodeXML.match(/\<name\/?.+/).toString(); var name = "untitled"; if (!/\<name\/\>/.test(btnName)) { name = btnName.replace(/\<\/?\w+\>/g, "").toString(); } var image = decodeXML.match(/\<image\/?.+/).toString(); var icon = ""; if (!/\<\image.*\[\].*\>$/.test(image)) { icon = image.match(/[^\[\]]+/g)[2].toString() .replace(/custombuttons\-stdicon\-\d/, "").toString(); } function htmlEntities(str) { return str.replace(/&/g, "&").replace(/</g, "<") .replace(/>/g, ">").replace(/"/g, """); } var xmlTemplate = "custombuttons/\"\n\ xmlns:html=\"http://www.w3.org/1999/xhtml\">\n\ <html:head>\n\ <html:title><![CDATA[" + name + "]]></html:title>\n\ <html:link rel=\"shortcut icon\" href=\"" + icon + "\"/>\n\ <html:style type=\"text/css\"><![CDATA[\n\ body { font-size: medium; margin: 0; }\n\ body, code:before, help:before, initcode:before {\n\ font-family: \"Verdana\", sans-serif;\n\ }\n\ #wrapper { position: fixed; top: 1em; right: 1em; text-align: center; }\n\ p { font-size: small; text-align: center; }\n\ #button {\n\ background-color: rgb(85, 168, 2);\n\ background-image: linear-gradient(to bottom, rgb(147, 200, 94),\ rgb(85, 168, 2));\n\ background-image: -moz-linear-gradient(top, rgb(147, 200, 94),\ rgb(85, 168, 2));\n\ background-image: -o-linear-gradient(top, rgb(147, 200, 94),\ rgb(85, 168, 2));\n\ background-image: -webkit-linear-gradient(top, rgb(147, 200, 94),\ rgb(85, 168, 2));\n\ border: 1px solid rgb(58, 116, 4);\n\ border-radius: .5em;\n\ -moz-border-radius: .5em;\n\ -webkit-border-radius: .5em;\n\ padding: 0;\n\ margin-bottom: 1em;\n\ box-shadow: 1px 2px 3px rgba(0, 0, 0, .25);\n\ -moz-box-shadow: 1px 2px 3px rgba(0, 0, 0, .25);\n\ -o-box-shadow: 1px 2px 3px rgba(0, 0, 0, .25);\n\ -webkit-box-shadow: 1px 2px 3px rgba(0, 0, 0, .25);\n\ }\n\ #button a {\n\ color: #000;\n\ text-shadow: -1pt -1px 0pt rgba(255, 255, 255, .5);\n\ padding: 1em;\n\ text-decoration: none;\n\ }\n\ :-moz-any-link:focus {\n\ color: white;\n\ outline-color: transparent;\n\ text-decoration: none;\n\ }\n\ #button a, code, code:before, initcode, initcode:before, help, help:before {\ \n display: block;\n\ }\n\ #credits { position: fixed; bottom: 1em; right: 1em; font-size: small; }\n\ custombutton { background-color: rgb(171, 171, 171); margin: 1em; }\n\ date, image, mode, accelkey { display: none; }\n\ name { font-weight: bold; font-size: x-large; }\n\ code:before, help:before, initcode:before {\n\ font-weight: bold;\n\ font-size: large;\n\ margin: 0 0 1em;\n\ padding: .5em;\n\ }\n\ code:before { content: \"Код\"; }\n\ help:before { content: \"Справка\"; }\n\ initcode:before { content: \"Инициализация\"; }\n\ code, initcode, help {\n\ background-color: rgb(255, 255, 255);\n\ border: 1px inset rgb(170, 170, 170);\n\ font: medium monospace;\n\ margin: 1em 1em 2em 0;\n\ padding: 1em;\n\ text-align: left;\n\ width: 840px;\n\ white-space: pre-wrap;\n\ word-wrap: break-word;\n\ }\n\ .clear { clear: both; }\n\ ]]></html:style>\n\ </html:head>\n\ <html:body>\n\ <html:div id=\"wrapper\">\n\ <html:div id=\"button\">\n\ <html:a href=\"" + cbURI + "\" rel=\"nofollow\" title=\"Установить " + htmlEntities(name, "ENT_COMPAT") +"\">\n\ <![CDATA[Установить кнопку]]>\n\ </html:a>\n\ </html:div>\n\ <html:div id=\"credits\">\n\ <html:a href=\"" + topicURL +"\">\n\ <![CDATA[Другие кнопки]]><html:br/>\ <![CDATA[на форуме Mozilla Россия]]>\n\ </html:a>\n\ </html:div>\n\ </html:div>\n\ </html:body>"; decodeXML = decodeXML.replace(/custombuttons\/\"\>/, xmlTemplate); name += ".xml"; saveToFile(decodeXML, name); var btn = document.popupNode; var as = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService); as.showAlertNotification(btn.image, "Кнопка: " + btn.name, "сохранена в XML файл", false, "", null); } var mrw = mostRecentWindow('navigator:browser'); var css = '@-moz-document url("chrome://browser/content/browser.xul"){' + this.Help + '}'; var uri = makeURI('data:text/css,' + encodeURIComponent(css)); var sss = Components.classes['@mozilla.org/content/style-sheet-service;1'].getService(Components.interfaces.nsIStyleSheetService); if (!sss.sheetRegistered(uri, sss.USER_SHEET)) sss.loadAndRegisterSheet(uri, sss.USER_SHEET); /////////////////////////////// Добавить кнопку из XML файл /////////////////////////////// this.loadXML = function loadXML() { var nsIFilePicker = Ci.nsIFilePicker; var fp = window.makeFilePicker(); fp.init(window, "Установить кнопку из XML файла", nsIFilePicker.modeOpen); fp.appendFilters(fp.filterXML); fp.appendFilter("Все файлы", "*.*"); fp.open(re=> { if ( re == fp.returnOK ) gBrowser.selectedTab = gBrowser.addTrustedTab(fp.file.path); }) } /////////////////////////////// Сохранить все кнопки в HTML файл /////////////////////////////// this.saveToHTMLALLCode = function saveToHTMLALLCode() { var visibleCBbuttons = [...document.querySelectorAll('[cb-mode]')]; var paletteCBbuttons = [...custombuttons.palette.querySelectorAll('[cb-mode]')]; var allCBbuttons = visibleCBbuttons.concat(paletteCBbuttons); var gn = btn => btn.getAttribute("label") || "Без названия"; allCBbuttons.sort((a, b) => gn(a).localeCompare(gn(b))); var array = []; allCBbuttons.forEach(but=> { var uri = but.URI ? but.URI : getPaleteButtonsURI(but); var name1 = but.getAttribute("label") || "Без названия"; var image = but.getAttribute("image") || "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACNFBMVEXDRgDweQDnbwC0NgDCRQC7PQDtpTu+QQD78q3PUwDCRAD//8vbYQDLTgDocAD0iQX1jQbGSgD7iAD4gwDVaw7vdwDyegD+igDweQDlawDyhAXveADmZwDzmBbtcwDwkhHveADmhBTkgxbweADkfRH+igD7hADXZQX0gADyjA/tfgvveQDiawDQVADRXgfnbwD1jAb9iQD9z0PVZAbxpinykRHtdgD5mRbERQDDRgDOYArCRAD9iQD3ewDxegD3dwDFRgDAQAD+hgD4fQDucgDtgQftfwTISQDCRQDvdgD5lxb1kRb2qh7wnynkagD766LDRQDDRwDDRQDspjbtpzbuqDbvqzv//8DUZAbCRQD//83pjhvveQbvggW+QQDfcxLlmUb//8veYADMTwDHSADVVwC8PgDwixb78q3oZgDUWADRVADCRQD9iQDERwDBQQDYVQC+PgC0NgDbYQDWWgDUWADSVQDFSAC+QAC7PAC0NgD+wRL+/kD+/zb+7i3+8Cv+/DX+wBL/+DD/rwz+qgz+rwz/tAz+sQzfbAT+3iP/+jD//Dz1jwP+nwf5iwf7pBz2tRr4lwb/ogfsdQT+2R7/9ET+2iT8yyLmgBL5iQL2egLokhP7zzT60zv1zUr0gAL1ewP50yn9+UL++EXooyngaAH41EPzowzyySj+xxzlhhHvvyruwjXxvTnUag3+zxrwigP+swz86U/ZXwD75lHqegD6xzb//kn+uhPTXAG3OAD/+UC2vFeJAAAAe3RSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAACfnwAIaelpAAA2+wD7UQAAa3oArKzRzMysnwgAvPQA/gAAw3prw0oALr16vS4AACnF6bspAAAA/mIAADQAAAAAAI8AAEwA0vv7kd2yAuuvr+vKABL23U+8Sk/d9vUDIIAQAAAQgCAfvupHAAABB0lEQVR4Xi3IU3fDABgA0C+u26FdZ9u2bdu2vZSzbds2/tyac3IfLxjpGyA6MimqY6gHTNgiiNwkwRM1E7EhTrYyTfMzzsh0ZEPiH+D6+u5mV1jEhpe5haVCYW1T4suEvUOkk7PLpVJ5WFnl7hEUDN5LPvsHJ6cazdn13f3DYxu0B35+/Y2qVSr17NzGeUgohIVHLK/PMDa39qKieRATGxd/9cS4uU1MwnmQktqY/qGlaVr7/ZOVDTmQm5df8PwyNj4xOTVdjOM4kCRZOr+wWFa+srpWQVEU8PnV2zu7NbV19UfHDQRBAIfTdNHc0soVdnR2dfdgGAgEvW99/QNc4eDQ8O8Ihv0D77NPgbVLZ6kAAAAASUVORK5CYII="; array.push("<li>\n<img src=" + image + "> \<a href=" + uri + ">" + name1 +"</a><br>\n"); }); var before = "<html>\n<head>\n<title>Custom Buttons</title>\n<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>\n"; var before1 = "<style type='text/css'>\nbody {background: beige;} a:link {color: black; text-decoration: none;} img {border: 0; margin: 0px 10px;}\n</style>\n"; var before2 = "</head>\n<body>\nCustom Buttons\n<p>\n"; var info = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo); var before3 = info.vendor + " " + info.name + " " + info.version + " (build " + info.appBuildID + ")\n"; var after = "\n</ol>\n</body>\n</html>"; var text = before + before1 + before2 + before3 + "<p>\n" + bDate + "<p>\n" + "<ol>" + array.join("") + after; var name = "CB buttons " + aDate + ".html" saveToFile(text, name); var alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService) alertsService.showAlertNotification(saveImg5, "Экспорт в HTML", "Экспортировал все CB кнопки как HTML"); setTimeout(()=> alertsService.closeAlert(), 4000); }; function getPaleteButtonsURI(but) { var uri = "chrome://custombuttons/content/nbftemplate.xml"; var stream = NetUtil.newChannel({uri, loadUsingSystemPrincipal: true}).open(); var doc = new DOMParser().parseFromStream(stream, null, stream.available(), "application/xml"); stream.close(); ["help,Help", "name,label", "image,image", "mode,cb-mode", "initcode,cb-init", "accelkey,cb-accelkey", "code,cb-oncommand"] .forEach(str=> { var arr = str.split(','); var value = but.getAttribute(arr[1]), name = arr[0]; custombutton.buttonSetText(doc, name, value, true); }); var ser = new XMLSerializer(); return "custombutton://" + escape(ser.serializeToString(doc)); }; /////////////////////////////// Сохранить кнопку в HTML файл /////////////////////////////// this.saveToHTMLCode = function saveToHTMLCode() { var btn = document.popupNode; var xml = '<html xmlns="' + xhtmlns + '">\n'; xml += '<head>\n'; xml += '<meta http-equiv = "Content-Type" content = "text/html; charset=utf-8"/>\n'; xml += '<title> ' + btn.name + ' для Custom Buttons </title>\n'; xml += '<link rel="icon" type="image/vnd.microsoft.icon" href = "'+ btn.image +'" />\n'; xml += '<style type="text/css">\n'; xml += '.button a{ \n'; xml += 'background-color: rgb(85, 168, 2); \n'; xml += 'background-image: linear-gradient(to bottom, rgb(147, 200, 94), rgb(85, 168, 2)); \n'; xml += 'background-image: -moz-linear-gradient(top, rgb(147, 200, 94), rgb(85, 168, 2)); \n'; xml += 'border: 1px solid rgb(58, 116, 4); \n'; xml += 'border-radius: .5em; \n'; xml += ' -webkit-border-radius: .5em; \n'; xml += 'padding: 0; \n'; xml += 'margin-bottom: 1em; \n'; xml += 'box-shadow: 1px 2px 3px rgba(0, 0, 0, .25); \n'; xml += ' -o-box-shadow: 1px 2px 3px rgba(0, 0, 0, .25); \n'; xml += ' -webkit-box-shadow: 1px 2px 3px rgba(0, 0, 0, .25); \n'; xml += ' color: #000; \n'; xml += ' text-shadow: -1pt -1px 0pt rgba(255, 255, 255, .5); \n'; xml += ' padding: 0.5em; \n'; xml += ' text-decoration: none; \n'; xml += '} '; xml += 'pre { border: 1px inset rgb(170, 170, 170); \n'; xml += 'background-color: rgb(255, 255, 255);} \n'; xml += 'body { background-color: rgb(245, 245, 220);} \n'; xml += '</style> \n'; xml += '</head>\n'; xml += '<body>\n'; xml += '<section id="install"><h1> ' + btn.name + ' </h1> \n'; xml += '</section>\n'; xml += '<div class="button"><a href = "' + btn.URI + '">Установить кнопку</a></div> \n'; xml += '<section id="init"><h2>Инициализация</h2><pre>' + e4xConv_encodeHTML(btn.cbInitCode) + '</pre></section>\n'; xml += '<section id="code"><h2>Код</h2><pre>' + e4xConv_encodeHTML(btn.cbCommand) + '</pre></section> \n'; xml += '<section id="help"><h2>Справка</h2><pre>' + e4xConv_encodeHTML(btn.Help) + '</pre></section> \n'; xml += '</body> \n'; xml += '</html> '; var html = '<!DOCTYPE html>\n' + xml; var name = btn.name + ".HTML"; saveToFile(html, name); var as = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService); as.showAlertNotification(btn.image, "Кнопка: " + btn.name, "сохранена в HTML файл", false, "", null); } function e4xConv_encodeHTML(s, isAttr) { s = String(s) .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """); if(isAttr) { s = s .replace(/\t/g, "	") .replace(/\n/g, "
") .replace(/\r/g, "
"); } return s; }; /////////////////////////////// Переместить кнопку /////////////////////////////// this.MoveToolbarButtons = MTB = { // Start editable preferences MoveButtonMICBContext: true, // Add "Move button" menu item to Custom Buttons context menu? MoveButtonMITBarContext: false, // Add "Move button" menu item to toolbars context menu? ShowMoveAlert: false, // Show the alert with instructions when moving buttons? MoveBtnImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAYklEQVQ4jWNgGJTgaAXHf2LEcGrGZQBBQ45WcPz/fZ0XpwG45FAUEDIAqzyyJLIiZIxNHqdmYvHRCo7/DLhsIEYziivQDcHnBawxgqyQUCzgjQlC6YCotEB2QkJWTIzY4AAAezv/caeCLKcAAAAASUVORK5CYII=", // End editable preferences _UID: "__cb_move_toolbar_buttons_" + custombuttons.getNumber(self.id), WindowIDs: ["main-window", "messengerWindow", "msgcomposeWindow"], ToolbarContexIDs: ["toolbar-context-menu", "aios-toolbar-contextmenu", "aios-sbhtoolbar-contextmenu"], Pref: "extensions.custombuttons.MoveToolbarButtons.Id" + custombuttons.getNumber(self.id) + ".MoveButtonID", SP: Services.prefs, Init: function() { if (!(MTB._UID in window)) { window[MTB._UID] = { Initialized: false }; } if (!window[MTB._UID]["Initialized"]) { window[MTB._UID]["Initialized"] = true; custombuttons.isPref(MTB.Pref, ""); if ("CustomizableUI" in window) { var originalFunction = custombuttons.persistCurrentSets.toString(); eval("custombuttons.persistCurrentSets=" + originalFunction .replace(", newButtonId)", ", newButtonId, aToRight)") .replace("pos + 1", "aToRight ? pos : pos + 1")); } if (MTB.MoveButtonMICBContext) { var contextPops = document.getElementsByTagName("menupopup"); let p = 0, pLen = contextPops.length; for (; p < pLen; p++) { var cPopID = contextPops[p].id; if (cPopID.substr(0, 26) === "custombuttons-contextpopup") { var cPopEl = document.getElementById(cPopID); var moveMIID = "custombuttons-contextpopup-moveButton" + cPopID.slice(26); var moveMIEl = document.getElementById(moveMIID); if (!moveMIEl) MTB.CreateMoveMI(moveMIID, cPopEl); } } } if (MTB.MoveButtonMITBarContext) { Array.prototype.slice.call(MTB.ToolbarContexIDs).forEach(function(aTBCtxID, aIndex) { let Ctx = document.getElementById(aTBCtxID); let tBarCtxMIID = MTB._UID + "moveButton" + aIndex; if (!document.getElementById(tBarCtxMIID)) { if (Ctx) { MTB.CreateMoveMI(tBarCtxMIID, Ctx); Ctx.addEventListener("popupshowing", function(aE) { document.getElementById(tBarCtxMIID).hidden = (document.popupNode.tagName !== "toolbarbutton"); }, false); } } }); } addDestructor(function(aReason) { if (aReason === "delete") { SP.resetUserPrefs(MTB.Pref); delete window[_UID]; } if (aReason === "delete" || aReason === "update") { window[MTB._UID]["Initialized"] = false; } }); } }, getPopupNode: function(aEl) { if (custombuttons.popupNode) return custombuttons.popupNode; var popupNode = aEl; while (popupNode.tagName.toLowerCase() !== "toolbarbutton") { popupNode = popupNode.parentNode; } return popupNode; }, CreateMoveMI: function(aMItemID, aPopupEl) { let moveMIEl = aPopupEl.appendChild(document.createElementNS(xulns, "menuitem")); moveMIEl.setAttribute("id", aMItemID); moveMIEl.setAttribute("label", "Переместить кнопку..."); moveMIEl.setAttribute("class", "menuitem-iconic"); moveMIEl.setAttribute("image", MTB.MoveBtnImage); moveMIEl.setAttribute("tooltip", MTB._UID + "moveButtonMI_tooltip"); moveMIEl.setAttribute("onclick", "document.getElementById(\"" + self.id + "\").MoveToolbarButtons.MoveOnClick(event);"); }, MoveOnClick: function(aE) { var popupNode = MTB.getPopupNode(aE.target); if (!popupNode) return; aE.stopPropagation(); aE.preventDefault(); if (aE.button === 0 && !aE.shiftKey && !aE.ctrlKey && !aE.altKey) { MTB.SP.setCharPref(MTB.Pref, popupNode.id); window.addEventListener('click', MTB.MoveListener, true); window.addEventListener('mouseup', MTB.DefaultPrevention, true); window.addEventListener('mousedown', MTB.DefaultPrevention, true); window.addEventListener('contextmenu', MTB.DefaultPrevention, true); MTB.HidePopup(aE.target); MTB.ShowMoveAlert && Services.prompt.alert(null, self.name, "Now click ANY toolbarbutton element inside ANY toolbar.\n" + "Left click will position the button to the left of the target.\n" + "Right click will position the button to the right of the target.\n\n" + "To cancel the movement, just click ANY element inside the browser that IS NOT a toolbarbutton.\n"); } }, MoveListener: function(aE) { MTB.DefaultPrevention(aE); window.removeEventListener('click', MTB.MoveListener, true); window.removeEventListener('mouseup', MTB.DefaultPrevention, true); window.removeEventListener('mousedown', MTB.DefaultPrevention, true); window.removeEventListener('contextmenu', MTB.DefaultPrevention, true); var anchor = aE.target; if (anchor.tagName !== "toolbarbutton") return; var toolbar = anchor.parentNode; var BtnToMove = document.getElementById(MTB.SP.getCharPref(MTB.Pref)); if (aE.button === 0 && !aE.shiftKey && !aE.ctrlKey && !aE.altKey) toolbar.insertBefore(BtnToMove, anchor); else if (aE.button === 2 && !aE.shiftKey && !aE.ctrlKey && !aE.altKey) toolbar.insertBefore(BtnToMove, anchor.nextSibling); if ("CustomizableUI" in window) custombuttons.persistCurrentSets(toolbar.id, anchor.id, BtnToMove.id || BtnToMove.getAttribute("id"), !(aE.button === 2)); else { toolbar.setAttribute("currentset", toolbar.currentSet); document.persist(toolbar.id, "currentset"); } MTB.SP.setCharPref(MTB.Pref, ""); }, DefaultPrevention: function(aE) { aE.preventDefault(); aE.stopImmediatePropagation && aE.stopImmediatePropagation(); aE.stopPropagation(); }, Tooltips: function(aRem) { var popSetID = MTB._UID + "popupset"; var popSetEl = document.getElementById(popSetID); if (popSetEl) popSetEl.parentNode.removeChild(popSetEl); if (aRem) return; if (!popSetEl) { popSetEl = document.createElementNS(xulns, "popupset"); popSetEl.setAttribute("id", popSetID); } popSetEl.appendChild(MTB.parseXML("<tooltip xmlns=\"" + xulns + "\" xmlns:html=\"" + xhtmlns + "\" id=\"" + MTB._UID + "moveButtonMI_tooltip" + "\">" + "<description><html:b>Instructions</html:b> : After clicking this menu item, you can " + "click ANY toolbarbutton element inside the application to place the currently " + "selected button to the left (with Left click) or to the right (with Right click) " + "of the targeted toolbarbutton.</description>" + "<separator/>" + "<description><html:b>Note</html:b> : It can be ANY toolbarbutton, not just " + "other Custom Buttons.</description>" + "</tooltip>")); setTimeout(function() { Array.prototype.slice.call(MTB.WindowIDs).forEach(function(aWinID) { let win = document.getElementById(aWinID); if (win) !document.getElementById(popSetID) && win.appendChild(popSetEl); }); }, 100); }, parseXML: function(aXML) { // Return parsed XML aXML = aXML.replace(/>\s+</g, "><"); // Linearize XML return (new DOMParser).parseFromString(aXML, "application/xml").documentElement; }, HidePopup: function(aEl) { try { aEl.hidePopup(); } catch (aError) { try { aEl.parentNode.hidePopup(); } catch (aError) { try { aEl.parentNode.parentNode.hidePopup(); } catch (aError) { try { aEl.parentNode.parentNode.parentNode.hidePopup(); } catch (aError) {} } } } } }; this.MoveToolbarButtons.Init();
И Экспорт всех CB кнопок в HTML файл
this.onclick =()=> menuPopup.openPopup(this, "after_start"); var array = [ [ "Экспорт всех CB кнопок в HTML файл", "setPathToHtmlFile()", "data:image/x-icon;base64,AAABAAEAEhIAAAEAIACABQAAFgAAACgAAAASAAAAJAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/w4P6P8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/zUq6P8OD+j/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/0RC//0cE+X/Dg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQW5/8tMOT/Njfw/0BA+v9JSP//UU///1hT//9aVv3/RUL5/zQy+f8zNPH/JSHa/w4P6P8AAAAAAAAAAAAAAAAAAAAAAAAAABAR5v0UFeL/Hh7v/Soo+P80Mf39PDn+/0I+//05NPn/F5sr/zlO0/08PeL/NDbb/Rwdyv8OD+j/AAAAAAAAAAAAAAAAAAAAAA4P6P8XGOn/Hh7x/yQk9f8rKvX/MjD1/zk0+f85NPn/F5sr/xebK/8lQ6n/Hx/D/w4P6P8AAAAAAAAAAAAAAAAAAAAAAAAAAA4P6P8OD+j/Dg/o/w4P6P8OD+j/Dg/o/w4P6P8OD+j/F5sr/zfyX/0Xmyv/Dg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH3EgP+W8J//m/Sk/6D5qv+k/K7/qPyz/6z8uP9t2H7/QuJf/zz/Xv8f7UX/F5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOQFP8f5D3/KexI/zL3U/87/V3/Qf9k/0T/aP9K/2v/Qf9j/zn5Wf8571X/Kt1J/xebK/8AAAAAAAAAAAAAAAAAAAAAAAAAAAeUGf0Y6Tj/IvNE/Sn6Tv81/lj9Pv9h/0X9Z/1H/mf/Rvpk/0HvXP064VP/MtZL/RrHN/8Xmyv/AAAAAAAAAAAAAAAAAAAAAAmYHP8JmBz/CZgc/wmYHP8JmBz/CZgc/wmYHP8JmBz/CZgc/zjgUf8x1kj/FMIy/xebK/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKL08/zDXSP0NvCz/F5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHKsv/xS9Lv8Xmyv/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/xebK/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//8BB/9/AQf/PwEH/x8BB/8PAQcABwEHAAMBBwAHAQcADwEHAA8BBwAHAQcAAwEHAAcBB/8PAQf/HwEH/z8BB/9/AQf//wEE="], [ "Открыть в вкладке HTML файл", "openHtmlFileInTab()", "data:image/x-icon;base64,AAABAAEAEhIAAAEAIACABQAAFgAAACgAAAASAAAAJAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXmyv/F5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABebK/8UvS7/HKsv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/w28LP8w10j9KL08/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXmyv/FMIy/zHWSP844FH/CZgc/wmYHP8JmBz/CZgc/wmYHP8JmBz/CZgc/wmYHP8JmBz/AAAAAAAAAAAAAAAAAAAAABebK/8axzf/MtZL/TrhU/9B71z9Rvpk/0f+Z/9F/Wf9Pv9h/zX+WP0p+k7/IvNE/RjpOP8HlBn9AAAAAAAAAAAAAAAAAAAAAAAAAAAXmyv/Kt1J/znvVf85+Vn/Qf9j/0r/a/9E/2j/Qf9k/zv9Xf8y91P/KexI/x/kPf8DkBT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/x/tRf88/17/QuJf/23Yfv+s/Lj/qPyz/6T8rv+g+ar/m/Sk/5bwn/99xID/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/xebK/838l/9F5sr/w4P6P8OD+j/Dg/o/w4P6P8OD+j/Dg/o/w4P6P8OD+j/AAAAAAAAAAAAAAAAAAAAAAAAAAAOD+j/Hx/D/yVDqf8Xmyv/F5sr/zk0+f85NPn/MjD1/ysq9f8kJPX/Hh7x/xcY6f8OD+j/AAAAAAAAAAAAAAAAAAAAAA4P6P8cHcr/NDbb/Tw94v85TtP9F5sr/zk0+f9CPv/9PDn+/zQx/f0qKPj/Hh7v/RQV4v8QEeb9AAAAAAAAAAAAAAAAAAAAAAAAAAAOD+j/JSHa/zM08f80Mvn/RUL5/1pW/f9YU///UU///0lI//9AQPr/Njfw/y0w5P8UFuf/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/xwT5f9EQv/9Dg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4P6P81Kuj/Dg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOD+j/Dg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//8BB/v/AQfz/wEH4/8BB8P/AQeAAwEHAAMBB4ADAQfAAwEHwAMBB4ADAQcAAwEHgAMBB8P/AQfj/wEH8/8BB/v/AQf//wEE="], [ "separator" ], [ "Открыть папку для экспорта CB кнопок", "openHtmlFileFolder()", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABZ0RVh0Q3JlYXRpb24gVGltZQAwOC8xMS8wNdiEE10AAAAldEVYdFNvZnR3YXJlAE1hY3JvbWVkaWEgRmlyZXdvcmtzIE1YIDIwMDSHdqzPAAACiUlEQVR4nKWTy0uUYRTGf+/np6PTODOmMpaGhJRaZmQgRAQtglaBf4BRtGgTFLUqKjBoF1QQlBLdKCgrscuiFEq6gGmQBWWSYLfpMqXMTM71+773PS0kQXBR9MBvdZ7z8HDgKBHhf2T9jUkdUbVKKTXfzH7eqVpdXbDDzWvRmrDngePyMZniXfsxLtLBFuAWhziqlOoQET0n4dlprk5/uysisTncO7Gqt3s/N5eeWCjD8T5ZcWa5nNvFmc6d7AEKRAQRgaHT9Gcyb0XyB+ain8jGC+ul5/15GXTuSN+3bmntapHj2+kFyv6E2K7DSrw0Yw9v8ys6gS9chfbgWvA5K2qXUb2knAfZflaXrWXTqg2MByNt12sG25JTiaRSqsI2wuLU5HdyU19p2TZOga+IfX27CUdqqG8KMeK9IKdchtLP8GpdaivXcN8S1g3cDwERWxvIJmP4K1qwfRmQl5wc6p450B14dLiHCecTzf5mtp7aC0BlqJx1M44iywjk4q/xVzSDxMEkkYNXkIOXKSsOoESwUChgoS+At/8GI5u7JOswDIhlDKR/DBKoXA4mCiYxS124nBLxqKCQoGjqwuV46QSTH0fIOYwCjm0MuOnPFAXrwB2eKWY8yKdoDJbgd35S5eYJmWkaQqWYfCGf3wyQc4gCrm0EvMwXiksXQW4SslnIZ0GEhkAJC3IJIq4mpNM0lgaxiqpJTX1SP38xCni2ESgtsxBjgd0OAYHATJHGmgH8Ja1ECusIWSHqa6rI5MKk4lGejjEKuLbWvJqMmdVDZ5vwPGbRGr5rxeDjahJuCtsUE43FSOaFRJpLIx9IAK4CbKAS8AHzPsw8MkAaiCsRQSll/8PybIiI6N8D8VYf0gJ8eQAAAABJRU5ErkJggg=="], [ "Экспорт всех CB кнопок в HTML файл без запроса", "exportsButtonsToHtmlFile()", "data:image/x-icon;base64,AAABAAEAEhIAAAEAIACABQAAFgAAACgAAAASAAAAJAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE8A/wBPAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE8A/wBkAP8ATwD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE8A/wB6AP0AUgD/AE8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAP8AZQD/AG4A/wB3AP8AfwD/AIQA/wCHAP8AiAD/AHkA/wBtAP8AbAD/AFgA/wBPAP8AAAAAAAAAAAAAAAAAAAAAAAAAAABQAP0AUgD/AFwA/QBmAP8AbgD9AHQA/wB4AP0AbwD/F5sr/wBzAP0AbgD/AGcA/QBQAP8ATwD/AAAAAAAAAAAAAAAAAAAAAABPAP8AVgD/AF0A/wBiAP8AZwD/AGsA/wBvAP8AbwD/F5sr/xebK/8AXgD/AFAA/wBPAP8AAAAAAAAAAAAAAAAAAAAAAAAAAABPAP8ATwD/AE8A/wBPAP8ATwD/AE8A/wBPAP8ATwD/F5sr/zfyX/0Xmyv/AE8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH3EgP+W8J//m/Sk/6D5qv+k/K7/qPyz/6z8uP9t2H7/QuJf/zz/Xv8f7UX/F5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOQFP8f5D3/KexI/zL3U/87/V3/Qf9k/0T/aP9K/2v/Qf9j/zn5Wf8571X/Kt1J/xebK/8AAAAAAAAAAAAAAAAAAAAAAAAAAAeUGf0Y6Tj/IvNE/Sn6Tv81/lj9Pv9h/0X9Z/1H/mf/Rvpk/0HvXP064VP/MtZL/RrHN/8Xmyv/AAAAAAAAAAAAAAAAAAAAAAmYHP8JmBz/CZgc/wmYHP8JmBz/CZgc/wmYHP8JmBz/CZgc/zjgUf8x1kj/FMIy/xebK/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKL08/zDXSP0NvCz/F5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHKsv/xS9Lv8Xmyv/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/xebK/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//8BB/9/AQf/PwEH/x8BB/8PAQcABwEHAAMBBwAHAQcADwEHAA8BBwAHAQcAAwEHAAcBB/8PAQf/HwEH/z8BB/9/AQf//wEE="] ]; var menuPopup = self.appendChild(document.createXULElement("menupopup")); array.forEach((m,i)=> { if ( m[0] == "separator" ) { menuPopup.appendChild(document.createXULElement("menuseparator")); return }; var mItem = menuPopup.appendChild(document.createXULElement("menuitem")); mItem.setAttribute("label", m[0]); mItem.setAttribute("class", "menuitem-iconic"); mItem.setAttribute("image", m[2]); mItem.addEventListener("command", ()=> eval(m[1])); }); menuPopup.setAttribute("onclick", "event.stopPropagation()"); function openHtmlFileInTab() { var fp = window.makeFilePicker(); fp.init(window, "Выберите HTML-файл для импорта закладок", fp.modeOpen); fp.appendFilters(fp.filterHTML); Cu.import("resource://gre/modules/FileUtils.jsm"); fp.displayDirectory = FileUtils.File(getPathToHtmlFileFolder()); fp.open(re=> { if ( re == fp.returnOK ) gBrowser.selectedTab = gBrowser.addTab(fp.file.path, { triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),}) }) }; function exportsButtonsToHtmlFile() { var visibleCBbuttons = [...document.querySelectorAll('[cb-mode]')]; var paletteCBbuttons = [...custombuttons.palette.querySelectorAll('[cb-mode]')]; var allCBbuttons = visibleCBbuttons.concat(paletteCBbuttons); var array = []; allCBbuttons.forEach(but=> { var uri = but.URI ? but.URI : getPaleteButtonsURI(but); var name = but.getAttribute("label") || "Без названия"; var image = but.getAttribute("image") || "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACNFBMVEXDRgDweQDnbwC0NgDCRQC7PQDtpTu+QQD78q3PUwDCRAD//8vbYQDLTgDocAD0iQX1jQbGSgD7iAD4gwDVaw7vdwDyegD+igDweQDlawDyhAXveADmZwDzmBbtcwDwkhHveADmhBTkgxbweADkfRH+igD7hADXZQX0gADyjA/tfgvveQDiawDQVADRXgfnbwD1jAb9iQD9z0PVZAbxpinykRHtdgD5mRbERQDDRgDOYArCRAD9iQD3ewDxegD3dwDFRgDAQAD+hgD4fQDucgDtgQftfwTISQDCRQDvdgD5lxb1kRb2qh7wnynkagD766LDRQDDRwDDRQDspjbtpzbuqDbvqzv//8DUZAbCRQD//83pjhvveQbvggW+QQDfcxLlmUb//8veYADMTwDHSADVVwC8PgDwixb78q3oZgDUWADRVADCRQD9iQDERwDBQQDYVQC+PgC0NgDbYQDWWgDUWADSVQDFSAC+QAC7PAC0NgD+wRL+/kD+/zb+7i3+8Cv+/DX+wBL/+DD/rwz+qgz+rwz/tAz+sQzfbAT+3iP/+jD//Dz1jwP+nwf5iwf7pBz2tRr4lwb/ogfsdQT+2R7/9ET+2iT8yyLmgBL5iQL2egLokhP7zzT60zv1zUr0gAL1ewP50yn9+UL++EXooyngaAH41EPzowzyySj+xxzlhhHvvyruwjXxvTnUag3+zxrwigP+swz86U/ZXwD75lHqegD6xzb//kn+uhPTXAG3OAD/+UC2vFeJAAAAe3RSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAACfnwAIaelpAAA2+wD7UQAAa3oArKzRzMysnwgAvPQA/gAAw3prw0oALr16vS4AACnF6bspAAAA/mIAADQAAAAAAI8AAEwA0vv7kd2yAuuvr+vKABL23U+8Sk/d9vUDIIAQAAAQgCAfvupHAAABB0lEQVR4Xi3IU3fDABgA0C+u26FdZ9u2bdu2vZSzbds2/tyac3IfLxjpGyA6MimqY6gHTNgiiNwkwRM1E7EhTrYyTfMzzsh0ZEPiH+D6+u5mV1jEhpe5haVCYW1T4suEvUOkk7PLpVJ5WFnl7hEUDN5LPvsHJ6cazdn13f3DYxu0B35+/Y2qVSr17NzGeUgohIVHLK/PMDa39qKieRATGxd/9cS4uU1MwnmQktqY/qGlaVr7/ZOVDTmQm5df8PwyNj4xOTVdjOM4kCRZOr+wWFa+srpWQVEU8PnV2zu7NbV19UfHDQRBAIfTdNHc0soVdnR2dfdgGAgEvW99/QNc4eDQ8O8Ihv0D77NPgbVLZ6kAAAAASUVORK5CYII="; array.push("<img src=" + image + "> <a href=" + uri + ">" + name +"</a><br>\n"); }); var before = "<html>\n<head>\n<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>\n</head>\n<body>\n"; var after = "\n</body>\n</html>"; var text = before + array.join("") + after; var text = convertFromUnicode("UTF-8", text); var date = new Date(); var time = date.toLocaleString('ru', {year: 'numeric', month: 'numeric', day: 'numeric'}) var time = time + '. ' + date.toLocaleTimeString().replace(/:/g, "˸"); var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); file.initWithPath(getPathToHtmlFileFolder()); file.append("CB buttons " + time + ".html"); custombuttonsUtils.writeFile(file.path, text); var alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService) alertsService.showAlertNotification(self.image, self.label, "Экспортировал все CB кнопки как HTML в " + file.path); setTimeout(()=> alertsService.closeAlert(), 4000); }; function getPaleteButtonsURI(but) { var uri = "chrome://custombuttons/content/nbftemplate.xml"; var stream = NetUtil.newChannel({uri, loadUsingSystemPrincipal: true}).open(); var doc = new DOMParser().parseFromStream(stream, null, stream.available(), "application/xml"); stream.close(); ["help,Help", "name,label", "image,image", "mode,cb-mode", "initcode,cb-init", "accelkey,cb-accelkey", "code,cb-oncommand"] .forEach(str=> { var arr = str.split(','); var value = but.getAttribute(arr[1]), name = arr[0]; custombutton.buttonSetText(doc, name, value, true); }); var ser = new XMLSerializer(); return "custombutton://" + escape(ser.serializeToString(doc)); }; function openHtmlFileFolder() { var folder = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); folder.initWithPath( getPathToHtmlFileFolder() ); folder.launch(); }; function setPathToHtmlFile() { var fp = window.makeFilePicker(); fp.init(window, "Укажите папку для экспорта CB кнопок!", fp.modeGetFolder); fp.open(re=> { if ( re != fp.returnOK ) return; cbu.setPrefs("CB.exportsButtonsToHtmlFile.path", convertFromUnicode("UTF-8", fp.file.path)); exportsButtonsToHtmlFile(); }) }; function getPathToHtmlFileFolder() { var s = "CB.exportsButtonsToHtmlFile.path", pref = Services.prefs; var str = pref.getStringPref ? pref.getStringPref(s) : pref.getComplexValue(s, Ci.nsISupportsString).data; try { return str } catch(e) { return "C:" }; }; function convertFromUnicode(charset, str) { var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); converter.charset = charset; str = converter.ConvertFromUnicode(str); return str + converter.Finish(); }; this.onmouseover =()=> { this.tooltipText = self.label + "\nЛ: Меню кнопки\nП: CB меню\n\nПапка для экспорта:\n" + getPathToHtmlFileFolder(); };
Просьба поправить для работы в форке r3dfox 127
Отсутствует
Есть две (уверен важные для многих) кнопки
Важные? Мб комуто...
покатал на 130rc2, вроде всё арбатает, но стоит проверить...
/*Initialization Code*/ ///////////////////////////////////////////////////////////////////////////// /////////////////////////////// Создание меню /////////////////////////////// ///////////////////////////////////////////////////////////////////////////// function $(aId) { return document.getElementById(aId); }; function addMenuItem(aNewIDs, aNodeIDs, aLabel, aIcon, aCommand) { for (var i = 0; i < aNewIDs.length; i++) { if ($(aNewIDs[i])) $(aNewIDs[i]).parentNode.removeChild($(aNewIDs[i])); var mi = document.createXULElement("menuitem"); mi.setAttribute("id", aNewIDs[i]); mi.setAttribute("class", "menuitem-iconic"); mi.setAttribute("image", aIcon); mi.setAttribute("label", aLabel); mi.setAttribute("oncommand", aCommand); if (i == 0) mi.setAttribute("observes", "custombuttons-contextbroadcaster-primary"); if ($(aNodeIDs[i])) { if ($(aNodeIDs[i]).nextSibling) { $(aNodeIDs[i]).parentNode.insertBefore(mi, $(aNodeIDs[i]).nextSibling); } else { $(aNodeIDs[i]).parentNode.appendChild(mi); } } } }; var saveImg1 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAnUlEQVQ4jc3RPQ4BURTF8Z+PgrAPtUJnIxZgBZagkolVqDWWIliARCFR6GSq0Twyw2SemcpJTnPzzv/edy//ohOymj7mARl6NRoOQ6YAiGmNFAm6TQBpePdAJwYYYIF+rpaE8CoGaGEbarsw7qfaVYCl4rY3mOOGaQwwU326O8Zhyi/AJPwxdv8rRmWAyw/hl89lgCZ+69AgvPcXegKfOWlGgoA/rgAAAABJRU5ErkJggg=="; var saveImg2 = "data:application/file;base64,AAABAAEAEBACAAEAAQCwAAAAFgAAACgAAAAQAAAAIAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAADbAAADpcAAA//AAANVwAAD/8AAAKsAAAD/AAAP//AAAP8AAAD/AAAD/8AAAwDAAAP/wAAA/wAAAP8AAA"; var saveImg3 = "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAAAAAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAAAAAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAAAAAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//+sQf//rEH4j6xB8IesQeHDrEHD4axBh/CsQYf4rEGH8KxBw+GsQeHDrEHwh6xB+I+sQf//rEH//6xB//+sQQ=="; var saveImg4 = "data:application/file;base64,AAABAAEAEBACAAEAAQCwAAAAFgAAACgAAAAQAAAAIAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAD/8AAA//AAAP/wAAD/8AAA//AAAP/wAAD/8AAA//AAAP/wAAD/8AAA//AAAP/wAAA/wAAAP8AAA"; var saveImg5 = "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU1FQr1FRT7BRUU+wUVFPsFFRT7BRUU+wUVFPsFFRT7BRUU+wUVFPsFFRT7BRUU+wU1FQrwAAAAAAAAAAAAAAAHd0cpz//////////////////////////////////////////////////////////3d0cpwAAAAAAAAAAAAAAAB4d3Sc/////+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg//////94d3ScAAAAAAAAAAAAAAAAenh3nP/////i4uL/4uLi/5yiz/9HYcT/PWrR/1qQ3P+nuNr/4uLi/+Li4v//////enh3nAAAAAAAAAAAAAAAAH18eJz/////5OTk/2FluP8IJ6r/D1TU/wli4v8FZeb/D3He/4y+5f/k5OT/+/v7/318eJwAAAAAAAAAAAAAAACBfXyc/////5Wc0v8JKq//E2Pd/yFTrv9EKTn/LjVZ/xaF2/8OdNP/zNnm//z8/P+BfXycAAAAAAAAAAAAAAAAhIGBnP////89Xc7/Dk7N/wpQ0/8zVp//TGCK/4U2Cf9DW2b/Eqj7/5C+5//8/Pz/hIGBnAAAAAAAAAAAAAAAAIaEgZz/////Kmnf/wlFzf8gPZ7/uXcl/8OAK/+UTBL/b1Az/zfG9f9srdX/+fn5/4aEgZwAAAAAAAAAAAAAAACJhoac/////0iN6P8HQtH/EVzd/2mCqf/dqkz/0pY6/6FnKv9Nvt7/kMfs//X19f+JhoacAAAAAAAAAAAAAAAAiomJnP////+Mr+r/FFnU/xVRyv+LorL/8Oqh//nXbP+5omH/Urvf/8bj7v/s7Oz/iomJnAAAAAAAAAAAAAAAAI6Kipz/////2+n3/5aSm/+hcEn/4uXC////2P/25KD/rqSD/7HR5//o6Oj/4eHh/46KipwAAAAAAAAAAAAAAACPjo6c//////j4+P/4+Pj/3s/F/9i/n//p27n/5NG0/+7r6f/r6+v/3t7e/9LS0v+Pjo6cAAAAAAAAAAAAAAAAk4+PnP/////6+vr/+vr6//r6+v/6+vr/+vr6//j4+P/19fX/r66t/62sq/ObmprrkI2NpgAAAAAAAAAAAAAAAJOTk5z//////Pz8//z8/P/8/Pz/+/v7//r6+v/4+Pj/9fX1/66trfHs7Ozrp6emp4aGhhMAAAAAAAAAAAAAAACWlpOc/////////////////v7+//39/f/6+vr/9/f3//Pz8/+bmprrp6enp3NzcxYAAAAAAAAAAAAAAAAAAAAAmJiWnJiYlpyYmJacmJiWnJeTk52SkZGemJiWnJeTk52SkZGej4+LpIaGhhMAAAAAAAAAAAAAAAAAAAAAgAMAAIADAACAAwAAgAMAAIADAACAAwAAgAMAAIADAACAAwAAgAMAAIADAACAAwAAgAMAAIADAACABwAAgA8AAA=="; var saveImg6 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABKklEQVR42mNkQAMNDAxCQMoTiB2BWAEq/ACI9wPxdqD8O2T1jGiao4HUEgb8IAaobimGAUDBGiDVzEAcqAWqb4EbQKTNWF3CCPXzW5ho/f//YDqHkZFhCpQNA7lAMV4gzY4QEmZEtx1mgCtQ8W4o2xLIPg5lJwDZUghDYkAGzAEyktENMAQqPA9l6wDZEkB6D6Yhc0EG7AGynfEZYAxkawHpxVC+A5CvC6RFGBj2Em2AIZCeg8Q3BtLSUAMIegGkwQBIz8U0YC7OQEQ2wAjIPoekGRQTUC/E4IxGkMKzaNEI8jso4chDbGdgA0UjekJ6A8S3gRikFWQyKOF/higGR50UFLPBEhLM9AZoUv4F1cAA1QTi/2SAJFkQnxdCoyZlJEPIz0xIhpCUnQFx83abgfUZOQAAAABJRU5ErkJggg=="; var saveImg7 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAASUlEQVR42mNkoBAw0s6ABob/aHxGkg1I8zEGM2dtOTskDED3MxCgGIBpASOGATANhACyi6hrAGVeoDgQB6UB2PxMvAFEAooNAAC7izYR2pQ0nAAAAABJRU5ErkJggg=="; var saveImg8 = "data:application/file;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///8A////AESqAABHpgAASKAAAEukAQxMpQMYR6MAAEepAQ9MpgOLRKgACUenAABHpgAARKoAAP///wD///8A////AP///wBEqgAARaIAAFS2FVBj0jS3Y9AzyVG0EUROrwt8TKcDs0ikAANInwAAR6YAAESqAAD///8A////AP///wD///8ARKQAAVvJKJtj0jX/SaAJ/0abCv9UtSH/U7QX8lW5IMddwyfQW8Iii0mqBQ1DqQAA////AP///wD///8A////AEWlAAFYwB6YXsYc5F7GFt9bwA+vVbgWvU6rAKBRrgf0RZgA/02oDP9ezCzJR6UBA////wD///8A////AP///wBFrAAASKIAADiGNQAeYIIpF1iJHVa4GKEve0tFLHl1Pla7J51exRnUWL8VjEetAAP///8A////AP///wD///8AC0WuAAk/tAAANdpIAFD6/wA+7f8gd6jqBlPX+QBE9PIGS8uDLnZLADqNJwAzjDMA////AP///wD///8A////AAAw0QAALc0AAEPdegBI4f8AK8P/ADHX/wAwzf8AL8b/AEno/gAz2zYALtEQAC3VAP///wD///8A////AP///wAAMssAADjSMwBA2pIATen/ADG9/wBe1v8ATcz/ADHK/wBN5/4ASeH/AEvl6wA10DP///8A////AP///wD///8AADnTSQBO5/8ANc7/ADnR/xC+9/8C0f//AMj//wCP8P8ALcX/ACrC/wBE3f8ASeOf////AP///wD///8A////AABI4Z4ARN3/ACvG/wJAxP8Z5v//AMT//wDE//8Axv7/AETM/wA51P8AUervADjSPP///wD///8A////AP///wAAOdRiAFry+QBS6/QATOP/H+P8/xDe//8J1///E9H4/wFE2f8AReC6ADTOEwAyywD///8A////AP///wD///8AADDNAAAyzCcARN7WACvG/wVfzf8d0vf/HM30/whf0/8AI7n/ADzV+AA40kUAMswA////AP///wD///8A////AAAwywAAPNdTAEfg/wAsw/8AOdb/ADLP/wAswv8AReP/AC7H/wA40f8AR+GfADDKAP///wD///8A////AP///wAAMswAADfRQgBY8f8AT+j/AE7o7AA+1/8AK8T/AE7o/wBN5f8AVe7/AD/ZbAAwywD///8A////AP///wD///8AADPMAAAyywAANM4vADjSUQA0zikAU+z3AEff/wBJ4sMAN9EtADjROQAyywAAM8wA////AP///wD///8A////AAAzzAAAM8wAADHLAAAwywAAMcsAAD/YXQBK4pYAN9AxAC/KAAAwygAAM8wAADPMAP///wD///8A+R8AAPAfAADABwAAwAMAAPgDAADwHwAA8AcAAOADAADAAwAAwAMAAMAHAADgBwAA4AcAAOAHAADwDwAA/j8AAA=="; var saveImg9 = "data:application/file;base64,AAABAAEAEBAAAAAAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAD///8BAAAAFwAAAGkAAABzAAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAADkAAAAP////AQAAAIdgZmj/YWlt/2FobP9haGz/YGhr/2Boa/9fZ2v/X2dr/15mav9dZWn/XGRo/0ZNUP8AAACdAAAAFf///wEAAACr2tzc/9ve4P/a3t//1dnZ/7S2tf+foJz/m5ya/6apqP/O0tP/09fZ/9DV1v+hqq//AAAAuQAAABX///8BAAAAq+3u7//e4eL/ub29/2hnXv9oVUX/U0As/zgxGf83Lx3/YWBX/7a5uv/S1tj/o6yx/wAAALkAAAAV////AQAAAKv29/f/19na/1dUQf9jXDv/dmtJ/4FoSP9VQiL/V0Ek/008Iv9HQTP/yc3P/6Wus/8AAAC5AAAAFf///wEAAACr+Pj4/5uamP9tY0L/g31b/6GLa/+McVH/eFY5/4xwUv9yXkD/RTki/4uMiv+nsLT/AAAAuQAAABX///8BAAAAq/n6+v+FfXL/waSM/8qznf/DrZP/ooFi/7WfhP+qh2//blk9/1A+Iv9aWlH/pK2x/wAAALkAAAAV////AQAAAKv6+/v/d3Rr/9zCsP/RxbH/z8Wu/9fJt//Qvab/qItv/5iOb/9tYUH/VVJK/6Wtsf8AAAC5AAAAFf///wEAAACr+/z8/4mHff+3pI//3NK//+HXxf/m3Mz/5trJ/9rMuf+bgWT/d14//2hnYP+osbX/AAAAuQAAABX///8BAAAAq/z9/f/FxL7/j4l+//Xw5f/29ez/8/Dl/+DMuv/VuaP/poZn/2dFKv+srav/oamt/wAAALkAAAAV////AQAAAKv+/v7/+/z8/5iZjf+5uqr/6+PW/+3i1P/kzL3/vZR+/4NhSf+Qh3z/z9HS/4qQkv8AAAC1AAAAFf///wEAAACr/v7+//7+/v/u7u3/tbiv/5WSgP+DfGj/e25Z/29gTv+sppz/vr6+/5aYmP90eHr/AAAApwAAABP///8BAAAAq/////////////////7+/v/9/f3//f39//v8/P/5+fn/1dXV/2pqav9TU1P/QUFB/wEBAYkAAAAJ////AQAAAKv7+/v//////////////////v7+//7+/v/+/v7/+vr6/9fY2P/V1tb/7Ozs/4KCgv8EBAQrAAAAA////wEAAACFlJSU/6ioqP+qqqr/qqqq/6qqqv+qqqr/qKio/6anp/2kpaX9o6Oj/4qKitUZGRk9////Af///wH///8BAAAAFQAAAFUAAABVAAAAVQAAAFUAAABVAAAAVQAAAFUAAABTBAQEUx8fH1dfX18z////Af///wH///8BAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//w=="; var loadImg = "data:image/x-icon;base64,AAABAAEAEBAAAAAAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAD///8B////Af///wH///8B////AQAAAB+yg2l71ZRt+daTa//Wk2v/1pNr/9aTa//Wk2v/v4NlywYEAycAAAAX////Af///wH///8B////Af///wHdo4M53Zx3/+Sgef/innb/4p52/+Kedv/lo3r/5aR6/+mqgfvPj27N////Af///wH///8B////Af///wH///8B4KSD8+mmff/opH3/56N6/+Whef/no3r/66qB/8KBXf/Fg1//0Y5s78+Pbqn///8B////Af///wH///8B////AeGlg//trIX/7ayE/+6thP/urIX/9bWL/8eFYf/GhF//yYZh/9SPa/nkn3j/////Af///wH///8B////Af///wHkn3j/76+G/+6uh//vrob/76+G//W3jP/GhF//y4di/9ONZ//XkWr/5J94/////wH///8B////Af///wH///8B5J94/++wif/wsIj/8LGJ//CxiP/0toz/y4di/8+KZf/vroP/766D/+SfeP////8B////Af///wH///8B////AeSfeP/xs4v/8bOL//Cziv/ws4v/87WL/9CNa+3QjWvt3p96/96fev/en3r/////Af///wH///8B////Af///wHkn3j/8rWN//K2jf/ytY3/8rWN//O2jvfdo4Lj0I5sJdCObCXQjmwl0I5sJf///wH///8B////Af///wH///8B5J94//O3j//zuI//87iP//O4j//zuZDx3aOD7////wH///8B////Af///wHdo4M/5J94/+SfeP/kn3j/5J94/++2j//zupH/9LqR//O6kv/0upL/87qR/+SfeP/kn3j/5J94/+SfeP////8B////Af///wHkoXr/9cCY//W8k//0vJT/9L2T//S8lP/0vZT/9LyU//S8lP/1vJT/9cCY/+Shev////8B////Af///wH///8B9b+WC+SjfP/2yqP/9b+W//a/lf/2v5X/9b6V//W+lv/1vpX/9sqj/+SjfP////8B////Af///wH///8B////Af///wH2wZgX5aZ+//fTrP/2wJj/9sCY//bAmP/2wZj/99Os/+Smf/////8B////Af///wH///8B////Af///wH///8B////Af///wHkqYH/99ax//fCmv/3wpn/99aw/+Sogf////8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AeWrhP/317L/99ey/+WrhP////8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B5a2F/+Wthf////8B////Af///wH///8B////Af///wH///8BAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//w=="; var moveToMenu = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABKElEQVR42o3TMUvDQBQH8P+7tLlEwaW4ugl+iU6CCA4i0tbdqavgZ/ErCE79DsVBkYpKLR2kuApOatG297zLJWkqXnIPwrsk937cveQIJXHZBZt8cgFyzaEqYGuTvl7feM2FVAIHR8Bj341UAu1T4PPdjXgBJgzyPKDFy4SDIkJZo1yRASZ+FDB5Itzfct7YBGjuBBBh6oT6ed2OazGjsV3wQ2Cu64bXUKM7FgZJgPaufinTSVFhrDPFheVIe01nwLgfq9HNVCRAaw8Q6USWS4B05mgVIH2/qG+ABh+46im7heP9EELOLRDZpVqAQev8ZwUS/DBLivMtlDWxc7Ycs6yBhyov9vqMGcBBDB5/rxT7/Qfntjn/FXsDrmIvoHUonMVegMllx/kXlvSRMQ0GPE4AAAAASUVORK5CYII="; var removeFromToolbar = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACMElEQVR42p3Sz2/SUBwA8G9pgQJd6QYZQQkOjUFdXMCLMn9B4l3myRgXhydPZgcTY2KyLfGiF/wT9GTmhfIXjMQ4NP5YD5qZTGdVdEx+9FVKSwttrTV4QD3AN3mH9837fr7v+/Kww1e4ic2HiSYMRGxufcHjxs87nQ5GN0zodnXQNLVomvCAL6ZR/xxmAS9VsX1umz1pJ/dfKGeD4+58OERNYQQO7Y4BWs8E3XCAqvRAEkWkdpTcNptm+4DpMVUOtboZl4tY2reXWmTGvbDTVKFnALicTrvYsFqbpgEOBw6tpgiigOb4Yoa1gTMzY1B+XUexKM1gLid8a3QgQHtBklQQBJm3RuAxDBiPl0z4aMq+eu1rFYmiFLOBowd8QJEEiLIBlbpV7PdArdZCApJX3j9O3e/Pe/Di0zTpJgvB8CSjSG1o7O7mbCA04QIHjoGsGuAfI6FRk0D8ISe3VlPc4OPGL61nab+/QDE0VD9/+T1CKOCCtqoDQRBAe0n4yH/nZUVLVtjTCP4R8cvPN8LRSKL6qVKygUjIC0rXAAMw6+EI6GkmoGaDM0DP8KuzfyHx+WfLe6KRpdpOlbMB+E9oWof78OhEcjB/5OqLbHAyUEB1oYTBCDFz7VWaYZg11BTYkYBj17lFyu3Lo5aYGwk4fuNNHgd8QVHk2EjA7K3NDVM3iuV708tDA2dXtqb0rr5mrWT57jQaGjh1+13eKio+uXOo9Gs/NJC6+TZhdf7zQ38Ceg0HgF1MCP0AAAAASUVORK5CYII="; var iconADD = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACDUlEQVR42nWT30sUURTHz91Zd9FkVBRrX0oScTMI8weSIYSU/QMFbb5oGAn+AQo9B/UH9BAF+lIr+OLrSETQQ4GhEVRrUFkP/SLRNcvUnXv8nrmz7XVcB86cy7nn+5kz556ryHrueKxIYcFkPMmbxXHgzA6NDyguatQewBzHkKMMQDnWPgDsIwYh8/hATP8HQCRJEFIc5iA1DpljZIGogJU/9WXp39DR1pj99QBwe45dZb6UhCXE2Hx6m4xtQZQ/8SDni+DdSNopVYtysUiFpVbDqp4vPL4uCWc6zt+H+wvbAOBrCBCRFgh0AtIA6BboBVADc6eeZLMCGOq/kkF8Hcs8AO8tgDwav5M0AI/bw87Xw9dml+bvSUamtfsGYmuIrQDwKgIoQirkF3pR9uCbz28vx+tTMWo6VRdsL79eLax80yePtc3MTlwYKwMIT8HTvYufFkc+bq4NOjWN9Kf6cIVsHNr4sePnf9LxytqH06Od1w6oICGA9uZGOnvEpb7tgkrefLl8UXZvdTV5CYe3vv9Wzy6dVnfL9KAKfkcALeihaSKT+yj3Imji1XRPBvFyTTSn4LHMi5Y5SCnrGFc3c5MCqKtMD5c5RnsOisfILlmD1NxA5yThwy96GhkkRtlxrP3oIO0d5ZKXfSSbUYaJ1/tGef9lovAyUeQyAaKCO4nLpPRBABWJlwCWt6vYBccZ9A793wmLAAAAAElFTkSuQmCC"; var customBtn = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjVJREFUeNqcUkuIUmEUPl4fML6bBsFRacRF2EaCcRO48bFLEIJcBIJLxb2b2UWLkIEgQQjauVFaKmgYuclUTMUHKoaKE4GPxnxh5r3ezh0QHJFmmA/OPZfDfx7fdw7AfojQ7qGx4QawdgMymeyRyWR6IZVKucFg8N10Ov0Ot4VGozmNRCLx5XL5F/HHbrefYZh7m1yWWq0+TafTn2kEdqXr9TrtcDje3JR4xRHH1QYCgXOz2Wzs9/sQj8dBIpEATtGrVqu9yWSywmdLNGq3AAeNsFgsz202mxk7QzKZBK1WCzqdjtHjKUmSx41Go4L+slQqpYvF4keKoibXpnA6nWfY+VehUKBSqRTJ0Oh2u3Qul6MHgwE9Ho9pLMD4H16v95zD4RxuU6BbrdYlPh5g8tfFYvET9XiIiRylUsnQgPl8DtgVhsOheL1eS6LRaGy1Wg02FAA5VmKxWB1/yUQioWOxWHKXy2XEYsDQEggEgKJCJpOBcrnMbOliW4MNSOaDCbVKpVISCoVGHBnQQygUgnK1AkeH9z+Ew+HX2xoQezZDjUaj3ygDiMViaLfbV8kK+TGw2WysJzzafry3QK1W+9Lr9RpIDbLZLEhE4vedTsdvMBieuN3ulwRBPLh2B7uYzWYXzWZzjBoc5PP5MJ70K1xfEsVc4cpNeDcnuLFvzM3978gILpcrRy/w+XybGE+v1z/z+/2frFarG9d5AHeBSqUyeDyetwqF4jHcFXw+/4TH44n+CTAA3Ccog288LRAAAAAASUVORK5CYII="; var saveAll = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACOElEQVR42mNkwAJ+7xf7//3tKwZeIUELRqf3JxnwAEZkzrtlwnv/MzE6/WfkWCwS/iTu7RLO/wzMPAwc/z4Lc0f/eIfTgP/7BM0PXDY5ofB9N8M/EB8k+BcoyQw1mEWd4SurLIO97lkUFzX9b/oPNmBznc7/////MbAzfIdoBoI/P77Abfnzn4XhH9A0kOLA7icQV88HKn0EdcH6Ss3/yM76/f0jg2vTXYZ/f39j9fdUgQkMdTp1DNFXoiEGrCzFNMCj6SrD/79/MDQzsbAzCEfyMTBwADkbGBjBBiwrRDXgF9AAz6ZLWF1QIlHCsFRnKdj2pYxLIQYsytPAMMC75SLYBVMkpzDkPM+By0lFSTEwCDAwvJ79eouoqKgv2IB5WWgGfPvI4N95kUEyQQwcJVXbq8CGeEp6MlzUuQi2fcKbCQgDZqWhG/CJIaDrLIPMf0kGBjeggAoDw5YNWxh8rHwYGMQZGB5PfszAysq6RUJCAmLAtCR1DAMCu08zzJSZxtDm0cbA8AQoyAxJGyDbWx+2MrCwsGyRkZGBGDApDpsBx8FhME95HkObfhtYM4MqA8OdnjtgNSAXyMvLQwzoi8JmwGF4NGoc12Bg6IHYXnuzFm6AsrIyxIAJ+UHXfj27oomIhc9AA/ajpAOdPToMV1yuwPnMzMxbNDU14QaEAqnGH28fqYGywt/fP5i8q5czYUtIMABygY6ODsSAJUuWOKMrUFHT2PPvzy90YZhX/79//36dt7d3KACPfPJHOU7GxAAAAABJRU5ErkJggg=="; let cIDs = ["custombuttons-contextpopup-exportXML", "custombuttons-contextpopup-exportXML-sub"]; let bIDs = ["custombuttons-contextpopup-bookmarkButton", "custombuttons-contextpopup-bookmarkButton-sub"]; addMenuItem(cIDs, bIDs, "Сохранить код кнопки в XML файл", saveImg9, "document.getElementById('" + this.id + "').saveXML(('triggerNode' in this.parentNode) " + "? this.parentNode.triggerNode.URI " + ": document.popupNode.URI);", "X"); let xIDs = ["custombuttons-contextpopup-importnewbutton", "custombuttons-contextpopup-importnewbutton-sub"]; let aIDs = ["custombuttons-contextpopup-addnewbutton", "custombuttons-contextpopup-addnewbutton-sub"]; addMenuItem(xIDs, aIDs, "Добавить кнопку из XML файла\u2026", loadImg, "document.getElementById('" + this.id + "').loadXML();"); let fIDs = ["custombuttons-contextpopup-copyImageURI", "custombuttons-contextpopup-copyImageURI-sub"]; let b2IDs = ["custombuttons-contextpopup-copyURI", "custombuttons-contextpopup-copyURI-sub"]; addMenuItem(fIDs, b2IDs, "Копировать изображение кнопки в формате base64", saveImg1, "document.getElementById('" + this.id + "').copyImageURI(('triggerNode' in this.parentNode) " + "? this.parentNode.triggerNode " + ": document.popupNode);", "6"); let f1IDs = ["custombuttons-contextpopup-saveButtonImage", "custombuttons-contextpopup-saveButtonImage-sub"]; addMenuItem(f1IDs, cIDs, "Сохранить изображение кнопки", saveImg8, "document.getElementById('" + this.id + "').saveImageURI(('triggerNode' in this.parentNode) " + "? this.parentNode.triggerNode " + ": document.popupNode);", "I"); let f2IDs = ["custombuttons-contextpopup-copyButtonsCodeText", "custombuttons-contextpopup-copyButtonsCodeText-sub"]; addMenuItem(f2IDs, b2IDs, "Копировать код кнопки как текст", saveImg2, "document.getElementById('" + this.id + "').copyButtonsCodeText(('triggerNode' in this.parentNode) " + "? this.parentNode.triggerNode " + ": document.popupNode);", "T"); let f3IDs = ["custombuttons-contextpopup-copyAsHTML", "custombuttons-contextpopup-copyAsHTML-sub"]; addMenuItem(f3IDs, b2IDs, "Копировать код кнопки как HTML ссылку", saveImg3, "document.getElementById('" + this.id + "').copyToHTMLCode(('triggerNode' in this.parentNode) " + "? this.parentNode.triggerNode " + ": document.popupNode);", "M"); let f4Ds = ["custombuttons-contextpopup-copyToBBCode", "custombuttons-contextpopup-copyToBBCode-sub"]; addMenuItem(f4Ds, b2IDs, "Копировать код кнопки как BBcode сылку", saveImg4, "document.getElementById('" + this.id + "').copyToBBCode(('triggerNode' in this.parentNode) " + "? this.parentNode.triggerNode " + ": document.popupNode);", "B"); let f5Ds = ["custombuttons-contextpopup-saveAsHTML", "custombuttons-contextpopup-saveAsHTML-sub"]; addMenuItem(f5Ds, bIDs, "Сохранить код кнопки в HTML файл", saveImg5, "document.getElementById('" + this.id + "').saveToHTMLCode(('triggerNode' in this.parentNode) " + "? this.parentNode.triggerNode " + ": document.popupNode);", "H"); let f8Ds = ["custombuttons-contextpopup-saveAsHTMLAll", "custombuttons-contextpopup-AsHTMLAll-sub"]; addMenuItem(f8Ds, f5Ds, "Сохранить все кнопки в HTML файл", saveAll, "document.getElementById('" + this.id + "').saveToHTMLALLCode()"); let f6Ds = ["custombuttons-contextpopup-getButtonId", "custombuttons-contextpopup-getButtonId-sub"]; let b1IDs = ["custombuttons-contextpopup-remove", "custombuttons-contextpopup-remove-sub"]; addMenuItem(f6Ds, b1IDs, "Показать Id кнопки", saveImg6, "document.getElementById('" + this.id + "').idMIonclick(('triggerNode' in this.parentNode) " + "? this.parentNode.triggerNode " + ": document.popupNode);", "D"); let f7Ds = ["custombuttons-contextpopup-addNextButton", "custombuttons-contextpopup-addNextButton-sub"]; var addMI = document.getElementById('custombuttons-contextpopup-addnewbutton'); addMI.setAttribute('image', iconADD); var addMI1 = document.getElementById('custombuttons-contextpopup-addnewbutton-sub'); addMI1.setAttribute('image', iconADD); var addMI2 = document.getElementById('custombuttons-contextpopup-move-moveToPanel'); addMI2.setAttribute('image', moveToMenu); var addMI3 = document.getElementById('custombuttons-contextpopup-move-removeFromToolbar'); addMI3.setAttribute('image', removeFromToolbar); var addMI4 = document.getElementById('custombuttons-contextpopup-customize'); addMI4.setAttribute('image', customBtn); ///////////////////////////////////////////////////////////////////////////// /////////////////////////////// Общие функци //////////////////////////////// ///////////////////////////////////////////////////////////////////////////// var options1 = {year: "numeric"}; var options2 = {day: "numeric", month: "long"}; var cDate = new Date().toLocaleDateString("ru-RU", options1); var dDate = new Date().toLocaleDateString("ru-RU", options2); var aDate = cDate + "г" + " " + dDate; var options3 = {weekday: "long", year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric", hour12: false}; var bDate = new Date().toLocaleDateString("ru-RU", options3); 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( !("inIsolatedMozBrowser" in window.browsingContext.originAttributes) ? window.browsingContext : 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(); } }); }; ///////////////////////////////////////////////////////////////////////////// ////////////////////////////Остальные функци //////////////////////////////// ///////////////////////////////////////////////////////////////////////////// /////////////////////////////// Показать Id кнопки /////////////////////////////// this.idMIonclick = function idMIonclick(aStrI) { var btn = aStrI.id; var box = custombuttons.confirmBox("Копировать в буфер", btn, "Да", "Нет"); if (box) { custombuttons.cbService.writeToClipboard(btn); custombuttons.alertSlide(btn, "Скопирована в буфер"); } } function mostRecentWindow(windowType) { return Components.classes['@mozilla.org/appshell/window-mediator;1'].getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow(windowType); } /////////////////////////////// Копировать изображение кнопки в формате base64 /////////////////////////////// this.copyImageURI = function copyImageURI(aStrA) { var btn = aStrA; if (!btn) return; cbu.gClipboard.write(btn.image); var as = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService); as.showAlertNotification(btn.image, "Кнопка: " + btn.name, "Изображение кнопки скопировано в буфер", false, "", null); } /////////////////////////////// Копировать код кнопки как текст /////////////////////////////// this.copyButtonsCodeText = function copyButtonsCodeText(aStrT) { var btn = aStrT; if (!btn) return; var code = ((btn.cbCommand == "") || (btn.Command == "/*CODE*/")) ? "" : ("\n/*CODE*/\n" + btn.cbCommand + "\n"); var init = ((btn.cbInitCode == "") || (btn.cbInitCode == "/*Initialization Code*/")) ? "" : ("\n/*Initialization Code*/\n" + btn.cbInitCode); cbu.gClipboard.write(code + init); //custombuttons.alertSlide(btn.name, "Код скопирван в буфер"); var as = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService); as.showAlertNotification(btn.image, "Кнопка: " + btn.name, "Код скопирван в буфер", false, "", null); } /////////////////////////////// Копировать код кнопки как HTML ссылку /////////////////////////////// this.copyToHTMLCode = function copyToHTMLCode(aStrM) { var btn = aStrM; if (!btn) return; var code = "<p><div id=\"install\" style=\"background: transparent -moz-linear-gradient(center top , rgb(224, 102, 255) 30%, rgb(125, 38, 205) 55%); text-shadow: 0pt -1px 0pt rgb(122, 55, 139); border: 1px outset rgb(85, 26, 139); border-radius: 1em; padding: 0; width: 240px; text-align: center;\"><a href=\"" + btn.URI + "\" style=\"display: block; padding: 1em; color: #ffffff; text-decoration: none;\" title=\"Click here to install " + btn.name + "\" rel=\"nofollow\"><img src=\"" + btn.image + "\" alt=\"" + btn.name + "\" style=\"vertical-align: middle; float: left;\"/>" + btn.name + "</a></div></p>"; cbu.gClipboard.write(code); var as = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService); as.showAlertNotification(btn.image, "Кнопка: " + btn.name, "HTML кнопки скопирован в буфер", false, "", null); } /////////////////////////////// Копировать код кнопки как BBcode сылку /////////////////////////////// this.copyToBBCode = function copyToBBCode(aStrBB) { var btn = aStrBB; if (!btn) return; var code = "[url=" + btn.URI + "][B]" + btn.name + "[/B][/url]"; cbu.gClipboard.write(code); //.toXMLString()); var as = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService); as.showAlertNotification(btn.image, "Кнопка: " + btn.name, "BBCode кнопки скопирован в буфер", false, "", null); } /////////////////////////////// Сохранить изображение кнопки /////////////////////////////// this.saveImageURI = function saveImageURI(aStrU) { var remove = gBrowser.removeCurrentTab.bind(gBrowser); var promiseTargetFile = async (...args) => { var res = await window.promiseTargetFile(...args); setTimeout(remove, 0); return res; } var internalSave = eval(`(${window.internalSave})`); var save = eval(`(${window.saveDocument})`); var saveBrowser = eval(`(${window.saveBrowser})`) var btn = aStrU; if (!btn) return; (saveButtonImage = btn => { if (btn.image != "") { var tab = gBrowser.selectedTab; gBrowser.selectedTab = gBrowser.addTab(btn.image, { triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal() }); setTimeout(function() { if (!!window.saveBrowser) { saveBrowser(gBrowser.selectedBrowser, true); } else { window.content.document.title = btn.name; save(window.content.document); } }, 2000); } else custombuttons.alertBox("Эта кнопка не имееет изображения!"); })(btn); } /////////////////////////////// Сохранить кнопку в XML файл /////////////////////////////// this.saveXML = function saveXML(aStrURI) { var cbURI = (aStrURI != undefined) ? aStrURI : readFromClipboard(); if (!cbURI || !/^custombutton\:\/\//.test(cbURI)) { custombuttons.uChelpButton(this); return; } var topicURL = "http://forum.mozilla-russia.org/viewforum.php?id=34" var cbXML = cbURI.replace(/^custombutton\:\/\//, ""); var decodeXML = unescape(cbXML); var btnName = decodeXML.match(/\<name\/?.+/).toString(); var name = "untitled"; if (!/\<name\/\>/.test(btnName)) { name = btnName.replace(/\<\/?\w+\>/g, "").toString(); } var image = decodeXML.match(/\<image\/?.+/).toString(); var icon = ""; if (!/\<\image.*\[\].*\>$/.test(image)) { icon = image.match(/[^\[\]]+/g)[2].toString() .replace(/custombuttons\-stdicon\-\d/, "").toString(); } function htmlEntities(str) { return str.replace(/&/g, "&").replace(/</g, "<") .replace(/>/g, ">").replace(/"/g, """); } var xmlTemplate = "custombuttons/\"\n\ xmlns:html=\"http://www.w3.org/1999/xhtml\">\n\ <html:head>\n\ <html:title><![CDATA[" + name + "]]></html:title>\n\ <html:link rel=\"shortcut icon\" href=\"" + icon + "\"/>\n\ <html:style type=\"text/css\"><![CDATA[\n\ body { font-size: medium; margin: 0; }\n\ body, code:before, help:before, initcode:before {\n\ font-family: \"Verdana\", sans-serif;\n\ }\n\ #wrapper { position: fixed; top: 1em; right: 1em; text-align: center; }\n\ p { font-size: small; text-align: center; }\n\ #button {\n\ background-color: rgb(85, 168, 2);\n\ background-image: linear-gradient(to bottom, rgb(147, 200, 94),\ rgb(85, 168, 2));\n\ background-image: -moz-linear-gradient(top, rgb(147, 200, 94),\ rgb(85, 168, 2));\n\ background-image: -o-linear-gradient(top, rgb(147, 200, 94),\ rgb(85, 168, 2));\n\ background-image: -webkit-linear-gradient(top, rgb(147, 200, 94),\ rgb(85, 168, 2));\n\ border: 1px solid rgb(58, 116, 4);\n\ border-radius: .5em;\n\ -moz-border-radius: .5em;\n\ -webkit-border-radius: .5em;\n\ padding: 0;\n\ margin-bottom: 1em;\n\ box-shadow: 1px 2px 3px rgba(0, 0, 0, .25);\n\ -moz-box-shadow: 1px 2px 3px rgba(0, 0, 0, .25);\n\ -o-box-shadow: 1px 2px 3px rgba(0, 0, 0, .25);\n\ -webkit-box-shadow: 1px 2px 3px rgba(0, 0, 0, .25);\n\ }\n\ #button a {\n\ color: #000;\n\ text-shadow: -1pt -1px 0pt rgba(255, 255, 255, .5);\n\ padding: 1em;\n\ text-decoration: none;\n\ }\n\ :-moz-any-link:focus {\n\ color: white;\n\ outline-color: transparent;\n\ text-decoration: none;\n\ }\n\ #button a, code, code:before, initcode, initcode:before, help, help:before {\ \n display: block;\n\ }\n\ #credits { position: fixed; bottom: 1em; right: 1em; font-size: small; }\n\ custombutton { background-color: rgb(171, 171, 171); margin: 1em; }\n\ date, image, mode, accelkey { display: none; }\n\ name { font-weight: bold; font-size: x-large; }\n\ code:before, help:before, initcode:before {\n\ font-weight: bold;\n\ font-size: large;\n\ margin: 0 0 1em;\n\ padding: .5em;\n\ }\n\ code:before { content: \"Код\"; }\n\ help:before { content: \"Справка\"; }\n\ initcode:before { content: \"Инициализация\"; }\n\ code, initcode, help {\n\ background-color: rgb(255, 255, 255);\n\ border: 1px inset rgb(170, 170, 170);\n\ font: medium monospace;\n\ margin: 1em 1em 2em 0;\n\ padding: 1em;\n\ text-align: left;\n\ width: 840px;\n\ white-space: pre-wrap;\n\ word-wrap: break-word;\n\ }\n\ .clear { clear: both; }\n\ ]]></html:style>\n\ </html:head>\n\ <html:body>\n\ <html:div id=\"wrapper\">\n\ <html:div id=\"button\">\n\ <html:a href=\"" + cbURI + "\" rel=\"nofollow\" title=\"Установить " + htmlEntities(name, "ENT_COMPAT") +"\">\n\ <![CDATA[Установить кнопку]]>\n\ </html:a>\n\ </html:div>\n\ <html:div id=\"credits\">\n\ <html:a href=\"" + topicURL +"\">\n\ <![CDATA[Другие кнопки]]><html:br/>\ <![CDATA[на форуме Mozilla Россия]]>\n\ </html:a>\n\ </html:div>\n\ </html:div>\n\ </html:body>"; decodeXML = decodeXML.replace(/custombuttons\/\"\>/, xmlTemplate); name += ".xml"; saveToFile(decodeXML, name); var btn = document.popupNode; var as = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService); as.showAlertNotification(btn.image, "Кнопка: " + btn.name, "сохранена в XML файл", false, "", null); } var mrw = mostRecentWindow('navigator:browser'); var css = '@-moz-document url("chrome://browser/content/browser.xul"){' + this.Help + '}'; var uri = makeURI('data:text/css,' + encodeURIComponent(css)); var sss = Components.classes['@mozilla.org/content/style-sheet-service;1'].getService(Components.interfaces.nsIStyleSheetService); if (!sss.sheetRegistered(uri, sss.USER_SHEET)) sss.loadAndRegisterSheet(uri, sss.USER_SHEET); /////////////////////////////// Добавить кнопку из XML файл /////////////////////////////// this.loadXML = function loadXML() { var nsIFilePicker = Ci.nsIFilePicker; var fp = window.makeFilePicker(); fp.init( !("inIsolatedMozBrowser" in window.browsingContext.originAttributes) ? window.browsingContext : window, "Установить кнопку из XML файла", nsIFilePicker.modeOpen); fp.appendFilters(fp.filterXML); fp.appendFilter("Все файлы", "*.*"); fp.open(re=> { if ( re == fp.returnOK ) gBrowser.selectedTab = gBrowser.addTrustedTab(fp.file.path); }) } /////////////////////////////// Сохранить все кнопки в HTML файл /////////////////////////////// this.saveToHTMLALLCode = function saveToHTMLALLCode() { var visibleCBbuttons = [...document.querySelectorAll('[cb-mode]')]; var paletteCBbuttons = [...custombuttons.palette.querySelectorAll('[cb-mode]')]; var allCBbuttons = visibleCBbuttons.concat(paletteCBbuttons); var gn = btn => btn.getAttribute("label") || "Без названия"; allCBbuttons.sort((a, b) => gn(a).localeCompare(gn(b))); var array = []; allCBbuttons.forEach(but=> { var uri = but.URI ? but.URI : getPaleteButtonsURI(but); var name1 = but.getAttribute("label") || "Без названия"; var image = but.getAttribute("image") || "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACNFBMVEXDRgDweQDnbwC0NgDCRQC7PQDtpTu+QQD78q3PUwDCRAD//8vbYQDLTgDocAD0iQX1jQbGSgD7iAD4gwDVaw7vdwDyegD+igDweQDlawDyhAXveADmZwDzmBbtcwDwkhHveADmhBTkgxbweADkfRH+igD7hADXZQX0gADyjA/tfgvveQDiawDQVADRXgfnbwD1jAb9iQD9z0PVZAbxpinykRHtdgD5mRbERQDDRgDOYArCRAD9iQD3ewDxegD3dwDFRgDAQAD+hgD4fQDucgDtgQftfwTISQDCRQDvdgD5lxb1kRb2qh7wnynkagD766LDRQDDRwDDRQDspjbtpzbuqDbvqzv//8DUZAbCRQD//83pjhvveQbvggW+QQDfcxLlmUb//8veYADMTwDHSADVVwC8PgDwixb78q3oZgDUWADRVADCRQD9iQDERwDBQQDYVQC+PgC0NgDbYQDWWgDUWADSVQDFSAC+QAC7PAC0NgD+wRL+/kD+/zb+7i3+8Cv+/DX+wBL/+DD/rwz+qgz+rwz/tAz+sQzfbAT+3iP/+jD//Dz1jwP+nwf5iwf7pBz2tRr4lwb/ogfsdQT+2R7/9ET+2iT8yyLmgBL5iQL2egLokhP7zzT60zv1zUr0gAL1ewP50yn9+UL++EXooyngaAH41EPzowzyySj+xxzlhhHvvyruwjXxvTnUag3+zxrwigP+swz86U/ZXwD75lHqegD6xzb//kn+uhPTXAG3OAD/+UC2vFeJAAAAe3RSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAACfnwAIaelpAAA2+wD7UQAAa3oArKzRzMysnwgAvPQA/gAAw3prw0oALr16vS4AACnF6bspAAAA/mIAADQAAAAAAI8AAEwA0vv7kd2yAuuvr+vKABL23U+8Sk/d9vUDIIAQAAAQgCAfvupHAAABB0lEQVR4Xi3IU3fDABgA0C+u26FdZ9u2bdu2vZSzbds2/tyac3IfLxjpGyA6MimqY6gHTNgiiNwkwRM1E7EhTrYyTfMzzsh0ZEPiH+D6+u5mV1jEhpe5haVCYW1T4suEvUOkk7PLpVJ5WFnl7hEUDN5LPvsHJ6cazdn13f3DYxu0B35+/Y2qVSr17NzGeUgohIVHLK/PMDa39qKieRATGxd/9cS4uU1MwnmQktqY/qGlaVr7/ZOVDTmQm5df8PwyNj4xOTVdjOM4kCRZOr+wWFa+srpWQVEU8PnV2zu7NbV19UfHDQRBAIfTdNHc0soVdnR2dfdgGAgEvW99/QNc4eDQ8O8Ihv0D77NPgbVLZ6kAAAAASUVORK5CYII="; array.push("<li>\n<img src=" + image + "> \<a href=" + uri + ">" + name1 +"</a><br>\n"); }); var before = "<html>\n<head>\n<title>Custom Buttons</title>\n<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>\n"; var before1 = "<style type='text/css'>\nbody {background: beige;} a:link {color: black; text-decoration: none;} img {border: 0; margin: 0px 10px;}\n</style>\n"; var before2 = "</head>\n<body>\nCustom Buttons\n<p>\n"; var info = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo); var before3 = info.vendor + " " + info.name + " " + info.version + " (build " + info.appBuildID + ")\n"; var after = "\n</ol>\n</body>\n</html>"; var text = before + before1 + before2 + before3 + "<p>\n" + bDate + "<p>\n" + "<ol>" + array.join("") + after; var name = "CB buttons " + aDate + ".html" saveToFile(text, name); var alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService) alertsService.showAlertNotification(saveImg5, "Экспорт в HTML", "Экспортировал все CB кнопки как HTML"); setTimeout(()=> alertsService.closeAlert(), 4000); }; function getPaleteButtonsURI(but) { var uri = "chrome://custombuttons/content/nbftemplate.xml"; var stream = NetUtil.newChannel({uri, loadUsingSystemPrincipal: true}).open(); var doc = new DOMParser().parseFromStream(stream, null, stream.available(), "application/xml"); stream.close(); ["help,Help", "name,label", "image,image", "mode,cb-mode", "initcode,cb-init", "accelkey,cb-accelkey", "code,cb-oncommand"] .forEach(str=> { var arr = str.split(','); var value = but.getAttribute(arr[1]), name = arr[0]; custombutton.buttonSetText(doc, name, value, true); }); var ser = new XMLSerializer(); return "custombutton://" + escape(ser.serializeToString(doc)); }; /////////////////////////////// Сохранить кнопку в HTML файл /////////////////////////////// this.saveToHTMLCode = function saveToHTMLCode(aStrH) { var btn = aStrH; var xml = '<html xmlns="' + xhtmlns + '">\n'; xml += '<head>\n'; xml += '<meta http-equiv = "Content-Type" content = "text/html; charset=utf-8"/>\n'; xml += '<title> ' + btn.name + ' для Custom Buttons </title>\n'; xml += '<link rel="icon" type="image/vnd.microsoft.icon" href = "'+ btn.image +'" />\n'; xml += '<style type="text/css">\n'; xml += '.button a{ \n'; xml += 'background-color: rgb(85, 168, 2); \n'; xml += 'background-image: linear-gradient(to bottom, rgb(147, 200, 94), rgb(85, 168, 2)); \n'; xml += 'background-image: -moz-linear-gradient(top, rgb(147, 200, 94), rgb(85, 168, 2)); \n'; xml += 'border: 1px solid rgb(58, 116, 4); \n'; xml += 'border-radius: .5em; \n'; xml += ' -webkit-border-radius: .5em; \n'; xml += 'padding: 0; \n'; xml += 'margin-bottom: 1em; \n'; xml += 'box-shadow: 1px 2px 3px rgba(0, 0, 0, .25); \n'; xml += ' -o-box-shadow: 1px 2px 3px rgba(0, 0, 0, .25); \n'; xml += ' -webkit-box-shadow: 1px 2px 3px rgba(0, 0, 0, .25); \n'; xml += ' color: #000; \n'; xml += ' text-shadow: -1pt -1px 0pt rgba(255, 255, 255, .5); \n'; xml += ' padding: 0.5em; \n'; xml += ' text-decoration: none; \n'; xml += '} '; xml += 'pre { border: 1px inset rgb(170, 170, 170); \n'; xml += 'background-color: rgb(255, 255, 255);} \n'; xml += 'body { background-color: rgb(245, 245, 220);} \n'; xml += '</style> \n'; xml += '</head>\n'; xml += '<body>\n'; xml += '<section id="install"><h1> ' + btn.name + ' </h1> \n'; xml += '</section>\n'; xml += '<div class="button"><a href = "' + btn.URI + '">Установить кнопку</a></div> \n'; xml += '<section id="init"><h2>Инициализация</h2><pre>' + e4xConv_encodeHTML(btn.cbInitCode) + '</pre></section>\n'; xml += '<section id="code"><h2>Код</h2><pre>' + e4xConv_encodeHTML(btn.cbCommand) + '</pre></section> \n'; xml += '<section id="help"><h2>Справка</h2><pre>' + e4xConv_encodeHTML(btn.Help) + '</pre></section> \n'; xml += '</body> \n'; xml += '</html> '; var html = '<!DOCTYPE html>\n' + xml; var name = btn.name + ".HTML"; saveToFile(html, name); var as = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService); as.showAlertNotification(btn.image, "Кнопка: " + btn.name, "сохранена в HTML файл", false, "", null); } function e4xConv_encodeHTML(s, isAttr) { s = String(s) .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """); if(isAttr) { s = s .replace(/\t/g, "	") .replace(/\n/g, "
") .replace(/\r/g, "
"); } return s; }; /////////////////////////////// Переместить кнопку /////////////////////////////// this.MoveToolbarButtons = MTB = { // Start editable preferences MoveButtonMICBContext: true, // Add "Move button" menu item to Custom Buttons context menu? MoveButtonMITBarContext: false, // Add "Move button" menu item to toolbars context menu? ShowMoveAlert: false, // Show the alert with instructions when moving buttons? MoveBtnImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAYklEQVQ4jWNgGJTgaAXHf2LEcGrGZQBBQ45WcPz/fZ0XpwG45FAUEDIAqzyyJLIiZIxNHqdmYvHRCo7/DLhsIEYziivQDcHnBawxgqyQUCzgjQlC6YCotEB2QkJWTIzY4AAAezv/caeCLKcAAAAASUVORK5CYII=", // End editable preferences _UID: "__cb_move_toolbar_buttons_" + custombuttons.getNumber(self.id), WindowIDs: ["main-window", "messengerWindow", "msgcomposeWindow"], ToolbarContexIDs: ["toolbar-context-menu", "aios-toolbar-contextmenu", "aios-sbhtoolbar-contextmenu"], Pref: "extensions.custombuttons.MoveToolbarButtons.Id" + custombuttons.getNumber(self.id) + ".MoveButtonID", SP: Services.prefs, Init: function() { if (!(MTB._UID in window)) { window[MTB._UID] = { Initialized: false }; } if (!window[MTB._UID]["Initialized"]) { window[MTB._UID]["Initialized"] = true; custombuttons.isPref(MTB.Pref, ""); if ("CustomizableUI" in window) { var originalFunction = custombuttons.persistCurrentSets.toString(); eval("custombuttons.persistCurrentSets=" + originalFunction .replace(", newButtonId)", ", newButtonId, aToRight)") .replace("pos + 1", "aToRight ? pos : pos + 1")); } if (MTB.MoveButtonMICBContext) { var contextPops = document.getElementsByTagName("menupopup"); let p = 0, pLen = contextPops.length; for (; p < pLen; p++) { var cPopID = contextPops[p].id; if (cPopID.substr(0, 26) === "custombuttons-contextpopup") { var cPopEl = document.getElementById(cPopID); var moveMIID = "custombuttons-contextpopup-moveButton" + cPopID.slice(26); var moveMIEl = document.getElementById(moveMIID); if (!moveMIEl) MTB.CreateMoveMI(moveMIID, cPopEl); } } } if (MTB.MoveButtonMITBarContext) { Array.prototype.slice.call(MTB.ToolbarContexIDs).forEach(function(aTBCtxID, aIndex) { let Ctx = document.getElementById(aTBCtxID); let tBarCtxMIID = MTB._UID + "moveButton" + aIndex; if (!document.getElementById(tBarCtxMIID)) { if (Ctx) { MTB.CreateMoveMI(tBarCtxMIID, Ctx); Ctx.addEventListener("popupshowing", function(aE) { document.getElementById(tBarCtxMIID).hidden = (document.popupNode.tagName !== "toolbarbutton"); }, false); } } }); } addDestructor(function(aReason) { if (aReason === "delete") { SP.resetUserPrefs(MTB.Pref); delete window[_UID]; } if (aReason === "delete" || aReason === "update") { window[MTB._UID]["Initialized"] = false; } }); } }, getPopupNode: function(aEl) { if (custombuttons.popupNode) return custombuttons.popupNode; var popupNode = aEl; while (popupNode.tagName.toLowerCase() !== "toolbarbutton") { popupNode = popupNode.parentNode; } return popupNode; }, CreateMoveMI: function(aMItemID, aPopupEl) { let moveMIEl = aPopupEl.appendChild(document.createElementNS(xulns, "menuitem")); moveMIEl.setAttribute("id", aMItemID); moveMIEl.setAttribute("label", "Переместить кнопку..."); moveMIEl.setAttribute("class", "menuitem-iconic"); moveMIEl.setAttribute("image", MTB.MoveBtnImage); moveMIEl.setAttribute("tooltip", MTB._UID + "moveButtonMI_tooltip"); moveMIEl.setAttribute("onclick", "document.getElementById(\"" + self.id + "\").MoveToolbarButtons.MoveOnClick(event);"); }, MoveOnClick: function(aE) { var popupNode = MTB.getPopupNode(aE.target); if (!popupNode) return; aE.stopPropagation(); aE.preventDefault(); if (aE.button === 0 && !aE.shiftKey && !aE.ctrlKey && !aE.altKey) { MTB.SP.setCharPref(MTB.Pref, popupNode.id); window.addEventListener('click', MTB.MoveListener, true); window.addEventListener('mouseup', MTB.DefaultPrevention, true); window.addEventListener('mousedown', MTB.DefaultPrevention, true); window.addEventListener('contextmenu', MTB.DefaultPrevention, true); MTB.HidePopup(aE.target); MTB.ShowMoveAlert && Services.prompt.alert(null, self.name, "Now click ANY toolbarbutton element inside ANY toolbar.\n" + "Left click will position the button to the left of the target.\n" + "Right click will position the button to the right of the target.\n\n" + "To cancel the movement, just click ANY element inside the browser that IS NOT a toolbarbutton.\n"); } }, MoveListener: function(aE) { MTB.DefaultPrevention(aE); window.removeEventListener('click', MTB.MoveListener, true); window.removeEventListener('mouseup', MTB.DefaultPrevention, true); window.removeEventListener('mousedown', MTB.DefaultPrevention, true); window.removeEventListener('contextmenu', MTB.DefaultPrevention, true); var anchor = aE.target; if (anchor.tagName !== "toolbarbutton") return; var toolbar = anchor.parentNode; var BtnToMove = document.getElementById(MTB.SP.getCharPref(MTB.Pref)); if (aE.button === 0 && !aE.shiftKey && !aE.ctrlKey && !aE.altKey) toolbar.insertBefore(BtnToMove, anchor); else if (aE.button === 2 && !aE.shiftKey && !aE.ctrlKey && !aE.altKey) toolbar.insertBefore(BtnToMove, anchor.nextSibling); if ("CustomizableUI" in window) custombuttons.persistCurrentSets(toolbar.id, anchor.id, BtnToMove.id || BtnToMove.getAttribute("id"), !(aE.button === 2)); else { toolbar.setAttribute("currentset", toolbar.currentSet); document.persist(toolbar.id, "currentset"); } MTB.SP.setCharPref(MTB.Pref, ""); }, DefaultPrevention: function(aE) { aE.preventDefault(); aE.stopImmediatePropagation && aE.stopImmediatePropagation(); aE.stopPropagation(); }, Tooltips: function(aRem) { var popSetID = MTB._UID + "popupset"; var popSetEl = document.getElementById(popSetID); if (popSetEl) popSetEl.parentNode.removeChild(popSetEl); if (aRem) return; if (!popSetEl) { popSetEl = document.createElementNS(xulns, "popupset"); popSetEl.setAttribute("id", popSetID); } popSetEl.appendChild(MTB.parseXML("<tooltip xmlns=\"" + xulns + "\" xmlns:html=\"" + xhtmlns + "\" id=\"" + MTB._UID + "moveButtonMI_tooltip" + "\">" + "<description><html:b>Instructions</html:b> : After clicking this menu item, you can " + "click ANY toolbarbutton element inside the application to place the currently " + "selected button to the left (with Left click) or to the right (with Right click) " + "of the targeted toolbarbutton.</description>" + "<separator/>" + "<description><html:b>Note</html:b> : It can be ANY toolbarbutton, not just " + "other Custom Buttons.</description>" + "</tooltip>")); setTimeout(function() { Array.prototype.slice.call(MTB.WindowIDs).forEach(function(aWinID) { let win = document.getElementById(aWinID); if (win) !document.getElementById(popSetID) && win.appendChild(popSetEl); }); }, 100); }, parseXML: function(aXML) { // Return parsed XML aXML = aXML.replace(/>\s+</g, "><"); // Linearize XML return (new DOMParser).parseFromString(aXML, "application/xml").documentElement; }, HidePopup: function(aEl) { try { aEl.hidePopup(); } catch (aError) { try { aEl.parentNode.hidePopup(); } catch (aError) { try { aEl.parentNode.parentNode.hidePopup(); } catch (aError) { try { aEl.parentNode.parentNode.parentNode.hidePopup(); } catch (aError) {} } } } } }; this.MoveToolbarButtons.Init();
/*Initialization Code*/ self._handleClick =()=> menuPopup.openPopup(this, "after_start"); self.setAttribute("type", "menu"); var array = [ [ "Экспорт всех CB кнопок в HTML файл", "setPathToHtmlFile()", "data:image/x-icon;base64,AAABAAEAEhIAAAEAIACABQAAFgAAACgAAAASAAAAJAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/w4P6P8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/zUq6P8OD+j/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/0RC//0cE+X/Dg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQW5/8tMOT/Njfw/0BA+v9JSP//UU///1hT//9aVv3/RUL5/zQy+f8zNPH/JSHa/w4P6P8AAAAAAAAAAAAAAAAAAAAAAAAAABAR5v0UFeL/Hh7v/Soo+P80Mf39PDn+/0I+//05NPn/F5sr/zlO0/08PeL/NDbb/Rwdyv8OD+j/AAAAAAAAAAAAAAAAAAAAAA4P6P8XGOn/Hh7x/yQk9f8rKvX/MjD1/zk0+f85NPn/F5sr/xebK/8lQ6n/Hx/D/w4P6P8AAAAAAAAAAAAAAAAAAAAAAAAAAA4P6P8OD+j/Dg/o/w4P6P8OD+j/Dg/o/w4P6P8OD+j/F5sr/zfyX/0Xmyv/Dg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH3EgP+W8J//m/Sk/6D5qv+k/K7/qPyz/6z8uP9t2H7/QuJf/zz/Xv8f7UX/F5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOQFP8f5D3/KexI/zL3U/87/V3/Qf9k/0T/aP9K/2v/Qf9j/zn5Wf8571X/Kt1J/xebK/8AAAAAAAAAAAAAAAAAAAAAAAAAAAeUGf0Y6Tj/IvNE/Sn6Tv81/lj9Pv9h/0X9Z/1H/mf/Rvpk/0HvXP064VP/MtZL/RrHN/8Xmyv/AAAAAAAAAAAAAAAAAAAAAAmYHP8JmBz/CZgc/wmYHP8JmBz/CZgc/wmYHP8JmBz/CZgc/zjgUf8x1kj/FMIy/xebK/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKL08/zDXSP0NvCz/F5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHKsv/xS9Lv8Xmyv/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/xebK/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//8BB/9/AQf/PwEH/x8BB/8PAQcABwEHAAMBBwAHAQcADwEHAA8BBwAHAQcAAwEHAAcBB/8PAQf/HwEH/z8BB/9/AQf//wEE="], [ "Открыть в вкладке HTML файл", "openHtmlFileInTab()", "data:image/x-icon;base64,AAABAAEAEhIAAAEAIACABQAAFgAAACgAAAASAAAAJAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXmyv/F5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABebK/8UvS7/HKsv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/w28LP8w10j9KL08/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXmyv/FMIy/zHWSP844FH/CZgc/wmYHP8JmBz/CZgc/wmYHP8JmBz/CZgc/wmYHP8JmBz/AAAAAAAAAAAAAAAAAAAAABebK/8axzf/MtZL/TrhU/9B71z9Rvpk/0f+Z/9F/Wf9Pv9h/zX+WP0p+k7/IvNE/RjpOP8HlBn9AAAAAAAAAAAAAAAAAAAAAAAAAAAXmyv/Kt1J/znvVf85+Vn/Qf9j/0r/a/9E/2j/Qf9k/zv9Xf8y91P/KexI/x/kPf8DkBT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/x/tRf88/17/QuJf/23Yfv+s/Lj/qPyz/6T8rv+g+ar/m/Sk/5bwn/99xID/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/xebK/838l/9F5sr/w4P6P8OD+j/Dg/o/w4P6P8OD+j/Dg/o/w4P6P8OD+j/AAAAAAAAAAAAAAAAAAAAAAAAAAAOD+j/Hx/D/yVDqf8Xmyv/F5sr/zk0+f85NPn/MjD1/ysq9f8kJPX/Hh7x/xcY6f8OD+j/AAAAAAAAAAAAAAAAAAAAAA4P6P8cHcr/NDbb/Tw94v85TtP9F5sr/zk0+f9CPv/9PDn+/zQx/f0qKPj/Hh7v/RQV4v8QEeb9AAAAAAAAAAAAAAAAAAAAAAAAAAAOD+j/JSHa/zM08f80Mvn/RUL5/1pW/f9YU///UU///0lI//9AQPr/Njfw/y0w5P8UFuf/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/xwT5f9EQv/9Dg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4P6P81Kuj/Dg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOD+j/Dg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg/o/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//8BB/v/AQfz/wEH4/8BB8P/AQeAAwEHAAMBB4ADAQfAAwEHwAMBB4ADAQcAAwEHgAMBB8P/AQfj/wEH8/8BB/v/AQf//wEE="], [ "separator" ], [ "Открыть папку для экспорта CB кнопок", "openHtmlFileFolder()", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABZ0RVh0Q3JlYXRpb24gVGltZQAwOC8xMS8wNdiEE10AAAAldEVYdFNvZnR3YXJlAE1hY3JvbWVkaWEgRmlyZXdvcmtzIE1YIDIwMDSHdqzPAAACiUlEQVR4nKWTy0uUYRTGf+/np6PTODOmMpaGhJRaZmQgRAQtglaBf4BRtGgTFLUqKjBoF1QQlBLdKCgrscuiFEq6gGmQBWWSYLfpMqXMTM71+773PS0kQXBR9MBvdZ7z8HDgKBHhf2T9jUkdUbVKKTXfzH7eqVpdXbDDzWvRmrDngePyMZniXfsxLtLBFuAWhziqlOoQET0n4dlprk5/uysisTncO7Gqt3s/N5eeWCjD8T5ZcWa5nNvFmc6d7AEKRAQRgaHT9Gcyb0XyB+ain8jGC+ul5/15GXTuSN+3bmntapHj2+kFyv6E2K7DSrw0Yw9v8ys6gS9chfbgWvA5K2qXUb2knAfZflaXrWXTqg2MByNt12sG25JTiaRSqsI2wuLU5HdyU19p2TZOga+IfX27CUdqqG8KMeK9IKdchtLP8GpdaivXcN8S1g3cDwERWxvIJmP4K1qwfRmQl5wc6p450B14dLiHCecTzf5mtp7aC0BlqJx1M44iywjk4q/xVzSDxMEkkYNXkIOXKSsOoESwUChgoS+At/8GI5u7JOswDIhlDKR/DBKoXA4mCiYxS124nBLxqKCQoGjqwuV46QSTH0fIOYwCjm0MuOnPFAXrwB2eKWY8yKdoDJbgd35S5eYJmWkaQqWYfCGf3wyQc4gCrm0EvMwXiksXQW4SslnIZ0GEhkAJC3IJIq4mpNM0lgaxiqpJTX1SP38xCni2ESgtsxBjgd0OAYHATJHGmgH8Ja1ECusIWSHqa6rI5MKk4lGejjEKuLbWvJqMmdVDZ5vwPGbRGr5rxeDjahJuCtsUE43FSOaFRJpLIx9IAK4CbKAS8AHzPsw8MkAaiCsRQSll/8PybIiI6N8D8VYf0gJ8eQAAAABJRU5ErkJggg=="], [ "Экспорт всех CB кнопок в HTML файл без запроса", "exportsButtonsToHtmlFile()", "data:image/x-icon;base64,AAABAAEAEhIAAAEAIACABQAAFgAAACgAAAASAAAAJAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE8A/wBPAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE8A/wBkAP8ATwD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE8A/wB6AP0AUgD/AE8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAP8AZQD/AG4A/wB3AP8AfwD/AIQA/wCHAP8AiAD/AHkA/wBtAP8AbAD/AFgA/wBPAP8AAAAAAAAAAAAAAAAAAAAAAAAAAABQAP0AUgD/AFwA/QBmAP8AbgD9AHQA/wB4AP0AbwD/F5sr/wBzAP0AbgD/AGcA/QBQAP8ATwD/AAAAAAAAAAAAAAAAAAAAAABPAP8AVgD/AF0A/wBiAP8AZwD/AGsA/wBvAP8AbwD/F5sr/xebK/8AXgD/AFAA/wBPAP8AAAAAAAAAAAAAAAAAAAAAAAAAAABPAP8ATwD/AE8A/wBPAP8ATwD/AE8A/wBPAP8ATwD/F5sr/zfyX/0Xmyv/AE8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH3EgP+W8J//m/Sk/6D5qv+k/K7/qPyz/6z8uP9t2H7/QuJf/zz/Xv8f7UX/F5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOQFP8f5D3/KexI/zL3U/87/V3/Qf9k/0T/aP9K/2v/Qf9j/zn5Wf8571X/Kt1J/xebK/8AAAAAAAAAAAAAAAAAAAAAAAAAAAeUGf0Y6Tj/IvNE/Sn6Tv81/lj9Pv9h/0X9Z/1H/mf/Rvpk/0HvXP064VP/MtZL/RrHN/8Xmyv/AAAAAAAAAAAAAAAAAAAAAAmYHP8JmBz/CZgc/wmYHP8JmBz/CZgc/wmYHP8JmBz/CZgc/zjgUf8x1kj/FMIy/xebK/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKL08/zDXSP0NvCz/F5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHKsv/xS9Lv8Xmyv/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/xebK/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5sr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//8BB/9/AQf/PwEH/x8BB/8PAQcABwEHAAMBBwAHAQcADwEHAA8BBwAHAQcAAwEHAAcBB/8PAQf/HwEH/z8BB/9/AQf//wEE="] ]; var menuPopup = self.appendChild(document.createElementNS(xulns, "menupopup")); array.forEach((m,i)=> { if ( m[0] == "separator" ) { menuPopup.appendChild(document.createElementNS(xulns, "menuseparator")); return }; var mItem = menuPopup.appendChild(document.createElementNS(xulns, "menuitem")); mItem.setAttribute("label", m[0]); mItem.setAttribute("class", "menuitem-iconic"); mItem.setAttribute("image", m[2]); mItem.addEventListener("command", ()=> eval(m[1])); }); menuPopup.setAttribute("onclick", "event.stopPropagation()"); function openHtmlFileInTab() { var fp = window.makeFilePicker(); fp.init( !("inIsolatedMozBrowser" in window.browsingContext.originAttributes) ? window.browsingContext : window, "Выберите HTML-файл для импорта закладок", fp.modeOpen); fp.appendFilters(fp.filterHTML); Cu.import("resource://gre/modules/FileUtils.jsm"); fp.displayDirectory = FileUtils.File(getPathToHtmlFileFolder()); fp.open(re=> { if ( re == fp.returnOK ) gBrowser.selectedTab = gBrowser.addTab(fp.file.path, { triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),}) }) }; function exportsButtonsToHtmlFile() { var visibleCBbuttons = [...document.querySelectorAll('[cb-mode]')]; var paletteCBbuttons = [...custombuttons.palette.querySelectorAll('[cb-mode]')]; var allCBbuttons = visibleCBbuttons.concat(paletteCBbuttons); var array = []; allCBbuttons.forEach(but=> { var uri = but.URI ? but.URI : getPaleteButtonsURI(but); var name = but.getAttribute("label") || "Без названия"; var image = but.getAttribute("image") || "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACNFBMVEXDRgDweQDnbwC0NgDCRQC7PQDtpTu+QQD78q3PUwDCRAD//8vbYQDLTgDocAD0iQX1jQbGSgD7iAD4gwDVaw7vdwDyegD+igDweQDlawDyhAXveADmZwDzmBbtcwDwkhHveADmhBTkgxbweADkfRH+igD7hADXZQX0gADyjA/tfgvveQDiawDQVADRXgfnbwD1jAb9iQD9z0PVZAbxpinykRHtdgD5mRbERQDDRgDOYArCRAD9iQD3ewDxegD3dwDFRgDAQAD+hgD4fQDucgDtgQftfwTISQDCRQDvdgD5lxb1kRb2qh7wnynkagD766LDRQDDRwDDRQDspjbtpzbuqDbvqzv//8DUZAbCRQD//83pjhvveQbvggW+QQDfcxLlmUb//8veYADMTwDHSADVVwC8PgDwixb78q3oZgDUWADRVADCRQD9iQDERwDBQQDYVQC+PgC0NgDbYQDWWgDUWADSVQDFSAC+QAC7PAC0NgD+wRL+/kD+/zb+7i3+8Cv+/DX+wBL/+DD/rwz+qgz+rwz/tAz+sQzfbAT+3iP/+jD//Dz1jwP+nwf5iwf7pBz2tRr4lwb/ogfsdQT+2R7/9ET+2iT8yyLmgBL5iQL2egLokhP7zzT60zv1zUr0gAL1ewP50yn9+UL++EXooyngaAH41EPzowzyySj+xxzlhhHvvyruwjXxvTnUag3+zxrwigP+swz86U/ZXwD75lHqegD6xzb//kn+uhPTXAG3OAD/+UC2vFeJAAAAe3RSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAACfnwAIaelpAAA2+wD7UQAAa3oArKzRzMysnwgAvPQA/gAAw3prw0oALr16vS4AACnF6bspAAAA/mIAADQAAAAAAI8AAEwA0vv7kd2yAuuvr+vKABL23U+8Sk/d9vUDIIAQAAAQgCAfvupHAAABB0lEQVR4Xi3IU3fDABgA0C+u26FdZ9u2bdu2vZSzbds2/tyac3IfLxjpGyA6MimqY6gHTNgiiNwkwRM1E7EhTrYyTfMzzsh0ZEPiH+D6+u5mV1jEhpe5haVCYW1T4suEvUOkk7PLpVJ5WFnl7hEUDN5LPvsHJ6cazdn13f3DYxu0B35+/Y2qVSr17NzGeUgohIVHLK/PMDa39qKieRATGxd/9cS4uU1MwnmQktqY/qGlaVr7/ZOVDTmQm5df8PwyNj4xOTVdjOM4kCRZOr+wWFa+srpWQVEU8PnV2zu7NbV19UfHDQRBAIfTdNHc0soVdnR2dfdgGAgEvW99/QNc4eDQ8O8Ihv0D77NPgbVLZ6kAAAAASUVORK5CYII="; array.push("<img src=" + image + "> <a href=" + uri + ">" + name +"</a><br>\n"); }); var before = "<html>\n<head>\n<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>\n</head>\n<body>\n"; var after = "\n</body>\n</html>"; var text = before + array.join("") + after; var text = convertFromUnicode("UTF-8", text); var date = new Date(); var time = date.toLocaleString('ru', {year: 'numeric', month: 'numeric', day: 'numeric'}) var time = time + '. ' + date.toLocaleTimeString().replace(/:/g, "˸"); var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); file.initWithPath(getPathToHtmlFileFolder()); file.append("CB buttons " + time + ".html"); custombuttonsUtils.writeFile(file.path, text); var alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService) alertsService.showAlertNotification(self.image, self.label, "Экспортировал все CB кнопки как HTML в " + file.path); setTimeout(()=> alertsService.closeAlert(), 4000); }; function getPaleteButtonsURI(but) { /* Streem */ var uri = "chrome://custombuttons/content/nbftemplate.xml"; var stream = NetUtil.newChannel({uri, loadUsingSystemPrincipal: true}).open(); var doc = new DOMParser().parseFromStream(stream, null, stream.available(), "application/xml"); stream.close(); ["help,Help", "name,label", "image,image", "mode,cb-mode", "initcode,cb-init", "accelkey,cb-accelkey", "code,cb-oncommand"] .forEach(str=> { var arr = str.split(','); var value = but.getAttribute(arr[1]), name = arr[0]; custombutton.buttonSetText(doc, name, value, true); }); var ser = new XMLSerializer(); return "custombutton://" + escape(ser.serializeToString(doc)); }; function openHtmlFileFolder() { var folder = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); folder.initWithPath( getPathToHtmlFileFolder() ); folder.launch(); }; function setPathToHtmlFile() { var fp = window.makeFilePicker(); fp.init( !("inIsolatedMozBrowser" in window.browsingContext.originAttributes) ? window.browsingContext : window, "Укажите папку для экспорта CB кнопок!", fp.modeGetFolder); fp.open(re=> { if ( re != fp.returnOK ) return; cbu.setPrefs("CB.exportsButtonsToHtmlFile.path", convertFromUnicode("UTF-8", fp.file.path)); exportsButtonsToHtmlFile(); }) }; function getPathToHtmlFileFolder() { var s = "CB.exportsButtonsToHtmlFile.path", pref = Services.prefs; var str = pref.getStringPref ? pref.getStringPref(s) : pref.getComplexValue(s, Ci.nsISupportsString).data; try { return str } catch(e) { return "C:" }; }; function convertFromUnicode(charset, str) { var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); converter.charset = charset; str = converter.ConvertFromUnicode(str); return str + converter.Finish(); }; this.onmouseover =()=> { this.tooltipText = self.label + "\nЛ: Меню кнопки\nП: CB меню\n\nПапка для экспорта:\n" + getPathToHtmlFileFolder(); };
Жизнь иногда такое выкидывает, что хочется подобрать...
На форуме
Farby
Дополнительные пункты в контекстном меню кнопки вроде неплохо.
А вот
Экспорт всех CB кнопок в HTML файл
, почему то дублирует копируемые кнопки ( но не критично)
Благодарность вам Уважаемый.
Отредактировано vv07 (31-08-2024 04:06:06)
Отсутствует
Farby
Извините дружище. Не подскажите, есть ли возможность поправить Автоматически добавлять выделенный текст в SearchBar
this._handleClick =()=> cbu.setPrefs(s, !cbu.getPrefs(s)); var s = 'CB.pasteIntoSearchBar'; cbu.isPref(s, true); toggleImage(); function toggleImage() self.checked = cbu.getPrefs(s); gPrefService.addObserver(s, toggleImage, false); addDestructor(()=> gPrefService.removeObserver(s, toggleImage) ); function pasteIntoSearchBar(e) { if ( e.button || !cbu.getPrefs(s) ) return; var sel = document.commandDispatcher.focusedWindow.getSelection(); if ( !sel.isCollapsed ) BrowserSearch.searchBar._textbox.value = sel; }; addEventListener('mouseup', pasteIntoSearchBar, false, gBrowser);
Хоть не особо важно, но все таки удобно. буду признателен.
Отсутствует
Автоматически добавлять выделенный текст в SearchBar
Про это ещё Dumby в далёком 2019
Я фик знает, неремонтопригодно.
но рабочий вариант там всё же есть.
Жизнь иногда такое выкидывает, что хочется подобрать...
На форуме