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

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

№1600111-11-2021 23:20:49

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 336
UA: Firefox 94.0

Re: Custom Buttons

Dumby
Не фига не понял,какой сплойер  ? где первый ,где второй...Да не увидел сам jsm измененный...Но этот старый - точнее показывает !!!

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

Выделить код

Код:

var EXPORTED_SYMBOLS = ["UCFMemIndReporterChild"];
var ai = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
var prop = ai.processType == ai.PROCESS_TYPE_DEFAULT ? "resident" : "residentUnique";
var pid = ai.processID;
var mrm = Cc["@mozilla.org/memory-reporter-manager;1"].getService(Ci.nsIMemoryReporterManager);
class UCFMemIndReporterChild extends JSProcessActorChild {receiveMessage() {return [pid, mrm[prop]];}}

Отредактировано ВВП (11-11-2021 23:43:39)

Отсутствует

 

№1600212-11-2021 00:31:45

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

Re: Custom Buttons

ВВП пишет

Не фига не понял,какой сплойер  ? где первый ,где второй...Да не увидел сам jsm измененный...

Может очки надень.

Но этот старый - точнее показывает !!!

Тогда не трогай, оставь как есть.

Отсутствует

 

№1600313-11-2021 00:38:03

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

Re: Custom Buttons

Может вопрос не по теме. Есть кнопка

скрытый текст
// Proxy, от 10.10.2016.

  var iconProxy = 'data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAQAAAAAIAA4GQAAnFmkAHQ5fAAQAKAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEBAQECAgICAgICAgICAgMBAQEAAAQBJBFQOLQ+nX38ecev/mu6of8gfFvtAyUXewAAAAsAAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEBAAAAAAMLUza7PKd//3S7oP2849X9zuvh/mW4mf4XiV7/AB4QZwAAAAAAAAAAAQEBAQAAAAAZGhgTKSwnLyYqJDErKCUnID8vXgaAUP9BlnH8b7ea/ojHrv+q2sf/a7CT+zGWbf8PakXGAAIAAAEBAQMHBwcbAAAAD2BiXn76/ff/4ebg/Onm4f+DtZ7/A31L/j2Wb/+Fwaj/ls23/7rh0v9+vaT+M5du/xKGWO0DIxIdAAAAAAEBAQEAAAABBgYFEaSmorbP08z239vX/4OwnP4ail3/RJlz/5HHsP/T7+X/ms64/3K2mP40k2r/D3tM7AUiExwhIx8meXt1mXt+eKJ3eXSce353n6esouDMysf/o7eq/kOdeP92uZv/vuPT/9Hs4P/C4tT/eLWa+juWbv8bcEq7AAYBAF1gWn7//////f39/P//////////////////////////lcKx/3i9pf/K7OD/2O/l/7ndzf6Fw6n/VK+I/AsxHj8AAAAAXF5bf+Ln2P+AnU/4fZ1N+4WiV/yKp13+jKlh/5CsZf+GpFj/Zpxh/4C5nf+i0L7+k8ex/1udf+UTOCZFAAAAAAEBAQJfYF5/3uXR/16IIPxciiH/Z5Iv/26YOP9ymz3/cpw+/3OcPf9wlzb/YI80/1mKNPu707X/YmZjiAAAAAAEBAQGAAAAAF9gXoDg5tT/cJU6/HGaPf9/pE3/hqtX/4uvXf+NsF7/iKxZ/4KoU/9+o0r/cpY6+9zjyf9ubm2JAAAAAAMEAwQAAAAAX2BegODm1P94nEX8e6JJ/4quXP+Vt2n/nb1z/6LBef+jwXz/ob96/527d/+NrGP71+HG/2praogAAAAABAQDBAAAAABfYF2A4ObU/4WlVvyPsmP/osB7/7HMj/+81J3/wdik/8DXo/+60pz/tc6X/6G6ffvY4sf/amtqiAAAAAAEBAMEAAAAAF9gXn/e5dL/n7l7/LLMk//B16X/zuG2/9jpwv/b68b/2enE/9Pkvv/Q4bv/uMud+9jhyP9qa2mHAAAAAAQEAwQAAAAAX2Bef97k0v+gt335sceT/LrNnfzC1Kj8ydmx/MzatfzK2bP8xtav/MbVr/ywwpL41+HH/2tsaokAAAAABAQDBAAAAABZW1Z3+fz1/+Dm1Pzj6db/5u3b/+nv3v/r8eD/6vDe/+ft2//k69j/4efT/9ngzPv7//b/ZGdhfwAAAAADBAMEAAAAABcZFRpZW1Z6YGFfgWBiYIBhYmGAYmJhgGJjYoBiY2KAYmJhgGFiYYBgYWCAX2BegF1fWoAbHRkeAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=';

// Настройка функций кликов мыши для кнопки ...................
this.onclick =e=> {

   // действие при клике ЛКМ ....
   if ( e.button == 0 )openMenuPopup();

   // действие при клике СКМ ....   
   if ( e.button == 1 )
        cbu.getPrefs("CB.Proxy.connectionsInTab") ? openConnectionsInTab() : openConnections();
};



// Подсказка для кнопки ...................
this.onmouseover =()=> {
   var arr = ["Без прокси", "Ручная настройка", "Автоматическая через URL", "", "Автоматическая настройка", "Системная настройка"];
   var str = arr.map((m, i)=> (cbu.getPrefs("network.proxy.type") == i ? "●" : "  ") + m).filter(m=> /\S/.test(m)).join("\n");
     
   this.tooltipText = "Proxy +\n"
      + "\n" + str
      + "\n\nЛ: Mеню кнопки \nС: Открыть настройки прокси"
      + "\n\nТекущие настройки прокси:"
      + "\nIP: " + cbu.getPrefs("network.proxy.http")
      + "\nПорт: " + cbu.getPrefs("network.proxy.http_port")
};



// Создать меню для кнопки ...................
function openMenuPopup() {

   
var array = [
   { label: "Без прокси", value: 0, radio: ''},
   { label: "Ручная настройка сервиса прокси:", value: 1, radio: ''},
   { label: "URL автоматической настройки сервиса прокси", value: 2, radio: ''},
   { label: "Автоматически определять настройки прокси для этой сети", value: 4, radio: ''},
   { label: "Использовать системные настройки прокси", value: 5, radio: ''},
   { separator: ''},
   { label: "Добавление прокси в контекстом меню", value: 'CB.Proxy.inContextMenu', checkbox: ''},
   { label: "Открывать настройки прокси как вкладку", value: 'CB.Proxy.connectionsInTab', checkbox: ''},
   { label: "Переключать на режим 'Без прокси' при закрытии браузера ", value: 'CB.Proxy.reset', checkbox: ''}
   ];
var menuPopup = self.appendChild( document.createXULElement("menupopup") );
menuPopup.setAttribute("onclick", "event.stopPropagation()");

   menuPopup.textContent = "";
 
   array.forEach(m=> {
      if ( "separator" in m ) { menuPopup.appendChild( document.createXULElement("menuseparator") ); return };
      var mItem = menuPopup.appendChild(document.createXULElement("menuitem"))
      mItem.setAttribute("label", m.label);

      if ( "radio" in m ) {
           mItem.setAttribute('type', 'radio');
           mItem.setAttribute('checked', cbu.getPrefs("network.proxy.type") == m.value);
           mItem.onclick =()=> cbu.setPrefs("network.proxy.type", m.value); 
           } 
      if ( "checkbox" in m ) {
           mItem.setAttribute('type', 'checkbox');
           mItem.setAttribute('checked', cbu.getPrefs(m.value) );
           mItem.onclick =()=> cbu.setPrefs(m.value, !cbu.getPrefs(m.value)); 
           }
   });
menuPopup.openPopup(self, "after_start");
};

var listenClick = win => {
    var args = ["click", win.close.bind(win), true];
    var unload = () => gBrowser.removeEventListener(...args);
    gBrowser.addEventListener(...args);
    win.addEventListener("unload", unload, {once: true});
}
var version = parseInt(Services.appinfo.platformVersion);
var url = `chrome://browser/content/preferences/dialogs/connection.x${version >= 72 ? "htm" : "u"}l`;

var fox73 = version >= 73, noop = () => {};
if (fox73) var grid = win => {
    var url = "data:text/css;charset=utf-8," + encodeURIComponent(`
        #proxy-grid, #dnsOverHttps-grid {
            display: grid;
            grid-template-columns: auto 1fr;
            align-items: center;
        }
        #proxy-grid > .thin {
            grid-column-end: 3;
            height: 20px;
        }
        #dnsOverHttps-grid.custom-container-hidden #networkCustomDnsOverHttpsInput,
        #dnsOverHttps-grid.custom-container-hidden #networkCustomDnsOverHttpsInputLabelContainer {
            display: none;
        }
    `);
    (grid = win => win.windowUtils.loadSheetUsingURIString(url, win.windowUtils.AUTHOR_SHEET))(win);
}
var winOpen = win => win.addEventListener("readystatechange", winReady, {once: true, capture: true});
var winReady = e => {
    var win = e.target.ownerGlobal, cw = win.isChromeWindow;
    if (cw || (win.location == url && !win.docShell.name)) winPatch(win, cw);
}
var winPatch = (win, cw) => {
    win.opener = {gSubDialog: {_dialogs: [{
        _frame: {get contentDocument() {
            cw && listenClick(win);
            delete this.contentDocument;
            return this.contentDocument = win.document;
        }},
        resizeVertically: cw ? () => win.sizeToContent() : noop
    }]}};
    fox73 && grid(win);
}
addEventListener("MozBeforeInitialXULLayout", winReady, false, gBrowser.tabpanels || 1);

for(var {contentWindow: win} of gBrowser.browsers)
    win && win.location == url && !win.opener && winPatch(win);


// Функция открывает настройки прокси в окне ................... 
function openConnections() {
    var win = [...Services.wm.getEnumerator(null)].find(w => w.location == url);
    win ? win.focus() : winOpen(openDialog(url, "Proxy", "centerscreen"));
}

// Функция открывает настройки прокси в вкладке ...................
function openConnectionsInTab() {
    var connections = gBrowser.getBrowserForTab(
        gBrowser.selectedTab = gBrowser.addTrustedTab(url)
    );

    // oбработчик ждет пока откроется прокси, удаляет себя и добавляет атрибут
    connections.addEventListener("pageshow",
        e => e.target.documentElement.setAttribute("type", "prefwindow")
    , {once: true});
}


// Установливать нужную иконку кнопки при старте баузера или при изменениях в 'about:config' ...................
var s = "network.proxy.type";
function toggleImage() {
   var icon = self.icon || self.ownerDocument.getAnonymousElementByAttribute(self, "class", "toolbarbutton-icon");
   switch( cbu.getPrefs(s) ) {
      case 0: icon.src = self.image; break;         
      case 1: icon.src = iconProxy; break;
      case 2: icon.src = iconProxy; break;
      case 4: icon.src = iconProxy; break;
      case 5: icon.src = iconProxy; break;
      default:icon.src = self.image;
   }
}; 
toggleImage();
Services.prefs.addObserver(s, toggleImage, false);
addDestructor(()=> Services.prefs.removeObserver(s, toggleImage));

// Переключать на режим 'Без прокси' при закрытии браузера если это разрешено в 'about:config' ...................
var switchOffProxy = {
    observe: function(subject, topic, data) {
       if ( data == "shutdown" && cbu.getPrefs("CB.Proxy.reset") ) cbu.setPrefs("network.proxy.type", 0); 
    }
};
Services.obs.addObserver(switchOffProxy, "quit-application", false);



// Создаем меню для добавление прокси в контекстном меню выделенного текста на странице ...................
var contextMenu = document.getElementById("contentAreaContextMenu");
var menuitem = document.createElementNS(xulns,"menuitem");
menuitem.setAttribute("label", "Добавить прокси");
menuitem.setAttribute("class", "menuitem-iconic");
menuitem.setAttribute("image", self.image);
menuitem.onclick =()=> addNewProxy(menuitem);
contextMenu.appendChild(menuitem); // как последний пункт меню
addDestructor(() => menuitem.remove());
addEventListener("popupshowing", () => {
    menuitem.hidden = !cbu.getPrefs("CB.Proxy.inContextMenu") || !gContextMenu.isContentSelected; // !gContextMenu.isTextSelected;
}, false, contextMenu);


// добавление прокси ...................
function addNewProxy(menuitem) {
    var sel = gBrowser.contentDocument
        ? gBrowser.contentDocument.defaultView.getSelection().toString() // Pale Moon 
        : gContextMenu.selectionInfo.fullText; // Firefox

    sel = sel.replace(/^\s+|\s+$/g, ""); // удалить пробелы, слева и справа от строки
    sel = sel.replace(/\s+/g, ":");      // заменить пробелы внутри строки

    // если только порт ...
    if (sel.length < 6 && isFinite(sel)) {
        var lab = 'порт';
        cbu.setPrefs("network.proxy.http_port", +sel);                   
    }

    // если только адрес ...
    if (sel.length > 5 && !/:/.test(sel) && sel.split(".").length == 4) {
        var lab = 'адрес';
        cbu.setPrefs("network.proxy.http", convertFromUnicode("UTF-8", sel)); 
    }

    // если адрес и порт ...   
    if (sel.length > 5 && /:/.test(sel) && sel.split(":").length == 2 && sel.split(".").length == 4) {
        var lab = 'адрес и порт';
        var arr = sel.split(":"), IP = arr[0], port = arr[1];
        cbu.setPrefs("network.proxy.http_port", +port);
        cbu.setPrefs("network.proxy.http", convertFromUnicode("UTF-8", IP));
    }

    // всплывающая подсказка рядом с выделенным текстом ...
    var mainPopupSet = document.getElementById('mainPopupSet');
    var tooltip = mainPopupSet.appendChild(document.createElementNS(xulns,"tooltip"));
    tooltip.style.cssText = "color: red !important; font-weight: bold !important; font-size: 14px !important; -moz-box-orient: horizontal; text-align: center;";

    var image = tooltip.appendChild(document.createElementNS(xulns, "image"));
    image.setAttribute("src", self.image);

    var label = tooltip.appendChild(document.createElementNS(xulns, "label"));
    label.setAttribute("value", "Установлен " + lab + " прокси: " + sel);

    tooltip.openPopup(menuitem.parentNode, "before_start");
    setTimeout(() => mainPopupSet.removeChild(tooltip), 3000);
};


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


В пункте URL автоматической настройки стоит http://antizapret.prostovpn.org/proxy.pac
Чтобы зайти на допустим сайт https://4pda.to/forum (в списке запрещеных) приходится пару раз нажать кнопку "Обновить" в пункте URL автоматической настройки и тогда все открывается.
Кто может объяснить

Отсутствует

 

№1600413-11-2021 16:09:57

Senflex
Участник
 
Группа: Members
Зарегистрирован: 18-07-2021
Сообщений: 29
UA: Chrome 95.0

Re: Custom Buttons

Как программно сделать скриншот сайта и сохранить его в определённую папку. Лиса 56.0.2. Заранее благодарю!

Отредактировано Senflex (13-11-2021 17:00:54)

Отсутствует

 

№1600513-11-2021 18:59:51

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

Re: Custom Buttons

Senflex пишет

Как программно сделать скриншот сайта и сохранить его в определённую папку. Лиса 56.0.2. Заранее благодарю!

За давностью не помню кто выкладывал кнопку.
Попробуйте, может подойдёт.

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

Выделить код

Код:

/*Initialization Code*/

// Сохранить как PNG ..........

self.label = "Сохранить как PNG";
self._handleClick =()=> menuPopup.showPopup(this, -1, -1, "popup", "bottomleft", "topleft");
self.image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGwSURBVHjarJPPaxNBGIafmd1km23saqtRaLB6kFYl2ELpRayCVL20RvCmJwk9ePNWvPsXtCA9eNCDeO0hLemPo96LYAuKkRhtsBViEtI0rrt+GyFQ1oMkfjAf883M+8w7w4zyfZ9uwsxms10RzCBNTd3sSLy2lvsDCCKzWMCKGHgotOTAlpamJPm+jCmFL00bmmbD5WlmsKXTdBltB3bcxowaLWJwsTpi4bvNVu1JMmVn5cmcqTB6/DAg3hcjGpUFskjZjlgFKdmvVIiISKlfUhlyQMVPywgDjvX1YCjpOBZ2fZ+9+TuUpxcZuz7Ebl7ArkfM0dgDcOAFCvfwHTi9URJJi2RCqEuPmRxPUXn9imodLo1D6orGjMHW6govZqfDDkYviDXBlZ4vsFsrk8vXqZRWeDY8hz55lvvpGU7sFEn0RhhTtTBg/tETCvlNdj68papsUoND3Lh6iyPOOYrvv/JufYNrqcssbW8zkjwdBnz7/JKL50/x4F4at9GgsFckX/2IefQHZyb6mbl9l2LpE8ff1PnufWkD/t87yC1v/pvi4V8AwZvuNFS33/m3AAMAhEeAiqLmty4AAAAASUVORK5CYII=";


var alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);


// Создать меню для кнопки .....
var array = [
   { label: "Сохранить всю страницу как PNG", func: "WebScreenShot.captureAll()", image: "data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAzAAAAiAcFBa4KCQmvCgkJrwoJCa8KCQmvCgkJrwoJCa8KCQmvCgkJrwoJCa8KCQmvCgkJrwsJCaECAQE/BQMDAAAAAJUgICD4V1ZW/2FhYf5hYWH/YmFh/2BgYP9fX1//X19f/19fX/9gYGD/YmFh/2FhYf9gYGD+ZmVl/1RSUuIVFBQtCgkJy1paWv+Li4v9h4eH/oiIiP6FhYX+i4uL/pKSkv6Sk5P+kpKS/ouLi/6FhYX+iIiI/oiIiP6Hh4f7lZaW/25tbYQNDQ3OcHBw/5KSkv6Li4v/i4uL/5mZmf+EhIT/ZGRk/1tbWv9kZGT/hISE/5mZmf+Li4v/jY2N/4yMjPyWl5f/iomJjQ4NDc13d3f/m5ub/pWVlf+goKD/XFxc/ygoKP8fHyD/GBsb/yAhIv8pKSn/W1tb/6CgoP+Wlpb/lpaW/J6env+Jh4eMDg4OzX1+fv+ioqL+qqqq/1hYWP8ZGRn/Ghwb/x4dHP8mIh//FhQR/xUWF/8aGhr/WFhY/6urq/+cnJz8pKSk/4qJiYwPDg7Ng4OD/7W1tf6MjIz/Ghoa/xYYGP8uKCb/ZEAo/5xyOP++saL/RD45/xISE/8bGxv/jY2N/6+vr/ypqan/ioiIjA8PD82IiIj/xMTE/l1cXP8LDAz/JiId/1o3LP9ADgD/mGog//Dt6P/VysX/Ih4Z/wsMDf9eXl7/v7+//K6urv+KiYmMEA8PzY+Pj//Kysr+SEhH/wEDBv9MPi7/hlES/3dCAP+VZAn/tJVO/7eVXf9OQTL/AAIE/0pJSf/FxcX8tLS0/4qJiYwQEBDNm5ub/9/e3/5SUlL/AAAA/0M7Mf/aya7/ybiO/5RmEf9aIAD/cjkX/z80KP8AAAD/U1JS/9nZ2fzAwMD/i4qKjBEREc2oqKn/8O/w/oeGhv8AAAD/DAsK/6qkof/17uj/nW8l/14eCf9hPTr/ExUU/wAAAP+Hh4f/6urq/MzMzf+Mi4uMERERzbCwsv/r6uz+3Nzd/yoqKv8AAAD/ExEP/2heU/9yWjv/UD0u/xcXFv8AAAD/Kioq/93d3v/l5eb81NTV/4yLi4wSERHNuLm5/+/v8P7z8/P/xsbG/yAgIP8AAAD/AQEB/wAAAP8BAQH/AAAA/yAgIP/Gxsb/9PT0/+np6vzb29v/jIuLjBIREc2+vb7/+Pj5/uvr7P/7+/v/4ODg/3Nyc/8uLi7/Hh4d/y0sLP9zc3P/4ODg//v7+//s7O3/8/P0/OHg4f+Mi4uLFBMTyMPDw//////7+Pj4/ff29v38/Pz9/////fr6+v3u7u79+vr6/f////38/Pz99/b2/fn5+f37+/v53t7e/5KSko4GBgZ7m5yc//j4+P/w8fH/8fLy//Dw8P/u7u7/8vLy//X19f/y8vL/7u7u//Dw8P/x8vL/8vLy/uXl5f/BwcH+k5GRUAAAAAQeHR1yb25uxn59fcZ9fHzGfXx8xn18fMZ9e3vGfHt7xn17e8Z9fHzGfXx8xn18fMZ9fHzGgH9/xYmIiGVaV1cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="},
   { separator: ''},
   { label: "Сохранить видимую часть страницы как PNG", func: "WebScreenShot.capturePage()", image: "data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAzAAAAiAcFBa4KCQmvCgkJrwoJCa8KCQmvCgkJrwoJCa8KCQmvCgkJrwoJCa8KCQmvCgkJrwsJCaECAQE/BQMDAAAAAJUgICD4V1ZW/2FhYf5hYWH/YmFh/2BgYP9fX1//X19f/19fX/9gYGD/YmFh/2FhYf9gYGD+ZmVl/1RSUuIVFBQtCgkJy1paWv+Li4v9h4eH/oiIiP6FhYX+i4uL/pKSkv6Sk5P+kpKS/ouLi/6FhYX+iIiI/oiIiP6Hh4f7lZaW/25tbYQNDQ3OcHBw/5KSkv6Li4v/i4uL/5mZmf+EhIT/ZGRk/1tbWv9kZGT/hISE/5mZmf+Li4v/jY2N/4yMjPyWl5f/iomJjQ4NDc13d3f/m5ub/pWVlf+goKD/XFxc/ygoKP8fHyD/GBsb/yAhIv8pKSn/W1tb/6CgoP+Wlpb/lpaW/J6env+Jh4eMDg4OzX1+fv+ioqL+qqqq/1hYWP8ZGRn/Ghwb/x4dHP8mIh//FhQR/xUWF/8aGhr/WFhY/6urq/+cnJz8pKSk/4qJiYwPDg7Ng4OD/7W1tf6MjIz/Ghoa/xYYGP8uKCb/ZEAo/5xyOP++saL/RD45/xISE/8bGxv/jY2N/6+vr/ypqan/ioiIjA8PD82IiIj/xMTE/l1cXP8LDAz/JiId/1o3LP9ADgD/mGog//Dt6P/VysX/Ih4Z/wsMDf9eXl7/v7+//K6urv+KiYmMEA8PzY+Pj//Kysr+SEhH/wEDBv9MPi7/hlES/3dCAP+VZAn/tJVO/7eVXf9OQTL/AAIE/0pJSf/FxcX8tLS0/4qJiYwQEBDNm5ub/9/e3/5SUlL/AAAA/0M7Mf/aya7/ybiO/5RmEf9aIAD/cjkX/z80KP8AAAD/U1JS/9nZ2fzAwMD/i4qKjBEREc2oqKn/8O/w/oeGhv8AAAD/DAsK/6qkof/17uj/nW8l/14eCf9hPTr/ExUU/wAAAP+Hh4f/6urq/MzMzf+Mi4uMERERzbCwsv/r6uz+3Nzd/yoqKv8AAAD/ExEP/2heU/9yWjv/UD0u/xcXFv8AAAD/Kioq/93d3v/l5eb81NTV/4yLi4wSERHNuLm5/+/v8P7z8/P/xsbG/yAgIP8AAAD/AQEB/wAAAP8BAQH/AAAA/yAgIP/Gxsb/9PT0/+np6vzb29v/jIuLjBIREc2+vb7/+Pj5/uvr7P/7+/v/4ODg/3Nyc/8uLi7/Hh4d/y0sLP9zc3P/4ODg//v7+//s7O3/8/P0/OHg4f+Mi4uLFBMTyMPDw//////7+Pj4/ff29v38/Pz9/////fr6+v3u7u79+vr6/f////38/Pz99/b2/fn5+f37+/v53t7e/5KSko4GBgZ7m5yc//j4+P/w8fH/8fLy//Dw8P/u7u7/8vLy//X19f/y8vL/7u7u//Dw8P/x8vL/8vLy/uXl5f/BwcH+k5GRUAAAAAQeHR1yb25uxn59fcZ9fHzGfXx8xn18fMZ9e3vGfHt7xn17e8Z9fHzGfXx8xn18fMZ9fHzGgH9/xYmIiGVaV1cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="},
   { separator: ''},
   { label: "Сохранить выбранный элемент страницы как PNG", func: "WebScreenShotByClick.init()", image: "data:image/x-icon;base64,AAABAAEAIBkAAAEAIAAMDQAAFgAAACgAAAAgAAAAMgAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD29fT/2tra/8jIyP/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8XFxf/FxcX/xcXF/8jIyP/a2tr/9vX0/+zs7P/ak0b/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/9qTRv/s7Oz/7Ozs/+J9Dv/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+/6SdmP/8+/r//Pv6//z7+v/8+/r//Pv6//z7+v/8+/r//Pv6//z7+v/8+/r/+vn4//z7+v/6+fj/4n0O/+zs7P/s7Oz/4n0O//z7+v/8+/r//Pv6//z7+v/8+/r//Pv6//z7+v/8+/r//Pv6//z7+v/8+/r//Pv6//z7+v/8+/r/aFtT//Lw7//y8O//8vDv//Lw7//y8O//8vDv//Lw7//y8O//8vDv//Lw7//y8O//8vDv//j39v/ifQ7/7Ozs/+zs7P/ifQ7/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P9oW1P/7+zq/+/s6v/v7Or/8O3r//Dt6//w7ev/8O3r//Dt6//w7ev/8O3r/+/s6v/w7ev/9fTy/+J9Dv/s7Oz/7Ozs/+J9Dv/49/b/+Pf2//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4/2hbU//q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/y8O//4n0O/+zs7P/s7Oz/4n0O//j39v/49/b/+Pf2//j39v/49/b/+Pf2//j39v/49/b/+Pf2//j39v/49/b/+Pf2//j39v/49/b/aFtT/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe//Dt6//ifQ7/7Ozs/+zs7P/ifQ7/9vX0//b19P/29fT/9vX0//b19P/29fT/9vX0//b19P/29fT/9vX0//b19P/29fT/9vX0//b19P9oW1P/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/7uro/+J9Dv/s7Oz/7Ozs/+J9Dv/08vH/9PLx//Ty8f/08vH/9PLx//Ty8f/08vH/9PLx//Ty8f/08vH/9PLx//Ty8f/08vH/9PLx/2hbU//x7+3/8vDv//Hv7f/x7+3/8e/t//Lw7//x7+3/8e/t//Lw7//x7+3/8vDv//Hv7f/29fT/4n0O/+zs7P/s7Oz/4n0O//Lw7//y8O//8vDv//Lw7//y8O//8vDv//Lw7//y8O//8vDv//Lw7//y8O//8vDv//Lw7//y8O//aFtT/6igmP+ooJj/qKCY/6igmP+ooJj/qKCY/6igmP+ooJj/qKCY/6igmP+ooJj/qKCY/8vGwf/ifQ7/7Ozs/+zs7P/ifQ7/8e/t//Hv7f/x7+3/8e/t//Hv7f/x7+3/8e/t//Hv7f/x7+3/8e/t//Hv7f/x7+3/8e/t//Hv7f9nWlL/aFtT/2hbU/9nWlL/Z1pS/2hbU/9oW1P/Z1pS/2daUv9oW1P/aFtT/2hbU/9nWlL/pJyX/+J9Dv/s7Oz/7Ozs/+J9Dv/w7ev/8O3r//Dt6//w7ev/8O3r//Dt6//x7+3/8O3r//Dt6//w7ev/8e/t//Dt6//w7ev/8O3r//Hv7f/w7ev/8O3r//Dt6//x7+3/8O3r//Dt6//w7ev/8e/t//Dt6//w7ev/8O3r//Dt6//w7ev/4n0O/+zs7P/s7Oz/4n0O/+/s6v/v7Or/7uro/+/s6v/v7Or/7+zq/+/s6v/v7Or/7+zq/+/s6v/v7Or/7+zq/+/s6v/v7Or/7+zq/+/s6v/v7Or/7+zq/+/s6v/v7Or/7+zq/+/s6v/v7Or/7+zq/+/s6v/u6uj/7+zq/+/s6v/ifQ7/7Ozs/+zs7P/ifQ7/7uro/+7q6P/u6uj/7uro/+zo5v/u6uj/7uro/+7q6P/s6Ob/7uro/+7q6P/u6uj/7Ojm/+7q6P/u6uj/7uro/+zo5v/u6uj/7uro/+7q6P/s6Ob/7uro/+7q6P/u6uj/7Ojm/+7q6P/u6uj/7Ojm/+J9Dv/s7Oz/7Ozs/+J9Dv/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/7Ojm/+zo5v/s6Ob/4n0O/+zs7P/s7Oz/4n0O/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/q5uT/6ubk/+rm5P/ifQ7/7Ozs/+zs7P/ifQ7/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+nl4v/p5eL/6eXi/+J9Dv/s7Oz/7Ozs/+J9Dv/m4d7/5uHe/+bh3v/p5eL/5uHe/+bh3v/m4d7/6eXi/+bh3v/m4d7/5uHe/+nl4v/m4d7/5uHe/+bh3v/p5eL/5uHe/+bh3v/m4d7/6eXi/+bh3v/m4d7/5uHe/+nl4v/m4d7/5uHe/+bh3v/p5eL/4n0O/+zs7P/s7Oz/4n0O/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/m4d7/5uHe/+bh3v/ifQ7/7Ozs/+zs7P/ifQ7/5uHe/+Tf3P/m4d7/5N/c/+bh3v/k39z/5uHe/+Tf3P/m4d7/5N/c/+bh3v/k39z/5uHe/+Tf3P/m4d7/5N/c/+bh3v/k39z/5uHe/+Tf3P/m4d7/5N/c/+bh3v/k39z/5uHe/+Tf3P/m4d7/5N/c/+J9Dv/s7Oz/7Ozs/+J9Dv/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/i3Nn/4tzZ/+Lc2f/k39z/4n0O/+zs7P/s7Oz/4n0O/+Lc2f/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/h29j/4dvY/+Hb2P/ifQ7/7Ozs/+zs7P/ifQ7/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+DZ1v/g2db/4NnW/+J9Dv/s7Oz/9fTy/+J9Dv/8+/r/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/+vn4//r5+P/6+fj/4n0O//X08v/8+/r/6KFU/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ifQ7/4n0O/+J9Dv/ooVT//Pv6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="},
   { separator: ''},
   { label: "Сохранить выбранную область страницы как PNG", func: "WebScreenShotByClipping.init()", image: "data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAADDn2Hfz5pE/8eVQP7IlkH/yJZB/8iWQf/IlUH/yJVA/8iVQP/IlED/yJQ//8iUP//IlD//yJM+/8iTPv/Hkj3/nI1w//bDbP//8OH//+zW///s1///69b//+rV///p1P//59L//+XQ///izf//38n//9vG///ZxP//1b///dG////Prf/KlkX/88N4/v37///99Pj//fT6//vy9v/68fT/+u/y//rt8P/66u3/+ufq//rl6P/64eT/+93h//3a3//71d7//9LK/86XR//0xHb//vv////18///9fT///f5///4////9f7///P8///v+f//7Pb//+nz///m8f//4eb//9vZ//3Y2v//1Mb/zphH//TGd//+/////Pj1///7///Q58r/m9aV/6TZnv+i15r/otWY/6LTlv+j0pb/mc6M/9DXuf//3+P//Nnc///Wyf/OmUf/9MZ3//7////8+/j//////53WnP+Y5pn/rvGv/6PvpP+e7p//me6b/5nvm/95533/mM+L///j7f/629z//9jL/86ZR//0xnf//v////z9+v//////qtup/8Xzxf/a/tn/z/vO/8n7yf/D+sL/xPvD/6Hzo/+j05b//+Tu//re3///2cz/zplI//XGeP/+/////P36//////+n26f/uvC6/9T71P/K+Mr/xvjG/8D3wP+/+L//nfCf/6LTlf//5u//+t/g///cz//OmUj/9MZ3//7////8/fr//////6rcqv/G9MX/3//f/9n92f/V/NX/0PzQ/9H+0P+s9a7/pdSY///o8f/64OL//9zP/86aSP/0xnf//v////z9+f//////ndid/5TjlP+v7q//qeyp/6jsqf+k7KX/p+6n/4Tlh/+Z0Y7//+r0//rh4v//3tH/zppI//TGd//+/////v77///////Y8Nj/p9+n/6/jr/+t4a3/rd2p/67bpv+u2ab/p9Wc/9jgx///6Oz//OPl///e0f/Omkj/9MV1//7//////fr///78///+/f///////////////////P////j////0+///8fn//+vu///m4v/94+P//97P/86ZSP/zx3v//v/////+/f///////f////v////7////+/////v+///7+///+/f///vz/P/98Pr//+33//3p9///5OL/zppL//a1Sv/0xoL/9cR7//XEfP/1xHz/9cR8//XEfP/1xH3/9cR8//XCev/1wXr/9b94//W9d//1u3X/87l0//y6bP/Llj7/+pMA/vWBAP/1gwD/9YMA//WDAP/1gwD/9YMA//WDAP/1gwD/9YQA//WEAP/1hAD/9YQA//WEAP/zhAH//okA/8qLIv3xpzP/4ptV/+OdU//jnVP/451T/+OdU//jnVP/451T/+OdU//jnVL/451S/+OdUv/jnVL/451S/+GdVf/qnUf/2aRJ/9q0c9/8yn7/98V5/vjGev/4xnr/+MZ6//jGev/4xnr/+MZ6//jGev/4xnr/+MZ6//jGev/4xnr/+MZ6/vrIe/+jj2y4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="},
];

