Полезная информация

Заказывай стафф с атрибутикой Mozilla и... пусть все вокруг завидуют тебе! Быть уникальным - быть с Mozilla!

№1712630-06-2024 19:48:55

mokujin
Участник
 
Группа: Members
Зарегистрирован: 17-02-2017
Сообщений: 505
UA: Firefox 102.0

Re: Custom Buttons

А как правильней\экономней\быстрее делать: мне нужно проверять, есть ли у вкладки(из массива всех вкладок) опред.аттрибут. Делать так

скрытый текст

Выделить код

Код:

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

Отсутствует

 

№1712730-06-2024 22:37:44

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2252
UA: Firefox 78.0

Re: Custom Buttons

mokujin пишет

как правильней\экономней\быстрее делать

На теоретические разговоры потянуло? :)


Создание отдельной функции, в данном случае,
выглядит совершенно ненужным.


Тем более такой дикой, ведь hasAttribute() уже́
возвращает true или false


Возможно, «мне нужно проверять» — имеется в виду,
что эта функция будет использоваться где-то ещё,
но в коде это нигде не указано.


Не нужно, здесь, и создавать функцию для forEach()
вполне можно обойтись перечислением for of


Избыточно и прибавлять единицу в цикле дважды.
Можно прибавить к q единицу до цикла, а в цикле написать 100 * ++q
Если значение в q используется в дальнейшем, то вычесть единицу после цикла.


Однако, самый интересный вопрос — сто́ит ли
здесь делать проверку hasAttribute() вообще?


Метод removeAttribute() не образует ошибку,
если скормить ему имя атрибута, которого нет.
В этом случае, метод просто не делает ничего (видимого).


То есть, вопрос в том, что если сразу использовать removeAttribute()
то не дешевле ли то, что при этом происходит внутри, в недрах движка,
чем вытаскивать существование атрибута наружу-в -JS

Отсутствует

 

№1712801-07-2024 01:42:04

mokujin
Участник
 
Группа: Members
Зарегистрирован: 17-02-2017
Сообщений: 505
UA: Firefox 102.0

Re: Custom Buttons

:D  ну, задавая вопрос, я руководствовался чисто практич. мотивами: полегше да правильней.
Это кнопка которую я, в попытках подтянуть шушуть 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;

Dumby пишет

Тем более такой дикой, ведь hasAttribute() уже́
возвращает true или false

Да я, блин, уже перестраховываюсь. Как-то не мог понять, почему у меня не работает скриптег; долго не мог. А оказалось, что то, что я присваивал, не всегда тру\фалсе а еще и андефайнед или вообще nan/ бывает. Счас не вспомню что и как, но как нашел, теперь перебдеваю.

Dumby пишет

Избыточно и прибавлять единицу в цикле дважды.
Можно прибавить к q единицу до цикла, а в цикле написать 100 * ++q

Первое что я проверил и да, работает. Мне-то главное было именно последоват. закрытие сделать. А в таком как у меня виде, без этого вначале q++ последоват. закрытия небыло. А додуматься до ++q я не смог. Пасиба.

Dumby пишет

Метод removeAttribute() не образует ошибку,

Не знал. запомню.

Dumby пишет

сто́ит ли здесь делать проверку hasAttribute() вообще?

Да. Как видишь, другая кнопка этот аттрибут вешает и я не хочу закрывать эти вкладки. Но иногда, с SHIFT - хочу. Для этого и нужно.

Буду править. Благодарю.


...программисты словно войну какую-то ведут за свои обновления. Блин, почему сейчас повсюду мания ухудшать интерфейсы и делать их максимально неудобными?! Radiation

Отсутствует

 

№1712901-07-2024 13:02:26

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2252
UA: Firefox 78.0

Re: Custom Buttons

mokujin пишет

то, что я присваивал, не всегда тру\фалсе

В данном коде всё это используется только в логическом контексте,
так что, даже если бы нарисовалось «андефайнед или вообще 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)

Отсутствует

 

№1713022-07-2024 22:05:14

foxboy
Участник
 
Группа: Members
Зарегистрирован: 06-06-2015
Сообщений: 34
UA: Firefox 102.0

Re: Custom Buttons

Когда-то была кнопка переключаться на вкладку слева при закрытии активной. Может есть такая для 115.

Отсутствует

 

№1713123-07-2024 09:09:25

fuchsfan
Участник
 
Группа: Members
Зарегистрирован: 07-08-2023
Сообщений: 130
UA: Firefox 115.0

Re: Custom Buttons

foxboy пишет

Когда-то была кнопка переключаться на вкладку слева при закрытии активной. Может есть такая для 115.

