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

Хотите узнать больше о расширениях? Посмотрите ролики, рассказывающие о работе с расширениями Firefox.

№1415126-01-2020 04:55:49

func4ptch4
Участник
 
Группа: Members
Зарегистрирован: 03-05-2018
Сообщений: 220
UA: Firefox 74.0

Re: Custom Buttons

Dumby, ура заработал! просто до этого пробовал не получалось.. с перезапуском сработал.
Насчет стилей я думал `..` значит там стиль, ну и <> скорее html ну или код верстки какой-то), ну я не прогер поэтому синтаксис не очень знаю. Видел код на js, скроллбар вроде там и стиль был и скрипт, интересно зачем к примеру в findbar-е один код используют как .css а другой как скрипт, когда удобнее в одно все сложить, хотя бы чтоб не путать.
upd: проверял кнопку, интересно он работает только после правки, а так после запуска [firefox] не работает.
Если внести любое изменение и сохранить, кнопка оживает и все работает как надо.

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

Выделить код

Код:

//Quick toggle for about:config preferences 24.07.2016[Fx] - forum.mozilla-russia.org/viewtopic.php?pid=777019#p777019||777123#p777123||777188#p777188
this.type="menu";custombuttons.initAutoPopup(self);
var menuPopup=self.appendChild(document.createXULElement("menupopup"));this.matches("toolbar[orient=vertical]>:scope")&&menuPopup.setAttribute("position","end_before");

//[?]menuPopup.id='quick-aboutconfig-menupopup';
 
// Изменить иконку при несоответствие любого параметра пользовательскому предпочтению (см.ниже)||Иконка меняется только при изменеии параметров через меню кнопки, либо после его открытия.
  var s='CB.hasNotUserChoice';function toggleImage(){var val=custombuttons.getPrefs(s);self.image=val
//var s='CB.hasNotUserChoice';function toggleImage(){        custombuttons.getPrefs(s)?self.style.cssText='':self.style.cssText='filter:grayscale(100%)';};
? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAB6klEQVQ4jZWTv2tUQRDHv8ntd28GLLQQfwS5VkuDSgRF/wlRiIiCQQQhhZ1VII1/wDUWkkLTBAsbC0FJYZGQ3NuZRcHYW6UQEQzoeXkW791xXh5CptodZr8z85kd4BBWRJwDgB5wyoCjh3mLbfK8C/ddW11XJlduNgYaeTFpvJWA0+P+BBx3Cf2sLEy5m4WrS8A0AGANaBUSrgKAKzdcY5k0PF4HJGm47NK6nSUMXOIXAEgSrrnG0oU/AGDKNb6qHe9c+Ms1lqbxqws/uoTfWVp3ksRll/DTJM6bcMWEn1KbDysBCW+zsnSNpWssTbg3PNf3uw7MuHDgym8uoW8aX496SxKXs7J0iTsFObcGRBfey8rShP1EXthSnDHhShJ0vM0H1uYiAKBSHWZqLYyDc+H7sSpeNlMX9l1jWWebEAgjgSxcbRRYB46YhCcVxH9bqDP3nbyUBB0XPk+Cjgnvj1qoqohvJqDtTUBdcGAmSzgIEQBM2R0fY/U41GPkwNpcTBKfmnDPNN4w4TOX+NnbfAQAWAKmXcMVAMgaNqrM1UfqkbMmrXkT/nGJO1XF4Xod8/0Ak4KcKzTe3AROjPs/AMdM2M8atk25a8IXAKYawTZZj5jNEvZN2TVldg3Ny/RfkYizALAFnByu819tzvCRWXKqTwAAAABJRU5ErkJggg=='
: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAACXBIWXMAAABnAAAAZwHVKNQmAAADGGlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjaY2BgnuDo4uTKJMDAUFBUUuQe5BgZERmlwH6egY2BmYGBgYGBITG5uMAxIMCHgYGBIS8/L5UBA3y7xsDIwMDAcFnX0cXJlYE0wJpcUFTCwMBwgIGBwSgltTiZgYHhCwMDQ3p5SUEJAwNjDAMDg0hSdkEJAwNjAQMDg0h2SJAzAwNjCwMDE09JakUJAwMDg3N+QWVRZnpGiYKhpaWlgmNKflKqQnBlcUlqbrGCZ15yflFBflFiSWoKAwMD1A4GBgYGXpf8EgX3xMw8BUMDVQYqg4jIKAX08EGIIUByaVEZhMXIwMDAoM2Qw7CDkY8xi/EskynTYmYR5i4WFpZGVibWNjYetmnsyuybOVw5bnIWcHFyLeV24n7E08KrwXuOr4xfnv+0QIWguuANoS5hO+EvIqtFU8TkxW6Jz5AIlxSXvCE1RzpBRk3mrexWuXp5LwUxhSeKm5SalENU1FR+qp5TW6JerRGsqaPFpvVIe5/ObN0qvSh9KwMZg3+Gj4yOG68xmWxaZZZs7mNhbqlkxWf12/qlzQ3bE3Y77Vc7zHWc6NTqXOVS4JruFuce7hHg6eXl6u3oY+dr7WfpbxFgEWgRZBlsHWIX6hTmFu4dERgZHhUfnR5TEFsZ1xzflzArcVnS5uSDKedT76W9S/+XKZClmG2S454bnZef31owq3Bj0YniByU/ygTLtStcKxOqaqpn1GytvVT3oYG/Ua/Jrzm/ZULrprYr7d87pbvsu5N7OnvX9V3t/zNRZZLP5JIp86aemPZphuxMz1mlsxfOOT/3z3ztBVELOxftXPxqqfQyn+V1KzaufLJaYo3P2sZ129a/2ai0KXLzxC0ntjFut9pRvHPtrhd7lPbG7Zu1/9pB4UOBh/uPnD3Gc9z7RPfJM6d5zvidnXDu0gXRixGX5lx+cFXlWtb19Te+3rK53Xzn1D2h+9EPljx8+9j8SePTM8/FXyS9XPfq9xuPt1PfPf5g+LHh0/kv8l/zv+3/IfAz6deWP2x/I/6t/v8fAATCIM0IpJTRAAAAIGNIUk0AAHolAACAgwAA+f8AAIDoAABSCAABFVgAADqXAAAXb9daH5AAAAEOSURBVHjabJGtS0MBFMXPJojBMMPwC1nV6FCZoGj/ZVGYiIJDBOEFm3XFP2DFIAu6ZrAYBM0OREEUnN20ICI40OfbsTzYB48b7oF74J4PWUnDjMU4GSv5PEubCo/UuwjMs8FEjLOEPNCkRloWAyxb3GEOGWKRTSLeLFYwXyLFBeaGH8w7z/yyRZlvilR5YV+kuMYY04r3NpNEfBByaYksZUyDAoPsYELmmKJKjj0CS0QYU4rl3WLMeceRCBMItW7CMEd9LxbIcUqOXQJLFld9Iks9Ii0qPTYjAo5pscYJrxzIIs1SV1B5ivzRsFjFfHaiLrDOaIxHCLmnyRmp5LLytKnw1FNWH2XaYoyM9T8AOvnw3YUOg90AAAAASUVORK5CYII=';};
    toggleImage();Services.prefs.addObserver(s,toggleImage,false);
addDestructor(()=>Services.prefs.removeObserver(s,toggleImage));

// nodeName: menuitem - для логических(boolean) параметров, menu - для целых(integer) и строковых(string). menuseparator - для разделителя.
// pref - параметр about:config.
// Параметры имеющие значения отличные от дефолтных - выделены жирным стилем текста.
// restart (задавать с пустым значением. т.е., restart: "") - добавляет возможность перезапуска браузера
// (с подтверждением в диалоговом окне) после изменения параметра.
// key - задает accesskey - клавиши для быстрой навигации по меню.
// userChoice - задает предпочитаемое значение и если текущее значение с ним не совпадает, пункт меню/название меню помечаются красным цветом.
// Также можно установить предупреждающую иконку для таких пунктов. См. стиль в посте ккнопки.
// А также меняется иконка самой кнопки (см. выше).
// strValues - значения и отображаемое в меню название значения. Задавать для целых(integer) и строковых(string) параметров.
// Задается в виде: значение,,,название,,,accesskey|||значение2,,,название2,,,accesskey2|||значение3,,,название3 и т.д. (accesskey - задается опционально)
// Полное значение отображается в подсказках, при наведении на название подменю/пункт подменю.
// Для логических(boolean) - отображается сразу после самого параметра (значение true - также ставит галочку для него).
// ЛКМ по пунктам меню - перключает значения для логических(boolean) параметров,
// любая кнопка по пунктам в субменю - задает это значение для целых(integer) и строковых(string) параметров.
// ПКМ по пунктам меню и названию субменю - сбрасывает значение параметра в дефолтное.
// Клавиатура: Enter - переключение параметра.
// Спецклавиша вызова контекстного меню / Shift+Enter - сброс в дефолтное значение.
// Alt + M - открыть меню кнопки. (Сочетание можно сменить на свое. См. в конце кода)
[ //{nodeName:"menuitem", name:"Откл. дискового кэша", pref:"browser.cache.disk.enable", userChoice:"false"},
  //{nodeName:"menuitem", name:"Откл. кэша в оперативной памяти", pref:"browser.cache.memory.enable", userChoice:"false"},
  //{nodeName:"menuseparator"},
  //{nodeName:"menuitem", name:"Откл. локального хранилища DB (Storage)", pref:"dom.indexedDB.enabled", key:'d'},
  //{nodeName:"menuitem", name:"Откл. локального хранилища", pref:"dom.storage.enabled", key:'s'},
  //{nodeName:"menuseparator"},
  //{nodeName:"menu", name:"Back-story-cash [Tessssttt]", pref:"browser.sessionhistory.max_total_viewers", strValues:"0,,,0"},
  //{nodeName:"menu", pref:"image.animation_mode", key:'i', userChoice:"none", strValues:"normal,,,Анимация картинок вкл.,,,|||none,,,Анимация картинок выкл.,,,"},
  //{nodeName:"menu", pref:"network.cookie.cookieBehavior", key:'k', userChoice:"1", strValues:"2,,,Не принимать куки с сайтов,,,|||0,,,Принимать куки со сторонних сайтов всегда,,,|||3,,,Принимать куки со сторонних посещённых сайтов,,,|||1,,,Принимать куки со сторонних сайтов никогда,,,"},
  //{nodeName:"menuseparator"},
  //{nodeName:"menu", pref:"general.useragent.locale", key:'l', restart:"", strValues:"en-US,,,English,,,e|||ru,,,Русский,,,r"},
  //{nodeName:"menu", name:"language", pref:"intl.accept_languages", strValues:"en-US, en;q=0.5,,,en-US, en;q=0.5,,,e|||en-US, en, ru-RU, ru,,,en-US, en, ru-RU, ru,,,r"},
  //{nodeName:"menu", pref:"browser.display.document_color_use", key:'c', userChoice:"0", strValues:"0,,,Automatic,,,0|||1,,,Always,,,1|||2,,,Never,,,2"},
  //{nodeName:"menu", pref:"CB.TEST", key:'t', userChoice:"C:\\Downloads\\TEST1", strValues:"C:\\Downloads\\TEST1,,,TEST1,,,1|||C:\\Downloads\\TEST2,,,TEST2,,,2"}
  //{nodeName:"menuseparator"},
  //{nodeName:"menuitem", name:"Откл. инфу начало/конец загрузки стр", pref:"dom.enable_performance", userChoice:"false"},
  //{nodeName:"menu", name:"Вкл/Выкл Referer", pref:"network.http.sendRefererHeader", strValues:"0,,,0"},
  //{nodeName:"menuitem", name:"В качестве реферера корень сайта", pref:"network.http.referer.spoofSource", userChoice:"true"},
  //{nodeName:"menu", name:"referer.trimmingPolicy", pref:"network.http.referer.trimmingPolicy", strValues:"2,,,2"},
  //{nodeName:"menuseparator"},
  //{nodeName:"menu", name:"On/Off Image", pref:"permissions.default.image", userChoice:1, strValues:"2,,,Off"},

  //{nodeName:"menuitem", name:"On/Off javascript", pref:"javascript.enabled", key:'j', userChoice:"true"},
  {nodeName:"menuitem", name:"On/Off useragentS", pref:"general.useragent.site_specific_overrides", userChoice:"true"},
  //{nodeName:"menuitem", pref:"dom.workers.enabled", key:'w', userChoice:"false"},
  //{nodeName:"menu", name:"Stopautoplay", pref:"media.autoplay.default", userChoice:0, strValues:"0,,,Stop,,,0|||1,,,Play,,,1"},
  //{nodeName:"menuitem", pref:"xpinstall.signatures.required"},                       //Check is compatibility
  //{nodeName:"menuitem", pref:"browser.bookmarks.autoExportHTML"},                    //BookmarksHtml [false=places.sqlite]
  //{nodeName:"menuitem", pref:"media.peerconnection.enabled"},                        //WebRTC false=off!

  {nodeName:"menuitem", name:"Drag&Drop(Safe) !Manual restart required!", pref:"browser.launcherProcess.enabled", userChoice:"true"},   //Drag&Drop(Safe) Manual restart required! - forum.mozilla-russia.org/viewtopic.php?pid=774980#p774980
  {nodeName:"menuitem", name:"On/Off media.play-stand-alone", pref:"media.play-stand-alone"},   //сразу скачивать медиафайлы, без перехода на новую страницу.
  {nodeName:"menuseparator"},
  {nodeName:"menu", name:"On/Off DoH", pref:"network.trr.mode", strValues:"3,,,3"},
  {nodeName:"menu", name:"Configure Proxies", pref:"network.proxy.type", userChoice:5, strValues:"1,,,httpP,,,1|||2,,,AutomaticP,,,2|||5,,,Use systemP,,,5"},
  {nodeName:"menu", name:"AutomaticP", pref:"network.proxy.autoconfig_url", strValues:"resource://FF/..pac,,,resource://FF/..pac,,,1|||https://antizapret.prostovpn.org/proxy.pac,,,https://antizapret.prostovpn.org/proxy.pac,,,2"},
  {nodeName:"menuseparator"}, 
  {nodeName:"menu", name:"User Agent", pref:"general.useragent.override", key:'u', strValues:"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0,,,Firefox 60/MacOSX 10.13|||Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36,,,Chrome 66/MacOSX 10.13.5|||Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36,,,Chrome 57/MacOSX|||Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.1 Safari/603.1.30,,,Safari Generic/MacOSX|||Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36,,,Chrome57/W7|||Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12 Version/12.16,,,Opera12/W8|||Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36,,,Chrome61/W10|||Mozilla/5.0 (Linux; Android 7.0; PLUS Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36,,,Chrome61/Android7|||Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html),,,GoogleBot|||Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots),,,YandexBot|||Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp),,,YahooBot|||Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm),,,BingBot|||DuckDuck bot/1.0; (+http://duckduckgo.com/duckduckbot.html),,,DuckDuckBot|||Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html),,,BaiduspiderBot|||ia_archiver (+http://www.alexa.com/site/help/webmasters; crawler@alexa.com),,,AlexaCrawlerBot|||Mozilla/5.0 (Linux; Android 5.1.1; SM-G928X Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.83 Mobile Safari/537.36,,,Samsung Galaxy S6 Edge Plus|||Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586,,,Microsoft Lumia 950|||Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586,,,Xbox One|||Mozilla/5.0 (PlayStation 4 3.11) AppleWebKit/537.73 (KHTML, like Gecko),,,Playstation 4|||,,,Пустое значение"},
]

.forEach(function(m){var mItem=document.createElementNS(xulns,m.nodeName);var browserRestart='';
if("restart"in m)browserRestart='if(custombuttons.confirmBox(null,"Restart?","Yes","Cancel"))Services.startup.quit(Services.startup.eAttemptQuit|Services.startup.eRestart);';
if("name"in m) mItem.setAttribute('name',m.name);
if("pref"in m){mItem.setAttribute('closemenu','none');
mItem.setAttribute('oncontextmenu','event.preventDefault();custombuttons.clearPrefs("'+m.pref+'");'+browserRestart);}
if("key"in m)  mItem.setAttribute('accesskey',m.key);
if(m.nodeName==="menuitem"){mItem.setAttribute('type','checkbox');
mItem.setAttribute('oncommand','custombuttons.setPrefs("'+m.pref+'",!custombuttons.getPrefs("'+m.pref+'"));if(event.shiftKey&&event.keyCode==event.DOM_VK_RETURN){event.preventDefault();custombuttons.clearPrefs("'+m.pref+'")};'+browserRestart);}
if(m.nodeName==="menu"){mItem.setAttribute('class','menu-iconic');

var subMenu=mItem.appendChild(document.createXULElement("menupopup"));

for (var value of m.strValues.split('|||')){var submItem=document.createXULElement("menuitem");
var smVal=value.split(',,,')[0];
var smValConv=convertFromUnicode("UTF-8",smVal);
var smName=value.split(',,,')[1];
var key=value.split(',,,')[2];

key&&submItem.setAttribute('accesskey',key);submItem.setAttribute('type','radio');
submItem.setAttribute('label',smName);submItem.setAttribute('tooltiptext',smVal);
submItem.setAttribute('closemenu','none');
submItem.setAttribute('oncommand','try{custombuttons.setPrefs("'+m.pref+'","'+smValConv.replace(/\\/g,'\\\\')+'")}catch(e){Services.prefs.setIntPref("'+m.pref+'","'+smValConv+'")};'+browserRestart);
subMenu.appendChild(submItem);}}
menuPopup.appendChild(mItem);

  // Листенеры отслеживающие переключение параметров
  // и устанавливающие соответствующие названия и чекбоксы для пунктов меню при открытии меню и кликах
  for (var type of ['command','popupshowing','contextmenu']){addEventListener(type,(e)=>{setTimeout(()=>{if ("pref" in m){var val,def;
   def=Services.prefs.prefHasUserValue(m.pref);
   try {val=Services.prefs.getComplexValue(m.pref,Ci.nsISupportsString).data;} catch(e) {
   if (Services.prefs.getPrefType(m.pref)==64) val=custombuttons.getPrefs(m.pref).toString();else val=custombuttons.getPrefs(m.pref);}
   def ? mItem.style.setProperty('font-weight', 'bold', 'important') : mItem.style.removeProperty('font-weight');}

     if (m.nodeName==='menuitem'){mItem.setAttribute('checked',val);mItem.label=(mItem.hasAttribute('name') ? mItem.getAttribute('name') : m.pref)+' - "'+val+'"';
     if ("userChoice" in m){try {var usrChc=(val.toString()===m.userChoice)} catch(e) {usrChc=false};

     mItem.setAttribute('user-choice',usrChc);usrChc ? mItem.style.removeProperty('color') : mItem.style.setProperty('color','orangered','important');}}
     if (subMenu){for (var smitem of subMenu.getElementsByTagName('menuitem')) {var smval=smitem.getAttribute('tooltiptext');smitem.setAttribute('checked',(val===smval) ? true : false);}}
     if (m.nodeName==="menu") {var vname;
     try {vname=subMenu.getElementsByAttribute('checked','true')[0].getAttribute('label');} catch(e) {if (!Services.prefs.prefHasUserValue(m.pref)) vname='Default';else vname='Other';}

     mItem.setAttribute('label',(mItem.hasAttribute('name') ? mItem.getAttribute('name') : m.pref)+' - "'+vname+'"');
     mItem.setAttribute('tooltiptext',val || 'This preferences has null value or does not exist.');

     if ("userChoice" in m) {var smUsrChc=(val===m.userChoice.toString());mItem.setAttribute('user-choice',smUsrChc);
     smUsrChc ? mItem.style.removeProperty('color') : mItem.style.setProperty('color','orangered','important');}}

     if ("userChoice" in m) {var hasNotUserChoice=menuPopup.getElementsByAttribute('user-choice','false')[0];custombuttons.setPrefs(s,hasNotUserChoice ? true : false);}}, 0)},false,menuPopup)}});

// Листенер позволяющий сброс параметров с субменю по Shift+Enter||За код спасибо Dumby
addEventListener("popupshown",{handleEvent:function(e){this[e.type](e);},
  popupshown:function(e){if(e.target!=menuPopup)return;menuPopup.addEventListener   ("popuphidden",this,false);window.addEventListener   ("keydown",this,true);},
 popuphidden:function(e){if(e.target!=menuPopup)return;menuPopup.removeEventListener("popuphidden",this,false);window.removeEventListener("keydown",this,true);},
popupshowing:function(e){e.target.parentNode.removeEventListener("popupshowing",this,false);e.preventDefault();},get old(){delete this.old;
this.e=new MouseEvent("contextmenu",{});return this.old=parseInt(Services.appinfo.platformVersion)<25;},get prop(){delete this.prop;
if("key"in KeyboardEvent.prototype)this.prop="key",this.val="Enter";else this.prop="keyCode",this.val=KeyboardEvent.DOM_VK_RETURN;return this.prop;},
keydown:function(e){if(!e.shiftKey||e.ctrlKey||e.altKey||e[this.prop]!=this.val)return;var target=menuPopup.querySelector("menu[_moz-menuactive]:not([open])");
if(!target)return;this.old ? target.addEventListener("popupshowing",this,false) : e.stopPropagation();target.dispatchEvent(this.e);menuPopup.dispatchEvent(this.e);}},false,menuPopup);

// Открыть меню кнопки по сочетанию клавиш Alt + M (не зависит от текущей раскладки клавиатуры)
addEventListener("keydown",e=>{if(e.altKey&&e.code=="KeyM"&&!e.shiftKey&&!e.ctrlKey)e.preventDefault(),self.open=true},false,window);

// Конвертировать текст в юникод .............
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();};