var menuPopup = self.appendChild(document.createElement("menupopup"));
array.forEach((m,i)=> {
   if ("separator" in m) { menuPopup.appendChild(document.createElement("menuseparator")); return };
   var mItem = menuPopup.appendChild(document.createElement("menuitem"));
   mItem.setAttribute("label", m.label);
   mItem.setAttribute("class", "menuitem-iconic");
   if ("image" in m) mItem.setAttribute("image", m.image || array[i-1].image);
   if ("func" in m) mItem.addEventListener("command", ()=> eval(m.func.toString()));
});
menuPopup.setAttribute("onclick", "event.stopPropagation()");



// Сохранить как PNG страницу или части страницы .....
WebScreenShot = {
   capture: function(win, x, y, width, height) {
      var canvas = document.createElementNS(xhtmlns, 'canvas');
      canvas.style.display = 'inline';
      canvas.width = width;
      canvas.height = height;
      var ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, width, height);
      ctx.save();
      try {
        ctx.scale(1.0, 1.0);
      }
      catch(e) {
        alertsService.showAlertNotification("chrome://global/skin/icons/error-16.png", "Слишком большая страница, не могу сохранить всё",
                                            "Кликни чтобы сохранить сколько можно", true, "", (s, t)=> {
           if ( t == 'alertclickcallback' ) WebScreenShot.capture(content, 0, 0, width, width*17);
        }, "");
        return;
      }
      ctx.drawWindow(win, x, y, width, height, "rgb(255,255,255)");
      ctx.restore();
      var url = canvas.toDataURL("image/png");
      var url = Services.io.newURI(url, null, null);

      var fp = window.makeFilePicker();
      fp.init(window, "Сохранить как…", fp.modeSave);
      fp.appendFilters(fp.filterImages);
      fp.defaultExtension = "png";

      var fileName = getTabLabel();
      fileName = fileName.replace(/[:\\\/<>?*|"]+/g, '').replace(/\s+/g, '_').slice(0, 100).replace(/^\s+|\s+$/g, '');
      var fileDate = (function () {
        var d = new Date(), z = function(n){return (n < 10 ? '0' : '') + n};
        return '[' + z(d.getFullYear()) + '_' + z(d.getMonth()+1) + '_' + z(d.getDate()) + '÷' + z(d.getHours()) + '_' + z(d.getMinutes()) + '_' + z(d.getSeconds()) + ']';
      })();

      fp.defaultString = fileName + "_" + fileDate + ".png";
      if (fp.show() == fp.returnCancel || !fp.file) return;
      var wbp = window.makeWebBrowserPersist();
      parseInt(Services.appinfo.version) < 36
      ? wbp.saveURI(url, null, null, null, null, fp.file, null)
      : wbp.saveURI(url, null, null, null, null, null, fp.file, null); // если FF36+

      canvas.remove();
   },
   captureAll: function() {
      var win = content;
      WebScreenShot.capture(win, 0, 0, win.innerWidth + win.scrollMaxX, win.innerHeight + win.scrollMaxY);
   },
   capturePage: function() {
      var win = content, doc = win.document, body = doc.body, html = doc.documentElement;
      var scrX = (body.scrollLeft || html.scrollLeft) - html.clientLeft;
      var scrY = (body.scrollTop || html.scrollTop) - html.clientTop;
      WebScreenShot.capture(win, scrX, scrY, win.innerWidth, win.innerHeight);
   },
   // Запомнить изображение на странице как base64 .....
   onImage: function(image) {
      var canvas = document.createElementNS(xhtmlns, 'canvas');
      canvas.width = image.naturalWidth;
      canvas.height = image.naturalHeight;
      var ctx = canvas.getContext('2d');
      ctx.drawImage(image, 0, 0);
      var base64 = canvas.toDataURL();
      gClipboard.write(base64);

      // стиль для изображение на сплывающей подсказке .....
      var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
      var uri = makeURI('data:text/css,'+ encodeURIComponent('#alertImage { height: 25px !important; width: 25px !important; }'));
      sss.loadAndRegisterSheet(uri, 0);

      // всплывающая подсказка .....
      alertsService.showAlertNotification(base64, self.label, "Запомнил изображение как base64", false, "", (s, t)=> {
         if (t == 'alertfinished')
             sss.unregisterSheet(uri, 0); // удалить стиль когда подсказка закрывается
      }, "");
   }
};


// Сохранить выбранную область страницы как PNG .....
WebScreenShotByClipping = {
   capture: WebScreenShot.capture,
   handleEvent: function(e) {
      if (e.button) return false;
          e.preventDefault();
          e.stopPropagation();
          switch(e.type){
                 case 'mousedown':
                    this.downX = e.pageX;
                    this.downY = e.pageY;
                    this.bs.left = this.downX + 'px';
                    this.bs.top = this.downY + 'px';
                    this.body.appendChild(this.box);
                    this.flag = true;
                    break;
                 case 'mousemove':
                    if (!this.flag) return;
                    this.moveX = e.pageX;
                    this.moveY = e.pageY;
                    if (this.downX > this.moveX) this.bs.left = this.moveX + 'px';
                    if (this.downY > this.moveY) this.bs.top  = this.moveY + 'px';
                    this.bs.width = Math.abs(this.moveX - this.downX) + 'px';
                    this.bs.height = Math.abs(this.moveY - this.downY) + 'px';
                    break;
                 case 'mouseup':
                    this.uninit();
                    break;
          }
   },
   init: function() {
      this.win = document.commandDispatcher.focusedWindow;
      if (this.win == window) this.win = content;
      this.doc = this.win.document;
      this.body = this.doc.body;
      if (!this.body instanceof HTMLBodyElement){
          alertsService.showAlertNotification(self.image, self.label, "Не удается захватить!");
          return false;
      }
      this.flag = null;
      this.box = this.doc.createElement('div');
      this.bs = this.box.style;
      this.bs.border = '#0f0 dashed 2px';
      this.bs.position = 'absolute';
      this.bs.zIndex = '2147483647';
      this.defaultCursor = getComputedStyle(this.body, '').cursor;
      this.body.style.cursor = 'crosshair';
      ["click", "mouseup", "mousemove", "mousedown"].forEach(type=> this.doc.addEventListener(type, this, true));
   },
   uninit: function() {
      var pos = [this.win, parseInt(this.bs.left), parseInt(this.bs.top), parseInt(this.bs.width), parseInt(this.bs.height)];
      this.body.style.cursor = this.defaultCursor;
      this.body.removeChild(this.box);
      this.capture.apply(this, pos);
      ["click", "mouseup", "mousemove", "mousedown"].forEach(type=> this.doc.removeEventListener(type, this, true));
   },
};


// Сохранить фрейм на странице как PNG .....
WebScreenShotByClick = {
   capture: WebScreenShot.capture,
   getPosition: function() {
   var html = this.doc.documentElement;
   var body = this.doc.body;
   var rect = this.target.getBoundingClientRect();
   return [
          this.win
          ,Math.round(rect.left) + (body.scrollLeft || html.scrollLeft) - html.clientLeft
          ,Math.round(rect.top) + (body.scrollTop || html.scrollTop) - html.clientTop
          ,parseInt(rect.width)
          ,parseInt(rect.height)
          ];
   },
   highlight: function() {
      this.orgStyle = this.target.hasAttribute('style') ? this.target.style.cssText : false;
      this.target.style.cssText += 'outline: red 2px solid; outline-offset: 2px; -moz-outline-radius: 2px;';
   },
   lowlight: function(e) {
      if (this.orgStyle) this.target.style.cssText = this.orgStyle;
      else this.target.removeAttribute('style');
   },
   handleEvent: function(e) {
      switch(e.type){
             case 'click':
                if (e.button) return;
                e.preventDefault();
                e.stopPropagation();
                this.lowlight();
                var pos = this.getPosition();
                this.capture.apply(this, pos);
                this.uninit();
                break;
             case 'mouseover':
                if (this.target) this.lowlight();
                this.target = e.target;
                this.highlight();
                break;
      }
   },
   init: function() {
      this.win = content;
      this.doc = content.document;
      ["click", "mouseover"].forEach(type=> this.doc.addEventListener(type, this, true));
   },
   uninit: function() {
      this.target = false;
      ["click", "mouseover"].forEach(type=> this.doc.removeEventListener(type, this, true));
   },
};


// Получить название вкладки без не сохраняемых символов и лишних пробелов .....
function getTabLabel() {
   var label = gBrowser.selectedTab.label;
   var label = label.replace(/[:+.\\\/<>?*|"]+/g, " ").replace(/\s\s+/g, " ");
   return label.substring(0, 50);
};


«The Truth Is Out There»

Отсутствует

 

№1600613-11-2021 20:51:38

Пострел
Участник
 
Группа: Members
Зарегистрирован: 08-04-2021
Сообщений: 51
UA: Firefox 94.0

Re: Custom Buttons

Andrey_Krropotkin, здравствуйте.
В этом виновата ваша кнопка. Сейчас её проверил, на 4pda, с "proxy.pac" не пускает, просит капчу.
И еще заметил глюк, не дает скачать торрент, если это - magnet-ссылка.
   
Если хотите как временное решение, пока не исправят вашу кнопку, воспользуйтесь этой, попроще.

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

Выделить код

Код:

custombutton://%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0D%0A%3Ccustombutton%20xmlns%3Acb%3D%22http%3A//xsms.nm.ru/custombuttons/%22%3E%0A%20%20%3Cname%3E%u0423%u043F%u0440%u0430%u0432%u043B%u0435%u043D%u0438%u0435%20%u043D%u0430%u0441%u0442%u0440%u043E%u0439%u043A%u0430%u043C%u0438%20%u043F%u0440%u043E%u043A%u0441%u0438%3C/name%3E%0A%20%20%3Cimage%3E%3C%21%5BCDATA%5Bdata%3Aimage/png%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA0ElEQVR4nLWRMU4DQQxFn1cUqagoOAZSuhQ5BAflANAFKV2kHIMSpUmxtj9FAsxm5FVSxNKMRp7v5+8Z4z/EbWEAD21ms3ndY+eb896GEAjW67eX39wEEDHGavW4tL72BBBst4ddm+sA0gHNDBMxRgnwGDNigRlcupBOy+OYNcBdmd+YWQ3wVAmI8BiGr8ZBSxGZEPFcjxDuev94+jRADH8mBBgpAUqfOJu2uC2Kv+qBmoNXlKqg09scvSkoNcNMh2vOHeCah5xoLgGV8H6P+AMlwWDGRU9JUgAAAABJRU5ErkJggg%3D%3D%5D%5D%3E%3C/image%3E%0A%20%20%3Cmode%3E0%3C/mode%3E%0A%20%20%3Cinitcode%3E%3C%21%5BCDATA%5Bthis._handleClick%20%3D%28%29%3D%3E%20%7B%0A%20%20%20%20cbu.setPrefs%28s%2C%20cbu.getPrefs%28s%29%20%3D%3D%202%20%3F%205%20%3A%202%29%3B%0A%7D%3B%0A%0Avar%20s%20%3D%20%22network.proxy.type%22%3B%0Afunction%20toggleImage%28%29%20%7B%0A%20%20%20%20var%20%7Bicon%7D%20%3D%20self%3B%0A%20%20%20%20switch%28%20cbu.getPrefs%28s%29%20%29%20%7B%0A%20%20%20%20%20%20%20%20case%205%3A%20icon.src%20%3D%20%22data%3Aimage/png%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA5UlEQVR4nLWSMU4DMRBFv60gsWlTcow0cBHgYlwlucBK0FDScwKKpIni+fNTeFdrJ3iVIPGlke3xzJP97YBJwm0KALAoM6+b7RfCsPOLBGC12x/eXp7XY64C3HXd4eHpcX3ROWgHYP/+8VnmYrlITi5JmAQD6pDQuePoZNlTncBS0pHEvXu+ZMiXkQZ7JFgyNQGJdDfLjWOMAAmSkEifBfyQGRDjZKYEAZA7Eq0NoFHffd/n40dM7yFIPrIqlS/2p38wJxVjEz73Z66qD3N0lCY0FM/W4cb5BeAaI6uac0Cr8P9MPAG8Q3OjXdF9sAAAAABJRU5ErkJggg%3D%3D%22%3B%20break%3B%0A%20%20%20%20%20%20%20%20case%201%3A%20icon.src%20%3D%20%22data%3Aimage/png%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAyUlEQVR4nLWROw7CQAxExwEJpFDlGkh0FJyHc+U0FAjRIXGRfKr1hyLksxt2lRRMtbLs5/EsYZRhnQgAttPK9X59d3WKzBgAQ3kpj33FAzhhOZzzU2q+fbavackDsLBWWiUNqJimAKImQxpEHclsjCeTjcQB7KzRBgTyXRgGaM65F3bgQLTWetgc/oupYSf7+AlOWYtb8QAIHaO3Yd9TAAf2sKHRNYpFPQNOElhOiQ3M+ilFRxjCD2WJDUveM8CSIL2eEBBr/F+IHyKXWDEkGup0AAAAAElFTkSuQmCC%22%3B%20break%3B%0A%20%20%20%20%20%20%20%20case%202%3A%20icon.src%20%3D%20%22data%3Aimage/png%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA0ElEQVR4nLWRMU4DQQxFn1cUqagoOAZSuhQ5BAflANAFKV2kHIMSpUmxtj9FAsxm5FVSxNKMRp7v5+8Z4z/EbWEAD21ms3ndY+eb896GEAjW67eX39wEEDHGavW4tL72BBBst4ddm+sA0gHNDBMxRgnwGDNigRlcupBOy+OYNcBdmd+YWQ3wVAmI8BiGr8ZBSxGZEPFcjxDuev94+jRADH8mBBgpAUqfOJu2uC2Kv+qBmoNXlKqg09scvSkoNcNMh2vOHeCah5xoLgGV8H6P+AMlwWDGRU9JUgAAAABJRU5ErkJggg%3D%3D%22%3B%20break%3B%0A%20%20%20%20%20%20%20%20default%3A%20icon.src%20%3D%20self.image%3B%0A%20%20%20%20%7D%0A%7D%0AtoggleImage%28%29%3B%0AServices.prefs.addObserver%28s%2C%20toggleImage%2C%20false%29%3B%0AaddDestructor%28%28%29%20%3D%3E%20Services.prefs.removeObserver%28s%2C%20toggleImage%29%29%3B%0A%0A%0Avar%20toggleButton%20%3D%20%7B%0A%20%20%20%20observe%28s%2C%20t%2C%20data%29%20%7B%0A%20%20%20%20%20%20%20%20cbu.getPrefs%28%22CB.Proxy.reset%22%29%20%26%26%20data%20%3D%3D%20%22shutdown%22%20%26%26%20cbu.setPrefs%28%22network.proxy.type%22%2C%205%29%3B%0A%20%20%20%20%7D%0A%7D%3B%5D%5D%3E%3C/initcode%3E%0A%20%20%3Ccode%3E%3C%21%5BCDATA%5Bthis.onclick%20%3D%20this.oncontextmenu%20%3D%20e%20%3D%3E%20%7B%0A%20%20%20%20switch%20%28e.button%29%20%7B%0A%20%20%20%20%20%20%20%20case%200%3A%20cbu.setPrefs%28s%2C%20cbu.getPrefs%28s%29%20%21%3D%202%20%3F%202%20%3A%200%29%3B%20break%0A%20%20%20%20%20%20%20%20case%201%3A%20cbu.getPrefs%28s%29%20%21%3D%205%20%26%26%20cbu.setPrefs%28s%2C%205%29%3B%20break%3B%0A%20%20%20%20%20%20%20%20case%202%3A%0A%20%20%20%20%20%20%20%20if%20%28e.shiftKey%20%7C%7C%20e.ctrlKey%20%7C%7C%20e.altKey%20%7C%7C%20e.metaKey%29%20return%3B%0A%20%20%20%20%20%20%20%20e.preventDefault%28%29%3B%20e.stopPropagation%28%29%3B%0A%20%20%20%20%20%20%20%20const%20url%20%3D%20%22about%3Apreferences%23advanced%22%2C%0A%20%20%20%20%20%20%20%20tab%20%3D%20gBrowser.selectedTab%20%3D%20gBrowser.addTab%28url%29%2C%0A%20%20%20%20%20%20%20%20br%20%3D%20tab.linkedBrowser%2C%0A%20%20%20%20%20%20%20%20onPageShow%20%3D%20e%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20win%20%3D%20e.target.defaultView%2C%20%7Btop%7D%20%3D%20win%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28top.location.href%20%3D%3D%20url%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20br.removeEventListener%28%22pageshow%22%2C%20onPageShow%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20gSubDialog%20%3D%20top.gSubDialog%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gSubDialog.open%28%22chrome%3A//browser/content/preferences/dialogs/connection.xhtml%22%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%3B%0A%20%20%20%20%20%20%20%20br.addEventListener%28%22pageshow%22%2C%20onPageShow%29%3B%0A%20%20%20%20%20%20%20%20break%3B%0A%20%20%20%20%7D%0A%7D%3B%5D%5D%3E%3C/code%3E%0A%20%20%3Caccelkey%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/accelkey%3E%0A%20%20%3Chelp%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/help%3E%0A%20%20%3Cattributes/%3E%0A%3C/custombutton%3E


   
Ребят, у кого есть кнопка переключающая в about:config, числовой параметр, то-есть 1 в 2 и обратно, с переключением иконок.
Поделитесь пожалуйста. Поиском рабочих кнопок не нашел. Нужно как шаблон.

Отсутствует

 

№1600713-11-2021 21:40:11

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 336
UA: Firefox 94.0

Re: Custom Buttons

Пострел
Почему 1 и 2 ? Пример (автомедиа)

Выделить код

Код:

custombutton://%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0D%0A%3Ccustombutton%20xmlns%3Acb%3D%22http%3A//xsms.nm.ru/custombuttons/%22%3E%0A%20%20%3Cname%3EStopautoplay%3C/name%3E%0A%20%20%3Cimage%3E%3C%21%5BCDATA%5Bdata%3Aimage/svg+xml%3Bbase64%2CPCEtLSBUaGlzIFNvdXJjZSBDb2RlIEZvcm0gaXMgc3ViamVjdCB0byB0aGUgdGVybXMgb2YgdGhlIE1vemlsbGEgUHVibGljCiAgIC0gTGljZW5zZSwgdi4gMi4wLiBJZiBhIGNvcHkgb2YgdGhlIE1QTCB3YXMgbm90IGRpc3RyaWJ1dGVkIHdpdGggdGhpcwogICAtIGZpbGUsIFlvdSBjYW4gb2J0YWluIG9uZSBhdCBodHRwOi8vbW96aWxsYS5vcmcvTVBMLzIuMC8uIC0tPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIGZpbGw9IiNGRjAwMDAiIGZpbGwtb3BhY2l0eT0iMSI+CiAgPHBhdGggZD0iTTE0Ljk0NCA0LjA1NmwtMS40NzggMS40NzhhNS45ODkgNS45ODkgMCAwIDEtNy45MyA3LjkzbC0xLjQ4NSAxLjQ4NUE3Ljk4MSA3Ljk4MSAwIDAgMCAxNC45NDQgNC4wNTZ6Ii8+CiAgPHBhdGggZD0iTTExLjk3NCA3LjAyNmwtNC42MDggNC42MDggNC44LTIuNzcxYTEgMSAwIDAgMCAwLTEuNzI2eiIvPgogIDxwYXRoIGQ9Ik0xNC43MDcgMS4yOTNhMSAxIDAgMCAwLTEuNDE0IDBsLS40LjRBNy44IDcuOCAwIDAgMCAxMC45OC41NzRhMSAxIDAgMCAwLS43NDYgMS44NTYgNS43NjcgNS43NjcgMCAwIDEgMS4yMzQuNjg4TDkuMTc1IDUuNDExIDYuNDk0IDMuODYzQTEgMSAwIDAgMCA1IDQuNzI2djQuODZsLTEuODg1IDEuODg1QTUuOTE5IDUuOTE5IDAgMCAxIDMgNC43MjFWNmEuNS41IDAgMCAwIDEgMFYyLjVhLjUuNSAwIDAgMC0uNS0uNWgtM2EuNS41IDAgMCAwIDAgMWgxLjI2MmE3Ljk2MyA3Ljk2MyAwIDAgMC0uMDc0IDkuOWwtLjM5NS4zOTVhMSAxIDAgMSAwIDEuNDE0IDEuNDE0bDEyLTEyYTEgMSAwIDAgMCAwLTEuNDE2eiIvPgo8L3N2Zz4K%5D%5D%3E%3C/image%3E%0A%20%20%3Cmode%3E0%3C/mode%3E%0A%20%20%3Cinitcode%3E%3C%21%5BCDATA%5B%28ps%20%3D%3E%20%7B%0A%0A%0A%20%20%20%20var%20s%20%3D%20%22media.autoplay.default%22%3B%0A%20%0A%20%20%20%20this._handleClick%20%3D%20%28%29%20%3D%3E%20ps.setIntPref%28s%2C%20ps.getIntPref%28s%2C%205%29%20%3F%200%20%3A%205%29%3B%0A%0A%20%20%20%20var%20toggleImage%20%3D%20val%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20this.icon.src%20%3D%20%28val%20%3D%20ps.getIntPref%28s%2C%205%29%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%3F%20this.image%0A%20%20%20%20%20%20%20%20%20%20%20%20%3A%20%22data%3Aimage/svg+xml%3Bcharset%3Dutf-8%3Bbase64%2CPCEtLSBUaGlzIFNvdXJjZSBDb2RlIEZvcm0gaXMgc3ViamVjdCB0byB0aGUgdGVybXMgb2YgdGhlIE1vemlsbGEgUHVibGljCiAgIC0gTGljZW5zZSwgdi4gMi4wLiBJZiBhIGNvcHkgb2YgdGhlIE1QTCB3YXMgbm90IGRpc3RyaWJ1dGVkIHdpdGggdGhpcwogICAtIGZpbGUsIFlvdSBjYW4gb2J0YWluIG9uZSBhdCBodHRwOi8vbW96aWxsYS5vcmcvTVBMLzIuMC8uIC0tPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjE5IiBoZWlnaHQ9IjE5IiB2aWV3Qm94PSIwIC0xIDE3IDE5IiBmaWxsPSJ5ZWxsb3ciIGZpbGwtb3BhY2l0eT0iY29udGV4dC1maWxsLW9wYWNpdHkiPgogIDxwYXRoIGQ9Ik0xMC45OC41NzRhMSAxIDAgMCAwLS43NDYgMS44NTZBNi4wMzQgNi4wMzQgMCAxIDEgMyA0LjcyMVY2YS41LjUgMCAwIDAgMSAwVjIuNWEuNS41IDAgMCAwLS41LS41aC0zYS41LjUgMCAwIDAgMCAxaDEuMjYyQTggOCAwIDEgMCAxMC45OC41NzR6Ii8+CiAgPHBhdGggZD0iTTYuNDk0IDEyLjEzN2w1LjY3Mi0zLjI3NGExIDEgMCAwIDAgMC0xLjcyNkw2LjQ5NCAzLjg2M0ExIDEgMCAwIDAgNSA0LjcyNnY2LjU0OGExIDEgMCAwIDAgMS40OTQuODYzeiIvPgo8L3N2Zz4K%22%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20this.tooltipText%20%3D%20val%20%3F%20%27Stop%20AutoMedia%27%20%3A%20%27Play%20AutoMedia%27%3B%20%0A%20%20%20%20%20%20%0A%20%20%20%20%7D%0A%20%20%20%20toggleImage%28%29%3B%0A%20%20%20%20ps.addObserver%28s%2C%20toggleImage%2C%20false%29%3B%0A%20%20%20%20addDestructor%28%28%29%20%3D%3E%20ps.removeObserver%28s%2C%20toggleImage%29%29%3B%0A%7D%29%28Services.prefs%29%3B%0A%0Athis.oncontextmenu%20%3De%3D%3E%20%7B%20e.button%20%26%26%20%21e.ctrlKey%20%26%26%20e.preventDefault%28%29%20%7D%3B%0Athis.onclick%20%3D%20e%20%3D%3E%20e.button%20%21%3D%201%20%7C%7C%20gShowPopup%28this%29%3B%20%0A%0A%0A%5D%5D%3E%3C/initcode%3E%0A%20%20%3Ccode%3E%3C%21%5BCDATA%5B/*CODE*/%5D%5D%3E%3C/code%3E%0A%20%20%3Caccelkey%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/accelkey%3E%0A%20%20%3Chelp%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/help%3E%0A%20%20%3Cattributes/%3E%0A%3C/custombutton%3E

Отсутствует

 

№1600814-11-2021 00:27:06

Пострел
Участник
 
Группа: Members
Зарегистрирован: 08-04-2021
Сообщений: 51
UA: Firefox 94.0

Re: Custom Buttons

ВВП.
Да, для примера.
То что искал, лаконично-незамудрённую. Кстати полезная кнопка.
Спасибо за оперативность. Очень выручили.

Отсутствует

 

№1600914-11-2021 23:27:05

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

Re: Custom Buttons

Пострел спасибо работает

Добавлено 14-11-2021 23:42:50
Dumby можешь объяснить этот казус, вот кнопка и мое сообщение, вот Пострел в своем посте дал временное решение В чем прикол, вроде кнопка, по моему твоя, вообще не влияет на то как браузер использует прокси, там только форма и порядок выбора действий и от адреса не зависит, или я в чем то ошибаюсь. будь добр разъясни.

Отредактировано Andrey_Krropotkin (14-11-2021 23:42:50)

Отсутствует

 

№1601015-11-2021 12:21:27

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 336
UA: Firefox 94.0

Re: Custom Buttons

Andrey_Krropotkin
network.proxy.type - 0 ....Это по умолчанию  Прописать можно в greprefs.js
И сама кнопка

Выделить код

Код:

custombutton://%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0D%0A%3Ccustombutton%20xmlns%3Acb%3D%22http%3A//xsms.nm.ru/custombuttons/%22%3E%0A%20%20%3Cname%3EProxy%3C/name%3E%0A%20%20%3Cimage%3E%3C%21%5BCDATA%5Bdata%3Aimage/png%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACFUlEQVR42mO0DwpKaG9vL2VmZmb8+/fvPwY84P///2DMwcHBcuHChZcp4eE5jJeePn2hIyUl/uDTJwZuLi4GFhYWBmZsmqH073//GD5+/MigIijIEJmTM4Px1Z8/H86dP8/vbmrKQBIAuiS1omIp46u/fz9cunSJ39nQkCT934AGZBUXL2F8+///h/MXLpBswMvfvxnKy8uXMH4GGnDg+HF+Hysr8gwAOuXDvhMn+L0tLUky4On37wzV1dUQAw6fPcvvZmJCkgEPP39mqK+vX8L4E2QAGWFw9/17hubm5iWMv4AGnL55k99KQ4MkA+68e8fQ0dGxlPHxt28vZDg5xUGCf4H4JxD/AOI/f/8y/AMmmt/AwAJhYCplYGRkZPjz5w9YnJeXFxSICxhN3N3zSkpK8kH6371791UOCHR0dIR+/frFAMIgDaDk++rVq78XL158BBT7xMPDw/f69evvrXV1pYxAjSDMA8R8wWlphfn5+SlAM/iB6R1sI0jz169fwfjs2bN3m5qaWu+fObMO6uAvjDA/uUdFle1YurQTxP4KxL+AmAnkFSAGuoxBREiIQRAU+l++fFHg5QXF+RUGqO0QICRkt2z58mU+bm7SXFADfkGl2ICYBYjfAsMCmHNPTaqvDwFyH6MaAAFyMvr6Eebm5hbq6uqyQL9yAQPs/5s3bz4D/X//8OHDh/68fLkWqO41TAMAPUoMne+Z1jQAAAAASUVORK5CYII%3D%5D%5D%3E%3C/image%3E%0A%20%20%3Cmode%3E0%3C/mode%3E%0A%20%20%3Cinitcode%3E%3C%21%5BCDATA%5B%0A%20%28ps%20%3D%3E%20%7B%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%0A%20%20%20this._handleClick%20%3D%20%28%29%20%3D%3E%20%7B%0A%09%09var%20direct%20%3D%20ps.getIntPref%28s%29%20%3D%3D%200%3B%0A%09%09var%20msg%20%3D%20%60%u041F%u0440%u043E%u043A%u0441%u0438%20%u0441%u0435%u0440%u0432%u0435%u0440%u044B%20%3A%20%u0412%24%7Bdirect%20%3F%20%22%22%20%3A%20%22%u044B%22%7D%u043A%u043B%u044E%u0447%u0438%u0442%u044C%20%3F%60%3B%0A%0A%09%09if%20%28%21Services.prompt.confirm%28null%2C%20%22%u0412%u041D%u0418%u041C%u0410%u041D%u0418%u0415%20%21%22%2C%20msg%29%29%20return%3B%0A%0A%09%09ps.setIntPref%28s%2C%20direct%20%3F%202%20%3A%200%29%3B%0A%09%09var%20method%20%3D%20%60%24%7Bdirect%20%3F%20%22en%22%20%3A%20%22dis%22%7Dable%60%3B%0A%09%09AddonManager.getAddonByID%28%22%7Bacf99872-d701-4863-adc2-cdda1163aa34%7D%22%29%0A%09%09%09.then%28addon%20%3D%3E%20addon%5Bmethod%5D%28%29%2C%20Cu.reportError%29%3B%0A%09%7D%0A%20%20%20%20%20var%20s%20%3D%20%22network.proxy.type%22%3B%0A%20%0A%20%20%20%20var%20toggleImage%20%3D%20val%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20this.icon.src%20%3D%20%28val%20%3D%20ps.getIntPref%28s%2C%202%29%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%3F%20this.image%0A%20%20%20%20%20%20%20%20%20%20%20%20%3A%20%22data%3Aimage/png%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACFklEQVR42mO0DwpKaG9vL2VmZmb8+/fvPwY84P///2DMwcHBcuHChZcp4eE5jJeePn2hIyUl/uDTJwZuLi4GFhYWBmZsmqH073//GD5+/MigIijIEJmTM4Px1Z8/H86dP8/vYWrKQAoAuSS1omIp46u/fz9cunSJ38XQkCQDvgINyCouXsL49v//D+cvXCDZgBe/fzOUl5cvYfwMNODA8eP8vlZW5BnwDWjAvhMn+H0sLUky4Mn37wzV1dUQAw6fPcvvbmJCkgEPPn9mqK+vX8L4E2QAGWFw5/17hubm5iWMv4AGnL55k99aQ4MkA26/e8fQ0dGxlPHxt28vZDg5xUGCf4H4JxD/AOI/f/8y/AMmmt/AwAJhYCplYGRkZPjz5w9YnJeXFxSICxhN3N3zSkpK8kH6371791UOCHR0dIR+/frFAMIgDaBE8+rVq78XL158BBT7xMPDw/f69evvrXV1pYxAjSDMA8R8wWlphfn5+SlAM/iB6R1sI0jz169fwfjs2bN3m5qaWu+fObMO6uAvjDA/uUdFle1YurQTxP4KxL+AmAnkFSAGuoxBREiIQRDIfvjlyxcFXl5QnF9hgNoOAUJCdsuWL1/m4+YmzQU14BdUig2IWYD4LTAsgDn31KT6+hAg9zGqARAgJ6OvH2Fubm6hrq4uC/QrFzDA/r958+Yz0P/3Dx8+fOjPy5drgepewzQAAJP3DZ3PnU32AAAAAElFTkSuQmCC%22%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20this.tooltipText%20%3D%20val%20%3F%20%27%u0410%u0432%u0442%u043E%u043F%u0440%u043E%u043A%u0441%u0438%27%20%3A%20%27%u0411%u0435%u0437%20%u043F%u0440%u043E%u043A%u0441%u0438%27%3B%0A%0A%0A%0A%20%20%20%20%20%20%20%20BrowserReload%28%29%3B%0A%20%0A%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%7D%0A%20%20%20%20toggleImage%28%29%3B%0A%20%20%20%20ps.addObserver%28s%2C%20toggleImage%2C%20false%29%3B%0A%20%20%20%20addDestructor%28%28%29%20%3D%3E%20ps.removeObserver%28s%2C%20toggleImage%29%29%3B%0A%7D%29%28Services.prefs%29%3B%0Athis.onclick%20%3D%20e%20%3D%3E%20e.button%20%21%3D%201%20%7C%7C%20gShowPopup%28this%29%3B%20%0Athis.oncontextmenu%20%3De%3D%3E%20%7B%20e.button%20%26%26%20%21e.ctrlKey%20%26%26%20e.preventDefault%28%29%20%7D%3B%0A%0A%5D%5D%3E%3C/initcode%3E%0A%20%20%3Ccode%3E%3C%21%5BCDATA%5B/*CODE*/%0A%5D%5D%3E%3C/code%3E%0A%20%20%3Caccelkey%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/accelkey%3E%0A%20%20%3Chelp%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/help%3E%0A%20%20%3Cattributes/%3E%0A%3C/custombutton%3E

Отсутствует

 

№1601115-11-2021 13:41:37

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

Re: Custom Buttons

Andrey_Krropotkin пишет

Dumby можешь объяснить этот казус

Нет, не могу, мне это проверить негде.
Но могу поделиться неким предположением.

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

Если перед переключением на pac настройка хотябы раз переключалась
в значение autodetect (4) или system (5), то при переключении на pac (2) PAC-файл будет перезагружен.


А если перед переключением на pac настройка ни разу не побывала
в значении autodetect или в значении system, то есть переключалась
только на direct (0) или manual (1), или только между ними, то PAC-файл перезагружен не будет.
Ну, кроме самого первого переключения на pac (после старта браузера).


У Пострел'а в коде жёстко прописано переключение system <—> pac (5 <—> 2),
а ты своей кнопкой, возможно, переключался direct <—> pac (0 <—> 2), отсюда и различие.


Проверить можешь просто: попробуй своей кнопкой переключаться только между
«Использовать системные настройки прокси» <—> «URL автоматической настройки сервиса прокси»,
если всё в порядке, значит оно.
И, наверно, не лишним будет открыть адрес PAC-файла во вкладке и почитать комментарии в начале,
про «once a minute», особенно.

Отсутствует

 

№1601218-11-2021 01:02:23

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 471
UA: Firefox 87.0

Re: Custom Buttons

Dumby пишет

Совсем разные вещи. У RV pageAction, а у VDH browserAction.

Такой способ обновления подсказок сложен, нужно подстраиваться под каждую кнопку! Я ожидал простой код обновления подсказок любых кнопок панели.
Сделал mouseenter для панелей page-action-buttons и nav-bar-customization-target. Подсказка обновляется при наведении:

Выделить код

Код:

var rv_btn = document.getElementById(`pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_`);
	if ((e.target == rv_btn) && (!/Режим/.test(rv_btn.tooltipText)))  // Reader View
		rv_btn.tooltipText = rv_help;

Отсутствует

 

№1601318-11-2021 10:11:12

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

Re: Custom Buttons

Dobrov пишет

Сделал mouseenter

Так если mouseenter устраивает, то что ты мне голову морочишь.
И раз «ожидал простой код», то можно ещё проще

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

Выделить код

Код:

var tooltips = {
	"pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_": "RV Tooltip",
	"_b9db16a4-6edc-47ec-a1f4-b86292ed211d_-browser-action": "VDH Tooltip",
};

.......

	var trg = e.target, ttt = tooltips[trg.id];
	if (ttt) trg.tooltipText = ttt;

для панелей page-action-buttons и nav-bar-customization-target

page-action-buttons то зачем?
Это дочерний элемент того же nav-bar-customization-target.

Отсутствует

 

№1601421-11-2021 01:31:25

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 336
UA: Firefox 94.0

Re: Custom Buttons

Dumby
Не могу запустить две 94 . Или профиль один работает... Может в INI что то новое надо ?

Отсутствует

 

№1601521-11-2021 06:13:27

Dobrov
Участник
 
Группа: Members
Зарегистрирован: 04-10-2011
Сообщений: 471
UA: Firefox 87.0

Re: Custom Buttons

Dumby пишет

Так если mouseenter устраивает, то что ты мне голову морочишь.

И не думал! Цель - улучшить демо-профиль, где многие скрипты уже включены. mouseenter не устраивает цитата в теме UCF: у меня перестал обрабатываться долгий клик в скрипте ToggleAboutConfig, когда добавил addEventListener("mouseenter" для nav-bar-customization-target в скрипт ucf_hookClicks. Ещё back/forward-button при "mouseenter" открывают меню, а не переходят вперёд/назад.
Я просил код, который может добавлять дополнительные клики на уже существующие кнопки тулбара, что позволит проще расширять их возможности, используя один скрипт.


Пробовал изменить твой код перехвата кликов, но не разобрался! Нужно, чтобы работало примерно так:
Изменение яркости скролом над "identity-box" вместо ★, перехват событий указанных id кнопок в начале кода, разбор как в твоём коде кликов:
512: saveSelectionToTxt, // СКМ Click (сохранить .txt) цифра содержит сумму событий: id кнопки, клавиша мыши, управляющие клавиши, дубль-клик, единица для scroll+ равно (num+1), scroll- результат: отрицательное число -(num+1). И добавить LongPress по возможности

ucf_hookClicks.js - события для указнных в начале кода пяти кнопок - строка 140

Выделить код

Код:

(async (id, func) => { // для custom_script_win.js: дополнительные клики и подсказки кнопок
	await window.delayedStartupPromise; var
	nav = document.getElementById("nav-bar-customization-target"), // кнопки панели
	btn = document.getElementById("downloads-button"), // 0 Загрузки
	pui = document.getElementById("PanelUI-menu-button"), // 1 меню
	fav = document.getElementById("star-button"), // 2
	vdh = "_b9db16a4-6edc-47ec-a1f4-b86292ed211d_-browser-action", // 3 Video DownloadHelper
	rv = "pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_"; // 4 Reader View
	if (!btn) return; btn_help =`

Двойной клик: ⬇︎ открыть [Загрузки]
…на картинке: ⧉ найти Похожие\n
Правый клик (Alt+S):  Сохранить
   в единый html всё / выделенное
…дважды  Картинки вкл/выкл\n
Ролик:	 Сохранить как файл .txt
Колёсико на рисунке: ➜ Сохранить`,	sgs_help =
`\nAlt⇧S	 ⌨ нажатие SingleSave`, PanelUI_help =

`Клик мыши:	меню Firefox ${Services.appinfo.platformVersion}
…+ Shift		⚑ Краткая справка
…+ Alt		Персонализация
Клик дважды	⊠ закрыть браузер \n
Правый клик	⇲ Свернуть
…+ дважды	⤾ Вернуть вкладку
…+ Alt		Диспетчер задач
…+ Shift		Адаптивный дизайн\n
Колёсико:	Развернуть | окно
…+ Alt		Полный экран
…+ дважды	Обновить без кэша`, rv_help =

`Reader View	${Services.appinfo.OS == "Darwin" ? "⌥⌘M" : "Ctrl+⇧+M"}\n
Клик мыши	Режим для чтения
Колёсико	Адаптивный дизайн`, vdh_help =

`Video DownloadHelper\nСкачивание проигрываемого видео`;

	var addDestructor = nextDestructor => {
		var {destructor} = ucf[id];
		ucf[id].destructor = () => {
			try {destructor();} catch(ex) {Cu.reportError(ex);}
			nextDestructor();
		}
	},
	switchToTab = (but, url) => { // открыть вкладку | закрыть, если открыта
		for(var tab of but.ownerGlobal.gBrowser.tabs)
			if ( tab.linkedBrowser.currentURI.spec == url ) {but.ownerGlobal.gBrowser.removeTab(tab); return;}; // закрыть
		but.ownerGlobal.switchToTabHavingURI(url, true, {relatedToCurrent: true, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()});
	},
	showInStatusPanel = (info, time = 5000) => {
		var win = Services.wm.getMostRecentWindow("navigator:browser"); StatusPanel = win.StatusPanel;
		if (StatusPanel.update.tid)
			clearTimeout(StatusPanel.update.tid)
		else {
			var {update} = StatusPanel;
			StatusPanel.update = () => {};
			StatusPanel.update.ret = () => {
				StatusPanel.update = update;
				StatusPanel.update();
			}
		}
		StatusPanel.update.tid = setTimeout(StatusPanel.update.ret, time);
		StatusPanel._label = info;
	},
	Title = (max, title) => { // получить заголовок. без обрезки: max не указан, домен: max <0, + дата: max=0
		if (!title) var title = document.title || gBrowser.selectedTab.label;
		if (max == undefined) return title; // заголовок как есть или ограничить длину, убрать служебные символы
		title = title.replace(/[\\\/?*\"'`]+/g,'').replace(/\s+/g,' ').replace(/[|<>]+/g,'_').replace(/:/g,'։').trim();
		if ( max > 0 ) return title.slice(0, max);
		if ( max == 0) return title.slice(0, 100) +"_"+ new Date().toLocaleDateString('ru', {day: 'numeric', month: 'numeric', year: '2-digit'}) +'-'+ new Date().toLocaleTimeString().replace(/:/g, "։");
		var host = decodeURIComponent(gURLBar.value); // max < 0
		if (!/^file:\/\//.test(host)) host = host.replace(/^.*url=|https?:\/\/|www\.|\/.*/g,'');
		return host.replace(/^ru\.|^m\.|forum\./,'').replace(/^club\.dns/,'dns');
	},
	saveSelectionToTxt = async () => { // сохранить страницу или выделенный текст как файл .txt
		var splice = saveURL.length == 10;
		var msgName = id + ":Save:GetSelection";
		var receiver = msg => {
			var args = ["data:text/plain," + encodeURIComponent(gBrowser.currentURI.spec + "\n\n" + msg.data),
				Title(0) + '.txt', null, false, true, null, window.document];
			splice && args.splice(5, 0, null);
			saveURL(...args); showInStatusPanel("√ текст сохранён: "+ Title(0).slice(0, 60));
		}
		messageManager.addMessageListener(msgName, receiver);
		addDestructor(() => messageManager.removeMessageListener(msgName, receiver));
		var func = fm => {
			var res, fed, win = {}, fe = fm.getFocusedElementForWindow(content, true, win);
			var sel = (win = win.value).getSelection();
			if (sel.isCollapsed) {
				var ed = fe && fe.editor;
				if (ed && ed instanceof Ci.nsIEditor)
					sel = ed.selection, fed = fe;
			}
			if (sel.isCollapsed)
				fed && fed.blur(), docShell.doCommand("cmd_selectAll"),
				res = win.getSelection().toString(), docShell.doCommand("cmd_selectNone"),
				fed && fed.focus();
			res = res || sel.toString();
			/\S/.test(res) && sendAsyncMessage("saveSelectionToTxt", res);
		}
		var url = "data:;charset=utf-8," + encodeURIComponent(`(${func})`.replace("saveSelectionToTxt", msgName)) + '(Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager));';
		(saveSelectionToTxt = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))();
	},
	save = async () => { // SingleHtml by Лекс, правка: Dumby, Dobrov
		var msgName = id + "ucfDwnldsBtnSaveSnapshotToHTML";
		if (typeof IOUtils != "object") { // Firefox 78 ESR
			var {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
			var PathUtils = {join: (...args) => OS.Path.join(...args)};
			var IOUtils = {writeUTF8: (path, txt) => OS.File.writeAtomic(path, new TextEncoder().encode(txt))};
		}
		var write = IOUtils.writeUTF8 ? "writeUTF8" : "writeAtomicUTF8";
		var msgListener = async msg => {
			var [fileContent, fileName] = msg.data, dir; // fileName: выделенный текст или null
			try {dir = prefs.getComplexValue("browser.download.dir", Ci.nsIFile);} catch {dir = dirsvc.get("DfltDwnld", Ci.nsIFile);}
			var arr = prefs.getStringPref("ucf_save.dirs","_Web||_Images|0").split('|').slice(0,2); //subdir: title|host
			arr[1] = (arr[1] == "0") ? Title(100) : (arr[1] == "1") ? Title(-1) : ""; // имя вкладки или домен
			arr.forEach(dir.append); // ucf_save.dirs = "_Web||_Pics|1" HTML сохранится в папку [Загрузки]/_Web/label
			dir.exists() && dir.isDirectory() || dir.create(dir.DIRECTORY_TYPE, 0o777); // создать, если не существует…
			var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
			file.initWithPath(dir.path);
			if (!fileName) fileName = Title(100); // убрать служебные символы
			dir.append(Title(0, fileName) +'.html');
			await IOUtils[write](dir.path, fileContent) && showInStatusPanel("√ страница записана: " + fileName.slice(0, 60));
			var d = await Downloads.createDownload({ source: "about:blank", target: FileUtils.File(dir.path)}); // Fake download
			(await Downloads.getList(Downloads.ALL)).add(d);
			d.refresh(d.succeeded = true); // кнопка Загрузки мигает
		}
		messageManager.addMessageListener(msgName, msgListener);
		addDestructor(() => messageManager.removeMessageListener(msgName, msgListener));

		var svc = 'globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services';
		var url = "data:;charset=utf8," + encodeURIComponent(`(${func})(${svc});`.replace("%MSG_NAME%", msgName));
		(save = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))();
	},
	tid, allowMousedown, listener = { // доп.события для 15 кнопок
		handleEvent(e) {
			if (e.detail > 2) return;
			var btn = e.target;
			var dbl = e.detail == 2;
			var num = e.button *512 + e.metaKey *256 + e.ctrlKey *128 + e.shiftKey *64 + e.altKey *32 + dbl *16 +
			(btn == document.getElementById(rv) && 4) +
			(btn == vdh && 3) + (btn == fav && 2) + (btn == pui && 1);

			if (!this[num]) {
				if (e.button == 1) return;
				if (e.button) {
					num = "context";
					for(var p in this.a) this.a[p] = e[p];
				} else
					num = "mousedown";
			}
			if (dbl) tid &&= clearTimeout(tid), this[num](btn);
			else tid = setTimeout(this.exec, 300, num, btn, this);
		},
		exec(num, btn, self) {
			tid = null;
			self[num](btn);
		},
		mousedown(e) {
			allowMousedown = true;
			e.dispatchEvent(new MouseEvent("mousedown", {}));
			allowMousedown = false;
		},
		context(e) {
			e.removeAttribute("context");
			e.dispatchEvent(new MouseEvent("contextmenu", this.a));
			e.toggleAttribute("context");
		},

		a: {__proto__: null, bubbles: true, screenX: 0, screenY: 0},

/*** ======= Downloads Clicks ======= ***/

		512: saveSelectionToTxt, // СКМ Click (сохранить .txt)
		16() { // Double Left Click - Обзор папки «Загрузки»
			Downloads.getSystemDownloadsDirectory().then(path => FileUtils.File(path).launch(), Cu.reportError) // Обзор папки «Загрузки»
		},
		1024: save, // ПКМ Click (Single HTML)
		1040(btn) { // Double Right Click
			var pref = "permissions.default.image";
			var one = prefs.getIntPref(pref) == 1;
			prefs.setIntPref(pref, one ? 2 : 1);
			btn.style.filter = one ? "hue-rotate(180deg) brightness(95%)" : "";
			BrowserReload();
		},

/*** ======= PanelUI-menu Clicks ======= 100*pui 32*e.button 8*e.ctrlKey 4*e.shiftKey 2*e.altKey dbl btn ***/

		33() { gCustomizeMode.enter(); // ЛКМ + Alt Персонализация
		},
		65() { // Shift + ЛКМ
			var help_ucf = ['chrome://user_chrome_files/content/help.html', 'http://forum.puppyrus.org/index.php?topic=22762'];
			var newURI = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry).convertChromeURL(Services.io.newURI(help_ucf[0])); // .spec = file:///
			(newURI.QueryInterface(Ci.nsIFileURL).file.exists()) ? switchToTab(pui, help_ucf[0]) : switchToTab(pui, help_ucf[1]);
		},
		545: BrowserFullScreen, // Alt + СКМ
		513() { // СКМ
			windowState != STATE_MAXIMIZED ? maximize() : restore();
		},
		529: BrowserReloadSkipCache,  // СКМ Double
		1025() { // ПКМ
			minimize();
		},
		1057(pui) { // Alt + ПКМ
			switchToTab(pui, 'about:performance');
		},
		1089(pui) { // Shift + ПКМ
			pui.ownerDocument.getElementById("key_responsiveDesignMode").doCommand(); // запуск пункта меню с HotKey
			if (gBrowser.selectedBrowser.browsingContext.inRDMPane) BrowserReload();
		},
		1153(pui) { // Shift + Alt + ПКМ
			var obj = ChromeUtils.import("resource://devtools/shared/Loader.jsm").require("devtools/client/menus").menuitems.find(menuitem => menuitem.id == "menu_devtools_remotedebugging");
			(this[138] = target => obj.oncommand({target}))(pui); // запуск пункта меню, у которого нет HotKey
		},
		17: BrowserTryToCloseWindow, // Double Left Click
		1041(pui) { // ПКМ Double Right Click
			pui.ownerGlobal.undoCloseTab();
		},
	}, // end listener

	keydown_win = e => { // нажатие клавиш
		if (e.keyCode == 83 && e.altKey) e.shiftKey // Alt+S [+Shift]
		? singlesave ? singlesave.click() : save() : save(); // имитировать клик по кнопке, используя её ID
		if (e.keyCode == 68 && e.altKey){ // Alt+D отладка - запуск внешнего JS
			// e.target.ownerDocument.getElementById("key_browserConsole").doCommand();
			eval(Cu.readUTF8URI(Services.io.newURI("chrome://user_chrome_files/content/custom_scripts/User.js")));
			console.log("END User.js " + Math.random());
		}
	},
	str_cut = (s, cut = 33) => { // сократить/разбить длинную строку
		return s.substring(0,cut) + `${s.length > cut - 1 ? `…\n…${s.substring(s.length -cut + 2, s.length)}`: ""}`;
	},
	{prefs, dirsvc} = Services, linux = /macos|linux/.test(AppConstants.platform), singlesave;
	prefs.setBoolPref("browser.download.autohideButton", false); // не скрывать кнопку Загрузки


	var hint_upd = function(e, text, find) { // обновить подсказку
		var tooltips = { "downloads-button": [btn_help, 1],
			"PanelUI-menu-button": [PanelUI_help],
			"pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_": [rv_help],
			"_b9db16a4-6edc-47ec-a1f4-b86292ed211d_-browser-action": [vdh_help],
		}, trg = e.target, hint = tooltips[trg.id][0], dw;
		if (tooltips[trg.id][1] == 1) { // здесь надо упростить
			hint = GetDynamicShortcutTooltipText(trg.id) + hint;
		if (document.getElementById('_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action') && !/SingleSave/.test(hint))
			hint = hint + sgs_help;
		if (!/выбранная/.test(hint))
			try {dw = prefs.getComplexValue("browser.download.dir",Ci.nsIFile)} catch {dw = dirsvc.get("DfltDwnld", Ci.nsIFile)};
			hint = hint + `${dw ? "\n\n[Загрузки] — выбранная папка:\n"+ str_cut(dw.path, 33) : ""}`;
		}
		if (trg.tooltipText != hint) trg.tooltipText = hint;
	}
	var mouseenter = function(e) {
		this.parentNode.addEventListener("mousedown", stop, true);
		this.addEventListener("mouseleave", mouseleave, {once: true});
		hint_upd(e);
	}
	var mouseleave = function(e) {
		this.parentNode.removeEventListener("mousedown", stop, true);
	}
	var stop = e => {
		e.button || allowMousedown || e.stopImmediatePropagation();
	}
	var btns = [btn, pui];
	for(var b of btns) {
		b.toggleAttribute("context"),
		b.addEventListener("click", listener, true),
		b.addEventListener("mouseenter", mouseenter);
	}
	var ucf = window.ucf_custom_script_win || window.ucf_custom_script_all_win;
	ucf[id] = {destructor() {
		for(var b of btns) {
			b.removeEventListener("click", listener, true);
			b.removeEventListener("mouseenter", mouseenter);
			if (b.matches(":hover"))
				b.removeEventListener("mouseleave", mouseleave),
				b.parentNode.removeEventListener("mousedown", stop, true);
		}
	}};
	ucf.unloadlisteners.push(id);


	var boxLst = e => {
		// console.log('@: '+ e.button);
		if (e.button == 1 && e.target.id == `pageAction-urlbar-_${rv}_`) { // Reader View Button
			e.stopImmediatePropagation(),	document.getElementById("key_responsiveDesignMode").doCommand(); // Адаптивный дизайн
			if (gBrowser.selectedBrowser.browsingContext.inRDMPane)
				BrowserReload();
		}
	}
	nav.addEventListener("auxclick", boxLst, true);
	nav.addEventListener("mouseenter", mouseenter, true);
	window.addEventListener("keydown", keydown_win);
	addDestructor(() => {
		nav.removeEventListener("auxclick", boxLst, true);
		nav.removeEventListener("mouseenter", mouseenter, true);
		window.removeEventListener("keydown", keydown_win);
	});

})("downloads-button-click-listener", ({io, focus}) => { // SingleHTML не сохраняет svg графику

	var resolveURL = function (url, base) {
		try { return io.newURI(url, null, io.newURI(base)).spec;} catch {}
	},
	getSelWin = function (w) {
		if (w.getSelection().toString()) return w;
		for (var i = 0, f, r; f = w.frames[i]; i++) {
			try { if (r = getSelWin(f)) return r;} catch(e) {}
		}
	},
	encodeImg = function (src, obj) {
		var canvas, img, ret = src;
		if (/^https?:\/\//.test(src)) {
			canvas = doc.createElement('canvas');
			if (!obj || obj.nodeName.toLowerCase() != 'img') {
				img = doc.createElement('img');
				img.src = src;
			} else
				img = obj;
			if (img.complete) try{
				canvas.width = img.width;
				canvas.height = img.height;
				canvas.getContext('2d').drawImage(img, 0, 0);
				ret = canvas.toDataURL((/\.jpe?g/i.test(src) ? 'image/jpeg' : 'image/png'));
			} catch (e) {};
			if (img != obj) img.src = 'about:blank';
		};
		return ret;
	},
	toSrc = function (obj) {
		var strToSrc = function (str) {
			var chr, ret = '', i = 0, meta = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\x22' : '\\\x22', '\\': '\\\\'};
			while (chr = str.charAt(i++)) {
				ret += meta[chr] || chr;
			};
			return '\x22' + ret + '\x22';
		},
		arrToSrc = function (arr) {
			var ret = [];
			for (var i = 0; i < arr.length; i++) {
				ret[i] = toSrc(arr[i]) || 'null';
			};
			return '[' + ret.join(',') + ']';
		},
		objToSrc = function (obj) {
			var val, ret = [];
			for (var prop in obj) {
				if (obj.hasOwnProperty(prop) && (val = toSrc(obj[prop]))) ret.push(strToSrc(prop) + ': ' + val);
			};
			return '{' + ret.join(',') + '}';
		};
		switch (Object.prototype.toString.call(obj).slice(8, -1)) {
			case 'Array': return arrToSrc(obj);
			case 'Boolean':
			case 'Function':
			case 'RegExp': return obj.toString();
			case 'Date': return 'new Date(' + obj.getTime() + ')';
			case 'Math': return 'Math';
			case 'Number': return isFinite(obj) ? String(obj) : 'null';
			case 'Object': return objToSrc(obj);
			case 'String': return strToSrc(obj);
			default: return obj ? (obj.nodeType == 1 && obj.id ? 'document.getElementById(' + strToSrc(obj.id) + ')' : '{}') : 'null';
		}
	},
	mainWin = {};
	focus.getFocusedElementForWindow(content, true, mainWin);
	mainWin = mainWin.value;

	var selWin = getSelWin(mainWin), win = selWin || mainWin, doc = win.document, loc = win.location;
	var ele, pEle, clone, reUrl = /(url\(\x22)(.+?)(\x22\))/g;

	if (selWin) {
		var rng = win.getSelection().getRangeAt(0);
		pEle = rng.commonAncestorContainer;
		ele = rng.cloneContents();
	} else {
		pEle = doc.documentElement;
		ele = (doc.body || doc.getElementsByTagName('body')[0]).cloneNode(true);
	};
	while (pEle) {
		if (pEle.nodeType == 1) {
			clone = pEle.cloneNode(false);
			clone.appendChild(ele);
			ele = clone;
		};
		pEle = pEle.parentNode
	};
	var sel = doc.createElement('div');
	sel.appendChild(ele);

	for (var el, all = sel.getElementsByTagName('*'), i = all.length; i--;) {
		el = all[i];
		if (el.style && el.style.backgroundImage) el.style.backgroundImage = el.style.backgroundImage.replace(reUrl, function (a, prev, url, next) {
			if (!/^[a-z]+:/.test(url)) url = resolveURL(url, loc.href);
			return prev + encodeImg(url) + next;
		});
		switch (el.nodeName.toLowerCase()) {
			case 'link':
			case 'style':
			case 'script': el.parentNode.removeChild(el); break;
			case 'a':
			case 'area': if (el.hasAttribute('href') && el.getAttribute('href').charAt(0) != '#') el.href = el.href; break;
			case 'img':
			case 'input': if (el.hasAttribute('src')) el.src = encodeImg(el.src, el); break;
			case 'audio':
			case 'video':
			case 'embed':
			case 'frame':
			case 'iframe': if (el.hasAttribute('src')) el.src = el.src; break;
			case 'object': if (el.hasAttribute('data')) el.data = el.data; break;
			case 'form': if (el.hasAttribute('action')) el.action = el.action; break;
		}
	};
	var head = ele.insertBefore(doc.createElement('head'), ele.firstChild), meta = doc.createElement('meta'), sheets = doc.styleSheets, title = doc.getElementsByTagName('title')[0];
	meta.httpEquiv = 'content-type';
	meta.content = 'text/html; charset=utf-8';
	head.appendChild(meta);
	if (title) head.appendChild(title.cloneNode(true));

	head.copyScript = function (unsafeWin) {
		if ('$' in unsafeWin) return;
		var f = doc.createElement('iframe');
		f.src = 'about:blank';
		f.setAttribute('style', 'position:fixed;left:0;top:0;visibility:hidden;width:0;height:0;');
		doc.documentElement.appendChild(f);
		var str, script = doc.createElement('script');
		script.type = 'text/javascript';
		for (var name in unsafeWin) {
			if (name in f.contentWindow || !/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) continue;
			try {
				str = toSrc(unsafeWin[name]);
				if (!/\{\s*\[native code\]\s*\}/.test(str)) {
					script.appendChild(doc.createTextNode('var ' + name + ' = ' + str.replace(/<\/(script>)/ig, '<\\/$1') + ';\n'));
				}
			} catch (e) {};
		};
		f.parentNode.removeChild(f);
		if (script.childNodes.length) this.nextSibling.appendChild(script);
	};
	head.copyScript(win.wrappedJSObject || win);

	head.copyStyle = function (s) {
		if (!s) return;
		var style = doc.createElement('style');
		style.type = 'text/css';
		if (s.media && s.media.mediaText) style.media = s.media.mediaText;
		try {
			for (var i = 0, rule; rule = s.cssRules[i]; i++) {
				if (rule.type != 3) {
					if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) {
						var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) {
							if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href);
							if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url);
							return prev + url + next;
						});
						style.appendChild(doc.createTextNode(css + '\n'));
					}
				} else {
					this.copyStyle(rule.styleSheet);
				}
			}
		} catch(e) {
			if (s.ownerNode) style = s.ownerNode.cloneNode(false);
		};
		this.appendChild(style);
	};
	for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]);
	head.appendChild(doc.createTextNode('\n'));
	var doctype = '', dt = doc.doctype;
	if (dt && dt.name) {
		doctype += '<!DOCTYPE ' + dt.name;
		if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22';
		if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22';
		doctype += '>\n';
	};
	var selText = selWin ? win.getSelection().toString().slice(0, 200) : undefined;
	sendAsyncMessage("%MSG_NAME%", [doctype + sel.innerHTML +'\n<a href='+ (loc.protocol != 'data:' ? loc.href : 'data:uri') +'><small><blockquote>источник: '+ new Date().toLocaleString("ru") +'</blockquote></small></a>', selText]); // выделенный текст

}); // END hookClicks