Поведение при закрытии вкладки:
browser.tabs.selectOwnerOnClose = true (по умолчанию): переместить фокус обратно на вкладку, которая ее открыла.
browser.tabs.selectOwnerOnClose = false: переместить фокус на соседнюю правую вкладку, если она существует; в противном случае - на соседнюю левую вкладку.
Для перемещения фокуса всегда на левую вкладку расширение "Focus On Left Tab After Closing" или "Focus left tab on close".

Отсутствует

 

№1713225-07-2024 16:33:44

Farby
Участник
 
Группа: Members
Зарегистрирован: 21-11-2012
Сообщений: 306
UA: Google 2.1

Re: Custom Buttons

Dumby здравствуйте.
Вы написали скрипт для включения / разблокировке поисковых движков, Всё было бы хорошо, но в [firefox] 129 выпилили иконки поисковиков, выглядит как то не комильфо в режиме search-config. Посмотрите пожалуйста можно адаптировать этот скрипт для режима [firefox] search-config-v2?
PS: Скорее всего выпилят в тихую и из ESR...


Жизнь иногда такое выкидывает, что хочется подобрать...

Отсутствует

 

№1713326-07-2024 12:16:18

Farby
Участник
 
Группа: Members
Зарегистрирован: 21-11-2012
Сообщений: 306
UA: Google 2.1

Re: Custom Buttons

Ещё просьба, может вы собирали обновлённый DOMi


Жизнь иногда такое выкидывает, что хочется подобрать...

Отсутствует

 

№1713406-08-2024 09:41:08

manuk
Участник
 
Группа: Members
Зарегистрирован: 17-10-2010
Сообщений: 306
UA: Firefox 129.0

Re: Custom Buttons

В 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)

Отсутствует

 

№1713506-08-2024 12:08:01

Farby
Участник
 
Группа: Members
Зарегистрирован: 21-11-2012
Сообщений: 306
UA: Google 2.1

Re: Custom Buttons

manuk
Проверял на [firefox] 129, но обнаружил что не все подменю в History и Bookmarks работают, если устроит пользуйтесь...

menu

Выделить код

Код:

/*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);
}));


Жизнь иногда такое выкидывает, что хочется подобрать...

Отсутствует

 

№1713606-08-2024 12:29:41

manuk
Участник
 
Группа: Members
Зарегистрирован: 17-10-2010
Сообщений: 306
UA: Firefox 129.0

Re: Custom Buttons

Farby, спасибо. Из того, чем пользуюсь, не работает "Справка - информация для решения проблем". Т.е. полного функционала у кнопки не будет? Может аналог в UCF есть?

Отсутствует

 

№1713706-08-2024 13:13:36

Farby
Участник
 
Группа: Members
Зарегистрирован: 21-11-2012
Сообщений: 306
UA: Google 2.1

Re: Custom Buttons

manuk пишет

Т.е. полного функционала у кнопки не будет? Может аналог в UCF есть?

К сожалению я не обладаю достаточной магией, чтобы квалифицированно поправить скрипт. Так что вам придётся спросить ещё кого...


Жизнь иногда такое выкидывает, что хочется подобрать...

Отсутствует

 

№1713806-08-2024 13:16:07

manuk
Участник
 
Группа: Members
Зарегистрирован: 17-10-2010
Сообщений: 306
UA: Firefox 129.0

Re: Custom Buttons

Farby пишет

Так что вам придётся спросить ещё кого...

Dumby, ау... :)

Отсутствует

 

№1713906-08-2024 14:03:56

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2252
UA: Firefox 78.0

Re: Custom Buttons

Farby пишет

для режима [firefox] 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);
}));

Отсутствует

 

№1714006-08-2024 14:15:13

manuk
Участник
 
Группа: Members
Зарегистрирован: 17-10-2010
Сообщений: 306
UA: Firefox 129.0

Re: Custom Buttons

Dumby пишет

Чисто формально, возможно, лучше как-то так

Так лучше. Только панель меню появляется после клика, которую после скрывать нужно. Спасибо.

Отсутствует

 

№1714107-08-2024 09:38:30

Farby
Участник
 
Группа: Members
Зарегистрирован: 21-11-2012
Сообщений: 306
UA: Google 2.1

Re: Custom Buttons

Dumby пишет

Ужаснись тогда что получится.
Только бэкап сначала сделать не забудь.

Спасибо! Все 154 у меня получилось. Я себе делал мод предыдущего скрипта, вот тогда-то я и ужаснулся от количества eBay`ев и Vikipedia`ев


Жизнь иногда такое выкидывает, что хочется подобрать...

Отсутствует

 

№1714207-08-2024 21:41:22

Andrey_Krropotkin
Участник
 
Группа: Members
Зарегистрирован: 11-11-2011
Сообщений: 484
UA: Firefox 129.0

Re: Custom Buttons

Подскажите пожалуйста в кнопке

скрытый текст

Выделить код

Код:

// Двойным левым кликом на папке закладок добавлять закладку в папку закладок
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);
});


ошибка в этом    if (!node || !PlacesUtils.nodeIsFolder(node)) return;

Отсутствует

 

№1714308-08-2024 09:15:14

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2252
UA: Firefox 78.0

Re: Custom Buttons

Andrey_Krropotkin пишет

PlacesUtils.nodeIsFolder

Bug 1904909
PlacesUtils.nodeIsFolder
PlacesUtils.nodeIsFolderOrShortcut

Отсутствует

 

№1714408-08-2024 17:02:31

Jurgens
Эйяфьядлайёкюдль
 
Группа: Members
Зарегистрирован: 25-06-2010
Сообщений: 190
UA: Firefox 115.0

Re: Custom Buttons

Dumby
Подскажите пожалуйста, это сейчас актуальная версия антиподписячего кода или уже таки есть новая?

Отсутствует

 

№1714530-08-2024 12:19:26

vv07
Участник
 
Группа: Members
Зарегистрирован: 07-11-2007
Сообщений: 689
UA: unknown 0.0

Re: Custom Buttons

Есть две (уверен важные для многих) кнопки
Дополнительные пункты в контекстном меню кнопки

Выделить код

Код:

/*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, "&amp;").replace(/</g, "&lt;")
                .replace(/>/g, "&gt;").replace(/"/g, "&quot;");
  }

  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 + ">&nbsp\<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, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;");
    if(isAttr) {
        s = s
            .replace(/\t/g, "&#x9;")
            .replace(/\n/g, "&#xA;")
            .replace(/\r/g, "&#xD;");
    }
    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 + ">&nbsp<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

Отсутствует

 

№1714630-08-2024 22:41:24

Farby
Участник
 
Группа: Members
Зарегистрирован: 21-11-2012
Сообщений: 306
UA: Google 2.1

Re: Custom Buttons

vv07 пишет

Есть две (уверен важные для многих) кнопки

Важные? Мб комуто...
покатал на [firefox] 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, "&amp;").replace(/</g, "&lt;")
                .replace(/>/g, "&gt;").replace(/"/g, "&quot;");
  }

  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 + ">&nbsp\<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, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;");
    if(isAttr) {
        s = s
            .replace(/\t/g, "&#x9;")
            .replace(/\n/g, "&#xA;")
            .replace(/\r/g, "&#xD;");
    }
    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 файл

Выделить код

Код:

/*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 + ">&nbsp<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();
};


ЗЫ: про форки не пробовал!!!


Жизнь иногда такое выкидывает, что хочется подобрать...

Отсутствует

 

№1714731-08-2024 04:05:36

vv07
Участник
 
Группа: Members
Зарегистрирован: 07-11-2007
Сообщений: 689
UA: Firefox 54.0

Re: Custom Buttons

Farby
Дополнительные пункты в контекстном меню кнопки вроде неплохо.
А вот

Экспорт всех CB кнопок в HTML файл

, почему то дублирует копируемые кнопки ( но не критично)
Благодарность вам Уважаемый.

Отредактировано vv07 (31-08-2024 04:06:06)

Отсутствует

 

№1714831-08-2024 06:25:15

vv07
Участник
 
Группа: Members
Зарегистрирован: 07-11-2007
Сообщений: 689
UA: Firefox 127.0

Re: Custom Buttons

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);

Хоть не особо важно, но все таки удобно. буду признателен.

Отсутствует

 

№1714901-09-2024 00:03:45

Farby
Участник
 
Группа: Members
Зарегистрирован: 21-11-2012
Сообщений: 306
UA: Google 2.1

Re: Custom Buttons

vv07 пишет

Автоматически добавлять выделенный текст в SearchBar

Про это ещё Dumby в далёком 2019

Dumby пишет

Я фик знает, неремонтопригодно.

но рабочий вариант там всё же есть.


Жизнь иногда такое выкидывает, что хочется подобрать...

Отсутствует

 

№1715001-09-2024 04:36:30

vv07
Участник
 
Группа: Members
Зарегистрирован: 07-11-2007
Сообщений: 689
UA: Firefox 54.0

Re: Custom Buttons

Farby
Все понял. Не критично. Обойдусь :)

Отсутствует

 

Board footer

Powered by PunBB
Modified by Mozilla Russia
Copyright © 2004–2020 Mozilla Russia GitHub mark
Язык отображения форума: [Русский] [English]