Отредактировано func4ptch4 (29-01-2020 09:38:25)

Отсутствует

 

№1415226-01-2020 08:27:40

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

Re: Custom Buttons

shadow_user для сплошного теста в окне перевода пробуйте

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

Выделить код

Код:

/*Initialization Code*/

var lc = navigator.lastClick = {};
addEventListener("mouseup", e => {
    if (e.button) return;
    lc.X = e.screenX - mozInnerScreenX;
    lc.Y = e.screenY - mozInnerScreenY;
}, false, gBrowser.tabpanels || 1);

var createWindow = function(text, status, title, id, pos, size){
var win = window, doc = win.document, wId = 'ujs_window'+(id || ''), w = doc.getElementById(wId);
    var keyDown = function(e){if(!e.shiftKey && !e.ctrlKey && !e.altKey && e.keyCode == 27)doc.getElementById(wId).closeWin()};
    if(w)w.closeWin();
    w = doc.createElementNS(xhtmlns, 'div');
     w.setAttribute('style', 'position:fixed;display:block;visibility:hidden;left:0;top:0;width:auto;height:auto;border:1px solid gray;padding:2px;margin:0;z-index:99999;overflow:hidden;cursor:move;'+(typeof w.style.borderRadius === 'string' ? 'background-color:#eaeaea;padding-top:0px;border-radius:4px;box-shadow:0 0 15px rgba(0,0,0,.4);' : 'background:-o-skin("Window Skin");'));
    w.id = wId;
    w.closeWin = function(){
        doc.removeEventListener('keydown', keyDown, false);
        this.parentNode.removeChild(this);
    };
    w.addEle = function(str, style){
        var ele = doc.createElementNS(xhtmlns, 'div');
        ele.setAttribute('style', style);
        if(str){
            ele.innerHTML = str;
            for(var el, all = ele.getElementsByTagName('*'), i = all.length; i--;){
                el = all[i];
                if(/^(script|frame|iframe|applet|embed|object)$/i.test(el.nodeName)){
                    el.parentNode.removeChild(el);
                }
                else{
                    for(var att = el.attributes, j = att.length; j--;){
                        if(/^on[a-z]+$/i.test(att[j].name))att[j].value = '';
                    }
                }
            }
        };
        return this.appendChild(ele);
    };
     w.addEle1 = function(str, style){
        var ele = doc.createElementNS(xhtmlns, 'textarea');
        ele.setAttribute('style', style);
        if(str){
            ele.innerHTML = str;
            for(var el, all = ele.getElementsByTagName('*'), i = all.length; i--;){
                el = all[i];
                if(/^(script|frame|iframe|applet|embed|object)$/i.test(el.nodeName)){
                    el.parentNode.removeChild(el);
                }else{
                    for(var att = el.attributes, j = att.length; j--;){
                        if(/^on[a-z]+$/i.test(att[j].name))att[j].value = '';
                    }
                }
            }
        };
        return this.appendChild(ele);
    };
    var img = doc.createElementNS(xhtmlns, 'div');
    img.setAttribute('style', 'display:block;float:right;width:16px;height:16px;padding:0;margin-top:2px;margin-right:1px;border:none;cursor:pointer;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACQUlEQVR4Xm2SPUhbURTHfzfNJ4nU0Axx7CJCN2kQtIgVCtq6OdQuBUftWIQqFNsKDo6iHTqIqN3a0kklUKTS2AZrcOjioFtRjFWUfH+803cS9GHwB4dzcu75/+8L9xgaSEDbLXhaASzAyXAMn5/DHxwwjeJgKLRxd3Q0atxuLhGgWqmQmp9PJ7LZJ5Ow3WhQFweDG20LC1FfRwc3kUsm+T48fPIzl3s8VTdxxLt+/2FhdlZkc1MkmdR8Pba2ajlrz3z1+9OvIOaIfb7DwsSEyNKSyM6OSLksEo/rbw2ttadntV7Gnv3k86VfqskvmDzv7hZ580Zkelrk4kJqFIsii4satVrRs+rYmBQHBuRvS4u8g/fuCmDOz+HgAIWpKRgfh3AYhoZQ8Hqxjo4o9PdT3d1FcQEl8KoBnJ7C/j6KZkZGYG4OIhEUFed7erD29q69jGrd1qVBqcQVKgwEuMSEQhjtXRk4JvW/kM1i2WGMga4uzMoKBIOIfbNiolEC6+uU+/qQRALFA1QBlwVYxmBcLmhuxqytQSgEKu7t1dBavwKvbeINh/Has2IMqnXpem4bky6qWLdvZgaOj2FwEHNyoqG19vRMZ8jZs1+NOfsNcZS3EFvzeNL51laRe/dEYrFadsLpZeyZDx7P6QN4Btwx1OE1xO4HAquP2tsjAZ+Pm8gWi3xMpc6W8/kXPyAO/DM4oOsZa2pafdjZGXF7PAgOpXKZL4nE2XImcyUGMDSg63kbhgvgtYCq8+akIL4J3y7Fyn+DokZOnLlMyQAAAABJRU5ErkJggg==");background:-o-skin("Caption Close Button Skin");');
    img.title = (win.navigator.language.indexOf('ru') == 0) ? '\u0417\u0430\u043A\u0440\u044B\u0442\u044C' : 'Close';
    img.addEventListener('click', function(){this.parentNode.closeWin()}, false);
    w.appendChild(img);
    var title = w.addEle(title, 'display:table;color:#000;font:17px Times New Roman;width:auto;height:auto;padding:0;margin:0 2px;cursor:text;');
        title.onclick = e => {
        e.preventDefault();
        var url = e.target.href;
        // Здесь открываем url как хотим.
        var ctabpos = gBrowser.selectedTab._tPos +1;
        gBrowser.moveTabTo(gBrowser.selectedTab = gBrowser.addWebTab(url), ctabpos);
        doc.getElementById(wId).closeWin();    
    }
    var cnt = w.addEle1(text, 'display:block;border:1px solid #aaa;padding-bottom:3px;padding-left:3px;background-color:#fafcfe;color:#000;font:16px Times New Roman;width:310px;height:160px;overflow:auto;cursor:text;-moz-user-focus:normal;-moz-user-select:text;');
    cnt.contentEditable="true";
    cnt.context="contentAreaContextMenu";
    w.addEle(status, 'display:table;font:12px Times New Roman;font-weight:bold;color:blue;width:auto;height:auto;padding-top:2px;margin:0 3px;cursor:pointer;');
    w.addEventListener('mousedown', function(e){
        if(e.target == w){
            e.preventDefault();
            var grabX = e.clientX, grabY = e.clientY, origX = parseInt(w.style.left), origY = parseInt(w.style.top);
            var mouseMove = function(ev){
                w.style.left = origX+ev.clientX-grabX+'px';
                w.style.top = origY+ev.clientY-grabY+'px';
            };
            doc.addEventListener('mousemove', mouseMove, false);
            doc.addEventListener('mouseup', function(){doc.removeEventListener('mousemove', mouseMove, false)}, false);
        }
    }, false);
    doc.documentElement.appendChild(w);
  
    if(size){
        cnt.style.height = size.height;
        cnt.style.width = size.width;
    }
    else{
        for(var i = 3; i < 10; i++){
            if(cnt.scrollHeight > cnt.offsetHeight || cnt.scrollWidth > cnt.offsetWidth){
                cnt.style.height = 80*i+'px';
                cnt.style.width = 160*i+'px';
            }
            else break;
        }
    };

    var docEle = (doc.compatMode == 'CSS1Compat' && win.postMessage) ? doc.documentElement : doc.body;
    var mX = docEle.clientWidth-w.offsetWidth, mY = docEle.clientHeight-w.offsetHeight;
    if(mX < 0){cnt.style.width = parseInt(cnt.style.width)+mX+'px'; mX = 0};
    if(mY < 0){cnt.style.height = parseInt(cnt.style.height)+mY+'px'; mY =0};
    var hW = parseInt(w.offsetWidth/2);
    w.style.left = (pos && pos.X < mX+hW ? (pos.X > hW ? pos.X-hW : 0) : mX)+'px';
    w.style.top = (pos && pos.Y+10 < mY ? pos.Y+10 : mY)+'px';
    w.style.visibility = 'visible';
    doc.addEventListener('keydown', keyDown, false);
    return w;
};