ucf_QuickToggle.js - здесь код LongPress

Отредактировано Dobrov (22-11-2021 01:40:08)

Отсутствует

 

№1601622-11-2021 21:22:51

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

Re: Custom Buttons

ВВП пишет

Не могу запустить две 94 . Или профиль один работает... Может в INI что то новое надо ?

У меня нормально запускаются. Каждая со своим профилем.
«в INI» ничего нового не добавлял. Проверил на Win 7 и 10.


Dobrov пишет

перестал обрабатываться долгий клик в скрипте ToggleAboutConfig, когда добавил

Не, это ты совсем что-то левое добавил.
Лучше отдельный фрагмент сделать,
только для тултипов, и со своим mouseenter-обработчиком.
Вот, правда в CB набирал, но, думаю, понятно.

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

Выделить код

Код:

var str_cut = s => s;

var dsym = Symbol();
var j = arr => arr.join("\n");
var tooltips = {

	"PanelUI-menu-button": j([
		`Клик мыши:	меню Firefox ${Services.appinfo.platformVersion}`,
		"…+ Shift		⚑ Краткая справка",
		"…+ Alt		Персонализация",
		"Клик дважды	⊠ закрыть браузер\n",

		"Правый клик	⇲ Свернуть",
		"…+ дважды	⤾ Вернуть вкладку",
		"…+ Alt		Диспетчер задач",
		"…+ Shift		Адаптивный дизайн\n",

		"Колёсико:	Развернуть | окно",
		"…+ Alt		Полный экран",
		"…+ дважды	Обновить без кэша"
	]),

	"pageAction-urlbar-_2495d258-41e7-4cd5-bc7d-ac15981f064e_": j([
		`Reader View	${Services.appinfo.OS == "Darwin" ? "⌥⌘M" : "Ctrl+⇧+M"}\n`,

		"Клик мыши	Режим для чтения",
		"Колёсико	Адаптивный дизайн"
	]),

	"_b9db16a4-6edc-47ec-a1f4-b86292ed211d_-browser-action": j([
		"Video DownloadHelper",
		"Скачивание проигрываемого видео"
	]),

	[dsym]: j([
		GetDynamicShortcutTooltipText("downloads-button"),

		"\nДвойной клик: ⬇︎ открыть [Загрузки]",
		"…на картинке: ⧉ найти Похожие\n",

		"Правый клик (Alt+S):  Сохранить",
		"   в единый html всё / выделенное",
		"…дважды  Картинки вкл/выкл\n",

		"Ролик:	 Сохранить как файл .txt",
		"Колёсико на рисунке: ➜ Сохранить"
	]),
	get "downloads-button"() {
		var hint = this[dsym];
		if (document.getElementById("_531906d3-e22f-4a6c-a102-8057b88a1a63_-browser-action"))
			hint += "\nAlt⇧S	 ⌨ нажатие SingleSave";
		try {var dw = Services.prefs.getComplexValue("browser.download.dir", Ci.nsIFile);}
		catch {dw = Services.dirsvc.get("DfltDwnld", Ci.nsIFile);}
		if (dw) hint += "\n\n[Загрузки] — выбранная папка:\n" + str_cut(dw.path, 33);
		return hint;
	},
};

addEventListener("mouseenter", e => {
	var hint = tooltips[e.target.id];
	if (hint) e.target.tooltipText = hint;
}, true, document.getElementById("nav-bar") || 1);

Отредактировано Dumby (22-11-2021 21:23:31)

Отсутствует

 

№1601723-11-2021 00:52:35

ВВП
Участник
 
Группа: Members
Зарегистрирован: 13-03-2021
Сообщений: 336
UA: Firefox 94.0

Re: Custom Buttons

Dumby
Да, косяк здесь был...Все норм. теперь.
[General]
StartWithLastProfile=1

[Profile0]
Name=default
IsRelative=1
Path=../../../
Default=1
Вопрос: Как рихтануть Attributes Inspector , чтобы наводил cursor:default ? А то кнопки pointer... Неудобно.

Отредактировано ВВП (23-11-2021 11:30:17)

Отсутствует

 

№1601824-11-2021 12:42:04

Letterman
Участник
 
Группа: Members
Зарегистрирован: 13-01-2017
Сообщений: 53
UA: Firefox 91.0

Re: Custom Buttons

Здравствуйте, для Firefox 91.0.2 устанавливаю версию custom_buttons-0.0.7.0.0.19, далее кнопку Undo Close Tabs 0.3.3.2 (2020-03-14), но кнопка не появляется в панели инструментов. Также нет нигде элемента меню Добавить кнопку. В Firefox 94.0.2 также ничего не работает. В Firefox 75 все работало без проблем. Подскажите пожалуйста, решение этой проблемы.

Код кнопки

Выделить код

Код:

custombutton://%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0D%0A%3Ccustombutton%20xmlns%3Acb%3D%22http%3A//xsms.nm.ru/custombuttons/%22%3E%0A%20%20%3Cname%3EUndo%20Close%20Tab%3C/name%3E%0A%20%20%3Cimage%3E%3C%21%5BCDATA%5Bdata%3Aimage/png%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABZVBMVEX////w8PD09PTx8fHw8PCPkIvv7++LjIfw8PDu7u6ZmZXv7+/29vbw8PD///+Txdt8lJ2RkY2Sk4+bzeJcnLsbcp6LjIcwf6bg4N/m//+XyuDf7/+LvNGmr68ufqbg4N9OhaLm8PJvrstCjrPg4N9Rk7Q8hqfk8PRoqMc5h60vgKk9ia/f4N7w8PDi7/ZgpMOLtMny9fYmeaIqfaff4N6hpKLv7+/h8PVwqcTB1N3L3ebv7+9trMqLjIeOj4rf39719vbM7PaMt81hpMPL7fmbnJeoqaXr6+tin774+/vF2t+lq6qKlI+hop38/Pz7+/v5+fn9/f29vruLjIeqq6f7+/v5+fnGxsSLjId5rcfg8vw4ibN8ud3n8vgacZ2extrA5//4+/wacp4yha8ZcZ18wuyIxuthrNc5irdvt+KRzvO62ep+w+7N6PeY1/+U1v+h2/9am7sbcp4keaXm8/ovgq07jLe+yJo8AAAAWXRSTlMAES5KZr+CMJ7X7Lr4ZwHdD4f0yftxJtP6Cj4Q/EIe9HPg/tXy/kvL/fr++fGfuf3Bzv787+6DptCRyLvRDs/u+P3O+TSw5Or8ovXiHqKWW0aBpyVHNSZMDw1FfDAAAACvSURBVHhehchTcwRBAIXRXmewtG3btm0jtn9/elPZmpqnnKd7P0DgADK5glyUQpH4b0pYkJo730t1PADxBSiKhlVvT4v11myBgSHD8Vz+cP388rr7rGlg0CIIojccrx5v7u4fjDCYMAxLWm1f33bHcuWEwXUBuT3eS58/cBuEIcQ8iURj8cT7RwqkM1n6LzabXtgUS6BcqdLO6o1mC7Q7XepZrz8YgtGYQphMZ+BfP976HHRDoNUhAAAAAElFTkSuQmCC%5D%5D%3E%3C/image%3E%0A%20%20%3Cmode%3E0%3C/mode%3E%0A%20%20%3Cinitcode%3E%3C%21%5BCDATA%5B//%20http%3A//infocatcher.ucoz.net/js/cb/undoCloseTabs.js%0A//%20https%3A//forum.mozilla-russia.org/viewtopic.php%3Fid%3D56267%0A//%20https%3A//github.com/Infocatcher/Custom_Buttons/tree/master/Undo_Close_Tabs%0A%0A//%20Undo%20Close%20Tabs%20button%20for%20Custom%20Buttons%0A//%20%28code%20for%20%22initialization%22%20section%29%0A%0A//%20%28c%29%20Infocatcher%202009-2015%2C%202017-2020%0A//%20version%200.3.3.2%20-%202020-03-14%0A%0Avar%20options%20%3D%20%7B%0A%09menuTemplate%3A%20%5B%0A%09%09%22closedWindows%22%2C%0A%09%09%22separator%22%2C%0A%09%09%22restoreClosedWindows%22%2C%0A%09%09%22clearClosedWindows%22%2C%0A%09%09%22separator%22%2C%0A%09%09%22closedTabs%22%2C%0A%09%09%22separator%22%2C%0A%09%09%22restoreClosedTabs%22%2C%0A%09%09%22clearClosedTabs%22%2C%0A%09%09%22separator%22%2C%0A%09%09%22clearAll%22%2C%0A%09%09%22separator%22%2C%0A%09%09%22restoreLastSession%22%2C%0A%09%09%22separator%22%2C%0A%09%09%22buttonMenu%22%0A%09%5D%2C%0A%09showInTabContextMenu%3A%20false%2C%0A%09/*%0A%09menuTemplateTabContext%3A%20%5B%20//%20like%20menuTemplate%0A%09%09%22closedTabs%22%2C%0A%09%09%22separator%22%2C%0A%09%09%22restoreClosedTabs%22%2C%0A%09%09%22clearClosedTabs%22%0A%09%5D%2C%0A%09*/%0A%09windowItemTemplate%3A%20%22%28%25count%29%20%25title%22%2C%0A%09windowSelectedTabPrefix%3A%20%22*%22%2C%0A%09buttonTipTemplate%3A%20%5B%22header%22%2C%20%22title%22%2C%20%22url%22%2C%20%22closedAt%22%5D%2C%0A%09itemTipTemplate%3A%20%5B%22title%22%2C%20%22url%22%2C%20%22closedAt%22%5D%2C%0A%09hideRestoreAllForSingleEntry%3A%20false%2C%0A%09allowDeleteEntries%3A%20true%2C%0A%09accesskeys%3A%20%7B%20//%20Empty%20string%20%28%22%22%29%20to%20disable%20or%20string%20with%20possible%20values%20%28%220123...%22%2C%20%22abcd...%22%29%0A%09%09closedTabs%3A%20%22%22%2C%0A%09%09closedWindows%3A%20%22%22%0A%09%7D%2C%0A%09accesskeySeparator%3A%20%22%20%22%2C%20//%20%3Caccesskey%3E%3Cseparator%3E%3Clabel%3E%0A%09openMenuOnMouseover%3A%20false%2C%0A%09useMenu%3A%20false%2C%0A%09rightClickToUndoCloseTab%3A%20false%20//%20Useful%20with%20%22useMenu%3A%20true%22%0A%7D%3B%0A%0Afunction%20_localize%28sid%29%20%7B%0A%09var%20strings%20%3D%20%7B%0A%09%09en%3A%20%7B%0A%09%09%09restoreTab%3A%20%22Restore%20the%20most%20recently%20closed%20tab%22%2C%0A%0A%09%09%09restoreAllTabs%3A%20%22Restore%20all%20tabs%22%2C%0A%09%09%09restoreAllTabsAccesskey%3A%20%22t%22%2C%0A%09%09%09clearTabsHistory%3A%20%22Clear%20history%20of%20closed%20tabs%22%2C%0A%09%09%09clearTabsHistoryAccesskey%3A%20%22b%22%2C%0A%0A%09%09%09restoreAllWindows%3A%20%22Restore%20all%20windows%22%2C%0A%09%09%09restoreAllWindowsAccesskey%3A%20%22w%22%2C%0A%09%09%09clearWindowsHistory%3A%20%22Clear%20history%20of%20closed%20windows%22%2C%0A%09%09%09clearWindowsHistoryAccesskey%3A%20%22d%22%2C%0A%0A%09%09%09clearAllHistory%3A%20%22Clear%20all%20history%22%2C%0A%09%09%09clearAllHistoryAccesskey%3A%20%22C%22%2C%0A%0A%09%09%09restoreLastSession%3A%20%22Restore%20last%20session%22%2C%0A%09%09%09restoreLastSessionAccesskey%3A%20%22s%22%2C%0A%0A%09%09%09deleteUndoEntry%3A%20%22Delete%22%2C%0A%0A%09%09%09buttonMenu%3A%20%22Button%20menu%22%2C%0A%09%09%09buttonMenuAccesskey%3A%20%22m%22%2C%0A%0A%09%09%09tabContextMenu%3A%20%22Recently%20Closed%20Tabs%22%2C%0A%09%09%09tabContextMenuAccesskey%3A%20%22y%22%2C%0A%0A%09%09%09itemTip%3A%20%22%25ago%20ago%2C%20%25date%22%2C%0A%09%09%09day%3A%20%22d%22%0A%09%09%7D%2C%0A%09%09ru%3A%20%7B%0A%09%09%09restoreTab%3A%20%22%u0412%u043E%u0441%u0441%u0442%u0430%u043D%u043E%u0432%u0438%u0442%u044C%20%u043F%u043E%u0441%u043B%u0435%u0434%u043D%u044E%u044E%20%u0437%u0430%u043A%u0440%u044B%u0442%u0443%u044E%20%u0432%u043A%u043B%u0430%u0434%u043A%u0443%22%2C%0A%0A%09%09%09restoreAllTabs%3A%20%22%u0412%u043E%u0441%u0441%u0442%u0430%u043D%u043E%u0432%u0438%u0442%u044C%20%u0432%u0441%u0435%20%u0432%u043A%u043B%u0430%u0434%u043A%u0438%22%2C%0A%09%09%09restoreAllTabsAccesskey%3A%20%22%u043B%22%2C%0A%09%09%09clearTabsHistory%3A%20%22%u041E%u0447%u0438%u0441%u0442%u0438%u0442%u044C%20%u0438%u0441%u0442%u043E%u0440%u0438%u044E%20%u0437%u0430%u043A%u0440%u044B%u0442%u044B%u0445%20%u0432%u043A%u043B%u0430%u0434%u043E%u043A%22%2C%0A%09%09%09clearTabsHistoryAccesskey%3A%20%22%u0434%22%2C%0A%0A%09%09%09restoreAllWindows%3A%20%22%u0412%u043E%u0441%u0441%u0442%u0430%u043D%u043E%u0432%u0438%u0442%u044C%20%u0432%u0441%u0435%20%u043E%u043A%u043D%u0430%22%2C%0A%09%09%09restoreAllWindowsAccesskey%3A%20%22%u043E%22%2C%0A%09%09%09clearWindowsHistory%3A%20%22%u041E%u0447%u0438%u0441%u0442%u0438%u0442%u044C%20%u0438%u0441%u0442%u043E%u0440%u0438%u044E%20%u0437%u0430%u043A%u0440%u044B%u0442%u044B%u0445%20%u043E%u043A%u043E%u043D%22%2C%0A%09%09%09clearWindowsHistoryAccesskey%3A%20%22%u043D%22%2C%0A%0A%09%09%09clearAllHistory%3A%20%22%u041E%u0447%u0438%u0441%u0442%u0438%u0442%u044C%20%u0432%u0441%u044E%20%u0438%u0441%u0442%u043E%u0440%u0438%u044E%22%2C%0A%09%09%09clearAllHistoryAccesskey%3A%20%22%u0447%22%2C%0A%0A%09%09%09restoreLastSession%3A%20%22%u0412%u043E%u0441%u0441%u0442%u0430%u043D%u043E%u0432%u0438%u0442%u044C%20%u043F%u043E%u0441%u043B%u0435%u0434%u043D%u044E%u044E%20%u0441%u0435%u0441%u0441%u0438%u044E%22%2C%0A%09%09%09restoreLastSessionAccesskey%3A%20%22%u0441%22%2C%0A%0A%09%09%09deleteUndoEntry%3A%20%22%u0423%u0434%u0430%u043B%u0438%u0442%u044C%22%2C%0A%0A%09%09%09buttonMenu%3A%20%22%u041C%u0435%u043D%u044E%20%u043A%u043D%u043E%u043F%u043A%u0438%22%2C%0A%09%09%09buttonMenuAccesskey%3A%20%22%u041C%22%2C%0A%0A%09%09%09tabContextMenu%3A%20%22%u041D%u0435%u0434%u0430%u0432%u043D%u043E%20%u0437%u0430%u043A%u0440%u044B%u0442%u044B%u0435%20%u0432%u043A%u043B%u0430%u0434%u043A%u0438%22%2C%0A%09%09%09tabContextMenuAccesskey%3A%20%22%u043E%22%2C%0A%0A%09%09%09itemTip%3A%20%22%25ago%20%u043D%u0430%u0437%u0430%u0434%2C%20%25date%22%2C%0A%09%09%09day%3A%20%22%u0434%22%0A%09%09%7D%0A%09%7D%3B%0A%09var%20locale%20%3D%20%28function%28%29%20%7B%0A%09%09if%28%22Services%22%20in%20window%20%26%26%20%22locale%22%20in%20Services%29%20%7B%0A%09%09%09var%20locales%20%3D%20Services.locale.requestedLocales%20//%20Firefox%2064+%0A%09%09%09%09%7C%7C%20Services.locale.getRequestedLocales%20%26%26%20Services.locale.getRequestedLocales%28%29%3B%0A%09%09%09if%28locales%29%0A%09%09%09%09return%20locales%5B0%5D%3B%0A%09%09%7D%0A%09%09var%20prefs%20%3D%20%22Services%22%20in%20window%20%26%26%20Services.prefs%0A%09%09%09%7C%7C%20Components.classes%5B%22@mozilla.org/preferences-service%3B1%22%5D%0A%09%09%09%09.getService%28Components.interfaces.nsIPrefBranch%29%3B%0A%09%09function%20pref%28name%2C%20type%29%20%7B%0A%09%09%09return%20prefs.getPrefType%28name%29%20%21%3D%20prefs.PREF_INVALID%20%3F%20prefs%5B%22get%22%20+%20type%20+%20%22Pref%22%5D%28name%29%20%3A%20undefined%3B%0A%09%09%7D%0A%09%09if%28%21pref%28%22intl.locale.matchOS%22%2C%20%22Bool%22%29%29%20%7B%20//%20Also%20see%20https%3A//bugzilla.mozilla.org/show_bug.cgi%3Fid%3D1414390%0A%09%09%09var%20locale%20%3D%20pref%28%22general.useragent.locale%22%2C%20%22Char%22%29%3B%0A%09%09%09if%28locale%20%26%26%20locale.substr%280%2C%209%29%20%21%3D%20%22chrome%3A//%22%29%0A%09%09%09%09return%20locale%3B%0A%09%09%7D%0A%09%09return%20Components.classes%5B%22@mozilla.org/chrome/chrome-registry%3B1%22%5D%0A%09%09%09.getService%28Components.interfaces.nsIXULChromeRegistry%29%0A%09%09%09.getSelectedLocale%28%22global%22%29%3B%0A%09%7D%29%28%29.match%28/%5E%5Ba-z%5D*/%29%5B0%5D%3B%0A%09_localize%20%3D%20function%28sid%29%20%7B%0A%09%09return%20strings%5Blocale%5D%20%26%26%20strings%5Blocale%5D%5Bsid%5D%20%7C%7C%20strings.en%5Bsid%5D%20%7C%7C%20sid%3B%0A%09%7D%3B%0A%09return%20_localize.apply%28this%2C%20arguments%29%3B%0A%7D%0A%0Avar%20JSON%20%3D%20%22JSON%22%20in%20window%0A%09%3F%20window.JSON%0A%09%3A%20%22nsIJSON%22%20in%20Components.interfaces%0A%09%09%3F%20%7B%0A%09%09%09parse%3A%20function%28s%29%20%7B%0A%09%09%09%09return%20Components.classes%5B%22@mozilla.org/dom/json%3B1%22%5D%0A%09%09%09%09%09.createInstance%28Components.interfaces.nsIJSON%29%0A%09%09%09%09%09.decode%28s%29%3B%0A%09%09%09%7D%0A%09%09%7D%0A%09%09%3A%20%7B%0A%09%09%09parse%3A%20function%28s%29%20%7B%0A%09%09%09%09return%20Components.utils.evalInSandbox%28%22%28%22%20+%20s%20+%20%22%29%22%2C%20new%20Components.utils.Sandbox%28%22about%3Ablank%22%29%29%3B%0A%09%09%09%7D%0A%09%09%7D%3B%0A%0Athis.onclick%20%3D%20function%28e%29%20%7B%0A%09if%28e.target%20%21%3D%20this%29%0A%09%09return%3B%0A%09if%28e.button%20%3D%3D%201%20%7C%7C%20e.button%20%3D%3D%200%20%26%26%20%28e.ctrlKey%20%7C%7C%20e.shiftKey%20%7C%7C%20e.altKey%20%7C%7C%20e.metaKey%29%29%0A%09%09this.undoCloseTabsList.clearAllLists%28%29%3B%0A%09else%20if%28%0A%09%09e.button%20%3D%3D%200%0A%09%09%7C%7C%20e.button%20%3D%3D%202%20%26%26%20%21e.ctrlKey%20%26%26%20%21e.shiftKey%20%26%26%20%21e.altKey%20%26%26%20%21e.metaKey%0A%09%09%09%26%26%20this.undoCloseTabsList.options.rightClickToUndoCloseTab%0A%09%29%20%7B%0A%09%09if%28%0A%09%09%09e.button%20%3D%3D%200%20%26%26%20%21this.undoCloseTabsList.options.useMenu%0A%09%09%09%7C%7C%20e.button%20%3D%3D%202%20%26%26%20this.undoCloseTabsList.options.rightClickToUndoCloseTab%0A%09%09%29%20%7B%0A%09%09%09if%28this.undoCloseTabsList.closedTabCount%29%0A%09%09%09%09this.undoCloseTabsList.undoCloseTab%28%29%3B%0A%09%09%09else%0A%09%09%09%09this.undoCloseTabsList.drawUndoList%28%29%20%26%26%20this.undoCloseTabsList.showMenu%28e%29%3B%0A%09%09%7D%0A%09%09//%20Allow%20use%20%22command%22%20section%20only%20from%20hotkey%3A%0A%09%09e.preventDefault%28%29%3B%0A%09%09e.stopPropagation%28%29%3B%0A%09%7D%0A%7D%3B%0Aif%28%21this.hasOwnProperty%28%22defaultContextId%22%29%29%0A%09this.defaultContextId%20%3D%20this.getAttribute%28%22context%22%29%20%7C%7C%20%22custombuttons-contextpopup%22%3B%0Athis.onmousedown%20%3D%20function%28e%29%20%7B%0A%09if%28e.target%20%21%3D%20this%29%0A%09%09return%3B%0A%09if%28this.undoCloseTabsList.options.useMenu%29%20%7B%0A%09%09if%28e.button%20%3D%3D%200%29%0A%09%09%09this.undoCloseTabsList.drawUndoList%28%29%3B%0A%09%7D%0A%09else%20if%28e.button%20%3D%3D%202%29%20%7B%0A%09%09var%20showCbMenu%20%3D%20e.ctrlKey%20%7C%7C%20e.shiftKey%20%7C%7C%20e.altKey%20%7C%7C%20e.metaKey%20%7C%7C%20%21this.undoCloseTabsList.drawUndoList%28%29%3B%0A%09%09this.setAttribute%28%0A%09%09%09%22context%22%2C%0A%09%09%09showCbMenu%0A%09%09%09%09%3F%20this.defaultContextId%0A%09%09%09%09%3A%20this.undoCloseTabsList.mpId%0A%09%09%29%3B%0A%09%7D%0A%7D%3B%0Athis.onmouseover%20%3D%20function%28e%29%20%7B%0A%09if%28e.target%20%21%3D%20this%29%0A%09%09return%3B%0A%09if%28%21this.disabled%29%0A%09%09this.undoCloseTabsList.updUI%28%29%3B%0A%09this.undoCloseTabsList.options.useMenu%20%26%26%20Array.prototype.some.call%28%0A%09%09this.parentNode.getElementsByTagName%28%22*%22%29%2C%0A%09%09function%28node%29%20%7B%0A%09%09%09if%28%0A%09%09%09%09node%20%21%3D%20this%0A%09%09%09%09%26%26%20node.namespaceURI%20%3D%3D%20xulns%0A%09%09%09%09//%20See%20https%3A//github.com/Infocatcher/Custom_Buttons/issues/28%0A%09%09%09%09//%26%26%20node.boxObject%0A%09%09%09%09//%26%26%20node.boxObject%20instanceof%20Components.interfaces.nsIMenuBoxObject%0A%09%09%09%09%26%26%20%22open%22%20in%20node%0A%09%09%09%09%26%26%20node.open%0A%09%09%09%09%26%26%20node.getElementsByTagName%28%22menupopup%22%29.length%0A%09%09%09%09%26%26%20this.undoCloseTabsList.drawUndoList%28%29%0A%09%09%09%29%20%7B%0A%09%09%09%09node.open%20%3D%20false%3B%0A%09%09%09%09this.open%20%3D%20true%3B%0A%09%09%09%09return%20true%3B%0A%09%09%09%7D%0A%09%09%09return%20false%3B%0A%09%09%7D%2C%0A%09%09this%0A%09%29%3B%0A%09if%28%0A%09%09this.undoCloseTabsList.options.openMenuOnMouseover%0A%09%09%26%26%20this.undoCloseTabsList.drawUndoList%28%29%0A%09%29%0A%09%09this.undoCloseTabsList.openMenu%28%29%3B%0A%7D%3B%0A%0Athis.undoCloseTabsList%20%3D%20%7B%0A%09button%3A%20this%2C%0A%09options%3A%20options%2C%0A%09mpId%3A%20this.id%20+%20%22-context%22%2C%0A%09cmId%3A%20this.id%20+%20%22-contextSub%22%2C%0A%09tcmId%3A%20this.id%20+%20%22-tabContextMenu%22%2C%0A%09tipId%3A%20this.id%20+%20%22-tooltip%22%2C%0A%09errPrefix%3A%20%22%5BCustom%20Buttons%20%3A%3A%20Undo%20Close%20Tabs%20List%5D%3A%20%22%2C%0A%09get%20mp%28%29%20%7B%0A%09%09var%20btn%20%3D%20this.button%3B%0A%09%09var%20mp%20%3D%20btn.getElementsByTagName%28%22menupopup%22%29%3B%0A%09%09mp%20%3D%20mp.length%20%26%26%20mp%5B0%5D%3B%0A%09%09mp%20%26%26%20mp.parentNode.removeChild%28mp%29%3B%0A%09%09mp%20%3D%20this.createElement%28%22menupopup%22%2C%20%7B%0A%09%09%09id%3A%20this.mpId%2C%0A%09%09%09onclick%3A%20%22this.parentNode.undoCloseTabsList.checkForMiddleClick%28event%29%3B%22%2C%0A%09%09%09onpopupshowing%3A%20%22if%28event.target%20%3D%3D%20this%29%20document.popupNode%20%3D%20this.parentNode%3B%22%2C%0A%09%09%09onpopuphidden%3A%20%22if%28event.target%20%3D%3D%20this%29%20document.popupNode%20%3D%20null%3B%22%0A%09%09%7D%29%3B%0A%09%09if%28this.cm%29%0A%09%09%09mp.setAttribute%28%22context%22%2C%20this.cmId%29%3B%0A%09%09var%20tb%20%3D%20btn.parentNode%3B%0A%09%09if%28%0A%09%09%09this.options.useMenu%0A%09%09%09%26%26%20tb.getAttribute%28%22orient%22%29%20%3D%3D%20%22vertical%22%0A%09%09%29%20%7B%0A%09%09%09//%20https%3A//addons.mozilla.org/firefox/addon/vertical-toolbar/%0A%09%09%09var%20isRight%20%3D%20tb.parentNode.getAttribute%28%22placement%22%29%20%3D%3D%20%22right%22%3B%0A%09%09%09mp.setAttribute%28%22position%22%2C%20isRight%20%3F%20%22start_before%22%20%3A%20%22end_before%22%29%3B%0A%09%09%7D%0A%09%09delete%20this.mp%3B%0A%09%09return%20this.mp%20%3D%20btn.appendChild%28mp%29%3B%0A%09%7D%2C%0A%09get%20useCentextMenu%28%29%20%7B%0A%09%09delete%20this.useCentextMenu%3B%0A%09%09return%20this.useCentextMenu%20%3D%20this.options.allowDeleteEntries%0A%09%09%09%26%26%20%28%22forgetClosedTab%22%20in%20this.ss%20%7C%7C%20%22forgetClosedWindow%22%20in%20this.ss%29%3B%0A%09%7D%2C%0A%09get%20cm%28%29%20%7B%0A%09%09delete%20this.cm%3B%0A%09%09if%28%21this.useCentextMenu%29%0A%09%09%09return%20this.cm%20%3D%20null%3B%0A%09%09var%20cm%20%3D%20document.getElementById%28this.cmId%29%3B%0A%09%09cm%20%26%26%20cm.parentNode.removeChild%28cm%29%3B%0A%09%09cm%20%3D%20this.createElement%28%22menupopup%22%2C%20%7B%0A%09%09%09id%3A%20this.cmId%2C%0A%09%09%09onpopupshowing%3A%20%22return%20this.undoCloseTabsList.canDeleteUndoEntry%28this.triggerNode%20%7C%7C%20document.popupNode%29%3B%22%0A%09%09%7D%29%3B%0A%09%09var%20mi%20%3D%20this.createElement%28%22menuitem%22%2C%20%7B%0A%09%09%09oncommand%3A%20%22this.parentNode.undoCloseTabsList.deleteUndoEntry%28this.parentNode.triggerNode%20%7C%7C%20document.popupNode%29%3B%22%2C%0A%09%09%09label%3A%20_localize%28%22deleteUndoEntry%22%29%2C%0A%09%09%09closemenu%3A%20%22single%22%0A%09%09%7D%29%3B%0A%09%09cm.appendChild%28mi%29%3B%0A%09%09cm.undoCloseTabsList%20%3D%20this%3B%0A%09%09return%20this.cm%20%3D%20document.getElementById%28%22mainPopupSet%22%29.appendChild%28cm%29%3B%0A%09%7D%2C%0A%09get%20cbMenu%28%29%20%7B%0A%09%09var%20cbPopup%20%3D%20document.getElementById%28this.button.defaultContextId%29%3B%0A%09%09if%28%21cbPopup%29%20%7B%0A%09%09%09Components.utils.reportError%28this.errPrefix%20+%20%22cb%20menu%20not%20found%22%29%3B%0A%09%09%09return%20this.cbMenu%20%3D%20null%3B%0A%09%09%7D%0A%09%09cbPopup%20%3D%20cbPopup.cloneNode%28true%29%3B%0A%09%09var%20id%20%3D%20%22-%22%20+%20this.button.id.match%28/%5Cd*%24/%29%5B0%5D%20+%20%22-cloned%22%3B%0A%09%09cbPopup.id%20+%3D%20id%3B%0A%09%09Array.prototype.slice.call%28cbPopup.getElementsByAttribute%28%22id%22%2C%20%22*%22%29%29.forEach%28function%28node%29%20%7B%0A%09%09%09node.id%20+%3D%20id%3B%0A%09%09%7D%29%3B%0A%09%09var%20menu%20%3D%20this.createElement%28%22menu%22%2C%20%7B%0A%09%09%09label%3A%20_localize%28%22buttonMenu%22%29%2C%0A%09%09%09accesskey%3A%20_localize%28%22buttonMenuAccesskey%22%29%0A%09%09%7D%29%3B%0A%09%09menu.appendChild%28cbPopup%29%3B%0A%09%09cbPopup.setAttribute%28%0A%09%09%09%22onpopupshowing%22%2C%0A%09%09%09%27%5C%0A%09%09%09var%20btn%20%3D%20document.popupNode%20%3D%20this.parentNode.parentNode.parentNode%5Cn%5C%0A%09%09%09%09.undoCloseTabsList.button%3B%5Cn%5C%0A%09%09%09custombutton.setContextMenuVisibility%28btn%29%3B%27%0A%09%09%29%3B%0A%09%09delete%20this.cbMenu%3B%0A%09%09return%20this.cbMenu%20%3D%20menu%3B%0A%09%7D%2C%0A%09get%20ss%28%29%20%7B%0A%09%09delete%20this.ss%3B%0A%09%09return%20this.ss%20%3D%20%22nsISessionStore%22%20in%20Components.interfaces%0A%09%09%09%3F%20%28%0A%09%09%09%09Components.classes%5B%22@mozilla.org/browser/sessionstore%3B1%22%5D%0A%09%09%09%09%7C%7C%20Components.classes%5B%22@mozilla.org/suite/sessionstore%3B1%22%5D%0A%09%09%09%29.getService%28Components.interfaces.nsISessionStore%29%0A%09%09%09%3A%20SessionStore%3B%20//%20Firefox%2061+%20https%3A//bugzilla.mozilla.org/show_bug.cgi%3Fid%3D1450559%0A%09%7D%2C%0A%09get%20appInfo%28%29%20%7B%0A%09%09delete%20this.appInfo%3B%0A%09%09return%20this.appInfo%20%3D%20Components.classes%5B%22@mozilla.org/xre/app-info%3B1%22%5D%0A%09%09%09.getService%28Components.interfaces.nsIXULAppInfo%29%3B%0A%09%7D%2C%0A%09get%20appVersion%28%29%20%7B%0A%09%09delete%20this.appVersion%3B%0A%09%09return%20this.appVersion%20%3D%20parseFloat%28this.appInfo.version%29%3B%0A%09%7D%2C%0A%09get%20appName%28%29%20%7B%0A%09%09delete%20this.appName%3B%0A%09%09return%20this.appName%20%3D%20this.appInfo.name%3B%0A%09%7D%2C%0A%0A%09init%3A%20function%28%29%20%7B%0A%09%09window.addEventListener%28%22TabClose%22%2C%20%20%20%20%20%20%20this%2C%20false%29%3B%0A%09%09window.addEventListener%28%22SSTabRestoring%22%2C%20this%2C%20false%29%3B%0A%09%09window.addEventListener%28%22unload%22%2C%20%20%20%20%20%20%20%20%20this%2C%20false%29%3B%0A%09%09if%28this.appName%20%3D%3D%20%22SeaMonkey%22%29%20//%20No%20SSTab*%20events%20in%20SeaMonkey%0A%09%09%09window.addEventListener%28%22TabOpen%22%2C%20this%2C%20false%29%3B%0A%09%09setTimeout%28function%28_this%29%20%7B%0A%09%09%09_this.mp.addEventListener%28%22DOMMenuItemActive%22%2C%20%20%20_this%2C%20false%29%3B%0A%09%09%09_this.mp.addEventListener%28%22DOMMenuItemInactive%22%2C%20_this%2C%20false%29%3B%0A%09%09%09_this.initTooltip%28%29%3B%0A%09%09%7D%2C%2050%2C%20this%29%3B%0A%09%09this.addPbExitObserver%28true%29%3B%0A%09%09this.updUIGlobal%28%29%3B%0A%09%09if%28this.options.showInTabContextMenu%29%20setTimeout%28function%28_this%29%20%7B%0A%09%09%09_this.initTabContext%28%29%3B%0A%09%09%7D%2C%20100%2C%20this%29%3B%0A%09%7D%2C%0A%09initTabContext%3A%20function%28%29%20%7B%0A%09%09var%20origMi%20%3D%20this.tabContextUndoClose%3B%0A%09%09if%28%21origMi%29%20%7B%0A%09%09%09LOG%28%22Can%27t%20find%20%5C%22Undo%20Close%20Tab%5C%22%20item%20in%20tab%20context%20menu%22%29%3B%0A%09%09%09return%3B%0A%09%09%7D%0A%09%09var%20menu%20%3D%20document.getElementById%28this.tcmId%29%3B%0A%09%09menu%20%26%26%20menu.parentNode.removeChild%28menu%29%3B%20//%20For%20SeaMonkey%0A%09%09menu%20%3D%20this.createElement%28%22menu%22%2C%20%7B%0A%09%09%09id%3A%20this.tcmId%2C%0A%09%09%09label%3A%20_localize%28%22tabContextMenu%22%29%2C%0A%09%09%09accesskey%3A%20_localize%28%22tabContextMenuAccesskey%22%29%2C%0A%09%09%09tooltip%3A%20this.tipId%2C%0A%09%09%09popupsinherittooltip%3A%20%22true%22%0A%09%09%7D%29%3B%0A%09%09menu.undoCloseTabsList%20%3D%20this%3B%0A%09%09menu.onclick%20%3D%20function%28e%29%20%7B%0A%09%09%09if%28e.target%20%21%3D%20this%29%0A%09%09%09%09return%3B%0A%09%09%09if%28e.button%20%3D%3D%201%20%7C%7C%20e.button%20%3D%3D%200%20%26%26%20%28e.ctrlKey%20%7C%7C%20e.shiftKey%20%7C%7C%20e.altKey%20%7C%7C%20e.metaKey%29%29%20%7B%0A%09%09%09%09if%28this.undoCloseTabsList.closedTabCount%29%20%7B%0A%09%09%09%09%09this.undoCloseTabsList.undoCloseTab%28%29%3B%0A%09%09%09%09%09closeMenus%28this%29%3B%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%3B%0A%09%09var%20origMp%20%3D%20this.mp%3B%0A%09%09var%20mp%20%3D%20origMp.cloneNode%28true%29%3B%0A%09%09mp.id%20%3D%20this.button.id%20+%20%22-tabContext%22%3B%0A%09%09var%20_this%20%3D%20this%3B%0A%09%09function%20drawUndoList%28%29%20%7B%0A%09%09%09var%20ok%20%3D%20false%3B%0A%09%09%09var%20opts%20%3D%20_this.options%3B%0A%09%09%09var%20origTemplate%20%3D%20opts.menuTemplate%3B%0A%09%09%09opts.menuTemplate%20%3D%20opts.menuTemplateTabContext%20%7C%7C%20origTemplate%3B%0A%09%09%09_this.mp%20%3D%20mp%3B%0A%09%09%09try%20%7B%0A%09%09%09%09ok%20%3D%20_this.drawUndoList%28%29%3B%0A%09%09%09%7D%0A%09%09%09catch%28e%29%20%7B%0A%09%09%09%09Components.utils.reportError%28e%29%3B%0A%09%09%09%7D%0A%09%09%09opts.menuTemplate%20%3D%20origTemplate%3B%0A%09%09%09_this.mp%20%3D%20origMp%3B%0A%09%09%09return%20ok%3B%0A%09%09%7D%0A%09%09function%20updMenu%28%29%20%7B%0A%09%09%09if%28drawUndoList%28%29%29%0A%09%09%09%09menu.removeAttribute%28%22disabled%22%29%3B%0A%09%09%09else%0A%09%09%09%09menu.setAttribute%28%22disabled%22%2C%20%22true%22%29%3B%0A%09%09%7D%0A%09%09mp._updatePopup%20%3D%20function%28e%29%20%7B%0A%09%09%09if%28e.target%20%21%3D%20this%29%0A%09%09%09%09return%3B%0A%09%09%09document.popupNode%20%3D%20_this.button%3B%0A%09%09%09drawUndoList%28%29%3B%0A%09%09%7D%3B%0A%09%09mp.setAttribute%28%22onpopupshowing%22%2C%20%22this._updatePopup%28event%29%3B%22%29%3B%0A%09%09mp.onclick%20%3D%20function%28e%29%20%7B%0A%09%09%09_this.checkForMiddleClick%28e%2C%20updMenu%29%3B%0A%09%09%7D%3B%0A%09%09menu.appendChild%28mp%29%3B%0A%09%09addEventListener%28%22popupshown%22%2C%20function%28e%29%20%7B%0A%09%09%09if%28e.target%20%3D%3D%20e.currentTarget%29%0A%09%09%09%09setTimeout%28updMenu%2C%200%29%3B%20//%20Pseudo%20async%0A%09%09%7D%2C%20false%2C%20origMi.parentNode%29%3B%0A%09%09addEventListener%28%22DOMMenuItemActive%22%2C%20%20%20this%2C%20false%2C%20mp%29%3B%0A%09%09addEventListener%28%22DOMMenuItemInactive%22%2C%20this%2C%20false%2C%20mp%29%3B%0A%09%09origMi.parentNode.insertBefore%28menu%2C%20origMi.nextSibling%29%3B%0A%09%09origMi.setAttribute%28%22hidden%22%2C%20%22true%22%29%3B%0A%09%7D%2C%0A%09initTooltip%3A%20function%28%29%20%7B%0A%09%09var%20tip%20%3D%20document.getElementById%28this.tipId%29%3B%0A%09%09tip%20%26%26%20tip.parentNode.removeChild%28tip%29%3B%0A%09%09tip%20%3D%20this.tip%20%3D%20this.createElement%28%22tooltip%22%2C%20%7B%0A%09%09%09id%3A%20this.tipId%2C%0A%09%09%09orient%3A%20%22vertical%22%2C%0A%09%09%09onpopupshowing%3A%20%22return%20this.undoCloseTabsList.updTooltip%28this%2C%20document.tooltipNode%29%3B%22%2C%0A%09%09%09onpopuphiding%3A%20%22this.cancelUpdateTimer%28%29%3B%22%0A%09%09%7D%29%3B%0A%09%09tip.undoCloseTabsList%20%3D%20this%3B%0A%09%09tip._updateTimer%20%3D%200%3B%0A%09%09tip.initUpdateTimer%20%3D%20function%28fn%2C%20context%29%20%7B%0A%09%09%09if%28this._updateTimer%29%0A%09%09%09%09clearInterval%28this._updateTimer%29%3B%0A%09%09%09this._updateTimer%20%3D%20setInterval%28function%28%29%20%7B%0A%09%09%09%09fn.call%28context%29%3B%0A%09%09%09%7D%2C%201000%29%3B%0A%09%09%7D%3B%0A%09%09tip.cancelUpdateTimer%20%3D%20function%28%29%20%7B%0A%09%09%09if%28this._updateTimer%29%20%7B%0A%09%09%09%09clearInterval%28this._updateTimer%29%3B%0A%09%09%09%09this._updateTimer%20%3D%200%3B%0A%09%09%09%7D%0A%09%09%7D%3B%0A%09%09var%20btn%20%3D%20this.button%3B%0A%09%09btn.removeAttribute%28%22tooltiptext%22%29%3B%0A%09%09btn.setAttribute%28%22tooltip%22%2C%20this.tipId%29%3B%0A%09%09btn.setAttribute%28%22popupsinherittooltip%22%2C%20%22true%22%29%3B%0A%09%09document.getElementById%28%22mainPopupSet%22%29.appendChild%28tip%29%3B%0A%09%09if%28this.appVersion%20%3E%3D%2061%20%26%26%20%22getAnonymousElementByAttribute%22%20in%20document%29%20%7B%0A%09%09%09var%20label%20%3D%20document.getAnonymousElementByAttribute%28tip%2C%20%22class%22%2C%20%22tooltip-label%22%29%3B%0A%09%09%09label%20%26%26%20label.remove%28%29%3B%0A%09%09%7D%0A%09%7D%2C%0A%09_hasPbExitObserver%3A%20false%2C%0A%09addPbExitObserver%3A%20function%28add%29%20%7B%0A%09%09if%28add%20%3D%3D%20this._hasPbExitObserver%20%7C%7C%20%21%28%22Services%22%20in%20window%29%29%0A%09%09%09return%3B%0A%09%09this._hasPbExitObserver%20%3D%20add%3B%0A%09%09if%28add%29%0A%09%09%09Services.obs.addObserver%28this%2C%20%22last-pb-context-exited%22%2C%20false%29%3B%0A%09%09else%0A%09%09%09Services.obs.removeObserver%28this%2C%20%22last-pb-context-exited%22%29%3B%0A%09%7D%2C%0A%09destroy%3A%20function%28%29%20%7B%0A%09%09window.removeEventListener%28%22TabClose%22%2C%20%20%20%20%20%20%20this%2C%20false%29%3B%0A%09%09window.removeEventListener%28%22SSTabRestoring%22%2C%20this%2C%20false%29%3B%0A%09%09window.removeEventListener%28%22unload%22%2C%20%20%20%20%20%20%20%20%20this%2C%20false%29%3B%0A%09%09if%28this.appName%20%3D%3D%20%22SeaMonkey%22%29%0A%09%09%09window.removeEventListener%28%22TabOpen%22%2C%20this%2C%20false%29%3B%0A%09%09this.mp.removeEventListener%28%22DOMMenuItemActive%22%2C%20%20%20this%2C%20false%29%3B%0A%09%09this.mp.removeEventListener%28%22DOMMenuItemInactive%22%2C%20this%2C%20false%29%3B%0A%09%09this.addPbExitObserver%28false%29%3B%0A%09%09var%20menu%20%3D%20document.getElementById%28this.tcmId%29%3B%0A%09%09if%28menu%29%20%7B%0A%09%09%09menu.parentNode.removeChild%28menu%29%3B%0A%09%09%09this.tabContextUndoClose.removeAttribute%28%22hidden%22%29%3B%0A%09%09%7D%0A%09%09var%20tip%20%3D%20this.tip%3B%0A%09%09tip%20%26%26%20tip.parentNode%20%26%26%20tip.parentNode.removeChild%28tip%29%3B%0A%09%7D%2C%0A%09handleEvent%3A%20function%28e%29%20%7B%0A%09%09switch%28e.type%29%20%7B%0A%09%09%09case%20%22TabClose%22%3A%0A%09%09%09case%20%22SSTabRestoring%22%3A%0A%09%09%09case%20%22TabOpen%22%3A%0A%09%09%09%09setTimeout%28function%28_this%29%20%7B%0A%09%09%09%09%09_this.updUI%28%29%3B%0A%09%09%09%09%7D%2C%200%2C%20this%29%3B%0A%09%09%09break%3B%0A%09%09%09case%20%22DOMMenuItemActive%22%3A%0A%09%09%09case%20%22DOMMenuItemInactive%22%3A%0A%09%09%09%09if%28%21%28%22XULBrowserWindow%22%20in%20window%29%29%0A%09%09%09%09%09break%3B%0A%09%09%09%09XULBrowserWindow.setOverLink%28%0A%09%09%09%09%09e.type%20%3D%3D%20%22DOMMenuItemActive%22%0A%09%09%09%09%09%09%3F%20%28e.target.getAttribute%28%22cb_urlDecoded%22%29%20%7C%7C%20%22%22%29%0A%09%09%09%09%09%09%09.replace%28/%20%5Cn/g%2C%20%22%2C%20%22%29%0A%09%09%09%09%09%09%3A%20%22%22%2C%0A%09%09%09%09%09null%0A%09%09%09%09%29%3B%0A%09%09%09break%3B%0A%09%09%09case%20%22unload%22%3A%0A%09%09%09%09this.updUIGlobal%28%29%3B%0A%09%09%09%09this.destroy%28%29%3B%0A%09%09%7D%0A%09%7D%2C%0A%09observe%3A%20function%28subject%2C%20topic%2C%20data%29%20%7B%0A%09%09if%28topic%20%3D%3D%20%22last-pb-context-exited%22%29%20%7B%0A%09%09%09setTimeout%28function%28_this%29%20%7B%0A%09%09%09%09_this.updUI%28%29%3B%0A%09%09%09%7D%2C%2025%2C%20this%29%3B%0A%09%09%7D%0A%09%7D%2C%0A%0A%09createElement%3A%20function%28name%2C%20attrs%29%20%7B%0A%09%09var%20node%20%3D%20document.createElementNS%28xulns%2C%20name%29%3B%0A%09%09if%28attrs%29%20for%28var%20attrName%20in%20attrs%29%20if%28attrs.hasOwnProperty%28attrName%29%29%0A%09%09%09node.setAttribute%28attrName%2C%20attrs%5BattrName%5D%29%3B%0A%09%09return%20node%3B%0A%09%7D%2C%0A%09get%20tabContextUndoClose%28%29%20%7B%0A%09%09return%20document.getElementById%28%22context_undoCloseTab%22%29%0A%09%09%09%7C%7C%20document.getElementById%28%22tabContextUndoCloseTab%22%29%20//%20Firefox%202.0%0A%09%09%09%7C%7C%20document.getAnonymousElementByAttribute%28gBrowser%2C%20%22tbattr%22%2C%20%22tabbrowser-undoclosetab%22%29%3B%20//%20SeaMonkey%0A%09%7D%2C%0A%09get%20closedWindowCount%28%29%20%7B%0A%09%09if%28%21%28%22getClosedWindowCount%22%20in%20this.ss%29%29%20%7B%0A%09%09%09delete%20this.closedWindowCount%3B%0A%09%09%09return%20this.closedWindowCount%20%3D%200%3B%0A%09%09%7D%0A%09%09this.__defineGetter__%28%22closedWindowCount%22%2C%20function%28%29%20%7B%0A%09%09%09return%20this.ss.getClosedWindowCount%28%29%3B%0A%09%09%7D%29%3B%0A%09%09return%20this.closedWindowCount%3B%0A%09%7D%2C%0A%09get%20closedTabCount%28%29%20%7B%0A%09%09return%20this.ss.getClosedTabCount%28window%29%3B%0A%09%7D%2C%0A%09undoCloseTab%3A%20function%28i%29%20%7B%0A%09%09if%28%22undoCloseTab%22%20in%20window%29%20//%20Firefox%202.0+%0A%09%09%09undoCloseTab%28i%29%3B%0A%09%09else%20//%20SeaMonkey%0A%09%09%09gBrowser.undoCloseTab%28i%29%3B%0A%09%7D%2C%0A%09clearUndoTabsList%3A%20function%28%29%20%7B%0A%09%09var%20closedTabCount%20%3D%20this.closedTabCount%3B%0A%09%09if%28%21closedTabCount%29%0A%09%09%09return%3B%0A%09%09if%28%22forgetClosedTab%22%20in%20this.ss%29%20//%20Gecko%201.9.2+%0A%09%09%09while%28closedTabCount--%29%0A%09%09%09%09this.ss.forgetClosedTab%28window%2C%200%29%3B%0A%09%09else%20%7B%0A%09%09%09//%20Doesn%27t%20work%20in%20SeaMonkey%0A%09%09%09const%20pName%20%3D%20%22browser.sessionstore.max_tabs_undo%22%3B%0A%09%09%09let%20val%20%3D%20cbu.getPrefs%28pName%29%3B%0A%09%09%09cbu.setPrefs%28pName%2C%200%29%3B%0A%09%09%09cbu.setPrefs%28pName%2C%20val%29%3B%0A%09%09%7D%0A%09%09this.updUIGlobal%28%29%3B%0A%09%7D%2C%0A%09clearUndoWindowsList%3A%20function%28%29%20%7B%0A%09%09var%20closedWindowCount%20%3D%20this.closedWindowCount%3B%0A%09%09if%28%21closedWindowCount%29%0A%09%09%09return%3B%0A%09%09if%28%22forgetClosedWindow%22%20in%20this.ss%29%20//%20Gecko%201.9.2+%0A%09%09%09while%28closedWindowCount--%29%0A%09%09%09%09this.ss.forgetClosedWindow%280%29%3B%0A%09%09else%0A%09%09%09this.ss.setWindowState%28window%2C%20%27%7B%22windows%22%3A%5B%7B%7D%5D%2C%22_closedWindows%22%3A%5B%5D%7D%27%2C%20false%29%3B%0A%09%09this.updUIGlobal%28%29%3B%0A%09%7D%2C%0A%09clearAllLists%3A%20function%28%29%20%7B%0A%09%09this.clearUndoTabsList%28%29%3B%0A%09%09this.clearUndoWindowsList%28%29%3B%0A%09%7D%2C%0A%09canDeleteUndoEntry%3A%20function%28mi%29%20%7B%0A%09%09switch%28mi.getAttribute%28%22cb_type%22%29%29%20%7B%0A%09%09%09case%20%22tab%22%3A%20%20%20%20return%20%22forgetClosedTab%22%20%20%20%20in%20this.ss%3B%0A%09%09%09case%20%22window%22%3A%20return%20%22forgetClosedWindow%22%20in%20this.ss%3B%0A%09%09%7D%0A%09%09return%20false%3B%0A%09%7D%2C%0A%09deleteUndoEntry%3A%20function%28mi%29%20%7B%0A%09%09var%20i%20%3D%20+mi.getAttribute%28%22cb_index%22%29%3B%0A%09%09if%28mi.getAttribute%28%22cb_type%22%29%20%3D%3D%20%22window%22%29%20%7B%0A%09%09%09this.ss.forgetClosedWindow%28i%29%3B%0A%09%09%09this.updUIGlobal%28%29%3B%0A%09%09%7D%0A%09%09else%20%7B%0A%09%09%09this.ss.forgetClosedTab%28window%2C%20i%29%3B%0A%09%09%09this.updUI%28%29%3B%0A%09%09%7D%0A%09%09this.drawUndoList%28%29%3B%0A%09%7D%2C%0A%09showMenu%3A%20function%28e%2C%20isContext%2C%20mp%29%20%7B%0A%09%09var%20btn%20%3D%20this.button%3B%0A%09%09document.popupNode%20%3D%20btn.ownerDocument.popupNode%20%3D%20btn%3B%0A%09%09if%28%21mp%29%0A%09%09%09mp%20%3D%20this.mp%3B%0A%09%09if%28%22openPopupAtScreen%22%20in%20mp%29%0A%09%09%09mp.openPopupAtScreen%28e.screenX%2C%20e.screenY%2C%20isContext%29%3B%0A%09%09else%0A%09%09%09mp.showPopup%28btn%2C%20e.screenX%2C%20e.screenY%2C%20isContext%20%3F%20%22context%22%20%3A%20%22popup%22%2C%20null%2C%20null%29%3B%0A%09%7D%2C%0A%09openMenu%3A%20function%28%29%20%7B%0A%09%09var%20mp%20%3D%20this.mp%3B%0A%09%09if%28%22openPopup%22%20in%20mp%29%0A%09%09%09mp.openPopup%28this.button%2C%20%22after_start%22%29%3B%0A%09%09else%0A%09%09%09mp.showPopup%28this.button%2C%20-1%2C%20-1%2C%20%22popup%22%2C%20%22bottomleft%22%2C%20%22topleft%22%29%3B%0A%09%7D%2C%0A%09drawUndoList%3A%20function%28%29%20%7B%0A%09%09var%20mp%20%3D%20this.mp%3B%0A%0A%09%09var%20wc%20%3D%20this.closedWindowCount%3B%0A%09%09var%20tc%20%3D%20this.closedTabCount%3B%0A%09%09var%20ss%20%3D%20this.ss%3B%0A%09%09var%20canRestoreLastSession%20%3D%20%22restoreLastSession%22%20in%20ss%20%26%26%20ss.canRestoreLastSession%0A%09%09if%28%21wc%20%26%26%20%21tc%20%26%26%20%21canRestoreLastSession%29%20%7B%0A%09%09%09mp.textContent%20%3D%20%22%22%3B%0A%09%09%09mp.hidePopup%28%29%3B%0A%09%09%09return%20false%3B%0A%09%09%7D%0A%0A%09%09this._undoWindowItems%20%3D%20wc%20%26%26%20JSON.parse%28ss.getClosedWindowData%28%29%29%3B%0A%09%09this._undoTabItems%20%20%20%20%3D%20tc%20%26%26%20JSON.parse%28ss.getClosedTabData%28window%29%29%3B%0A%09%09var%20df%20%3D%20document.createDocumentFragment%28%29%3B%0A%0A%09%09this.options.menuTemplate.forEach%28function%28sid%2C%20indx%2C%20arr%29%20%7B%0A%09%09%09switch%28sid%29%20%7B%0A%09%09%09%09case%20%22closedWindows%22%3A%0A%09%09%09%09%09wc%20%26%26%20this.addUndoWindowsList%28df%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09case%20%22restoreClosedWindows%22%3A%0A%09%09%09%09%09wc%20%3E%20this.options.hideRestoreAllForSingleEntry%0A%09%09%09%09%09%26%26%20df.appendChild%28this.createElement%28%22menuitem%22%2C%20%7B%0A%09%09%09%09%09%09label%3A%20_localize%28%22restoreAllWindows%22%29%2C%0A%09%09%09%09%09%09accesskey%3A%20_localize%28%22restoreAllWindowsAccesskey%22%29%2C%0A%09%09%09%09%09%09oncommand%3A%20%22for%28var%20i%20%3D%200%3B%20i%20%3C%20%22%20+%20this._undoWindowItems.length%20+%20%22%3B%20++i%29%20undoCloseWindow%28%29%3B%22%0A%09%09%09%09%09%7D%29%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09case%20%22clearClosedWindows%22%3A%0A%09%09%09%09%09wc%20%26%26%20df.appendChild%28this.createElement%28%22menuitem%22%2C%20%7B%0A%09%09%09%09%09%09label%3A%20_localize%28%22clearWindowsHistory%22%29%2C%0A%09%09%09%09%09%09accesskey%3A%20_localize%28%22clearWindowsHistoryAccesskey%22%29%2C%0A%09%09%09%09%09%09oncommand%3A%20%22this.parentNode.parentNode.undoCloseTabsList.clearUndoWindowsList%28%29%3B%22%0A%09%09%09%09%09%7D%29%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09case%20%22closedTabs%22%3A%0A%09%09%09%09%09tc%20%26%26%20this.addUndoTabsList%28df%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09case%20%22restoreClosedTabs%22%3A%0A%09%09%09%09%09tc%20%3E%20this.options.hideRestoreAllForSingleEntry%0A%09%09%09%09%09%26%26%20df.appendChild%28this.createElement%28%22menuitem%22%2C%20%7B%0A%09%09%09%09%09%09label%3A%20_localize%28%22restoreAllTabs%22%29%2C%0A%09%09%09%09%09%09accesskey%3A%20_localize%28%22restoreAllTabsAccesskey%22%29%2C%0A%09%09%09%09%09%09oncommand%3A%20%22for%28var%20i%20%3D%200%3B%20i%20%3C%20%22%20+%20this._undoTabItems.length%20+%20%22%3B%20++i%29%20this.parentNode.parentNode.undoCloseTabsList.undoCloseTab%28%29%3B%22%0A%09%09%09%09%09%7D%29%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09case%20%22clearClosedTabs%22%3A%0A%09%09%09%09%09tc%20%26%26%20df.appendChild%28this.createElement%28%22menuitem%22%2C%20%7B%0A%09%09%09%09%09%09label%3A%20_localize%28%22clearTabsHistory%22%29%2C%0A%09%09%09%09%09%09accesskey%3A%20_localize%28%22clearTabsHistoryAccesskey%22%29%2C%0A%09%09%09%09%09%09oncommand%3A%20%22this.parentNode.parentNode.undoCloseTabsList.clearUndoTabsList%28%29%3B%22%0A%09%09%09%09%09%7D%29%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09case%20%22clearAll%22%3A%0A%09%09%09%09%09%28%0A%09%09%09%09%09%09wc%20%26%26%20tc%0A%09%09%09%09%09%09%7C%7C%20wc%20%26%26%20arr.indexOf%28%22clearClosedWindows%22%29%20%3D%3D%20-1%0A%09%09%09%09%09%09%7C%7C%20tc%20%26%26%20arr.indexOf%28%22clearClosedTabs%22%29%20%3D%3D%20-1%0A%09%09%09%09%09%29%0A%09%09%09%09%09%26%26%20df.appendChild%28this.createElement%28%22menuitem%22%2C%20%7B%0A%09%09%09%09%09%09label%3A%20_localize%28%22clearAllHistory%22%29%2C%0A%09%09%09%09%09%09accesskey%3A%20_localize%28%22clearAllHistoryAccesskey%22%29%2C%0A%09%09%09%09%09%09oncommand%3A%20%22this.parentNode.parentNode.undoCloseTabsList.clearAllLists%28%29%3B%22%0A%09%09%09%09%09%7D%29%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09case%20%22restoreLastSession%22%3A%20//%20Gecko%202.0+%0A%09%09%09%09%09canRestoreLastSession%20%26%26%20df.appendChild%28this.createElement%28%22menuitem%22%2C%20%7B%0A%09%09%09%09%09%09label%3A%20_localize%28%22restoreLastSession%22%29%2C%0A%09%09%09%09%09%09accesskey%3A%20_localize%28%22restoreLastSessionAccesskey%22%29%2C%0A%09%09%09%09%09%09oncommand%3A%20%22this.parentNode.parentNode.undoCloseTabsList.ss.restoreLastSession%28%29%3B%22%0A%09%09%09%09%09%7D%29%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09case%20%22buttonMenu%22%3A%0A%09%09%09%09%09let%20cbMenu%20%3D%20this.cbMenu%3B%0A%09%09%09%09%09if%28cbMenu%29%0A%09%09%09%09%09%09df.appendChild%28cbMenu%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09case%20%22separator%22%3A%0A%09%09%09%09%09if%28df.hasChildNodes%28%29%20%26%26%20df.lastChild.localName%20%21%3D%20%22menuseparator%22%29%0A%09%09%09%09%09%09df.appendChild%28document.createElementNS%28xulns%2C%20%22menuseparator%22%29%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09default%3A%0A%09%09%09%09%09Components.utils.reportError%28this.errPrefix%20+%20%27Invalid%20template%20entry%3A%20%22%27%20+%20sid%20+%20%27%22%27%29%3B%0A%09%09%09%7D%0A%09%09%7D%2C%20this%29%3B%0A%0A%09%09while%28df.hasChildNodes%28%29%20%26%26%20df.lastChild.localName%20%3D%3D%20%22menuseparator%22%29%0A%09%09%09df.removeChild%28df.lastChild%29%3B%0A%0A%09%09this._undoWindowItems%20%3D%20this._undoTabItems%20%3D%20null%3B%0A%0A%09%09mp.textContent%20%3D%20%22%22%3B%0A%09%09if%28%21df.hasChildNodes%28%29%29%20%7B%0A%09%09%09mp.hidePopup%28%29%3B%0A%09%09%09return%20false%3B%0A%09%09%7D%0A%09%09mp.appendChild%28df%29%3B%0A%09%09return%20true%3B%0A%09%7D%2C%0A%09addUndoWindowsList%3A%20function%28undoPopup%29%20%7B%0A%09%09//%20Based%20on%20code%20from%20chrome%3A//browser/content/browser.js%0A%09%09//%20Mozilla/5.0%20%28Windows%3B%20U%3B%20Windows%20NT%205.1%3B%20en-US%3B%20rv%3A1.9.3a1pre%29%20Gecko/20090824%20Minefield/3.7a1pre%0A%0A%09%09var%20keys%20%3D%20this.options.accesskeys.closedWindows%3B%0A%09%09this._undoWindowItems.forEach%28function%28undoItem%2C%20i%29%20%7B%0A%09%09%09var%20tabs%20%3D%20undoItem.tabs%3B%0A%09%09%09var%20%5Bkey%2C%20keyPrefix%5D%20%3D%20this.getKey%28keys%2C%20i%29%3B%0A%09%09%09var%20title%20%3D%20undoItem.title%3B%0A%09%09%09var%20selectedTab%20%3D%20tabs%5BundoItem.selected%20-%201%5D%3B%0A%09%09%09var%20urls%20%3D%20%5B%5D%3B%0A%09%09%09tabs.forEach%28function%28tab%29%20%7B%0A%09%09%09%09if%28%21tab.entries%20%7C%7C%20%21tab.entries.length%29%20//%20Can%20be%20%5B%5D%20for%20about%3Ablank%0A%09%09%09%09%09return%3B%0A%09%09%09%09var%20url%20%3D%20this.convertURI%28tab.entries%5Btab.index%20-%201%5D.url%2C%20120%29%3B%0A%09%09%09%09var%20selectedPrefix%20%3D%20tab%20%3D%3D%20selectedTab%20%26%26%20tabs.length%20%3E%201%0A%09%09%09%09%09%3F%20this.options.windowSelectedTabPrefix%0A%09%09%09%09%09%3A%20%22%22%3B%0A%09%09%09%09urls.push%28selectedPrefix%20+%20url%29%3B%0A%09%09%09%7D%2C%20this%29%3B%0A%09%09%09var%20url%20%3D%20urls.join%28%22%20%5Cn%22%29%3B%0A%09%09%09var%20mi%20%3D%20this.createElement%28%22menuitem%22%2C%20%7B%0A%09%09%09%09label%3A%20keyPrefix%20+%20this.options.windowItemTemplate%0A%09%09%09%09%09.replace%28%22%25title%22%2C%20title%29%0A%09%09%09%09%09.replace%28%22%25count%22%2C%20tabs.length%29%2C%0A%09%09%09%09accesskey%3A%20key%2C%0A%09%09%09%09%22class%22%3A%20%22menuitem-iconic%20bookmark-item%20menuitem-with-favicon%22%2C%0A%09%09%09%09oncommand%3A%20%22undoCloseWindow%28%22%20+%20i%20+%20%22%29%3B%22%2C%0A%09%09%09%09cb_url%3A%20url%2C%0A%09%09%09%09cb_urlDecoded%3A%20this.convertURI%28url%29%2C%0A%09%09%09%09cb_closedAt%3A%20undoItem.closedAt%20%7C%7C%200%2C%0A%09%09%09%09cb_index%3A%20i%2C%0A%09%09%09%09cb_type%3A%20%22window%22%0A%09%09%09%7D%29%3B%0A%09%09%09if%28this.cm%29%0A%09%09%09%09mi.setAttribute%28%22context%22%2C%20this.cmId%29%3B%0A%09%09%09var%20icon%20%3D%20selectedTab.image%20%7C%7C%20selectedTab.attributes%20%26%26%20selectedTab.attributes.image%3B%0A%09%09%09if%28icon%29%0A%09%09%09%09mi.setAttribute%28%22image%22%2C%20this.cachedIcon%28icon%29%29%3B%0A%09%09%09if%28i%20%3D%3D%200%29%0A%09%09%09%09mi.setAttribute%28%22key%22%2C%20%22key_undoCloseWindow%22%29%3B%0A%09%09%09undoPopup.appendChild%28mi%29%3B%0A%09%09%7D%2C%20this%29%3B%0A%09%7D%2C%0A%09addUndoTabsList%3A%20function%28undoPopup%29%20%7B%0A%09%09//%20Based%20on%20code%20from%20chrome%3A//browser/content/browser.js%0A%09%09//%20Mozilla/5.0%20%28Windows%3B%20U%3B%20Windows%20NT%205.1%3B%20en-US%3B%20rv%3A1.9.3a1pre%29%20Gecko/20090824%20Minefield/3.7a1pre%0A%0A%09%09var%20keys%20%3D%20this.options.accesskeys.closedTabs%3B%0A%09%09this._undoTabItems.forEach%28function%28undoItem%2C%20i%29%20%7B%0A%09%09%09var%20state%20%3D%20undoItem.state%3B%0A%09%09%09var%20%5Bkey%2C%20keyPrefix%5D%20%3D%20this.getKey%28keys%2C%20i%29%3B%0A%09%09%09var%20title%20%3D%20undoItem.title%3B%0A%09%09%09var%20url%20%3D%20state%20%26%26%20state.entries%20%26%26%20state.entries%5Bstate.index%20-%201%5D.url%20%7C%7C%20%22%22%3B%0A%09%09%09var%20mi%20%3D%20this.createElement%28%22menuitem%22%2C%20%7B%0A%09%09%09%09label%3A%20keyPrefix%20+%20title%2C%0A%09%09%09%09accesskey%3A%20key%2C%0A%09%09%09%09class%3A%20%22menuitem-iconic%20bookmark-item%20menuitem-with-favicon%22%2C%0A%09%09%09%09oncommand%3A%20%22this.parentNode.parentNode.undoCloseTabsList.undoCloseTab%28%22%20+%20i%20+%20%22%29%3B%22%2C%0A%09%09%09%09cb_url%3A%20url%2C%0A%09%09%09%09cb_urlDecoded%3A%20this.convertURI%28url%29%2C%0A%09%09%09%09cb_closedAt%3A%20undoItem.closedAt%20%7C%7C%200%2C%0A%09%09%09%09cb_index%3A%20i%2C%0A%09%09%09%09cb_type%3A%20%22tab%22%0A%09%09%09%7D%29%3B%0A%09%09%09if%28%0A%09%09%09%09state%0A%09%09%09%09%26%26%20%22attributes%22%20in%20state%0A%09%09%09%09%26%26%20%22privateTab-isPrivate%22%20in%20state.attributes%0A%09%09%09%29%20//%20https%3A//addons.mozilla.org/addon/private-tab/%0A%09%09%09%09mi.setAttribute%28%22privateTab-isPrivate%22%2C%20%22true%22%29%3B%0A%09%09%09if%28this.cm%29%0A%09%09%09%09mi.setAttribute%28%22context%22%2C%20this.cmId%29%3B%0A%09%09%09var%20image%20%3D%20undoItem.image%20//%20Firefox%0A%09%09%09%09%7C%7C%20state%20%26%26%20state.attributes%20%26%26%20state.attributes.image%20//%20SeaMonkey%0A%09%09%09%09%7C%7C%20state%20%26%26%20state.xultab%0A%09%09%09%09%09%26%26%20/%28%3F%3A%5E%7C%20%29image%3D%28%5CS+%29/.test%28state.xultab%29%0A%09%09%09%09%09%26%26%20decodeURI%28RegExp.%241%29%3B%20//%20Only%20Firefox%202.0%20%3F%0A%09%09%09if%28image%29%0A%09%09%09%09mi.setAttribute%28%22image%22%2C%20this.cachedIcon%28image%29%29%3B%0A%09%09%09if%28i%20%3D%3D%200%29%0A%09%09%09%09mi.setAttribute%28%22key%22%2C%20%22key_undoCloseTab%22%29%3B%0A%09%09%09undoPopup.appendChild%28mi%29%3B%0A%09%09%7D%2C%20this%29%3B%0A%09%7D%2C%0A%09getKey%3A%20function%28keys%2C%20i%29%20%7B%0A%09%09var%20key%20%3D%20keys%20%26%26%20keys.charAt%28i%20%25%20keys.length%29%3B%0A%09%09var%20keyPrefix%20%3D%20keys%20%26%26%20%28key%20+%20this.options.accesskeySeparator%29%3B%0A%09%09return%20%5Bkey%2C%20keyPrefix%5D%3B%0A%09%7D%2C%0A%09checkForMiddleClick%3A%20function%28e%2C%20upd%29%20%7B%0A%09%09var%20mi%20%3D%20e.target%3B%0A%09%09if%28%0A%09%09%09%22doCommand%22%20in%20mi%0A%09%09%09%26%26%20e.button%20%3D%3D%201%0A%09%09%09%26%26%20mi.parentNode%20%3D%3D%20e.currentTarget%0A%09%09%29%20%7B%0A%09%09%09mi.doCommand%28%29%3B%0A%09%09%09if%28upd%29%0A%09%09%09%09upd%28%29%3B%0A%09%09%09else%0A%09%09%09%09this.drawUndoList%28%29%3B%0A%09%09%7D%0A%09%7D%2C%0A%09crop%3A%20function%28s%2C%20crop%29%20%7B%0A%09%09if%28crop%20%3D%3D%20undefined%29%0A%09%09%09crop%20%3D%20500%3B%0A%09%09if%28s.length%20%3C%3D%20crop%29%0A%09%09%09return%20s%3B%0A%09%09var%20start%20%3D%20Math.round%28crop*0.6%29%3B%0A%09%09return%20s.substr%280%2C%20start%29%20+%20%22%u2026%22%20+%20s.substr%28start%20-%20crop%29%3B%0A%09%7D%2C%0A%09convertURI%3A%20function%28uri%2C%20crop%29%20%7B%0A%09%09if%28%21uri%20%7C%7C%20uri.indexOf%28%22%5Cn%22%29%20%21%3D%20-1%29%0A%09%09%09return%20uri%3B%0A%09%09uri%20%3D%20this.losslessDecodeURI%28uri%29%3B%0A%09%09return%20this.crop%28uri%2C%20crop%29%3B%0A%09%7D%2C%0A%09losslessDecodeURI%3A%20function%28uri%29%20%7B%0A%09%09if%28uri%29%20try%20%7B%0A%09%09%09return%20this._losslessDecodeURI%28uri%29%3B%0A%09%09%7D%0A%09%09catch%28e%29%20%7B%0A%09%09%09Components.utils.reportError%28e%29%3B%0A%09%09%7D%0A%09%09return%20uri%3B%0A%09%7D%2C%0A%09get%20_losslessDecodeURI%28%29%20%7B%0A%09%09var%20ldu%3B%0A%09%09if%28%22losslessDecodeURI%22%20in%20window%29%0A%09%09%09ldu%20%3D%20losslessDecodeURI%3B%0A%09%09else%20if%28%22UrlbarInput%22%20in%20window%29%20//%20Firefox%2075+%0A%09%09%09ldu%20%3D%20Components.utils.import%28%22resource%3A///modules/UrlbarInput.jsm%22%2C%20%7B%7D%29.losslessDecodeURI%3B%0A%09%09delete%20this._losslessDecodeURI%3B%0A%09%09return%20this._losslessDecodeURI%20%3D%20ldu%0A%09%09%09%3F%20function%28uri%29%20%7B%0A%09%09%09%09return%20ldu%28makeURI%28uri%29%29%3B%0A%09%09%09%7D%0A%09%09%09%3A%20decodeURI%3B%0A%09%7D%2C%0A%09cachedIcon%3A%20function%28src%29%20%7B%0A%09%09src%20%3D%20src.replace%28/%5B%26%23%5D-moz-resolution%3D%5Cd+%2C%5Cd+%24/%2C%20%22%22%29%3B%20//%20Firefox%2022+%0A%09%09if%28%0A%09%09%09%21/%5Ehttps%3F%3A/.test%28src%29%0A%09%09%09//%20IDN%2C%20see%20https%3A//bugzilla.mozilla.org/show_bug.cgi%3Fid%3D311045%0A%09%09%09%7C%7C%20/%5Ehttps%3F%3A%5C/%5C/%5B%5E.%3A%5C/%5D+%5C.%5B%5Ea-z0-9-%5D+%28%3F%3A%5C/%7C%24%29/.test%28src%29%0A%09%09%09%7C%7C%20this.appName%20%3D%3D%20%22SeaMonkey%22%20%26%26%20this.appVersion%20%3C%3D%202%0A%09%09%09%7C%7C%20this.appName%20%3D%3D%20%22Firefox%22%20%20%20%26%26%20this.appVersion%20%3C%3D%203.5%0A%09%09%29%0A%09%09%09return%20src%3B%0A%09%09return%20%22moz-anno%3Afavicon%3A%22%20+%20src%3B%20//%20https%3A//bugzilla.mozilla.org/show_bug.cgi%3Fid%3D467828%0A%09%7D%2C%0A%09updUI%3A%20function%28%29%20%7B%0A%09%09var%20tabsCount%20%3D%20this.closedTabCount%3B%0A%09%09var%20dis%20%3D%20%21tabsCount%20%26%26%20%21this.closedWindowCount%3B%0A%09%09if%28%0A%09%09%09dis%0A%09%09%09%26%26%20this.options.useMenu%0A%09%09%09%26%26%20this.options.menuTemplate.indexOf%28%22restoreLastSession%22%29%20%21%3D%20-1%0A%09%09%09%26%26%20%22restoreLastSession%22%20in%20this.ss%20%26%26%20this.ss.canRestoreLastSession%0A%09%09%29%0A%09%09%09dis%20%3D%20false%3B%0A%09%09this.button.disabled%20%3D%20dis%3B%0A%09%7D%2C%0A%09updTooltip%3A%20function%28tip%2C%20tn%29%20%7B%0A%09%09var%20template%2C%20header%2C%20title%2C%20url%2C%20closedAt%3B%0A%09%09if%28tn%20%3D%3D%20this.button%29%20%7B%0A%09%09%09template%20%3D%20this.options.buttonTipTemplate%3B%0A%09%09%09header%20%3D%20_localize%28%22restoreTab%22%29%3B%0A%09%09%09let%20undoTabItems%20%3D%20JSON.parse%28this.ss.getClosedTabData%28window%29%29%3B%0A%09%09%09if%28undoTabItems.length%29%20%7B%0A%09%09%09%09let%20lastItem%20%3D%20undoTabItems%5B0%5D%3B%0A%09%09%09%09title%20%3D%20lastItem.title%3B%0A%09%09%09%09url%20%3D%20lastItem.state%20%26%26%20lastItem.state.entries%0A%09%09%09%09%09%26%26%20lastItem.state.entries%5BlastItem.state.index%20-%201%5D.url%3B%0A%09%09%09%09closedAt%20%3D%20lastItem.closedAt%20%7C%7C%200%3B%0A%09%09%09%7D%0A%09%09%7D%0A%09%09else%20if%28tn.hasAttribute%28%22cb_index%22%29%29%20%7B%0A%09%09%09template%20%3D%20this.options.itemTipTemplate%3B%0A%09%09%09title%20%3D%20tn.getAttribute%28%22label%22%29%3B%0A%09%09%09url%20%3D%20tn.getAttribute%28%22cb_url%22%29%3B%0A%09%09%09closedAt%20%3D%20+tn.getAttribute%28%22cb_closedAt%22%29%3B%0A%09%09%7D%0A%09%09else%20%7B%0A%09%09%09return%20false%3B%0A%09%09%7D%0A%0A%09%09var%20tipData%20%3D%20this.getTooltipData%28template%2C%20header%2C%20title%2C%20url%2C%20closedAt%29%3B%0A%09%09tip.textContent%20%3D%20%22%22%3B%0A%09%09tip.appendChild%28tipData%29%3B%0A%09%09if%28closedAt%20%26%26%20template.indexOf%28%22closedAt%22%29%20%21%3D%20-1%29%20%7B%0A%09%09%09tip.initUpdateTimer%28function%28%29%20%7B%0A%09%09%09%09var%20tipData%20%3D%20this.getTooltipData%28template%2C%20header%2C%20title%2C%20url%2C%20closedAt%29%3B%0A%09%09%09%09if%28tipData.textContent%20%21%3D%20tip.textContent%29%20%7B%0A%09%09%09%09%09tip.textContent%20%3D%20%22%22%3B%0A%09%09%09%09%09tip.appendChild%28tipData%29%3B%0A%09%09%09%09%7D%0A%09%09%09%7D%2C%20this%29%3B%0A%09%09%7D%0A%09%09return%20tip.hasChildNodes%28%29%3B%0A%09%7D%2C%0A%09getTooltipData%3A%20function%28template%2C%20header%2C%20title%2C%20url%2C%20closedAt%29%20%7B%0A%09%09var%20df%20%3D%20document.createDocumentFragment%28%29%3B%0A%09%09var%20hasHeader%20%3D%20header%20%26%26%20template.indexOf%28%22header%22%29%20%21%3D%20-1%3B%0A%09%09function%20item%28key%2C%20val%29%20%7B%0A%09%09%09var%20lbl%20%3D%20document.createElementNS%28xulns%2C%20%22label%22%29%3B%0A%09%09%09lbl.className%20%3D%20%22cb-%22%20+%20key%20+%20%22%20tooltip-label%22%3B%0A%09%09%09lbl.textContent%20%3D%20val%3B%0A%09%09%09lbl.setAttribute%28%22maxwidth%22%2C%20%22450%22%29%3B%20//%20Trick%20to%20restore%20right%20border%20for%20long%20lines%0A%09%09%09if%28key%20%3D%3D%20%22closedAt%22%20%7C%7C%20hasHeader%20%26%26%20key%20%21%3D%20%22header%22%29%0A%09%09%09%09lbl.style.color%20%3D%20%22grayText%22%3B%0A%09%09%09return%20df.appendChild%28lbl%29%3B%0A%09%09%7D%0A%09%09template.forEach%28function%28key%29%20%7B%0A%09%09%09switch%28key%29%20%7B%0A%09%09%09%09case%20%22header%22%3A%0A%09%09%09%09%09if%28header%29%0A%09%09%09%09%09%09item%28key%2C%20header%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09case%20%22title%22%3A%0A%09%09%09%09%09if%28title%20%26%26%20title%20%21%3D%20url%29%0A%09%09%09%09%09%09item%28key%2C%20title%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09case%20%22url%22%3A%0A%09%09%09%09%09if%28url%29%0A%09%09%09%09%09%09item%28key%2C%20this.convertURI%28url%29%29%3B%0A%09%09%09%09break%3B%0A%09%09%09%09case%20%22closedAt%22%3A%0A%09%09%09%09%09if%28%21closedAt%29%0A%09%09%09%09%09%09break%3B%0A%09%09%09%09%09let%20dt%20%3D%20Math.round%28Math.max%280%2C%20Date.now%28%29%20-%20closedAt%29/1000%29%3B%0A%09%09%09%09%09let%20days%20%3D%20Math.floor%28dt/24/3600%29%3B%0A%09%09%09%09%09dt%20-%3D%20days*24*3600%3B%0A%09%09%09%09%09let%20d%20%3D%20new%20Date%28%28dt%20+%20new%20Date%28dt%29.getTimezoneOffset%28%29*60%29*1000%29%3B%0A%09%09%09%09%09let%20m%20%3D%20d.getMinutes%28%29%3B%0A%09%09%09%09%09let%20ts%20%3D%20d.getHours%28%29%20+%20%22%3A%22%20+%20%28m%20%3E%209%20%3F%20m%20%3A%20%220%22%20+%20m%29%3B%0A%09%09%09%09%09if%28days%29%0A%09%09%09%09%09%09ts%20%3D%20days%20+%20_localize%28%22day%22%29%20+%20%22%20%22%20+%20ts%3B%0A%09%09%09%09%09let%20tsTip%20%3D%20_localize%28%22itemTip%22%29%0A%09%09%09%09%09%09.replace%28%22%25ago%22%2C%20ts%29%0A%09%09%09%09%09%09.replace%28%22%25date%22%2C%20new%20Date%28closedAt%29.toLocaleString%28%29%29%3B%0A%09%09%09%09%09item%28key%2C%20tsTip%29%3B%0A%09%09%09%7D%0A%09%09%7D%2C%20this%29%3B%0A%09%09return%20df%3B%0A%09%7D%2C%0A%09get%20wm%28%29%20%7B%0A%09%09delete%20this.wm%3B%0A%09%09return%20this.wm%20%3D%20Components.classes%5B%22@mozilla.org/appshell/window-mediator%3B1%22%5D%0A%09%09%09.getService%28Components.interfaces.nsIWindowMediator%29%3B%0A%09%7D%2C%0A%09updUIGlobal%3A%20function%28%29%20%7B%0A%09%09var%20isSeaMonkey%20%3D%20this.appName%20%3D%3D%20%22SeaMonkey%22%3B%0A%09%09var%20ws%20%3D%20this.wm.getEnumerator%28isSeaMonkey%20%3F%20null%20%3A%20%22navigator%3Abrowser%22%29%3B%0A%09%09const%20id%20%3D%20this.button.id%3B%0A%09%09while%28ws.hasMoreElements%28%29%29%20%7B%0A%09%09%09let%20win%20%3D%20ws.getNext%28%29%3B%0A%09%09%09if%28isSeaMonkey%20%26%26%20%21this.isBrowserWindow%28win%29%29%0A%09%09%09%09continue%3B%0A%09%09%09let%20btn%20%3D%20win.document.getElementById%28id%29%3B%0A%09%09%09if%28btn%20%26%26%20%22undoCloseTabsList%22%20in%20btn%29%20%7B%0A%09%09%09%09let%20ucl%20%3D%20btn.undoCloseTabsList%3B%0A%09%09%09%09ucl.ensureSessionsInitialized%28ucl.updUI%2C%20ucl%29%3B%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D%2C%0A%09isBrowserWindow%3A%20function%28win%29%20%7B%0A%09%09var%20loc%20%3D%20window.location.href%3B%0A%09%09return%20loc%20%3D%3D%20%22chrome%3A//browser/content/browser.xul%22%0A%09%09%09%7C%7C%20loc%20%3D%3D%20%22chrome%3A//navigator/content/navigator.xul%22%3B%0A%09%7D%2C%0A%09ensureSessionsInitialized%3A%20function%28callback%2C%20context%29%20%7B%0A%09%09var%20_this%20%3D%20this%3B%0A%09%09var%20stopTime%20%3D%20Date.now%28%29%20+%203e3%3B%0A%09%09%28function%20ensureInitialized%28%29%20%7B%0A%09%09%09try%20%7B%0A%09%09%09%09_this.ss.getClosedTabCount%28window%29%3B%0A%09%09%09%09callback.call%28context%29%3B%0A%09%09%09%09return%3B%0A%09%09%09%7D%0A%09%09%09catch%28e%29%20%7B%0A%09%09%09%09if%28Date.now%28%29%20%3E%20stopTime%29%20%7B%0A%09%09%09%09%09Components.utils.reportError%28%0A%09%09%09%09%09%09_this.errPrefix%0A%09%09%09%09%09%09+%20%22Can%27t%20initialize%3A%20nsISessionStore.getClosedTabCount%28%29%20failed%22%0A%09%09%09%09%09%29%3B%0A%09%09%09%09%09Components.utils.reportError%28e%29%3B%0A%09%09%09%09%09return%3B%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%09setTimeout%28ensureInitialized%2C%2050%29%3B%0A%09%09%7D%29%28%29%3B%0A%09%7D%0A%7D%3B%0A%0Aif%28%21this.undoCloseTabsList.options.useMenu%20%26%26%20this.undoCloseTabsList.useCentextMenu%29%20%7B%0A%09this.oncontextmenu%20%3D%20function%28e%29%20%7B%0A%09%09if%28%0A%09%09%09e.target%20%21%3D%20this%0A%09%09%09%7C%7C%20e.ctrlKey%20%7C%7C%20e.shiftKey%20%7C%7C%20e.altKey%20%7C%7C%20e.metaKey%0A%09%09%09%7C%7C%20%21this.undoCloseTabsList.mp.hasChildNodes%28%29%0A%09%09%29%0A%09%09%09return%3B%0A%09%09e.preventDefault%28%29%3B%0A%09%09this.undoCloseTabsList.showMenu%28e%29%3B%20//%20Show%20menu%20without%20%22context%22%20flag%0A%09%7D%3B%0A%7D%0Aif%28this.undoCloseTabsList.options.rightClickToUndoCloseTab%29%20%7B%0A%09this.oncontextmenu%20%3D%20function%28e%29%20%7B%0A%09%09if%28e.target%20%3D%3D%20this%20%26%26%20%21e.ctrlKey%20%26%26%20%21e.shiftKey%20%26%26%20%21e.altKey%20%26%26%20%21e.metaKey%29%0A%09%09%09e.preventDefault%28%29%3B%0A%09%7D%3B%0A%7D%0A%0Athis.disabled%20%3D%20true%3B%0AsetTimeout%28function%28_this%29%20%7B%0A%09_this.undoCloseTabsList.init%28%29%3B%0A%7D%2C%200%2C%20this%29%3B%0A%0A//%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%0A//%20Styles%0A//%20Used%20icons%20from%20Undo%20Closed%20Tabs%20Button%20extension%0A%0A//%20Styles%20can%27t%20override%20hardcoded%20icon%0Aif%28%20//%20Remove%20icon%20only%20if%20nsIStyleSheetService%20works%20on-the-fly%20%28Firefox%203.0+%29%0A%09%21Components.ID%28%22%7B41d979dc-ea03-4235-86ff-1e3c090c5630%7D%22%29%0A%09%09.equals%28Components.interfaces.nsIStyleSheetService%29%0A%29%20%7B%0A%09let%20icon%20%3D%20this.icon%0A%09%09%7C%7C%20this.ownerDocument.getAnonymousElementByAttribute%28this%2C%20%22class%22%2C%20%22toolbarbutton-icon%22%29%3B%0A%09if%28icon%29%0A%09%09icon.src%20%3D%20%22%22%3B%0A%09else%0A%09%09this.image%20%3D%20%22%22%3B%0A%7D%0A%0Avar%20cssStr%20%3D%20%27%5C%0A%09@namespace%20url%28%22http%3A//www.mozilla.org/keymaster/gatekeeper/there.is.only.xul%22%29%3B%5Cn%5C%0A%09@-moz-document%20url%28%22%25windowURL%25%22%29%20%7B%5Cn%5C%0A%09%09%25button%25%20%7B%5Cn%5C%0A%09%09%09list-style-image%3A%20url%28%22data%3Aimage/png%3Bbase64%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%22%29%20%21important%3B%5Cn%5C%0A%09%09%09-moz-image-region%3A%20rect%280%2C%2024px%2C%2024px%2C%200%29%20%21important%3B%5Cn%5C%0A%09%09%7D%5Cn%5C%0A%09%09%25button%25%3Ahover%20%7B%5Cn%5C%0A%09%09%09-moz-image-region%3A%20rect%280%2C%2048px%2C%2024px%2C%2024px%29%20%21important%3B%5Cn%5C%0A%09%09%7D%5Cn%5C%0A%09%09%25button%25%5Bdisabled%3D%22true%22%5D%20%7B%5Cn%5C%0A%09%09%09-moz-image-region%3A%20rect%280%2C%2072px%2C%2024px%2C%2048px%29%20%21important%3B%5Cn%5C%0A%09%09%7D%5Cn%5C%0A%09%09toolbar%5Biconsize%3D%22small%22%5D%20%25button%25%20%7B%5Cn%5C%0A%09%09%09-moz-image-region%3A%20rect%2824px%2C%2016px%2C%2040px%2C%200%29%20%21important%3B%5Cn%5C%0A%09%09%7D%5Cn%5C%0A%09%09toolbar%5Biconsize%3D%22small%22%5D%20%25button%25%3Ahover%20%7B%5Cn%5C%0A%09%09%09-moz-image-region%3A%20rect%2824px%2C%2032px%2C%2040px%2C%2016px%29%20%21important%3B%5Cn%5C%0A%09%09%7D%5Cn%5C%0A%09%09toolbar%5Biconsize%3D%22small%22%5D%20%25button%25%5Bdisabled%3D%22true%22%5D%20%7B%5Cn%5C%0A%09%09%09-moz-image-region%3A%20rect%2824px%2C%2048px%2C%2040px%2C%2032px%29%20%21important%3B%5Cn%5C%0A%09%09%7D%5Cn%5C%0A%09%7D%27%0A%09.replace%28/%25windowURL%25/g%2C%20window.location.href%29%0A%09.replace%28/%25button%25/g%2C%20%22%23%22%20+%20this.id%29%3B%0Avar%20cssURI%20%3D%20this.cssURI%20%3D%20Components.classes%5B%22@mozilla.org/network/io-service%3B1%22%5D%0A%09.getService%28Components.interfaces.nsIIOService%29%0A%09.newURI%28%22data%3Atext/css%2C%22%20+%20encodeURIComponent%28cssStr%29%2C%20null%2C%20null%29%3B%0Avar%20sss%20%3D%20this.sss%20%3D%20Components.classes%5B%22@mozilla.org/content/style-sheet-service%3B1%22%5D%0A%09.getService%28Components.interfaces.nsIStyleSheetService%29%3B%0Aif%28%21sss.sheetRegistered%28cssURI%2C%20sss.USER_SHEET%29%29%0A%09sss.loadAndRegisterSheet%28cssURI%2C%20sss.USER_SHEET%29%3B%0A%0A%0Athis.onDestroy%20%3D%20function%28reason%29%20%7B%0A%09this.undoCloseTabsList.destroy%28%29%3B%0A%09if%28reason%20%3D%3D%20%22destructor%22%29%20//%20May%20happens%20before%20%22unload%22%0A%09%09this.undoCloseTabsList.updUIGlobal%28%29%3B%0A%09if%28reason%20%3D%3D%20%22update%22%20%7C%7C%20reason%20%3D%3D%20%22delete%22%29%20%7B%0A%09%09let%20sss%20%3D%20this.sss%3B%0A%09%09let%20cssURI%20%3D%20this.cssURI%3B%0A%09%09if%28sss.sheetRegistered%28cssURI%2C%20sss.USER_SHEET%29%29%0A%09%09%09sss.unregisterSheet%28cssURI%2C%20sss.USER_SHEET%29%3B%0A%09%7D%0A%7D%3B%0Aif%28this.undoCloseTabsList.options.useMenu%29%20%7B%0A%09this.type%20%3D%20%22menu%22%3B%0A%09this.orient%20%3D%20%22horizontal%22%3B%0A%7D%5D%5D%3E%3C/initcode%3E%0A%20%20%3Ccode%3E%3C%21%5BCDATA%5Bif%28%21event.target%29%20//%20Button%27s%20hotkey%20pressed%0A%09this.undoCloseTabsList.drawUndoList%28%29%20%26%26%20this.undoCloseTabsList.openMenu%28%29%3B%5D%5D%3E%3C/code%3E%0A%20%20%3Caccelkey%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/accelkey%3E%0A%20%20%3Chelp%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/help%3E%0A%20%20%3Cattributes/%3E%0A%3C/custombutton%3E