var getHash = function (txt) {
    TKK=eval('((function(){var a\x3d817046147;var b\x3d-335196159;return 410049+\x27.\x27+(a+b)})())');
    function sM(a) {
        var b;
        if (null !== yr)
            b = yr;
        else {
            b = wr(String.fromCharCode(84));
            var c = wr(String.fromCharCode(75));
            b = [b(), b()];
            b[1] = c();
            b = (yr = window[b.join(c())] || "") || ""
        }
        var d = wr(String.fromCharCode(116))
            , c = wr(String.fromCharCode(107))
            , d = [d(), d()];
        d[1] = c();
        c = "&" + d.join("") + "=";
        d = b.split(".");
        b = Number(d[0]) || 0;
        for (var e = [], f = 0, g = 0; g < a.length; g++) {
            var l = a.charCodeAt(g);
            128 > l ? e[f++] = l : (2048 > l ? e[f++] = l >> 6 | 192 : (55296 == (l & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (l = 65536 + ((l & 1023) << 10) + (a.charCodeAt(++g) & 1023),
                e[f++] = l >> 18 | 240,
                e[f++] = l >> 12 & 63 | 128) : e[f++] = l >> 12 | 224,
                e[f++] = l >> 6 & 63 | 128),
                e[f++] = l & 63 | 128)
        }
        a = b;
        for (f = 0; f < e.length; f++)
            a += e[f],
                a = xr(a, "+-a^+6");
        a = xr(a, "+-3^+b+-f");
        a ^= Number(d[1]) || 0;
        0 > a && (a = (a & 2147483647) + 2147483648);
        a %= 1E6;
        return c + (a.toString() + "." + (a ^ b))
    }

    var yr = null;
    var wr = function(a) {
        return function() {
            return a
        }
    }
        , xr = function(a, b) {
        for (var c = 0; c < b.length - 2; c += 3) {
            var d = b.charAt(c + 2)
                , d = "a" <= d ? d.charCodeAt(0) - 87 : Number(d)
                , d = "+" == b.charAt(c + 1) ? a >>> d : a << d;
            a = "+" == b.charAt(c) ? a + d & 4294967295 : a ^ d
        }
        return a
    }; 

    return sM(txt);
}; 
 
  
 
var ujs_google_translate = function (dir){
    var lng = window.navigator.language.slice(0, 2), txt = gContextMenu.selectionInfo.fullText , l = dir.split('|');
    var encTxt = encodeURIComponent(txt);
    var winWait = function(lng){createWindow('', (lng == 'ru' ? 'Подождите идет перевод' : 'Wait, is going Translating')+'\u2026', 'Google Translate', '_gt', window.navigator.lastClick)};
    if (txt) {
    winWait(lng);
        var xhr = new XMLHttpRequest();
        var url = 'https://translate.google.com/translate_a/single?client=gtx&sl=' + l[0] + '&tl=' + l[1] + '&hl=' + lng + '&eotf=0&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t' + getHash(txt);
        var urlt = "http://translate.google.com/translate_t?text="+encTxt+"&sl='  + langFrom_google_text + '&tl=' + langTo_google_text +'&hl=' + lng + '&eotf=0&ujs=gtt";
      
        xhr.open('POST', url, true);
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
        xhr.onreadystatechange = function() {
            try{
                if (xhr.readyState == 4 && xhr.status == 200) {
                   var result = '', status = '', tmp = JSON.parse(xhr.responseText.replace(/\[(?=,)/g, '[0').replace(/,(?=,|\])/g, ',0').replace(/\\n/g, "").replace(/\\r/g, ""));
                    for(var i = 0, n; n = tmp[0][i]; i++){
                        if(n[0])result += n[0].toString();
                    };
                    status = tmp[8][0][0].toUpperCase() + ' -\u203A ' + l[1].toUpperCase();
                     createWindow(result, status, '<a href="'+urlt.replace(/&/g,'&amp;')+'" target="_blank" style="display:inline;padding:0;margin:0;text-decoration:none;border:none;color:#009;font:16px Times New Roman;">Google Translate</a>', '_gt', window.navigator.lastClick);
                }
            } catch (x){LOG(x)};
        };
         xhr.send('q=' + encodeURIComponent(txt));
    } else {
        var urlt = gBrowser.currentURI.spec;  
        var url = "http://translate.google.com/translate?u="+encodeURIComponent(urlt)+"&hl="+lng+"&langpair="+dir+"&tbb=1";
        var ctabpos = gBrowser.selectedTab._tPos +1;
        gBrowser.moveTabTo(gBrowser.selectedTab = gBrowser.addWebTab(url), ctabpos);
    };
};

var contextMenu = document.getElementById("contentAreaContextMenu");
var nextEleMenu = document.getElementById("context-inspect");

var menuId = "context-ext-google-translate";
var menuItem = document.getElementById(menuId);
if (menuItem) {
    contextMenu.removeChild(menuItem.nextElementSibling);
    contextMenu.removeChild(menuItem.nextElementSibling);
    contextMenu.removeChild(menuItem);
};

menuItem = document.createXULElement("menuitem");
menuItem.setAttribute("id", menuId);
menuItem.setAttribute("label", "Перевести на русский");
menuItem.setAttribute("class", "menuitem-iconic");
menuItem.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABBUlEQVR4Ac2RMU4DMRREB2MqihQpAkUaqnAduuQw4Sx03CGcJYIiDYqQ0lCsZ77535ZFcgAkRuPvV7zd/dLiz3N1PFb8hmRckrfELZrF9ONQ1B6Yz0MyM7S0O6zGkVprh/3+Kw/JzkHSpRpJKZkpr9fYbOx0cjVsCbWG31oHBM9mtt0q73ZcrdLhAMlYQKkUI22aqsNo8HKZAMQhvVaKSHWj2Q2aPU3mJQFY7nuHyvYFduP83WF3AJRfcPNYnr/Lp1G1uK4m9sno1LaUbnX/htf8BNzoneUD5NhjvLCMhURQSQ93QCZwXYjFwg3I0NZKrvoknQPMIHkt/jRAQKMeG2yX89/mB4EJbKbZxIhFAAAAAElFTkSuQmCC");
menuItem.addEventListener("command", function(){ujs_google_translate('auto|ru')}, false);
contextMenu.insertBefore(menuItem, nextEleMenu);

menuItem = document.createXULElement("menuitem");
menuItem.setAttribute("label", "Перевести на английский");
menuItem.setAttribute("class", "menuitem-iconic");
menuItem.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAAB5UlEQVR4AWOgPZg0c9+Oq2+qpx9LaQaiw4mNB27efbs2uXFNQh2Q4Zm9zSNth23MhqjGnXMC86vnHmUS4udxv7OvOd2yPE7PTlfCTk9GVVEoyJA7WI8dyPA0k3U1l+jJMV7CeThpTZeoKDdDUsvBPSff/V+6/P/Bvf///2+bdvU/EKRm/k9IBNIlfZe+LFrzvbsbyJ636pKkyQyQhoUb7tZNvPpw3/0/TfX/ISAm5n94BIiRm/n/xYsLd946ei4vajoiqDuRAejQf//+o4PQ0P9+fmhiQGVnrr1kXJNYG2zEzXDxDsPv3wy/fkFJoOTPn39+/fr/69e/37//AUX+/mXRkO458wWHDba2f8wswCyQ3N+/f//8/fP7z5+TV18w2Mdt6plzPiptx5Wr7/+/ffMzOR6kysjkt74hWMPfp06O+2dulZCeFZKwnkE4m8E8bN3i9aCQ+dxY96GrK6bkGJD9R1v3l6Y20NVW9kt+/v//ZdbcFwkxTVPPMQimM8XEqkb7a/zoqLxkH9v4zVyI5+///wyMmtKMmhJAnbLqQjHxaw5r2orOmZN5uj470Zahat6BKS7JzpmLBHXm8GhM5lCdcP7ai1ZpixZxk9NXXjKIFzOIFjAI54oY1vXuue5qmscw+AAAW0tKxtPoicEAAAAASUVORK5CYII=");
menuItem.addEventListener("command", function(){ujs_google_translate('auto|en')}, false);
contextMenu.insertBefore(menuItem, nextEleMenu);

contextMenu.insertBefore(document.createXULElement("menuseparator"), nextEleMenu);

Отсутствует

 

№1415326-01-2020 09:51:53

shadow_user
Участник
 
Группа: Members
Зарегистрирован: 14-02-2007
Сообщений: 244
UA: Firefox 68.0

Re: Custom Buttons

Andrey_Krropotkin пишет

для сплошного теста в окне перевода пробуйте

Спасибо, работает. После правки t->gtx качество перевода улучшилось, стало 1:1 с Simple Translate.

Отсутствует

 

№1415426-01-2020 13:36:10

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

Re: Custom Buttons

solombala пишет

Дай код полностью! И проверим..

Скопировать из первоисточника сюда?
Как-то ... . Но, если поможет

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

Выделить код

Код:

// http://infocatcher.ucoz.net/js/cb/undoCloseTabs.js
// https://forum.mozilla-russia.org/viewtopic.php?id=56267
// https://github.com/Infocatcher/Custom_Buttons/tree/master/Undo_Close_Tabs

// Undo Close Tabs button for Custom Buttons
// (code for "initialization" section)

// (c) Infocatcher 2009-2015, 2017-2018
// version 0.3.3.1 - 2018-08-01

var options = {
    menuTemplate: [
        "closedWindows",
        "separator",
        "restoreClosedWindows",
        "clearClosedWindows",
        "separator",
        "closedTabs",
        "separator",
        "restoreClosedTabs",
        "clearClosedTabs",
        "separator",
        "clearAll",
        "separator",
        "restoreLastSession",
        "separator",
        "buttonMenu"
    ],
    showInTabContextMenu: false,
    /*
    menuTemplateTabContext: [ // like menuTemplate
        "closedTabs",
        "separator",
        "restoreClosedTabs",
        "clearClosedTabs"
    ],
    */
    windowItemTemplate: "(%count) %title",
    windowSelectedTabPrefix: "*",
    buttonTipTemplate: ["header", "title", "url", "closedAt"],
    itemTipTemplate: ["title", "url", "closedAt"],
    hideRestoreAllForSingleEntry: false,
    allowDeleteEntries: true,
    accesskeys: { // Empty string ("") to disable or string with possible values ("0123...", "abcd...")
        closedTabs: "",
        closedWindows: ""
    },
    accesskeyPostfix: " ", // <accesskey><postfix><label>
    openMenuOnMouseover: false,
    useMenu: false,
    rightClickToUndoCloseTab: false // Useful with "useMenu: true"
};

function _localize(sid) {
    var strings = {
        en: {
            restoreTab: "Restore the most recently closed tab",

            restoreAllTabs: "Restore all tabs",
            restoreAllTabsAccesskey: "t",
            clearTabsHistory: "Clear history of closed tabs",
            clearTabsHistoryAccesskey: "b",

            restoreAllWindows: "Restore all windows",
            restoreAllWindowsAccesskey: "w",
            clearWindowsHistory: "Clear history of closed windows",
            clearWindowsHistoryAccesskey: "d",

            clearAllHistory: "Clear all history",
            clearAllHistoryAccesskey: "C",

            restoreLastSession: "Restore last session",
            restoreLastSessionAccesskey: "s",

            deleteUndoEntry: "Delete",

            buttonMenu: "Button menu",
            buttonMenuAccesskey: "m",

            tabContextMenu: "Recently Closed Tabs",
            tabContextMenuAccesskey: "y",

            itemTip: "%ago ago, %date",
            day: "d"
        },
        ru: {
            restoreTab: "Восстановить последнюю закрытую вкладку",

            restoreAllTabs: "Восстановить все вкладки",
            restoreAllTabsAccesskey: "л",
            clearTabsHistory: "Очистить историю закрытых вкладок",
            clearTabsHistoryAccesskey: "д",

            restoreAllWindows: "Восстановить все окна",
            restoreAllWindowsAccesskey: "о",
            clearWindowsHistory: "Очистить историю закрытых окон",
            clearWindowsHistoryAccesskey: "н",

            clearAllHistory: "Очистить всю историю",
            clearAllHistoryAccesskey: "ч",

            restoreLastSession: "Восстановить последнюю сессию",
            restoreLastSessionAccesskey: "с",

            deleteUndoEntry: "Удалить",

            buttonMenu: "Меню кнопки",
            buttonMenuAccesskey: "М",

            tabContextMenu: "Недавно закрытые вкладки",
            tabContextMenuAccesskey: "о",

            itemTip: "%ago назад, %date",
            day: "д"
        }
    };
    var locale = (function() {
        if("Services" in window && "locale" in Services) {
            var locales = Services.locale.requestedLocales // Firefox 64+
                || Services.locale.getRequestedLocales && Services.locale.getRequestedLocales();
            if(locales)
                return locales[0];
        }
        var prefs = "Services" in window && Services.prefs
            || Components.classes["@mozilla.org/preferences-service;1"]
                .getService(Components.interfaces.nsIPrefBranch);
        function pref(name, type) {
            return prefs.getPrefType(name) != prefs.PREF_INVALID ? prefs["get" + type + "Pref"](name) : undefined;
        }
        if(!pref("intl.locale.matchOS", "Bool")) { // Also see https://bugzilla.mozilla.org/show_bug.cgi?id=1414390
            var locale = pref("general.useragent.locale", "Char");
            if(locale && locale.substr(0, 9) != "chrome://")
                return locale;
        }
        return Components.classes["@mozilla.org/chrome/chrome-registry;1"]
            .getService(Components.interfaces.nsIXULChromeRegistry)
            .getSelectedLocale("global");
    })().match(/^[a-z]*/)[0];
    _localize = function(sid) {
        return strings[locale] && strings[locale][sid] || strings.en[sid] || sid;
    };
    return _localize.apply(this, arguments);
}

var JSON = "JSON" in window
    ? window.JSON
    : "nsIJSON" in Components.interfaces
        ? {
            parse: function(s) {
                return Components.classes["@mozilla.org/dom/json;1"]
                    .createInstance(Components.interfaces.nsIJSON)
                    .decode(s);
            }
        }
        : {
            parse: function(s) {
                return Components.utils.evalInSandbox("(" + s + ")", new Components.utils.Sandbox("about:blank"));
            }
        };

this.onclick = function(e) {
    if(e.target != this)
        return;
    if(e.button == 1 || e.button == 0 && (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey))
        this.undoCloseTabsList.clearAllLists();
    else if(
        e.button == 0
        || e.button == 2 && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey
            && this.undoCloseTabsList.options.rightClickToUndoCloseTab
    ) {
        if(
            e.button == 0 && !this.undoCloseTabsList.options.useMenu
            || e.button == 2 && this.undoCloseTabsList.options.rightClickToUndoCloseTab
        ) {
            if(this.undoCloseTabsList.closedTabCount)
                this.undoCloseTabsList.undoCloseTab();
            else
                this.undoCloseTabsList.drawUndoList() && this.undoCloseTabsList.showMenu(e);
        }
        // Allow use "command" section only from hotkey:
        e.preventDefault();
        e.stopPropagation();
    }
};
if(!this.hasOwnProperty("defaultContextId"))
    this.defaultContextId = this.getAttribute("context") || "custombuttons-contextpopup";
this.onmousedown = function(e) {
    if(e.target != this)
        return;
    if(this.undoCloseTabsList.options.useMenu) {
        if(e.button == 0)
            this.undoCloseTabsList.drawUndoList();
    }
    else if(e.button == 2) {
        var showCbMenu = e.ctrlKey || e.shiftKey || e.altKey || e.metaKey || !this.undoCloseTabsList.drawUndoList();
        this.setAttribute(
            "context",
            showCbMenu
                ? this.defaultContextId
                : this.undoCloseTabsList.mpId
        );
    }
};
this.onmouseover = function(e) {
    if(e.target != this)
        return;
    if(!this.disabled)
        this.undoCloseTabsList.updUI();
    this.undoCloseTabsList.options.useMenu && Array.prototype.some.call(
        this.parentNode.getElementsByTagName("*"),
        function(node) {
            if(
                node != this
                && node.namespaceURI == xulns
                // See https://github.com/Infocatcher/Custom_Buttons/issues/28
                //&& node.boxObject
                //&& node.boxObject instanceof Components.interfaces.nsIMenuBoxObject
                && "open" in node
                && node.open
                && node.getElementsByTagName("menupopup").length
                && this.undoCloseTabsList.drawUndoList()
            ) {
                node.open = false;
                this.open = true;
                return true;
            }
            return false;
        },
        this
    );
    if(
        this.undoCloseTabsList.options.openMenuOnMouseover
        && this.undoCloseTabsList.drawUndoList()
    )
        this.undoCloseTabsList.openMenu();
};

this.undoCloseTabsList = {
    button: this,
    options: options,
    mpId: this.id + "-context",
    cmId: this.id + "-contextSub",
    tcmId: this.id + "-tabContextMenu",
    tipId: this.id + "-tooltip",
    errPrefix: "[Custom Buttons :: Undo Close Tabs List]: ",
    get mp() {
        var btn = this.button;
        var mp = btn.getElementsByTagName("menupopup");
        mp = mp.length && mp[0];
        mp && mp.parentNode.removeChild(mp);
        mp = this.createElement("menupopup", {
            id: this.mpId,
            onclick: "this.parentNode.undoCloseTabsList.checkForMiddleClick(event);",
            onpopupshowing: "if(event.target == this) document.popupNode = this.parentNode;",
            onpopuphidden: "if(event.target == this) document.popupNode = null;"
        });
        if(this.cm)
            mp.setAttribute("context", this.cmId);
        var tb = btn.parentNode;
        if(
            this.options.useMenu
            && tb.getAttribute("orient") == "vertical"
        ) {
            // https://addons.mozilla.org/firefox/addon/vertical-toolbar/
            var isRight = tb.parentNode.getAttribute("placement") == "right";
            mp.setAttribute("position", isRight ? "start_before" : "end_before");
        }
        delete this.mp;
        return this.mp = btn.appendChild(mp);
    },
    get useCentextMenu() {
        delete this.useCentextMenu;
        return this.useCentextMenu = this.options.allowDeleteEntries
            && ("forgetClosedTab" in this.ss || "forgetClosedWindow" in this.ss);
    },
    get cm() {
        delete this.cm;
        if(!this.useCentextMenu)
            return this.cm = null;
        var cm = document.getElementById(this.cmId);
        cm && cm.parentNode.removeChild(cm);
        cm = this.createElement("menupopup", {
            id: this.cmId,
            onpopupshowing: "return this.undoCloseTabsList.canDeleteUndoEntry(this.triggerNode || document.popupNode);"
        });
        var mi = this.createElement("menuitem", {
            oncommand: "this.parentNode.undoCloseTabsList.deleteUndoEntry(this.parentNode.triggerNode || document.popupNode);",
            label: _localize("deleteUndoEntry"),
            closemenu: "single"
        });
        cm.appendChild(mi);
        cm.undoCloseTabsList = this;
        return this.cm = document.getElementById("mainPopupSet").appendChild(cm);
    },
    get cbMenu() {
        var cbPopup = document.getElementById(this.button.defaultContextId);
        if(!cbPopup) {
            Components.utils.reportError(this.errPrefix + "cb menu not found");
            return this.cbMenu = null;
        }
        cbPopup = cbPopup.cloneNode(true);
        var id = "-" + this.button.id.match(/\d*$/)[0] + "-cloned";
        cbPopup.id += id;
        Array.prototype.slice.call(cbPopup.getElementsByAttribute("id", "*")).forEach(function(node) {
            node.id += id;
        });
        var menu = this.createElement("menu", {
            label: _localize("buttonMenu"),
            accesskey: _localize("buttonMenuAccesskey")
        });
        menu.appendChild(cbPopup);
        cbPopup.setAttribute(
            "onpopupshowing",
            '\
            var btn = document.popupNode = this.parentNode.parentNode.parentNode\n\
                .undoCloseTabsList.button;\n\
            custombutton.setContextMenuVisibility(btn);'
        );
        delete this.cbMenu;
        return this.cbMenu = menu;
    },
    get ss() {
        delete this.ss;
        return this.ss = "nsISessionStore" in Components.interfaces
            ? (
                Components.classes["@mozilla.org/browser/sessionstore;1"]
                || Components.classes["@mozilla.org/suite/sessionstore;1"]
            ).getService(Components.interfaces.nsISessionStore)
            : SessionStore; // Firefox 61+ https://bugzilla.mozilla.org/show_bug.cgi?id=1450559
    },
    get appInfo() {
        delete this.appInfo;
        return this.appInfo = Components.classes["@mozilla.org/xre/app-info;1"]
            .getService(Components.interfaces.nsIXULAppInfo);
    },
    get appVersion() {
        delete this.appVersion;
        return this.appVersion = parseFloat(this.appInfo.version);
    },
    get appName() {
        delete this.appName;
        return this.appName = this.appInfo.name;
    },

    init: function() {
        window.addEventListener("TabClose",       this, false);
        window.addEventListener("SSTabRestoring", this, false);
        window.addEventListener("unload",         this, false);
        if(this.appName == "SeaMonkey") // No SSTab* events in SeaMonkey
            window.addEventListener("TabOpen", this, false);
        setTimeout(function(_this) {
            _this.mp.addEventListener("DOMMenuItemActive",   _this, false);
            _this.mp.addEventListener("DOMMenuItemInactive", _this, false);
            _this.initTooltip();
        }, 50, this);
        this.addPbExitObserver(true);
        this.updUIGlobal();
        if(this.options.showInTabContextMenu) setTimeout(function(_this) {
            _this.initTabContext();
        }, 100, this);
    },
    initTabContext: function() {
        var origMi = this.tabContextUndoClose;
        if(!origMi) {
            LOG("Can't find \"Undo Close Tab\" item in tab context menu");
            return;
        }
        var menu = document.getElementById(this.tcmId);
        menu && menu.parentNode.removeChild(menu); // For SeaMonkey
        menu = this.createElement("menu", {
            id: this.tcmId,
            label: _localize("tabContextMenu"),
            accesskey: _localize("tabContextMenuAccesskey"),
            tooltip: this.tipId,
            popupsinherittooltip: "true"
        });
        menu.undoCloseTabsList = this;
        menu.onclick = function(e) {
            if(e.target != this)
                return;
            if(e.button == 1 || e.button == 0 && (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey)) {
                if(this.undoCloseTabsList.closedTabCount) {
                    this.undoCloseTabsList.undoCloseTab();
                    closeMenus(this);
                }
            }
        };
        var origMp = this.mp;
        var mp = origMp.cloneNode(true);
        mp.id = this.button.id + "-tabContext";
        var _this = this;
        function drawUndoList() {
            var ok = false;
            var opts = _this.options;
            var origTemplate = opts.menuTemplate;
            opts.menuTemplate = opts.menuTemplateTabContext || origTemplate;
            _this.mp = mp;
            try {
                ok = _this.drawUndoList();
            }
            catch(e) {
                Components.utils.reportError(e);
            }
            opts.menuTemplate = origTemplate;
            _this.mp = origMp;
            return ok;
        }
        function updMenu() {
            if(drawUndoList())
                menu.removeAttribute("disabled");
            else
                menu.setAttribute("disabled", "true");
        }
        mp._updatePopup = function(e) {
            if(e.target != this)
                return;
            document.popupNode = _this.button;
            drawUndoList();
        };
        mp.setAttribute("onpopupshowing", "this._updatePopup(event);");
        mp.onclick = function(e) {
            _this.checkForMiddleClick(e, updMenu);
        };
        menu.appendChild(mp);
        addEventListener("popupshown", function(e) {
            if(e.target == e.currentTarget)
                setTimeout(updMenu, 0); // Pseudo async
        }, false, origMi.parentNode);
        addEventListener("DOMMenuItemActive",   this, false, mp);
        addEventListener("DOMMenuItemInactive", this, false, mp);
        origMi.parentNode.insertBefore(menu, origMi.nextSibling);
        origMi.setAttribute("hidden", "true");
    },
    initTooltip: function() {
        var tip = document.getElementById(this.tipId);
        tip && tip.parentNode.removeChild(tip);
        tip = this.tip = this.createElement("tooltip", {
            id: this.tipId,
            orient: "vertical",
            onpopupshowing: "return this.undoCloseTabsList.updTooltip(this, document.tooltipNode);",
            onpopuphiding: "this.cancelUpdateTimer();",
            style: "padding: 0;"
        });
        tip.undoCloseTabsList = this;
        tip._updateTimer = 0;
        tip.initUpdateTimer = function(fn, context) {
            if(this._updateTimer)
                clearInterval(this._updateTimer);
            this._updateTimer = setInterval(function() {
                fn.call(context);
            }, 1000);
        };
        tip.cancelUpdateTimer = function() {
            if(this._updateTimer) {
                clearInterval(this._updateTimer);
                this._updateTimer = 0;
            }
        };
        var btn = this.button;
        btn.removeAttribute("tooltiptext");
        btn.setAttribute("tooltip", this.tipId);
        btn.setAttribute("popupsinherittooltip", "true");
        document.getElementById("mainPopupSet").appendChild(tip);
        if(this.appVersion >= 61 && "getAnonymousElementByAttribute" in document) {
            var label = document.getAnonymousElementByAttribute(tip, "class", "tooltip-label");
            label && label.remove();
        }
    },
    _hasPbExitObserver: false,
    addPbExitObserver: function(add) {
        if(add == this._hasPbExitObserver || !("Services" in window))
            return;
        this._hasPbExitObserver = add;
        if(add)
            Services.obs.addObserver(this, "last-pb-context-exited", false);
        else
            Services.obs.removeObserver(this, "last-pb-context-exited");
    },
    destroy: function() {
        window.removeEventListener("TabClose",       this, false);
        window.removeEventListener("SSTabRestoring", this, false);
        window.removeEventListener("unload",         this, false);
        if(this.appName == "SeaMonkey")
            window.removeEventListener("TabOpen", this, false);
        this.mp.removeEventListener("DOMMenuItemActive",   this, false);
        this.mp.removeEventListener("DOMMenuItemInactive", this, false);
        this.addPbExitObserver(false);
        var menu = document.getElementById(this.tcmId);
        if(menu) {
            menu.parentNode.removeChild(menu);
            this.tabContextUndoClose.removeAttribute("hidden");
        }
        var tip = this.tip;
        tip && tip.parentNode && tip.parentNode.removeChild(tip);
    },
    handleEvent: function(e) {
        switch(e.type) {
            case "TabClose":
            case "SSTabRestoring":
            case "TabOpen":
                setTimeout(function(_this) {
                    _this.updUI();
                }, 0, this);
            break;
            case "DOMMenuItemActive":
            case "DOMMenuItemInactive":
                if(!("XULBrowserWindow" in window))
                    break;
                XULBrowserWindow.setOverLink(
                    e.type == "DOMMenuItemActive"
                        ? (e.target.getAttribute("cb_urlDecoded") || "")
                            .replace(/ \n/g, ", ")
                        : "",
                    null
                );
            break;
            case "unload":
                this.updUIGlobal();
                this.destroy();
        }
    },
    observe: function(subject, topic, data) {
        if(topic == "last-pb-context-exited") {
            setTimeout(function(_this) {
                _this.updUI();
            }, 25, this);
        }
    },

    createElement: function(name, attrs) {
        var node = document.createElementNS(xulns, name);
        if(attrs) for(var attrName in attrs) if(attrs.hasOwnProperty(attrName))
            node.setAttribute(attrName, attrs[attrName]);
        return node;
    },
    get tabContextUndoClose() {
        return document.getElementById("context_undoCloseTab")
            || document.getElementById("tabContextUndoCloseTab") // Firefox 2.0
            || document.getAnonymousElementByAttribute(gBrowser, "tbattr", "tabbrowser-undoclosetab"); // SeaMonkey
    },
    get closedWindowCount() {
        if(!("getClosedWindowCount" in this.ss)) {
            delete this.closedWindowCount;
            return this.closedWindowCount = 0;
        }
        this.__defineGetter__("closedWindowCount", function() {
            return this.ss.getClosedWindowCount();
        });
        return this.closedWindowCount;
    },
    get closedTabCount() {
        return this.ss.getClosedTabCount(window);
    },
    undoCloseTab: function(i) {
        if("undoCloseTab" in window) // Firefox 2.0+
            undoCloseTab(i);
        else // SeaMonkey
            gBrowser.undoCloseTab(i);
    },
    clearUndoTabsList: function() {
        var closedTabCount = this.closedTabCount;
        if(!closedTabCount)
            return;
        if("forgetClosedTab" in this.ss) // Gecko 1.9.2+
            while(closedTabCount--)
                this.ss.forgetClosedTab(window, 0);
        else {
            // Doesn't work in SeaMonkey
            const pName = "browser.sessionstore.max_tabs_undo";
            let val = cbu.getPrefs(pName);
            cbu.setPrefs(pName, 0);
            cbu.setPrefs(pName, val);
        }
        this.updUIGlobal();
    },
    clearUndoWindowsList: function() {
        var closedWindowCount = this.closedWindowCount;
        if(!closedWindowCount)
            return;
        if("forgetClosedWindow" in this.ss) // Gecko 1.9.2+
            while(closedWindowCount--)
                this.ss.forgetClosedWindow(0);
        else
            this.ss.setWindowState(window, '{"windows":[{}],"_closedWindows":[]}', false);
        this.updUIGlobal();
    },
    clearAllLists: function() {
        this.clearUndoTabsList();
        this.clearUndoWindowsList();
    },
    canDeleteUndoEntry: function(mi) {
        switch(mi.getAttribute("cb_type")) {
            case "tab":    return "forgetClosedTab"    in this.ss;
            case "window": return "forgetClosedWindow" in this.ss;
        }
        return false;
    },
    deleteUndoEntry: function(mi) {
        var i = +mi.getAttribute("cb_index");
        if(mi.getAttribute("cb_type") == "window") {
            this.ss.forgetClosedWindow(i);
            this.updUIGlobal();
        }
        else {
            this.ss.forgetClosedTab(window, i);
            this.updUI();
        }
        this.drawUndoList();
    },
    showMenu: function(e, isContext, mp) {
        var btn = this.button;
        document.popupNode = btn.ownerDocument.popupNode = btn;
        if(!mp)
            mp = this.mp;
        if("openPopupAtScreen" in mp)
            mp.openPopupAtScreen(e.screenX, e.screenY, isContext);
        else
            mp.showPopup(btn, e.screenX, e.screenY, isContext ? "context" : "popup", null, null);
    },
    openMenu: function() {
        var mp = this.mp;
        if("openPopup" in mp)
            mp.openPopup(this.button, "after_start");
        else
            mp.showPopup(this.button, -1, -1, "popup", "bottomleft", "topleft");
    },
    drawUndoList: function() {
        var mp = this.mp;

        var wc = this.closedWindowCount;
        var tc = this.closedTabCount;
        var ss = this.ss;
        var canRestoreLastSession = "restoreLastSession" in ss && ss.canRestoreLastSession
        if(!wc && !tc && !canRestoreLastSession) {
            mp.textContent = "";
            mp.hidePopup();
            return false;
        }

        this._undoWindowItems = wc && JSON.parse(ss.getClosedWindowData());
        this._undoTabItems    = tc && JSON.parse(ss.getClosedTabData(window));
        var df = document.createDocumentFragment();

        this.options.menuTemplate.forEach(function(sid, indx, arr) {
            switch(sid) {
                case "closedWindows":
                    wc && this.addUndoWindowsList(df);
                break;
                case "restoreClosedWindows":
                    wc > this.options.hideRestoreAllForSingleEntry
                    && df.appendChild(this.createElement("menuitem", {
                        label: _localize("restoreAllWindows"),
                        accesskey: _localize("restoreAllWindowsAccesskey"),
                        oncommand: "for(var i = 0; i < " + this._undoWindowItems.length + "; ++i) undoCloseWindow();"
                    }));
                break;
                case "clearClosedWindows":
                    wc && df.appendChild(this.createElement("menuitem", {
                        label: _localize("clearWindowsHistory"),
                        accesskey: _localize("clearWindowsHistoryAccesskey"),
                        oncommand: "this.parentNode.parentNode.undoCloseTabsList.clearUndoWindowsList();"
                    }));
                break;
                case "closedTabs":
                    tc && this.addUndoTabsList(df);
                break;
                case "restoreClosedTabs":
                    tc > this.options.hideRestoreAllForSingleEntry
                    && df.appendChild(this.createElement("menuitem", {
                        label: _localize("restoreAllTabs"),
                        accesskey: _localize("restoreAllTabsAccesskey"),
                        oncommand: "for(var i = 0; i < " + this._undoTabItems.length + "; ++i) this.parentNode.parentNode.undoCloseTabsList.undoCloseTab();"
                    }));
                break;
                case "clearClosedTabs":
                    tc && df.appendChild(this.createElement("menuitem", {
                        label: _localize("clearTabsHistory"),
                        accesskey: _localize("clearTabsHistoryAccesskey"),
                        oncommand: "this.parentNode.parentNode.undoCloseTabsList.clearUndoTabsList();"
                    }));
                break;
                case "clearAll":
                    (
                        wc && tc
                        || wc && arr.indexOf("clearClosedWindows") == -1
                        || tc && arr.indexOf("clearClosedTabs") == -1
                    )
                    && df.appendChild(this.createElement("menuitem", {
                        label: _localize("clearAllHistory"),
                        accesskey: _localize("clearAllHistoryAccesskey"),
                        oncommand: "this.parentNode.parentNode.undoCloseTabsList.clearAllLists();"
                    }));
                break;
                case "restoreLastSession": // Gecko 2.0+
                    canRestoreLastSession && df.appendChild(this.createElement("menuitem", {
                        label: _localize("restoreLastSession"),
                        accesskey: _localize("restoreLastSessionAccesskey"),
                        oncommand: "this.parentNode.parentNode.undoCloseTabsList.ss.restoreLastSession();"
                    }));
                break;
                case "buttonMenu":
                    let cbMenu = this.cbMenu;
                    if(cbMenu)
                        df.appendChild(cbMenu);
                break;
                case "separator":
                    if(df.hasChildNodes() && df.lastChild.localName != "menuseparator")
                        df.appendChild(document.createElementNS(xulns, "menuseparator"));
                break;
                default:
                    Components.utils.reportError(this.errPrefix + 'Invalid template entry: "' + sid + '"');
            }
        }, this);

        while(df.hasChildNodes() && df.lastChild.localName == "menuseparator")
            df.removeChild(df.lastChild);

        this._undoWindowItems = this._undoTabItems = null;

        mp.textContent = "";
        if(!df.hasChildNodes()) {
            mp.hidePopup();
            return false;
        }
        mp.appendChild(df);
        return true;
    },
    addUndoWindowsList: function(undoPopup) {
        // Based on code from chrome://browser/content/browser.js
        // Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.3a1pre) Gecko/20090824 Minefield/3.7a1pre

        var keys = this.options.accesskeys.closedWindows;
        this._undoWindowItems.forEach(function(undoItem, i) {
            var tabs = undoItem.tabs;
            var [key, keyPrefix] = this.getKey(keys, i);
            var title = undoItem.title;
            var selectedTab = tabs[undoItem.selected - 1];
            var urls = [];
            tabs.forEach(function(tab) {
                if(!tab.entries || !tab.entries.length) // Can be [] for about:blank
                    return;
                var url = this.convertURI(tab.entries[tab.index - 1].url, 120);
                var selectedPrefix = tab == selectedTab && tabs.length > 1
                    ? this.options.windowSelectedTabPrefix
                    : "";
                urls.push(selectedPrefix + url);
            }, this);
            var url = urls.join(" \n");
            var mi = this.createElement("menuitem", {
                label: keyPrefix + this.options.windowItemTemplate
                    .replace("%title", title)
                    .replace("%count", tabs.length),
                accesskey: key,
                "class": "menuitem-iconic bookmark-item menuitem-with-favicon",
                oncommand: "undoCloseWindow(" + i + ");",
                cb_url: url,
                cb_urlDecoded: this.convertURI(url),
                cb_closedAt: undoItem.closedAt || 0,
                cb_index: i,
                cb_type: "window"
            });
            if(this.cm)
                mi.setAttribute("context", this.cmId);
            var icon = selectedTab.image || selectedTab.attributes && selectedTab.attributes.image;
            if(icon)
                mi.setAttribute("image", this.cachedIcon(icon));
            if(i == 0)
                mi.setAttribute("key", "key_undoCloseWindow");
            undoPopup.appendChild(mi);
        }, this);
    },
    addUndoTabsList: function(undoPopup) {
        // Based on code from chrome://browser/content/browser.js
        // Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.3a1pre) Gecko/20090824 Minefield/3.7a1pre

        var keys = this.options.accesskeys.closedTabs;
        this._undoTabItems.forEach(function(undoItem, i) {
            var state = undoItem.state;
            var [key, keyPrefix] = this.getKey(keys, i);
            var title = undoItem.title;
            var url = state && state.entries && state.entries[state.index - 1].url || "";
            var mi = this.createElement("menuitem", {
                label: keyPrefix + title,
                accesskey: key,
                class: "menuitem-iconic bookmark-item menuitem-with-favicon",
                oncommand: "this.parentNode.parentNode.undoCloseTabsList.undoCloseTab(" + i + ");",
                cb_url: url,
                cb_urlDecoded: this.convertURI(url),
                cb_closedAt: undoItem.closedAt || 0,
                cb_index: i,
                cb_type: "tab"
            });
            if(
                state
                && "attributes" in state
                && "privateTab-isPrivate" in state.attributes
            ) // https://addons.mozilla.org/addon/private-tab/
                mi.setAttribute("privateTab-isPrivate", "true");
            if(this.cm)
                mi.setAttribute("context", this.cmId);
            var image = undoItem.image // Firefox
                || state && state.attributes && state.attributes.image // SeaMonkey
                || state && state.xultab
                    && /(?:^| )image=(\S+)/.test(state.xultab)
                    && decodeURI(RegExp.$1); // Only Firefox 2.0 ?
            if(image)
                mi.setAttribute("image", this.cachedIcon(image));
            if(i == 0)
                mi.setAttribute("key", "key_undoCloseTab");
            undoPopup.appendChild(mi);
        }, this);
    },
    getKey: function(keys, i) {
        var key = keys && keys.charAt(i % keys.length);
        var keyPrefix = keys && (key + this.options.accesskeyPostfix);
        return [key, keyPrefix];
    },
    checkForMiddleClick: function(e, upd) {
        var mi = e.target;
        if(
            "doCommand" in mi
            && e.button == 1
            && mi.parentNode == e.currentTarget
        ) {
            mi.doCommand();
            if(upd)
                upd();
            else
                this.drawUndoList();
        }
    },
    crop: function(s, crop) {
        if(crop == undefined)
            crop = 500;
        if(s.length <= crop)
            return s;
        var start = Math.round(crop*0.6);
        return s.substr(0, start) + "…" + s.substr(start - crop);
    },
    convertURI: function(uri, crop) {
        if(!uri || uri.indexOf("\n") != -1)
            return uri;
        try {
            uri = "losslessDecodeURI" in window
                ? losslessDecodeURI(makeURI(uri))
                : decodeURI(uri);
        }
        catch(e) {
            Components.utils.reportError(e);
        }
        return this.crop(uri, crop);
    },
    cachedIcon: function(src) {
        src = src.replace(/[&#]-moz-resolution=\d+,\d+$/, ""); // Firefox 22+
        if(
            !/^https?:/.test(src)
            // IDN, see https://bugzilla.mozilla.org/show_bug.cgi?id=311045
            || /^https?:\/\/[^.:\/]+\.[^a-z0-9-]+(?:\/|$)/.test(src)
            || this.appName == "SeaMonkey" && this.appVersion <= 2
            || this.appName == "Firefox"   && this.appVersion <= 3.5
        )
            return src;
        return "moz-anno:favicon:" + src; // https://bugzilla.mozilla.org/show_bug.cgi?id=467828
    },
    updUI: function() {
        var tabsCount = this.closedTabCount;
        var dis = !tabsCount && !this.closedWindowCount;
        if(
            dis
            && this.options.useMenu
            && this.options.menuTemplate.indexOf("restoreLastSession") != -1
            && "restoreLastSession" in this.ss && this.ss.canRestoreLastSession
        )
            dis = false;
        this.button.disabled = dis;
    },
    updTooltip: function(tip, tn) {
        var template, header, title, url, closedAt;
        if(tn == this.button) {
            template = this.options.buttonTipTemplate;
            header = _localize("restoreTab");
            let undoTabItems = JSON.parse(this.ss.getClosedTabData(window));
            if(undoTabItems.length) {
                let lastItem = undoTabItems[0];
                title = lastItem.title;
                url = lastItem.state && lastItem.state.entries
                    && lastItem.state.entries[lastItem.state.index - 1].url;
                closedAt = lastItem.closedAt || 0;
            }
        }
        else if(tn.hasAttribute("cb_index")) {
            template = this.options.itemTipTemplate;
            title = tn.getAttribute("label");
            url = tn.getAttribute("cb_url");
            closedAt = +tn.getAttribute("cb_closedAt");
        }
        else {
            return false;
        }

        var tipData = this.getTooltipData(template, header, title, url, closedAt);
        tip.textContent = "";
        tip.appendChild(tipData);
        if(closedAt && template.indexOf("closedAt") != -1) {
            tip.initUpdateTimer(function() {
                var tipData = this.getTooltipData(template, header, title, url, closedAt);
                if(tipData.textContent != tip.textContent) {
                    tip.textContent = "";
                    tip.appendChild(tipData);
                }
            }, this);
        }
        return tip.hasChildNodes();
    },
    getTooltipData: function(template, header, title, url, closedAt) {
        var df = document.createDocumentFragment();
        var hasHeader = header && template.indexOf("header") != -1;
        function item(key, val) {
            var lbl = document.createElementNS(xulns, "label");
            lbl.className = "cb-" + key;
            //lbl.setAttribute("value", val);
            lbl.textContent = val;
            lbl.setAttribute("maxwidth", "450"); // Trick to restore right border for long lines
            if(key == "closedAt" || hasHeader && key != "header")
                lbl.style.color = "grayText";
            return df.appendChild(lbl);
        }
        template.forEach(function(key) {
            switch(key) {
                case "header":
                    if(header)
                        item(key, header);
                break;
                case "title":
                    if(title && title != url)
                        item(key, title);
                break;
                case "url":
                    if(url)
                        item(key, this.convertURI(url));
                break;
                case "closedAt":
                    if(!closedAt)
                        break;
                    let dt = Math.round(Math.max(0, Date.now() - closedAt)/1000);
                    let days = Math.floor(dt/24/3600);
                    dt -= days*24*3600;
                    let d = new Date((dt + new Date(dt).getTimezoneOffset()*60)*1000);
                    let m = d.getMinutes();
                    let ts = d.getHours() + ":" + (m > 9 ? m : "0" + m);
                    if(days)
                        ts = days + _localize("day") + " " + ts;
                    let tsTip = _localize("itemTip")
                        .replace("%ago", ts)
                        .replace("%date", new Date(closedAt).toLocaleString());
                    item(key, tsTip);
            }
        }, this);
        return df;
    },
    get wm() {
        delete this.wm;
        return this.wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
            .getService(Components.interfaces.nsIWindowMediator);
    },
    updUIGlobal: function() {
        var isSeaMonkey = this.appName == "SeaMonkey";
        var ws = this.wm.getEnumerator(isSeaMonkey ? null : "navigator:browser");
        const id = this.button.id;
        while(ws.hasMoreElements()) {
            let win = ws.getNext();
            if(!isSeaMonkey || this.isBrowserWindow(win)) {
                let btn = win.document.getElementById(id);
                if(btn && "undoCloseTabsList" in btn) {
                    let ucl = btn.undoCloseTabsList;
                    ucl.ensureSessionsInitialized(ucl.updUI, ucl);
                }
            }
        }
    },
    isBrowserWindow: function(win) {
        var loc = window.location.href;
        return loc == "chrome://browser/content/browser.xul"
            || loc == "chrome://navigator/content/navigator.xul";
    },
    ensureSessionsInitialized: function(callback, context) {
        var _this = this;
        var stopTime = Date.now() + 3e3;
        (function ensureInitialized() {
            try {
                _this.ss.getClosedTabCount(window);
                callback.call(context);
                return;
            }
            catch(e) {
                if(Date.now() > stopTime) {
                    Components.utils.reportError(
                        _this.errPrefix
                        + "Can't initialize: nsISessionStore.getClosedTabCount() failed"
                    );
                    Components.utils.reportError(e);
                    return;
                }
            }
            setTimeout(ensureInitialized, 50);
        })();
    }
};

if(!this.undoCloseTabsList.options.useMenu && this.undoCloseTabsList.useCentextMenu) {
    this.oncontextmenu = function(e) {
        if(
            e.target != this
            || e.ctrlKey || e.shiftKey || e.altKey || e.metaKey
            || !this.undoCloseTabsList.mp.hasChildNodes()
        )
            return;
        e.preventDefault();
        this.undoCloseTabsList.showMenu(e); // Show menu without "context" flag
    };
}
if(this.undoCloseTabsList.options.rightClickToUndoCloseTab) {
    this.oncontextmenu = function(e) {
        if(e.target == this && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey)
            e.preventDefault();
    };
}

this.disabled = true;
setTimeout(function(_this) {
    _this.undoCloseTabsList.init();
}, 0, this);

//===================
// Styles
// Used icons from Undo Closed Tabs Button extension

// Styles can't override hardcoded icon
if( // Remove icon only if nsIStyleSheetService works on-the-fly (Firefox 3.0+)
    !Components.ID("{41d979dc-ea03-4235-86ff-1e3c090c5630}")
        .equals(Components.interfaces.nsIStyleSheetService)
) {
    let icon = this.icon
        || this.ownerDocument.getAnonymousElementByAttribute(this, "class", "toolbarbutton-icon");
    if(icon)
        icon.src = "";
    else
        this.image = "";
}

var cssStr = '\
    @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");\n\
    @-moz-document url("%windowURL%") {\n\
        %button% {\n\
            list-style-image: url("data:image/png;base64,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") !important;\n\
            -moz-image-region: rect(0, 24px, 24px, 0) !important;\n\
        }\n\
        %button%:hover {\n\
            -moz-image-region: rect(0, 48px, 24px, 24px) !important;\n\
        }\n\
        %button%[disabled="true"] {\n\
            -moz-image-region: rect(0, 72px, 24px, 48px) !important;\n\
        }\n\
        toolbar[iconsize="small"] %button% {\n\
            -moz-image-region: rect(24px, 16px, 40px, 0) !important;\n\
        }\n\
        toolbar[iconsize="small"] %button%:hover {\n\
            -moz-image-region: rect(24px, 32px, 40px, 16px) !important;\n\
        }\n\
        toolbar[iconsize="small"] %button%[disabled="true"] {\n\
            -moz-image-region: rect(24px, 48px, 40px, 32px) !important;\n\
        }\n\
    }'
    .replace(/%windowURL%/g, window.location.href)
    .replace(/%button%/g, "#" + this.id);
var cssURI = this.cssURI = Components.classes["@mozilla.org/network/io-service;1"]
    .getService(Components.interfaces.nsIIOService)
    .newURI("data:text/css," + encodeURIComponent(cssStr), null, null);
var sss = this.sss = Components.classes["@mozilla.org/content/style-sheet-service;1"]
    .getService(Components.interfaces.nsIStyleSheetService);
if(!sss.sheetRegistered(cssURI, sss.USER_SHEET))
    sss.loadAndRegisterSheet(cssURI, sss.USER_SHEET);


this.onDestroy = function(reason) {
    this.undoCloseTabsList.destroy();
    if(reason == "update" || reason == "delete") {
        let sss = this.sss;
        let cssURI = this.cssURI;
        if(sss.sheetRegistered(cssURI, sss.USER_SHEET))
            sss.unregisterSheet(cssURI, sss.USER_SHEET);
    }
};
if(this.undoCloseTabsList.options.useMenu) {
    this.type = "menu";
    this.orient = "horizontal";
}

Andrey_Krropotkin пишет

подправь пожалуйста (срабатывает только со второго раза)

Замысел непонятен. Если типа для всех findbar'ов вообще,
то примерно так, а если только для открытых двойным СКМ,
то нужно описание.

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

Выделить код

Код:

(obj => {
    for(var findbar of gBrowser.tabpanels.getElementsByTagName("findbar"))
        obj.initFindBar(findbar);
    addEventListener("TabFindInitialized",
        e => obj.initFindBar(e.target._findBar)
    , false, gBrowser.tabContainer || 1);
    addDestructor(() => Array.from(
        document.getElementsByClassName("clearFindbar-button")
    ).forEach(obj.destroyFindBar, obj));
})({
    initFindBar(findbar) {
        var btn = document.importNode(this.btn);
        btn.style; // ???
        btn.onclick = this.click;
        (btn.findbar = findbar).getElement("highlight").before(btn);
        findbar.onwheel = this.wheel;
        findbar.getElement("find-closebutton")
            .setAttribute("style", "-moz-box-ordinal-group: 0 !important;");
    },
    destroyFindBar(btn) {
        btn.findbar.getElement("find-closebutton").removeAttribute("style");
        btn.findbar = btn.findbar.onwheel = null;
        btn.remove();
    },
    click(e) {
        if (e.button == 1) return;
        this.findbar._findField.value = e.button ? "" : gClipboard.read().trim();
        this.findbar.onFindAgainCommand();
    },
    wheel(e) {
        this.onFindAgainCommand(e.deltaY < 0);
    },
    get btn() {
        delete this.btn;
        var btn = MozXULElement.parseXULToFragment(`<toolbarbutton
            type="button"
            style="margin: 0 6px !important;"
            class="toolbarbutton-1 clearFindbar-button"
            tooltiptext="ЛКМ - вставить из буфера.&#xA;ПКМ - очистить поиск."
            image="data:image/x-icon;base64,AAABAAEADhAAAAEAIADoAwAAFgAAACgAAAAOAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5eXn/eXl5/3l5ef95eXn/eXl5/3l5ef95eXn/eXl5/ylTda0pU3X/KVN1/ylTdf8pU3X/HTpS/4WFhf/w8PL/8fHz//Hx8//x8fP/8fHz//Hx8/+FhYX/KVN1/yRJaP8jSGf/I0dl/yNHZP8YMEX/j4+P//Hx8//x8vP/8fLz//Hy8//x8vP/8fLz/4+Pj/8pU3X/JUxr/yVLav8kSmn/JElo/xkyR/+cnJz/8vLz//Ly9P/y8vT/8vL0//Ly9P/y8vT/nJyc/ylTdf8nTm3/Jk1t/yVMa/8lSmn/GjNJ/6urq//y8vT/8/P1//Pz9f/z8/X/8/P1//Pz9f+rq6v/KVN1/ydPb/8nTm7/Jk1t/yZMa/8aNEr/srKy//X19v/19vf/9fb3//X29//19vf/9fb3/7Kysv8pU3X/J1Bx/ydQb/8nTm//Jk1t/xs2S/+8vLz/+fr6//r7+//6+/v/ubm5/7e3t/+3t7f/ubm5/ylTdf8oUXP/KFBx/ydQcf8nT2//GzZN/76+vv/6+/v/+/v8//v7/P/ExMT/9vb2/7e3t/na2tpfKVN1/ylTdP8pUXP/KFBy/yhPcP8bN03/v7+///v7/P/7/Pz/+/z8/8rKyv+3t7f/4OLgaQAAAAApU3X/KVN1/yhSdP8oUnT/KFJy/xw4UP+/v7//v7+//7+/v/+/v7//uru7/2OBmf8AAAAAAAAAAClTdf8pU3X/KVN1/ylSdP8pUnT/JEpn/yRIZv8kSGX/I0dk/yNGY/8jRWL/KVN1/wAAAAAAAAAAKVN1/ylTdf8lS2n/IztO/yM7Tv8jO07/IztO/yM7Tv8jO07/JUtp/ydOb/8lS2n/AAAAAAAAAAApU3X/K2GQ/yhahv91dXX/XV1d/11dXf9dXV3/XV1d/4B/f/8oWob/Kmad/ylTdf8AAAAAAAAAAClTda0pU3X/KVN1/7O0tP/h4eD/3t7f/97f3//g4OD/s7S0/ylTdf8pU3X/KVN1rQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1yds1dXFv1XVxb9Wxxdc8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJUwFASZMCwAlTAsAI00LIys1CxcXFsEYFxbCJS01DAAlTQsAJk0LASZNCwAlTQUAAAAAAAAAAPwArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAASsQQAMrEEADKxBAAysQQAMrEEADKxB8PysQQAMrEE="
        />`).firstChild;
        btn.remove();
        return this.btn = btn;
    }
});

func4ptch4 пишет

проверял кнопку, интересно он работает только после правки, а так после запуска [firefox] не работает.

Не получается воспроизвести. Можно так попробовать
this.onmouseover = e => custombuttons.initAutoPopup(this) && this.onmouseover(e);

Отсутствует

 

№1415526-01-2020 14:03:15

solombala
Забанен
 
Группа: Members
Зарегистрирован: 20-07-2019
Сообщений: 652
UA: Firefox 72.0

Re: Custom Buttons

Dumby
Как это? Заработало! Ну, ты и Magic , в натуре.

Отсутствует

 

№1415626-01-2020 14:03:52

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

Re: Custom Buttons

Dumby спасибо, да именно то что нужно

Отсутствует

 

№1415726-01-2020 18:52:36

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3231
UA: Firefox 72.0

Re: Custom Buttons

Andrey_Krropotkin
А открытие FindBar двойным СКМ появилось?

Отсутствует

 

№1415826-01-2020 19:25:37

sonyas75
Участник
 
Группа: Members
Откуда: Ставрополь
Зарегистрирован: 22-03-2011
Сообщений: 557
UA: Firefox 72.0

Re: Custom Buttons

а есть (можно ли сделать) кнопка, которая закрывает вкладку по клавише Esc?

Отсутствует

 

№1415926-01-2020 19:51:43

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

Re: Custom Buttons

voqabuhe этот  код - отдельное добавление не связан с СКМ

Отсутствует

 

№1416026-01-2020 20:00:36

shadow_user
Участник
 
Группа: Members
Зарегистрирован: 14-02-2007
Сообщений: 244
UA: Firefox 68.0

Re: Custom Buttons

Andrey_Krropotkin
Все варианты кнопки перевода добавляют в низ окна с переводом пустые строки, бесполезно увеличивая тем самым площадь окна на 20-30%. Может, это можно пофиксить?
1.1580057867.png

Отсутствует

 

№1416126-01-2020 20:04:26

unter_officer
Участник
 
Группа: Members
Откуда: Санкт-Петербург
Зарегистрирован: 27-03-2011
Сообщений: 537
UA: Firefox 52.0

Re: Custom Buttons

sonyas75 пишет

а есть (можно ли сделать) кнопка, которая закрывает вкладку по клавише Esc?

Попробуйте так:

Выделить код

Код:

// Закрыть активную вкладку по Escape .....
document.onkeydown=function(e) {
  if (e.which == 27) { gBrowser.removeCurrentTab(); }
}

«The Truth Is Out There»

Отсутствует

 

№1416226-01-2020 20:08:57

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

Re: Custom Buttons

shadow_user попробуй поэкспериментируй вот здесь
cnt.style.height = 50*i+'px';
cnt.style.width = 100*i+'px';
и наверно пропорция окна width:240px;height:120px

Отредактировано Andrey_Krropotkin (26-01-2020 20:32:05)

Отсутствует

 

№1416326-01-2020 20:15:07

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3231
UA: Firefox 72.0

Re: Custom Buttons

Andrey_Krropotkin пишет

этот  код - отдельное добавление не связан с СКМ

Для чего этот я понял. Я спрашивал вообще, что-нибудь появилось для СКМ, чтоб не пропустить?

Добавлено 26-01-2020 20:19:57

unter_officer пишет

Попробуйте так:

Прикольная фишка получилась, спасибо.

Отредактировано voqabuhe (26-01-2020 20:20:30)

Отсутствует

 

№1416426-01-2020 20:24:22

sonyas75
Участник
 
Группа: Members
Откуда: Ставрополь
Зарегистрирован: 22-03-2011
Сообщений: 557
UA: Firefox 72.0

Re: Custom Buttons

unter_officer
да! спасибо :)

Отсутствует

 

№1416526-01-2020 20:34:47

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

Re: Custom Buttons

voqabuhe нет, как раньше дал Dumby код по СКМ, больше изменений не было.

Отсутствует

 

№1416626-01-2020 21:58:54

shadow_user
Участник
 
Группа: Members
Зарегистрирован: 14-02-2007
Сообщений: 244
UA: Firefox 68.0

Re: Custom Buttons

unter_officer пишет

кнопка, которая закрывает вкладку по клавише Esc?

voqabuhe пишет

Прикольная фишка получилась, спасибо.

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

Andrey_Krropotkin пишет

shadow_user попробуй поэкспериментируй вот здесь

Не помогло. Ну да ладно, это уже чисто эстетика.

Отсутствует

 

№1416726-01-2020 22:43:45

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3231
UA: Firefox 72.0

Re: Custom Buttons

shadow_user пишет

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

Не могу заценить, у меня нет никаких окон перевода.  А для перевода давно понял, что для меня пока нет ничего удобнее QTranslate.

Добавлено 26-01-2020 22:49:07
А возможность осталась любым способом восстановить адресную строку в окне добавления закладок через звёздочку и сделать всегда развёрнутым окошко дерева закладок там же?

Отредактировано voqabuhe (26-01-2020 22:50:06)

Отсутствует

 

№1416827-01-2020 01:05:15

solombala
Забанен
 
Группа: Members
Зарегистрирован: 20-07-2019
Сообщений: 652
UA: Firefox 72.0

Re: Custom Buttons

Кто там хотел "Перевод" с идеальным окном ?

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

Выделить код

Код:

/*Initialization Code*/

var lc = navigator.lastClick = {};
addEventListener("mouseup", e => {
    if (e.button) return;
    lc.X = e.screenX - mozInnerScreenX;
    lc.Y = e.screenY - mozInnerScreenY;
}, false, gBrowser.tabpanels || 1);

var createWindow = function(text, status, title, id, pos, size){
var win = window, doc = win.document, wId = 'ujs_window'+(id || ''), w = doc.getElementById(wId);
    var keyDown = function(e){if(!e.shiftKey && !e.ctrlKey && !e.altKey && e.keyCode == 27)doc.getElementById(wId).closeWin()};
    if(w)w.closeWin();
    w = doc.createElementNS(xhtmlns, 'div');
     w.setAttribute('style', 'position:fixed;display:block;visibility:hidden;left:0;top:0;width:auto;height:auto;border:1px solid gray;padding:2px;margin:0;z-index:99999;overflow:hidden;cursor:move;'+(typeof w.style.borderRadius === 'string' ? 'background-color:#eaeaea;padding-top:0px;border-radius:4px;box-shadow:0 0 15px rgba(0,0,0,.4);' : 'background:-o-skin("Window Skin");'));
    w.id = wId;
    w.closeWin = function(){
        doc.removeEventListener('keydown', keyDown, false);
        this.parentNode.removeChild(this);
    };
    w.addEle = function(str, style){
        var ele = doc.createElementNS(xhtmlns, 'div');
        ele.setAttribute('style', style);
        if(str){
            ele.innerHTML = str;
            for(var el, all = ele.getElementsByTagName('*'), i = all.length; i--;){
                el = all[i];
                if(/^(script|frame|iframe|applet|embed|object)$/i.test(el.nodeName)){
                    el.parentNode.removeChild(el);
                }
                else{
                    for(var att = el.attributes, j = att.length; j--;){
                        if(/^on[a-z]+$/i.test(att[j].name))att[j].value = '';
                    }
                }
            }
        };
        return this.appendChild(ele);
    };
     w.addEle1 = function(str, style){
        var ele = doc.createElementNS(xhtmlns, 'textarea');
        ele.setAttribute('style', style);
        if(str){
            ele.innerHTML = str;
            for(var el, all = ele.getElementsByTagName('*'), i = all.length; i--;){
                el = all[i];
                if(/^(script|frame|iframe|applet|embed|object)$/i.test(el.nodeName)){
                    el.parentNode.removeChild(el);
                }else{
                    for(var att = el.attributes, j = att.length; j--;){
                        if(/^on[a-z]+$/i.test(att[j].name))att[j].value = '';
                    }
                }
            }
        };
        return this.appendChild(ele);
    };
    var img = doc.createElementNS(xhtmlns, 'div');
    img.setAttribute('style', 'display:block;float:right;width:15px;height:15px;padding:0;margin-top:3px;margin-right:2px;border:none;cursor:pointer;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAACwklEQVR42i2TW0hVeRjFf98+aloWQUbkedBCIkgKusAxRCiiBy3yrZJuxEB0Bh/moemh6EoXkuhGSQ9dToHVW3XwKS1qhnFmcIIEmTNQYD3UoIWdtDJt76+1j/5hbfbe//196/+ttbah9adQLNwWmqFpLtTlYcwg8Q3C6VD6H/y9HR66vokRCPaPLt/jG2EMttXPmXPbWlvh0ycoKtKmdmfNYvTcOTL5fHoPtOstw3HNX7pEwjjsqK+szAQPHkRUVFihXyIh3pAC2fv3nm9qCi4NDv68D650TBUXiXFrw8yZt8hkQubNCzAzhoddzCZmZ/ZsUxNnaCj6sGtX4uTISHotXLNH0NgAnSVtbSHJZEBjo6nY6e42Xr+GqipYs8YpKTE6O51cLsodOpQ4Ay3WCydWrF69n1QqKDDs3u2eTJq9fSslJWUqhVdWYn19zvHjRm+v+8BAeAFu2B9wsC6ZPMbKlcbXr051tZFO40uX4jq9RRH25Alqysc3b1wq26g0uCnh7Dc4XD9t2hEWLtQrmZCXSVu2ELadJfF5BC8vx5qbyWezBTtjceUD1+Pip2JeDsfKi4stmpjwIJUy2tuhtpZIVgWxVc+fw86djOZyLhtsRDRX4+JnmnkV7FfXILF4sZHNutfUmD2Ld07AgQPQIElfvXI2bLDvaiB3osLMl2Gjth7WzpgRat6A+/eN8XGnpcX8xQts2TLo6HB0MjZtcjngXV++BFfgF3usZP4OP22W8YtqakLmzw8oKzP6+13JMiXNWbJkUsx376Kely8TF+HUXbhgGQ2/blKA9Da4XF1XFyoQAaWlsd+TIo6NudLmfT09wWkV3oHzGmbQ4vBNCAoibbB3h06QXL8eMVFYcXFZGf92dXHU/eQ9MW5VYdXU/8CQUDH18KuiukiZ+qiesbJq7KVQ0g39WbirH+l/pYsFwg9RIBTyj1ZRogAAAABJRU5ErkJggg==");background:-o-skin("Caption Close Button Skin");');
    img.title = (win.navigator.language.indexOf('ru') == 0) ? '\u0417\u0430\u043A\u0440\u044B\u0442\u044C' : 'Close';
    img.addEventListener('click', function(){this.parentNode.closeWin()}, false);
    w.appendChild(img);
    var title = w.addEle(title, 'display:table;color:#000;font:17px Times New Roman;width:auto;height:auto;padding:0;margin:0 2px;cursor:text;');
        title.onclick = e => {
        e.preventDefault();
        var url = e.target.href;
        // Здесь открываем url как хотим.
        var ctabpos = gBrowser.selectedTab._tPos +1;
        gBrowser.moveTabTo(gBrowser.selectedTab = gBrowser.addWebTab(url), ctabpos);
        doc.getElementById(wId).closeWin();    
    }
    var cnt = w.addEle1(text, 'display:block;border:1px solid #aaa;padding-bottom:3px;padding-left:3px;background-color:#fafcfe;color:#000;font:17px Times New Roman;width:260px;height:100px;overflow:auto;cursor:text;-moz-user-focus:normal;');
    cnt.contentEditable="true";
    cnt.context="contentAreaContextMenu";
    w.addEle(status, 'display:table;font:12px Times New Roman;font-weight:bold;color:blue;width:auto;height:auto;padding-top:2px;margin:0 3px;cursor:pointer;');
    w.addEventListener('mousedown', function(e){
        if(e.target == w){
            e.preventDefault();
            var grabX = e.clientX, grabY = e.clientY, origX = parseInt(w.style.left), origY = parseInt(w.style.top);
            var mouseMove = function(ev){
                w.style.left = origX+ev.clientX-grabX+'px';
                w.style.top = origY+ev.clientY-grabY+'px';
            };
            doc.addEventListener('mousemove', mouseMove, false);
            doc.addEventListener('mouseup', function(){doc.removeEventListener('mousemove', mouseMove, false)}, false);
        }
    }, false);
    doc.documentElement.appendChild(w);
  
    if(size){
        cnt.style.height = 40*i+'px';
        cnt.style.width = 130*i+'px';
    }
    else{
        for(var i = 3; i < 10; i++){
            if(cnt.scrollHeight > cnt.offsetHeight || cnt.scrollWidth > cnt.offsetWidth){
                cnt.style.height = 40*i+'px';
                cnt.style.width = 130*i+'px';
            }
            else break;
        }
    };

    var docEle = (doc.compatMode == 'CSS1Compat' && win.postMessage) ? doc.documentElement : doc.body;
    var mX = docEle.clientWidth-w.offsetWidth, mY = docEle.clientHeight-w.offsetHeight;
    if(mX < 0){cnt.style.width = parseInt(cnt.style.width)+mX+'px'; mX = 0};
    if(mY < 0){cnt.style.height = parseInt(cnt.style.height)+mY+'px'; mY =0};
    var hW = parseInt(w.offsetWidth/2);
    w.style.left = (pos && pos.X < mX+hW ? (pos.X > hW ? pos.X-hW : 0) : mX)+'px';
    w.style.top = (pos && pos.Y+10 < mY ? pos.Y+10 : mY)+'px';
    w.style.visibility = 'visible';
    doc.addEventListener('keydown', keyDown, false);
    return w;
};

var getHash = function (txt) {
    TKK=eval('((function(){var a\x3d817046147;var b\x3d-335196159;return 410049+\x27.\x27+(a+b)})())');
    function sM(a) {
        var b;
        if (null !== yr)
            b = yr;
        else {
            b = wr(String.fromCharCode(84));
            var c = wr(String.fromCharCode(75));
            b = [b(), b()];
            b[1] = c();
            b = (yr = window[b.join(c())] || "") || ""
        }
        var d = wr(String.fromCharCode(116))
            , c = wr(String.fromCharCode(107))
            , d = [d(), d()];
        d[1] = c();
        c = "&" + d.join("") + "=";
        d = b.split(".");
        b = Number(d[0]) || 0;
        for (var e = [], f = 0, g = 0; g < a.length; g++) {
            var l = a.charCodeAt(g);
            128 > l ? e[f++] = l : (2048 > l ? e[f++] = l >> 6 | 192 : (55296 == (l & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (l = 65536 + ((l & 1023) << 10) + (a.charCodeAt(++g) & 1023),
                e[f++] = l >> 18 | 240,
                e[f++] = l >> 12 & 63 | 128) : e[f++] = l >> 12 | 224,
                e[f++] = l >> 6 & 63 | 128),
                e[f++] = l & 63 | 128)
        }
        a = b;
        for (f = 0; f < e.length; f++)
            a += e[f],
                a = xr(a, "+-a^+6");
        a = xr(a, "+-3^+b+-f");
        a ^= Number(d[1]) || 0;
        0 > a && (a = (a & 2147483647) + 2147483648);
        a %= 1E6;
        return c + (a.toString() + "." + (a ^ b))
    }

    var yr = null;
    var wr = function(a) {
        return function() {
            return a
        }
    }
        , xr = function(a, b) {
        for (var c = 0; c < b.length - 2; c += 3) {
            var d = b.charAt(c + 2)
                , d = "a" <= d ? d.charCodeAt(0) - 87 : Number(d)
                , d = "+" == b.charAt(c + 1) ? a >>> d : a << d;
            a = "+" == b.charAt(c) ? a + d & 4294967295 : a ^ d
        }
        return a
    }; 

    return sM(txt);
}; 
 
  
 
var ujs_google_translate = function (dir){
    var lng = window.navigator.language.slice(0, 2), txt = gContextMenu.selectionInfo.fullText, l = dir.split('|');
    var encTxt = encodeURIComponent(txt);
    var winWait = function(lng){createWindow('', (lng == 'ru' ? 'Подождите идет перевод' : 'Wait, is going Translating')+'\u2026', 'Google Translate', '_gt', window.navigator.lastClick)};
    if (txt) {
    winWait(lng);
        var xhr = new XMLHttpRequest();
         var url = 'https://translate.google.com/translate_a/single?client=gtx&sl=' + l[0] + '&tl=' + l[1] + '&hl=' + lng + '&eotf=0&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t' + getHash(txt);
        var urlt = "http://translate.google.com/translate_t?text="+encTxt+"&sl='  + langFrom_google_text + '&tl=' + langTo_google_text +'&hl=' + lng + '&eotf=0&ujs=gtt";
      
        xhr.open('POST', url, true);
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
        xhr.onreadystatechange = function() {
            try{
                if (xhr.readyState == 4 && xhr.status == 200) {
                    var result = '', status = '', tmp = JSON.parse(xhr.responseText.replace(/\[(?=,)/g, '[0').replace(/,(?=,|\])/g, ',0').replace(/\\n/g, "<br />"));
                    for(var i = 0, n; n = tmp[0][i]; i++){
                        if(n[0])result += n[0].toString();
                    };
                    status = tmp[8][0][0].toUpperCase() + ' -\u203A ' + l[1].toUpperCase();
                     createWindow(result, status, '<a href="'+urlt.replace(/&/g,'&amp;')+'" target="_blank" style="display:inline;padding:0;margin:0;text-decoration:none;border:none;color:blue;font:17px Arian;">Google Translate</a>', '_gt', window.navigator.lastClick);
                }
            } catch (x){LOG(x)};
        };
        xhr.send('q=' + encodeURIComponent(txt));
    } else {
        var urlt = gBrowser.currentURI.spec;  
        var url = "http://translate.google.com/translate?u="+encodeURIComponent(urlt)+"&hl="+lng+"&langpair="+dir+"&tbb=1";
        var ctabpos = gBrowser.selectedTab._tPos +1;
        gBrowser.moveTabTo(gBrowser.selectedTab = gBrowser.addWebTab(url), ctabpos);
    };
};

var contextMenu = document.getElementById("contentAreaContextMenu");
var nextEleMenu = document.getElementById("context-inspect");

var menuId = "context-ext-google-translate";
var menuItem = document.getElementById(menuId);
if (menuItem) {
    contextMenu.removeChild(menuItem.nextElementSibling);
    contextMenu.removeChild(menuItem.nextElementSibling);
    contextMenu.removeChild(menuItem);
};

menuItem = document.createXULElement("menuitem");
menuItem.setAttribute("id", menuId);
menuItem.setAttribute("label", "Перевести на русский");
menuItem.setAttribute("class", "menuitem-iconic");
menuItem.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABBUlEQVR4Ac2RMU4DMRREB2MqihQpAkUaqnAduuQw4Sx03CGcJYIiDYqQ0lCsZ77535ZFcgAkRuPvV7zd/dLiz3N1PFb8hmRckrfELZrF9ONQ1B6Yz0MyM7S0O6zGkVprh/3+Kw/JzkHSpRpJKZkpr9fYbOx0cjVsCbWG31oHBM9mtt0q73ZcrdLhAMlYQKkUI22aqsNo8HKZAMQhvVaKSHWj2Q2aPU3mJQFY7nuHyvYFduP83WF3AJRfcPNYnr/Lp1G1uK4m9sno1LaUbnX/htf8BNzoneUD5NhjvLCMhURQSQ93QCZwXYjFwg3I0NZKrvoknQPMIHkt/jRAQKMeG2yX89/mB4EJbKbZxIhFAAAAAElFTkSuQmCC");
menuItem.addEventListener("command", function(){ujs_google_translate('auto|ru')}, false);
contextMenu.insertBefore(menuItem, nextEleMenu);

menuItem = document.createXULElement("menuitem");
menuItem.setAttribute("label", "Перевести на английский");
menuItem.setAttribute("class", "menuitem-iconic");
menuItem.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAAB5UlEQVR4AWOgPZg0c9+Oq2+qpx9LaQaiw4mNB27efbs2uXFNQh2Q4Zm9zSNth23MhqjGnXMC86vnHmUS4udxv7OvOd2yPE7PTlfCTk9GVVEoyJA7WI8dyPA0k3U1l+jJMV7CeThpTZeoKDdDUsvBPSff/V+6/P/Bvf///2+bdvU/EKRm/k9IBNIlfZe+LFrzvbsbyJ636pKkyQyQhoUb7tZNvPpw3/0/TfX/ISAm5n94BIiRm/n/xYsLd946ei4vajoiqDuRAejQf//+o4PQ0P9+fmhiQGVnrr1kXJNYG2zEzXDxDsPv3wy/fkFJoOTPn39+/fr/69e/37//AUX+/mXRkO458wWHDba2f8wswCyQ3N+/f//8/fP7z5+TV18w2Mdt6plzPiptx5Wr7/+/ffMzOR6kysjkt74hWMPfp06O+2dulZCeFZKwnkE4m8E8bN3i9aCQ+dxY96GrK6bkGJD9R1v3l6Y20NVW9kt+/v//ZdbcFwkxTVPPMQimM8XEqkb7a/zoqLxkH9v4zVyI5+///wyMmtKMmhJAnbLqQjHxaw5r2orOmZN5uj470Zahat6BKS7JzpmLBHXm8GhM5lCdcP7ai1ZpixZxk9NXXjKIFzOIFjAI54oY1vXuue5qmscw+AAAW0tKxtPoicEAAAAASUVORK5CYII=");
menuItem.addEventListener("command", function(){ujs_google_translate('auto|en')}, false);
contextMenu.insertBefore(menuItem, nextEleMenu);

contextMenu.insertBefore(document.createXULElement("menuseparator"), nextEleMenu);

Отсутствует

 

№1416927-01-2020 04:14:07

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3231
UA: Firefox 69.0

Re: Custom Buttons

unter_officer
А можно сделать, чтобы "Закрыть активную вкладку по Escape ....." не закрывала вкладку в Полноэкранном режиме? Из него выход же тоже по Esc. А то уже три раза по ошибке фильм закрывал, приходится потом искать откуда смотреть. :)

Отсутствует

 

№1417027-01-2020 07:46:28

unter_officer
Участник
 
Группа: Members
Откуда: Санкт-Петербург
Зарегистрирован: 27-03-2011
Сообщений: 537
UA: Firefox 52.0

Re: Custom Buttons

voqabuhe пишет

А можно сделать, чтобы "Закрыть активную вкладку по Escape ....." не закрывала вкладку в Полноэкранном режиме?

Попробуйте так:

Выделить код

Код:

document.onkeydown=function(e) {
  if (e.which == 27 && window.fullScreen) {
    window.fullScreen = !window.fullScreen;
  }
  else if (e.which == 27) {
    gBrowser.removeCurrentTab();
  }
}

Отредактировано unter_officer (27-01-2020 08:43:41)


«The Truth Is Out There»

Отсутствует

 

№1417127-01-2020 08:52:58

shadow_user
Участник
 
Группа: Members
Зарегистрирован: 14-02-2007
Сообщений: 244
UA: Firefox 68.0

Re: Custom Buttons

voqabuhe пишет

Не могу заценить, у меня нет никаких окон перевода.

Речь об обсуждаемом контекстном (из конт. меню) переводе от Andrey_Krropotkin.

solombala пишет

Кто там хотел "Перевод" с идеальным окном ?

Теперь получше. Плюсы: иногда совсем нет пустых строк, примерно один раз из пяти; количество пустых строк уменьшилось. Минусы: в большинстве случаев пустые строки все же есть.

Отсутствует

 

№1417227-01-2020 08:54:12

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3231
UA: Firefox 72.0

Re: Custom Buttons

unter_officer пишет

Попробуйте так:

Во, теперь просто здорово. Спасибо.

Отсутствует

 

№1417327-01-2020 09:51:46

shadow_user
Участник
 
Группа: Members
Зарегистрирован: 14-02-2007
Сообщений: 244
UA: Firefox 68.0

Re: Custom Buttons

А можно сделать, чтобы "Закрыть активную вкладку по Escape ....." не закрывала вкладку в Полноэкранном режиме?

unter_officer пишет

Попробуйте так:

Логика работы великолепная, первое нажатие выводит из полноэкранного режима, второе нажатие закрывает вкладку. А не сможете сделать то же самое и для вкладки с окном перевода - первое нажатие закрывает окно перевода (это действие входит в код кнопки перевода), второе нажатие закрывает вкладку? Сейчас первое нажатие закрывает таб, невзирая на наличие в нем окна перевода.
Как вариант, на самый тяжелый случай, если всплывающее окошко перевода открыто в полноэкранном режиме Firefox, первое нажатие закрывает окошко перевода, второе выводит из полноэкранного режима, третье закрывает вкладку.

Отредактировано shadow_user (27-01-2020 12:22:22)

Отсутствует

 

№1417427-01-2020 10:05:41

solombala
Забанен
 
Группа: Members
Зарегистрирован: 20-07-2019
Сообщений: 652
UA: Firefox 72.0

Re: Custom Buttons

d

Отредактировано solombala (27-01-2020 12:45:12)

Отсутствует

 

№1417527-01-2020 10:18:03

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3231
UA: Firefox 0.8

Re: Custom Buttons

shadow_user пишет

Логика работы великолепная, первое нажатие выводит из полноэкранного режима, второе нажатие закрывает вкладку.

И не говори, теперь вкладки закрывать одно удовольствие.:)

Отсутствует

 

Board footer

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