Отсутствует

 

№1601924-11-2021 13:04:07

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

Re: Custom Buttons

Letterman
у меня работает. та же версия ФФ и та же кнопка, за исключением небольшого косяка - при наведении курсора на кнопку появляется пустой тултип, но для меня это не критично.
сама кнопка
в секцию "код"

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

Выделить код

Код:

/*CODE*/
if(!event.target) // Button's hotkey pressed
	this.undoCloseTabsList.drawUndoList() && this.undoCloseTabsList.openMenu();


в секцию "инициализация"
скрытый текст

Выделить код

Код:

/*Initialization Code*/
// 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-2020
// version 0.3.3.2 - 2020-03-14

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: ""
	},
	accesskeySeparator: " ", // <accesskey><separator><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();"
		});
		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.accesskeySeparator);
		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;
		uri = this.losslessDecodeURI(uri);
		return this.crop(uri, crop);
	},
	losslessDecodeURI: function(uri) {
		if(uri) try {
			return this._losslessDecodeURI(uri);
		}
		catch(e) {
			Components.utils.reportError(e);
		}
		return uri;
	},
	get _losslessDecodeURI() {
		var ldu;
		if("losslessDecodeURI" in window)
			ldu = losslessDecodeURI;
		else if("UrlbarInput" in window) // Firefox 75+
			ldu = Components.utils.import("resource:///modules/UrlbarInput.jsm", {}).losslessDecodeURI;
		delete this._losslessDecodeURI;
		return this._losslessDecodeURI = ldu
			? function(uri) {
				return ldu(makeURI(uri));
			}
			: decodeURI;
	},
	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 + " tooltip-label";
			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))
				continue;
			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,iVBORw0KGgoAAAANSUhEUgAAAEgAAAAoCAYAAABdGbwdAAAOW0lEQVR4Xu1ZCXRT15n+73tPetLTYsvIeN9k4wXZ8W5I2MJqYAI0gTQhTdIUkmkhwaVJAwdSWiC0zEwTAtOZQMChZCYLYTidaVJiEggEQkkh2BjjBWy8ywteJEuydr335pexGSNw7QDm5MzhO+c/15b0fVf69N37dP8Ho4T7OCCKdL0oykRRJDAKQF3qeL2//r0HdTukmhqRTbJCgtUGk4sB5HCXUSGK0koX6IK18GBxG+qPEtasWaNZu3btk3fVoNPNotwbAVkiiK+v3ff5tqW/+ugI3EUcx1SCAzK9LnHLmvc+37703z78YpTMCWMY5hwm9CP8W3rnBmHUUY1TB8JEm5v/3eb9xxblRGlTZQyV7EvURlEcRmtk+iFeyHN5+N9u+vjYo2lhmlQW9X2JuptLbcOGDTqFQlGi1+ujcXSyLMsNRWBGuB+QSgAFb4GpNt6zYeOHx/Lm6mOpgoeT4Gh5g/pfzp1em9AadKTCLF7uKAHL9OnEC34Yib4Xl6zN7dnw6w+PTcyKCaF+Ni0NvqxsVL+1/69rksPGHC0TxcvdX4H1Vvol589ROMzCCoK/A0OzIaqq6vJvEhMT5fHx8VRXVxcvCELpzp1vV6rV6jMp45O3Z2XmmAcIZID4+ze2/hSHdViB4AcJy5IxkXFMcEouu/UvJfQ/ZCbCE3lJoJICdJjtcNHQCR9+UwXtPVZ+Sgj97rJFj/0ySQu9hBBxkP4LOKzFUsINIMBIUT8qTjo2JUeB+pIcXSQsyNUDSwPUtnZAdVsnHCuvB0HgvZNCmD3LFz261l//fGnxMZpmYhmG7oQhgGYoS4pLk5KTk+nw8HDwwev1gtlsBovFAq1trQJDM7zNZnto9erV564bhOZIcTLjj370Y1YTeKM/IpZVoEmt1UOt3vs5mapPhLk5erhiAaCRrWEBxsoA0oMADD0OWP9fJ8AtkiObX8x/PAfAAmhSv37XU0ufkavVATfp2wmD+t4+/Yy4aJiUOg4azd4+fY6hQM1SEKlioLGjC/7jRAmoFNwXr7+U/8MBfUyPz/SOjPQsCX5gB9wCbW1tdFFRkRyTQ7Ra7VBJ9r0OamtrnTzP5xQUFFQMLDEOSwgZG+JEN4XBJC9QlInhZPuOlxFGykFSkh4u9VwzzoPVZr9WF00AcUo57F6WDyvfOzrzD++f+kXN05O3jgNw9etDaGjYLfV7GFa276sSQtESCAsNh/I2Kwj92TD2j5VXAbQcC/+YPxneLvp6lp8+0/92xN7eXifcAj09PaxcLgdcRjAUCCHgSxZN02xjY+Mn77zzjt5/DxLQxe7BJIoIFCe4uWempgauKjwsOXL2PGSNT74mCGSQOkC5g0BHL4HXFk2mXnqv6LUDxyuPAsCpEelPSQtcdblIcrqiGuIjIwfidQN67QCdFhrmZOqpP50+768/wED9mxEVFQUOhyPoypUr2nHjxlESiQSGQkhICEGjQ61W65abDEIXb5iAYHGCh4lRSG3bl+WHrSosYp0uNyTrYvtiVFVfD2arBQLUaogIDgajSg28WwoPxEbSV1qNr/gMGk5fIXroWNTf8fy8sFV7PmM9Xi9EjQ3pi3xzRwc4nQ6QyWQwBpenHVNgkVAwRhNI17aZ/PXFQfr+wPQndePzDkxHZGxsLI0Ag8HAoxk+wwSlUkmNGTOG4N8+kziPxzPN3yARcdMEBESQi25jjNJn0lxdwbtFcofLCSpOAXVNDfyPp+i7q9pMquNnz8qjQsPAhebZ3QLx8N5xI9EHEfUptynGZ9LyebpVhZ/JPR4vyFkZdBk7+eempXZVtpjUp6uvyLUBGggZowWHmyduD5/gr4RlhL8D3IN8z7taW1vjQ0NDaTQBZsyYUWS32+WYmNy6ujoFpo1IpVLACr3JIIqijEP9YFKK3p74ANb+1rJ5+oLCQxzDsBDESS3LcmNOiiROanKlz5/9xp8ZpVwBHSYzaBVU0HfV16ml9u3Pzx9fsPsQ1w0UCeZYy/LcmK+F3Dhplz1tfv62Txg5KweeF8Dmct9KvxuGAV7FTuPr3N3d3SmYTAGN6MACNCbxasdV2ul0yhmGAZZlxWH3oMGggQcFuIwJQT6T5qat2n1IDVLOSYlCOwGRjlCzIgUoYDaTLpMRlkzMbfvzd9SXo358IGvf8cK8tBd3fqoiQDuJILQzRKTDVaxIo36vw0EsNitMnZbS/t83brLDJWhwkr6oqanxYHJiB3F8l/m+/Qkft+G4td8g/01uaNCCACrRZUrScsZ/f26GlDidTf0c5mR1GxFFIJ1Gk6iUSYSZGQkHvqu+pF8/QSMz7lo+SyLaHdf1j1Y2UygP5l6rqOakwqyMhP1DL+HhkZCQcBAJFJYACJPJJKEZWsrzvAcTZsIE7WX8LnPCSCJKoeMBovtqVriaxq3NiVTR7uZlqz8+zXjRIRVH85ufnnWREeHQneg/EKJEfa5P3+zwcGv/dJbmUV/NMV7Uv0BJUH+ke9DQl/bBv5U0EkZCEBcxPbMnTJjgYvBHnAQJK/0SNCxoNAKL9HNALpPIXp2bxbeaLdTD6eMa1RrVZrsF6vr1V9+pvlrG2l6dlyl02x0wSa9rCtQoN5mlUI9HjBAkFKL5dhylw+gPl6jWqksVPCbKioQ4LCODWBceHvFYRERkMRKSsIxwG+ABlIvzksilxqbLTRdOe4qbmjQ/X7HScYKiXouJjn0sPCKiDAk6rO7b1X98QjJUNxtqm8r+5ihtrA9etfIl5wWK2hYWFp6qVKjMSFDh5zHCbQI3altSYorM7rCHNDc3rkDC8wwSYh79wRI7IeQYnksO3e4HkIhij4QSfpupiwrREE9g46VyGjXFN7f9c9SiRY/ZkPAXvKQ6b/cLkFCiWULDxoy4qEhcflzDpYsEIZZdLHUEa8dWovbbbrebv5MEIf8VmqZlAeqAlS0U1QQIhhDqW3S9GQ9rH9xhBxBcNts+vGzGMBSVjYTa/jX+LU56FfUP3AX9D/C4oEP9VCTUXdOnzuIcBp7nywBBURTcLgRB6EYtGjWOoe4lQDA0TZ3BBznfk3epVeolFHEgoXXAIKxLd0sfdXg0wYKE9muGkG9xkOMXYIS7ANQmQUFBh3Eww/cG93Ef93HnPWHk/39FqyhyO882TL1dk3xN948qrmYA8u/gLsRULC1831BvEgP3FDedebrwiCfi5b2/+K78DlFU/rG05fgPdx12R7z8x5VwG1i3bt0KvH8lYK2Bewj/pn0iDtxgQkR8clD32NQ9re1dut8szIWJWw6UR0u9+x4I8BRueWm5GRCD+DHgdxMxKi4poCcyfe+pi3Xjf5mfBc/uOXwuQurZlRJOf7Rt2TP2QXckZDg8gqUEPxSfK5nf02NeiL0bFs9K7eoA9amI8LBdCxYs+vKeGbRjx5tbCUWtYqVS5wBBplBRHaHp6vP1HfQrCybDGE4CLHihqLwJPi2uFjut1gWn1i89BIjtO97cjMMreMC7zmc5BdUblaM6XNZM/2TWBAjkWOgwGqGssR0uNraJNqdjztevPXUUEKUXSt6XsbKF2JPx3LA0Kyq5lpZWNjs7mzAMA52dnb4TN7S3twPO9fOVK1f+6z0x6K3tvz+Ox41JY8eGCAMnyio7SBb+bj9VsGQBBGq04BUBVBKAGCVAotIDvzp4ij9X364r2/xUE/KPLVz46BRsuF/n19iJZOE/7SdLpj0IUrkKvIIICgmFRjMg4W3w8alSvsfmjCndtLQFDTqui4t/EIC4B/3sJwcPHlSmpaWBSqWCwcDeMpSVlTnwaDRpxYoV52EUwQwiuLGT1jxACGcY+eOT06IPHD9F5k+ZAhShoPjqVVArFKAL0cCTD6XSDSZbEfL0WMT3Cxr5DQP8sYxE/kheSvTRknKSlZzSF9VLPT3A9fWWlTAuMoyubG7/DLnp/aZ6BZ6/zqdpGvLy8jTV1dXheMqmCCF96cGU9d2ZwMa7rKWlZTdSc++VQQIh5LpBcpEnr85I6XS5vVmffnWCUnIcCB67x+7yMmfkHJmVMR6wb5zg1zA3/B/fS9bPTu3a5OUzv6msoHD5AgNej8PDMzQtIaHaYDD1OpL95jfAIOh0OgMab8HGehLLsgRNM+KhVIH/y8LCwgiey+IAcU8MEkEU/d+gEryG9fnpxl97vbM+L66mXp6Z+s1Pp6epcrYczPjyQjUx9zrpAT4B0mewH7954/zMrvVefvYX52uogun6My/OeECRjfx2QvtSR/s1u1rAD3h7GA/WlB33nRw0pQKTw508eSIblxlRKBSOUTfIr19s8CeowGXY9EhWd6CEjM+L1ZZebu+ZYHN5iWAywrzscRWVgwi34nPIf31hdpdGSukf0gWXVLWbJtjdHiLarDA7M7686jrZL0F+SeI4rk6j0TRYrdaHpVKWwrlc2Dl4HUYZvo6iGicL9EVoqDcYAB7DxvzUE0gQC7+pnYJGwBR9tPvZ6enLo9/YGoD8IKRfT5A/1OBp3jg39aSP/+7faicDEJiZrnMvn53zkxewI4j8YEJABMD5hwCmp+85NGg6Li1MO3yam5u3G0YZZE/hzv9RqdQ5M2fMkSKeG47ActyTxfWGxQ0Xvu1uudoyOUgu/0NgoCZ72tTpCvxmnxoBf+mF+pbFNaVnujpbm6bNmTNvF6ZDj1dAqcvlenY4Pi6rJ7q6OhcYTd1GfP28zIzsulFNEJpiWbL4iU8wBX/FCQ3DOioI70+Mj653Gq4ktjbWshJ1QPcPFi0+KAjCaeQ3w3Dg+X2ZushL1uaalLamOgab44boqJgLeMn+mqKoYefHTXqvVhtcivNldHZ1EhhlMHI59wGaY7TZbFdGQsAP0owRb5DL5InI70D++/38hhHyDchvZFlpvI+PBv0nGmNCfiMgRmCQz0QDwzDlyOuA7zXu4z7+F3tr0Z6/wf5JAAAAAElFTkSuQmCC") !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 == "destructor") // May happens before "unload"
		this.undoCloseTabsList.updUIGlobal();
	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";
}

Отсутствует

 

№1602024-11-2021 13:21:21

kokoss
Участник
 
Группа: Members
Зарегистрирован: 15-02-2018
Сообщений: 1739
UA: Firefox 52.0

Re: Custom Buttons

Letterman пишет

далее кнопку Undo Close Tabs 0.3.3.2 (2020-03-14)

Вообще то есть более свежая версия 0.3.3.3, не знаю как в [firefox] 91 а в [firefox] 94 вроде работает!


Win7

Отсутствует

 

№1602124-11-2021 13:24:52

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

Re: Custom Buttons

kokoss
о! спасибо, не знал об обновлении :beer:

Отсутствует

 

№1602224-11-2021 16:59:22

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

Re: Custom Buttons

Letterman пишет

нет нигде элемента меню Добавить кнопку

Пункт «Добавить новую кнопку…» должен быть
в меню «Вид» главного меню [Файл Правка Вид Журнал ...],
и в контекстном меню тулбаров, таком,
как, например, появляющимся при клике ПКМ по кнопке гамбургера [Ξ].
Ещё есть одноимённая кнопка в разделе «Custom Buttons» на странице about:addons


Если этого всего нет, то, скорее всего, установка CB просто не произошла,
типа как поставить paxmod на недолеченный релиз или бету,
в аддон-менеджере будет, но не более того, просто бесполезный manifest.json

для Firefox 91.0.2 устанавливаю версию custom_buttons-0.0.7.0.0.19

Вот засада, в 0.0.7.0.0.19 не работают клонированные CB-меню
(используется в кнопке Undo Close Tabs).
А в последней версии работают, но она не совместима с Firefox 91.


Оказии пока не случилось, а из-за одной строчки собирать
новую версию не хотелось, но, пожалуй, следует. Чтобы была совместимая.


Custom Buttons 0.0.7.0.0.22. paxmod и bootstrap в zip-папке.


kokoss пишет

есть более свежая версия 0.3.3.3

Кстати, под угрозой.
В Firefox 95 SessionStore.getClosed{Tab, Window}Data()
будет всегда возвращать собственно сам объект,
а не его JSON.stringify() представление, как это было до этого по умолчанию.


Вариант фикса

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

Выделить код

Код:

var JSON = "JSON" in window
	//? window.JSON
	? {
		parse: function(arg) {
			return typeof arg == "string"
				? (JSON = window.JSON).parse(arg)
				: (this.parse = function(obj) {
					return obj;
				}) && arg;
		}
	}

Отредактировано Dumby (24-11-2021 17:13:39)

Отсутствует

 

№1602324-11-2021 17:45:27

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

Re: Custom Buttons

Dumby пишет

как поставить paxmod на недолеченный релиз или бету

Не, это я что-то не не то загнул.
Например, если править AppConstants.jsm в omni.ja,
выключить xpinstall.signatures.required
и не влючить extensions.experiments.enabled, то да,
но такое совсем маловероятно. Тогда не понятно в чём дело.


ВВП пишет

Вопрос: Как рихтануть Attributes Inspector , чтобы наводил cursor:default ? А то кнопки pointer... Неудобно.

Попробуй — поиск в коде: outline-offset
следующей строкой добавить: cursor: default !important;\n\

Отредактировано Dumby (24-11-2021 18:15:35)

Отсутствует

 

№1602424-11-2021 19:41:48

Letterman
Участник
 
Группа: Members
Зарегистрирован: 13-01-2017
Сообщений: 53
UA: Firefox 91.0

Re: Custom Buttons

sonyas75, Dumby
Спасибо, в моем случае все решилось банальным запуском чистого профиля.
 
Dumby, не получилось скачать ваш Custom Buttons 0.0.7.0.0.22. paxmod, Eset чего-то на него ругается. Подскажите, куда вставить ваш вариант фикса Undo Close Tabs?
 
kokoss, спасибо за свежий вариант.

Отсутствует

 

№1602524-11-2021 20:03:47

kokoss
Участник
 
Группа: Members
Зарегистрирован: 15-02-2018
Сообщений: 1739
UA: Firefox 52.0

Re: Custom Buttons

Letterman пишет

Подскажите, куда вставить ваш вариант фикса Undo Close Tabs?

Там же написано, фикс для [firefox] 95!

не получилось скачать ваш Custom Buttons 0.0.7.0.0.22. paxmod, Eset чего-то на него ругается.

А отключить Eset на время скачивания файла не вариант?!


Win7

Отсутствует

 

Board footer

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