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

Mozilla Россия — свежие версии программ Mozilla, а также масса полезной информации по каждому продукту.

№1705124-10-2023 17:43:45

_backup
Участник
 
Группа: Members
Зарегистрирован: 12-02-2007
Сообщений: 25
UA: Firefox 78.0

Re: Custom Buttons

Пролистал топик и нашёл всего три полезных кнопки, остальные кнопки не подписанные, непонятно что они делают. Может, кто выложит рабочие кнопки под FF78? Буду очень благодарен.

Отсутствует

 

№1705225-10-2023 13:06:38

kazarin
Участник
 
Группа: Members
Зарегистрирован: 23-11-2016
Сообщений: 83
UA: unknown 0.0

Re: Custom Buttons

Приветствую всех:)
Перешёл с 102 на 115. Отказали две кнопки:

Редактировать размеры поля выбора вкладок в окне добавления закладки звёздочки

Выделить код

Код:

// Редактировать размеры поля выбора вкладок в окне добавления закладки звёздочки

((css, panel) => ({
	init() {
		panel = document.getElementById("editBookmarkPanel");
		if (panel) {
			addEventListener("popupshowing", this, false, panel);
			this.destroy && this.destroy();
			return;
		} else if (this.destroy) return;

		var mo = new MutationObserver(this.init.bind(this));
		mo.observe(document.getElementById("mainPopupSet"), {childList: true});
		addDestructor(this.destroy = reason => {
			mo.disconnect();
			if (reason) return;
			self._destructors.splice(self._destructors.findIndex(
				d => d.destructor == this.destroy
			), 1);
			delete this.destroy;
		});
	},
	pref: "CB.editBMPanel_folderTreeRow_WidthHeight",
	handleEvent(e) {
		css = encodeURIComponent(css.replace(/;/g, " !important;"));
		var args = ["data:text/css," + css, windowUtils.USER_SHEET];
		windowUtils.loadSheetUsingURIString(...args);

		var row = document.getElementById("editBMPanel_folderTreeRow");

		var fox86 = parseInt(Services.appinfo.platformVersion) >= 86;
		var trg = this.trg = fox86 ? row.style : row;
		this.map = fox86 ? s => s + "px" : s => s;
		var rem = fox86 ? "removeProperty" : "removeAttribute";

		addEventListener("popuphidden", this, false, panel);

		addDestructor(reason => {
			windowUtils.removeSheetUsingURIString(...args);
			trg[rem]("width"); trg[rem]("height");
			reason == "delete" && Services.prefs.clearUserPref(this.pref);
		});

		this.handleEvent = e => e.target == panel && this[e.type]();
		this.popupshowing();
	},
	popupshowing() {
		var [width, height] = Services.prefs.getStringPref(this.pref, "332 184").split(" ").map(this.map);
		this.trg.width = width; this.trg.height = height;
		gEditItemOverlay.toggleFolderTreeVisibility();

		gEditItemOverlay._paneInfo.visibleRows.add("keywordRow");
		gEditItemOverlay._element("keywordRow").collapsed = false;
		gEditItemOverlay._initKeywordField().catch(Cu.reportError);
	},
	popuphidden() {
		var {width, height} = this.trg;
		Services.prefs.setStringPref(this.pref, parseInt(width) + " " + Math.max(184, parseInt(height)));
	}
}).init())(`

	#editBookmarkPanel #editBMPanel_folderTreeRow {
		resize: both;
		overflow: hidden;
		min-width: 332px;
	}

	#editBookmarkPanel box.panel-header {
		padding: 0;
		border: none;
	}
	#editBookmarkPanel #editBookmarkSeparator,
	#editBookmarkPanel #editBookmarkPanelInfoArea,
	#editBookmarkPanel #editBookmarkHeaderSeparator {
		display: none;
	}
	#editBookmarkPanel #editBookmarkPanelRows {
		padding-top: 1px;
	}
	#editBookmarkPanel #editBMPanel_keywordRow,
	#editBookmarkPanel #editBMPanel_locationRow {
		visibility: visible;
	}
	#editBookmarkPanel #editBMPanel_tagsRow > hbox,
	#editBookmarkPanel #editBMPanel_folderRow > hbox,
	#editBookmarkPanel #editBookmarkPanelRows > vbox:not([id*="folderTree"]):not([id*="tagsSelector"]) {
		display: flex;
		align-items: center;
	}
	#editBookmarkPanel #editBMPanel_tagsField,
	#editBookmarkPanel #editBMPanel_folderMenuList,
	#editBookmarkPanel #editBookmarkPanelRows > vbox > label:first-child + * {
		flex-grow: 1;
	}
	#editBookmarkPanel moz-input-box {
		width: 100%;
	}
`);

Открывать закладки левым кликом в новой вкладке не закрывая меню закладок

Выделить код

Код:

/* Открывать закладки левым кликом в новой вкладке не закрывая меню закладок
   удалять закладки средним кликом на закладке, от 11.06.2019. .............*/
function openBook(e, target = e.originalTarget) { 
   if ( target.localName != "menuitem" 
        || !(target._placesNode && PlacesUtils.nodeIsURI(target._placesNode) ) ) return;
               
   // блокировать действия по умолчанию для левого клика ....
   if ( e.button == 0 ) {   // ЛКМ 
        e.preventDefault();
        e.stopPropagation(); 
        };
        
   // открыть закладку в новой вкладке или для указанных адресов в текущей вкладке ....
   if ( e.button == 0 && e.type == "mouseup" ) {   // ЛКМ 
        var itemUri = target._placesNode.uri;
        var array = ["about:newtab", "about:blank", "chrome://browser/content/bookmarks/bookmarksPanel.xul"];
        var where = (~array.indexOf(gBrowser.currentURI.spec) || e.ctrlKey) ? "current" : "tab"; 
       
        openLinkIn(itemUri, where, {
           inBackground: false,
           relatedToCurrent: true,
           triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()
        });

        setTimeout(()=> document.getElementById('placesContext').hidePopup(), 50);
        };
    
    // удалить закладку ....
    if ( e.button == 1 && e.type == "mouseup" ) {   // СКМ
         setTimeout(()=> {
            var itemId = target._placesNode.itemId;
            try { PlacesUtils.bookmarks.removeItem(itemId) } catch(e) {};                   
         }, 0);
         };       

    // автоматически закрыть все меню закладок при уходе курсора .... 
    var menu = target.parentNode;
    if ( !menu || menu.localName != 'menupopup' || e.type != 'click' || e.button == 2 ) return;
                     
    menu.onmouseover =()=> menu.f = true;
    menu.onmouseleave =()=> { 
       menu.f = false;        
       setTimeout(()=> {   
          if ( menu.f ) return;
          for ( var node = menu; node; node = node.parentNode )
                node.nodeName == 'menupopup' && node.hidePopup();
          menu.onmouseleave = null;
       }, 500);    
    };  
}
!self.hasAttribute("initialized") && ["click", "mouseup", "mousedown"].forEach(type=> addEventListener(type, openBook, true));


Можно ли их подправить?

Отредактировано kazarin (25-10-2023 13:08:42)

Отсутствует

 

№1705325-10-2023 15:03:43

_backup
Участник
 
Группа: Members
Зарегистрирован: 12-02-2007
Сообщений: 25
UA: Firefox 78.0

Re: Custom Buttons

Есть кнопка брал тут https://forum.mozilla-russia.org/viewto … 44#p782144. Автор утверждает, что она работает под FF78, но, к сожалению, это не так. Кнопка не всегда срабатывает - не открывает меню сохранить и загрузить сессию. Приходится по 20 раз нажимать на неё, но если заработает, то со своими функциями справляется. Автор так же утверждает, что у неё проблемы с функцией prompt.

Выделить код

Код:

/*Initialization Code*/

// Simple Session Manager (https://forum.mozilla-russia.org/viewtopic.php?pid=744023#p744023) ..........

// Подсказки для кнопки .....
this.tooltipText = "Simple Session Manager\n\
------------------------------\n\
Л:   Меню сессий\n\
дЛ: Сохранить сессию\n\
П:   CB меню";

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

  this.onmouseup =e=> {        // левый клик
    if ( e.button ) return;
    clearTimeout(self.timer);
    self._handleClick =()=> menupopup.openPopup(this, "after_start");
  }

  if ( e.button == 0 ) {       // длинный левый клик
    self.timer = setTimeout(()=> {
    self.onmouseup = '';
      saveCurrentSession();
    }, 500);
  }

  if ( e.button == 2 ) {       // правый клик
    gShowPopup(this);
  }

}
self.onclick =e=> e.preventDefault();


var menupopup = self.appendChild(document.createXULElement("menupopup"));
menupopup.id = "ssm_menupopup";

var scs = document.createXULElement("menuitem");
scs.setAttribute("label", "Сохранить сессию");
scs.setAttribute("class", "menuitem-iconic");
scs.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKVSURBVHjajFNNTBNREJ6+7na73bLbQn8I0BKNCYWKGr0oYoiJPxeNh6oHozcOxgSVi4le1JNHQRPigRsewURNPKiJMQicSISUACelRVJ2tz/bdktpy9adBzT8xTjJ5L35ezNv5hsLHEAv7noEntguChx7EuV8oTydKRhfno8kCnt9LTuFZ7f87mAz/8rnl86GOoOBBq+LQX1S1ioLs0txWdEmsulS38Phlcy+BwZ6W0L+JsfolcjpsFDnBKNcgQ193bRUwSrwQFgr6Dkd3o9NzilqMdI/FF+sPYCZ245I4zdunw9DtQr6LxlK6bVdpdrcPAiHfGBYLDD69ltUXsmfw0oIGoPNjkHMjMHa3J9asDyRpoyEOrQR0+dq5MxR0c29Rj3Bhvn8YjeWjZmN9cpWcApSkzpkptYg8T1FdWjTfysg1Ang9YtdT+80OogTbJc7OlsD+OftzOqsBrMflqHe6QKXIEL00zLV0UpSBbM/G9DeEQy6OXKJsfPsCbdXYjb0Yu2/nmMS9LSGYGlYpXLPkxCwkq1mR98Gn8Q4XexxYhhgYKf3TPTfRDaPqklkvViaSSpaxSpw/x1v5e0UG8W10k+iW8qfF2ZiccIydFQ7ScsXKO8ep4NiYj4ai6k5+Eoev1F1Wcn8QJDgnAnHbGYRWTh800cZ77Ryzmr6eCGXzYGiZCcQ2vQ32XT5PiIMTJBI4Waw1ZtZzLu7XaSMd1s9b9paKJA+vpuKqols3y4ov7wXaPN67GPXIl1hnDOOansyVicHhGHMzHkzeDKqqPnr/UOJxX3LNNDb5BJd3KC3Uexu7wgEGxq3limRqcxH47FVWRtPreYePBpJagdu4zYhwjx1cMFus59CuVgqTmPDDlrnvwIMAGS8IFCLagHpAAAAAElFTkSuQmCC");
scs.addEventListener("command", saveCurrentSession, false);
menupopup.appendChild(scs);

var menusep = document.createXULElement("menuseparator"); // Сепаратор .....
menupopup.appendChild(menusep);

var savedSessions = loadFile(); // Сохраненный список .....
for (name in savedSessions) {
  makeitems(name);
}

// overwrite = 1 - Открыть сессию в текущем окне (все открытые вкладки будут закрыты) .....
// overwrite = 0 - Добавить вкладки в текущее окно (сессия будет добавлена к уже открытым вкладкам) .....
var overwrite = 1,
Cc = Components.classes,
Ci = Components.interfaces,
Cu = Components.utils,
SS = "nsISessionStore" in Components.interfaces ? ( Components.classes["@mozilla.org/browser/sessionstore;1"] || Components.classes["@mozilla.org/suite/sessionstore;1"] )
      .getService(Components.interfaces.nsISessionStore) : SessionStore;

if (!window.Services) { Cu.import("resource://gre/modules/Services.jsm"); }

// Функции работы с файлами .....
function saveFile(data) {
  var file = Services.dirsvc.get('UChrm', Ci.nsIFile);
  file.append("simple_session_manager.json");

  var suConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
  suConverter.charset = 'UTF-8';
  data = suConverter.ConvertFromUnicode(data);

  var foStream = Cc['@mozilla.org/network/file-output-stream;1'].createInstance(Ci.nsIFileOutputStream);
  foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0);
  foStream.write(data, data.length);
  foStream.close();
}

function loadFile() {
  var file = Services.dirsvc.get('UChrm', Ci.nsIFile);
  file.append("simple_session_manager.json");
  if (file.exists() === false) return false;
  var fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
  var sstream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
  fstream.init(file, -1, 0, 0);
  sstream.init(fstream);

  var data = sstream.read(sstream.available());
    try { data = decodeURIComponent(escape(data)); } catch(e) {}
  sstream.close();
  fstream.close();
  if (data === "undefined") return false;
  data = JSON.parse(data);
  return data;
}

// Получить текущее время .....
function getTime() {
  var d = new Date();
    function addzero(t) {
      (t < 10) ? t = '0' + t : t;
      return t;
    }
  var t = addzero(d.getFullYear()) + '.' + addzero(d.getMonth()+1) + '.' + addzero(d.getDate()) + '-' + addzero(d.getHours()) + ':' + addzero(d.getMinutes()) + ':' + addzero(d.getSeconds());
  return t;
}

// Получить название вкладки .....
function getTabLabel() {
  var label = gBrowser.selectedTab.label;
  return label.substring(0, 70);
}

// Сохранение сессий .....
function saveSession(ssdata) {
  var name = prompt('Сохранить:', getTabLabel() + ', ' + gBrowser.tabs.length + ' (B) ' + '[' + getTime() + ']' );
    if (name != null) {
      if (loadFile() === false) { var data = {}; }
      else { var data = loadFile(); }
        if (data[name]) { alert('Сессия с тем же именем уже существует!'); return; }
          data[name] = JSON.parse(ssdata);
          saveFile(JSON.stringify(data));
          makeitems(name);
    }
}

// Сохранить текущую сессию .....
function saveCurrentSession() {
  var ssdata = SS.getBrowserState();
  saveSession(ssdata);
}

// Удалить сессию .....
function remove() {
  var node = this.parentNode.parentNode;
  var name = node.getAttribute("label");
  var cf = confirm('Вы уверены, что хотите удалить ' + name + ' ?');
    if (cf === true) {
      node.style.display = "none";
      var data = loadFile();
      delete data[name];
      saveFile(JSON.stringify(data));
    }
}

// Переименовать сессию .....
function rename() {
  var node = this.parentNode.parentNode;
  var name = node.getAttribute("label");
  var newname = prompt('Переименовать ' + '"' + name + '"' + ' в:', 'введите новое имя');
  if (!newname) return;
  this.parentNode.parentNode.setAttribute("label", newname);
  var data = loadFile();
  var value = data[name];
  data[newname] = value;
  delete data[name];
  saveFile(JSON.stringify(data));
}

// Восстановить сессию .....
function restoreSession(stateString) {
  if (typeof stateString === "string") {
    var state = stateString;
  }
  else {
    var name = this.parentNode.parentNode.getAttribute("label");
    var data = loadFile();
    var state = JSON.stringify(data[name]);
  }
  switch (overwrite) {
    case 0:
    SS.setWindowState(window, state, false);
    break;

    case 1:
    SS.setBrowserState(state);
    break;
  }
}

// Создаем меню .....
function makeitems(name) {
  var ss = document.createXULElement("menu");
  ss.setAttribute("label", name);
  ss.setAttribute("class", "savedSessions");
  ss.className = "menu-iconic";
  ss.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAEnQAABJ0BfDRroQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGxSURBVDiNnZE/T1NRGMZ/7zn3lmKLkIKpaUxZFINEJZ0YHXRwcnBxMQ6aOJi4+FH8Dm5OOjA4+AEYGCTRook1JlVIVUrbW/rnPg63UtReIr7bOXmf5/ye59jDlanHS3O+wn/Mu+/DF8HFeVe5f+vaPTdfPpF4UNvk6frmhwAvXOEsvrR0IoN47xM4CHCADmDQBkAHbdTrTBRZdgYLs6NTD/MiMC+gC8MO6ke8ffWsXv3S3JpksHouv7Z4/UEeM8z6IwKfEGjYRt0G1d3m1p3n0Y1JBi/vTtfKw1Yec2CHBDFmXYjboAgL4tTc5pXsmcNcDxIDUFQHuqgfYT69OAuE9qqAoX4jIcAL7b9H+0deOYYg3tkYXxx2EAo7dQYEBF/TEULD5oow7KHut18RhGVD3GwxMZ36YWn6IJd37vQCSMSNBpYQCMs43PQMAJXlwtr6k7CGfo9iznN1ebGY7Ak1NSJwYERYJgM+Q+nClVzp/OXc3wWMwdT+jAVKCMwLC2PUeoMrrEI4m94BQq0a6mxjoca/YKFgUCfeqR8jPhoHcIAHe3ST2+UFLv2T8o/5uMvrnx9Wn65p5nMEAAAAAElFTkSuQmCC");

  var ss_popup = document.createXULElement("menupopup");
  var rs = document.createXULElement("menuitem");
  rs.setAttribute("label", "Восстановить");
  rs.setAttribute("class", "menuitem-iconic");
  rs.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAACzElEQVQ4jX2QPWwbZRjHf+/5vfPdObZjO3Ga2pVpGtxCP4QIDKgqDCDUNQwgJCS2qFI3hBCRCvXSCcTAAu0GY0Fi4kuq+IjUCpWAgCTq4IpS3Di2G8c+x/bZ57t7mSJFMfBf/3p+z+95BPvy3pufxqKmcVY3ZFFKmQtFGIReuNnrDze6lv5TqfSyx4EIgA/e+fzkZML6MDmVnD80mz1kxW3DMAxQCs/z6Hb6g3q1Xt1ttdfa7dbFN668vrkHkADJhPntufNnc0LTDi7AjFkkUknzcGF2LvCDuZVvfiwCj+/1GoAmhL3x6x2cZhsVqjFIGIZs15ts/LJOJCLt/Z0EiE3Y9eLpR1ONaoMH9zbHAGiC9FSKkwunWF1Z3RoDABhRg/zRPPmj+XHA/0QDaLectFLj6gcT+AHdTm9mzMC27e766lrWtCwy2Qz2hIUeNVDAaDCku9ujWW/ij3wsO9oaMzCiunf66TMU5gt4wyGbf1Upr5W5u15mq1JDhYqZQo6HIuqtueLw4vLXzwC89NZXeQFw/ePv7zx5buHEf6nf3qgMVipOGE0ko6EKhoQi3NnZ+c51BwsaQLOxM9N1uv86vNtz+aHSDn0pH9S2tl6r/Pn3s/VG/WYunzs/NZ2OSID0dKpRrzZS98v3kYbEsi1004BQcbtc9Q07bdYb229/dvmFL5aWVvVts9mq1Wo/e54vJIAQqGOPzQHgj3zcvos39BAIBshRqJQYjYZ/AFy79tQIeHVx+ctiIDRTA+g43Xud9q4PIHVJPBknk82QzqY5VZg2UUrEYhOX9s5aXL5RnMykb8Rj9kcC4OrSVZ1Hpt+PJ5PPz+SzR5KpyYRpGgRKMei7fHLr7lBmZ1XHcX4LgsCxLPt4JBLRm82Hr4j9DyuVSprdO/ZELGafkXpkXtPA94OK03Vv/R4/csEw5XOGbuieN6y6bv/S9XdfvPkPTgcoDlpQJpwAAAAASUVORK5CYII=");
  rs.addEventListener("command", restoreSession, false);

  var rn = document.createXULElement("menuitem");
  rn.setAttribute("label", "Переименовать");
  rn.setAttribute("class", "menuitem-iconic");
  rn.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPFJREFUeNrEU0sOgkAMbc1IIHoQT+KeY7hkBW5ccwLdsOICxI2X8peIGhggI21gggpCwsImM01f+tpOO0WlFIwR0efgeR5nsG0boihizPd91A5UwZDjuq5qwycwUkQYhttSr4Y4l76fDdtBEAQqz3OVZdnPQ09o2sQhrpBSQgnAen/qzLxZzljHcawxy7KAuCJNUyiKAm53SS0FBGQNlUW3lFO2iVCLYRhAXJEkCQPn65NGAswpL/4fWAebt1ZGXB3geHlw9maXsKqjS94CHNxF7xRM0/wKgI7jDBojvbnZAz3Gv/9E7NvGvmXCsev8EmAAWocA9ofpaRIAAAAASUVORK5CYII=");
  rn.addEventListener("command", rename, false);

  var rm = document.createXULElement("menuitem");
  rm.setAttribute("label", "Удалить");
  rm.setAttribute("class", "menuitem-iconic");
  rm.setAttribute("image", "data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAABt0lEQVQ4ja2RT2sTURTFz8tk0nntFAQrVLBQxIUg/tkkMoLyIEVECHZhNrrxI+hOP5Mb6eBCcEipYIjZ2LpvhFasUtBSkwzOve+6mE6YSScuxLt67753fudyLvA/a7T+qCHmiTfrfWCMd3j9diPfq2SHX+uPnzJx71gP33w3bX9avBcE2j+SkK30Di7ffJ71VebMxD1hC2GGEEfH41prpftynIm92A0t2aYQQYgBThrndz/2KwCgf9Z2LNtImFOAtc356ijcCwJdJrZEUWzPfJpMAAAStPWR/h2Ktc10CoIQRUKEabFNvNbKfndcAKSjtrVfHW5YorWTzxDKYAxLtOWM+P7yt51hIYPpsDTNTyB/EwNAtWxdMuV8GCfbgxjxIviUYSV/SQOrbVjitbx4N8alBeXcdZR+3Tl3xS8FlIkt0dbnWH3xlbPgKgUo3HEq+tX7C4EuAAbGeOmqCuLIJt69s3PeQ1epKGfapCQJO6vGmwAWf/C1Wau6td8dV123BaAAUfHw6gSwtP3ugxA/y6X9INszAOQgbwFAIC/MQb9/Kv2vF2/UByejlVVn1Xiby/X6rPd/qj/1ak71UYKuwQAAAABJRU5ErkJggg==");
  rm.addEventListener("command", remove, false);

  ss_popup.appendChild(rs);
  ss_popup.appendChild(rn);
  ss_popup.appendChild(rm);
  ss.appendChild(ss_popup);
  menupopup.appendChild(ss);
}

Можно ли как то подправить код под FF78?

Отсутствует

 

№1705426-10-2023 15:58:04

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

Re: Custom Buttons

kazarin пишет

Перешёл с 102 на 115. Отказали две кнопки:
Редактировать размеры поля выбора вкладок в окне добавления закладки звёздочки

Может эту попробуй.
И следующие два поста посмотри.

Открывать закладки левым кликом в новой вкладке не закрывая меню закладок

Проверил на 115 — вроде всё работает.


_backup пишет

Кнопка не всегда срабатывает - не открывает меню сохранить и загрузить сессию. Приходится по 20 раз нажимать на неё

Не вижу ничего подобного.
Меню открывается с первого клика.

Автор так же утверждает, что у неё проблемы с функцией prompt.

Нету «у неё» никакой проблемы с функцией prompt.
Это косячок в лисе такой (был). Дальше там написано.

Отсутствует

 

№1705526-10-2023 16:35:17

_backup
Участник
 
Группа: Members
Зарегистрирован: 12-02-2007
Сообщений: 25
UA: Firefox 78.0

Re: Custom Buttons

Dumby пишет

Не вижу ничего подобного.
Меню открывается с первого клика.

Если сохранить сессию, а после удалить ее, то кнопка перестает реагировать на клик, помогает ее реанимировать только правый клик по ней. Посмотрите, пожалуйста.

Simple_Session_Manager.gif

Отредактировано _backup (26-10-2023 17:42:01)

Отсутствует

 

№1705626-10-2023 19:25:22

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

Re: Custom Buttons

_backup пишет

Если сохранить сессию, а после удалить ее, то кнопка перестает реагировать на клик, помогает ее реанимировать только правый клик по ней

О, другое дело! Это — вижу.


Не понимаю почему так происходит.
Однако, у меня, помогает тормознуть скрытие пункта.

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

Выделить код

Код:

/*
      node.style.display = "none";
*/
      requestAnimationFrame(() => node.style.display = "none");

Отсутствует

 

№1705726-10-2023 23:07:20

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

Re: Custom Buttons

А можно ли так вообще?!  Я что-то сделал и оно работает. НО правильно ли так?
Закрыть дубликаты вкладок вчера, почему-то, перестал работать. Когда я что-то подправил, получилось что закрывалась вкладка активная, если у нее был дубликат. Это, ессно, нехорошо.
Решил что нужно сделать самому при помощи интронэтофф и вот что получилось: три строки кода, работает, вычисляет и закрывает.., но я не уверен что так прально. Ессно искал и находил разные примеры, многие из которых опирались именно на set(), как решение.
Из многих примеров, которые тоже были на пару десятков строк и с десяток if\for() собрал вот такое, не до конца понимая что сделал. Я пользую sort() для сравнения элементов массива и заполнения набора set(). Прошу совета, мнения, лулзов или совета в виде лулзов, - но по сути. ( делаю это в PaleMoon).

Выделить код

Код:

// Закрыть дубликаты вкладок
 this.closeDuplicateTabs = function() {
    let tabs = Array.from(gBrowser.visibleTabs), uniq = new Set();
        tabs.sort( (a,b) => (a.linkedBrowser.currentURI.spec === b.linkedBrowser.currentURI.spec) ? uniq.add(b) : "" );
       uniq.forEach( tab => (tab.pinned && tab.selected && tab.hasAttribute("tabProtect")) ? "" : gBrowser.removeTab(tab) );
 }

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

Отсутствует

 

№1705827-10-2023 08:13:28

kazarin
Участник
 
Группа: Members
Зарегистрирован: 23-11-2016
Сообщений: 83
UA: Firefox 119.0

Re: Custom Buttons

Dumby пишет

Может эту попробуй.
И следующие два поста посмотри.

Всё стало как раньше! Огромное спасибо!

Dumby пишет

Проверил на 115 — вроде всё работает.

А это я, оказывается, накосячил. У меня мегакнопка с кучей кодов, и там каким-то образом оказался вырван кусок. А код копировал из 102, где она нормальная.

Отсутствует

 

№1705927-10-2023 11:05:15

_backup
Участник
 
Группа: Members
Зарегистрирован: 12-02-2007
Сообщений: 25
UA: Firefox 78.0

Re: Custom Buttons

Dumby пишет

Однако, у меня, помогает тормознуть скрытие пункта.

Благодарю, все работает.

Отсутствует

 

№1706027-10-2023 21:17:24

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

Re: Custom Buttons

mokujin пишет

Прошу совета, мнения

Моё мнение таково: приведённый код — полная чепуха.


Не закрывает он никакие дубликаты, кроме разве что из таких,
которые идут прямо рядом подряд встык,


и, тогда, может закрыть и активную вкладку, если дубликат впереди,
ну, разве что только если она не какая-то совсем уж особенная,
типа ещё и закреплённая, и, при этом, ещё и имеющая атрибут "tabProtect".


Может что-то такое рассмотри

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

Выделить код

Код:

var tabs = new Set(gBrowser.visibleTabs), urls = new Set();
for(var tab of tabs)
	if (tab.pinned || tab.selected || tab.hasAttribute("tabProtect"))
		tabs.delete(tab), urls.add(tab.linkedBrowser.currentURI.spec);
for(tab of tabs) {
	var url = tab.linkedBrowser.currentURI.spec;
	urls.has(url) ? gBrowser.removeTab(tab) : urls.add(url);
}


Ну, дальше можно добро циклов в try catch завернуть,
на всякий случай, чтобы цикл не прервался из-за какой-нибудь ошибки.


И, если в PaleMoon у gBrowser'а есть метод removeTabs()
то, наверно, лучше не закрывать вкладки сразу самому,
а собрать кандидатов на закрытие, и скормить этому методу.

Отсутствует

 

№1706130-10-2023 21:46:55

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

Re: Custom Buttons

Dumby
Как подрихтовать,при добавлении в прейлист пропадает предыдущая ссылка, в хроме через расширение -нет.

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

Выделить код

Код:

var run = (...a) => {
		var file = FileUtils.File(path);
		(run = (args, quit) => {
			if (!file.exists()) return custombuttons.alertBox("File not exists!", path);
			var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
			
			process.init(file);
			gBrowser.selectedBrowser.browsingContext.mediaController.pause();
                        args.push("/add");
                         window.minimize();
			process.runwAsync(args, args.length);
			
		})(...a);
	}

args.push("/add"); - это норм ?

Это чертов Gom Player, в MPC - норм.

Отредактировано ВВП (30-10-2023 22:35:45)

Отсутствует

 

№1706231-10-2023 11:47:54

ifln
Участник
 
Группа: Members
Зарегистрирован: 20-09-2013
Сообщений: 232
UA: Firefox 115.0

Re: Custom Buttons

Выложите пожалуйста готовую кнопку cookiesPermissions.js для ff115.
Пытался отредактировать как здесь Farby предложил. С Undo Close Tab всё получилось. А с этой никак. Не появляются нормальные иконки.


Добавлено:
Farby, спасибо!

Отредактировано ifln (31-10-2023 13:49:42)

Отсутствует

 

№1706331-10-2023 12:06:29

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

Re: Custom Buttons

ifln пишет

Выложите пожалуйста готовую кнопку

cookiesPermissions.js

Выделить код

Код:

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

// Cookies Permissions button for Custom Buttons
// (code for "initialization" section)

// (c) Infocatcher 2010-2021
// version 0.2.1pre8 - 2021-02-14

var {Components} = window; // Prevent garbage collection in Firefox 3.6 and older

var cp = Components.interfaces.nsICookiePermission;
var options = {
	removeUnprotectedCookiesEnabled: false,
	// true  - periodically remove unprotected cookies by default
	// false - don't remove by default
	removeUnprotectedCookiesInterval: 10*60*1000,
	// Periodically remove unprotected cookies (leave only cookies with "Allow" permission)
	// Time in milliseconds like 30*60*1000 (30 minutes) or -1 to disable
	removeAllUnprotectedCookies: false,
	// true  - periodically ("removeUnprotectedCookiesInterval" option) remove all unprotected cookies
	// false - or exclude cookies from opened sites
	showTempPermissions: true, // Show items about temporary permissions (only Gecko 2.0+)
	tempExpire: -1, // Type of temporary permissions
	// -1 - session, otherwise - expire after given time (in milliseconds)
	useBaseDomain: {
		// 0 - use full domain name: addons.mozilla.org, www.google.com
		// 1 - strip "www." prefix from full domain name: addons.mozilla.org, google.com
		// 2 - use top-level domains (TLDs): mozilla.org, google.com
		addPermission: 1, // Add (and toggle) permission action
		openPermissions: 0,  // Filter in "Show Exceptions" window
		showCookies: 2, // Filter in "Show Cookies" window
		removeCurrentSiteCookies: 2, // For "Remove All Current Site Cookies" action
		preserveCurrentSitesCookies: 2 // For "removeAllUnprotectedCookies: false"
	},
	showDefaultPolicy: true, // Show default cookies policy
	toggleMode: [cp.ACCESS_ALLOW, cp.ACCESS_DENY, cp.ACCESS_DEFAULT],
	// ACCESS_DENY, ACCESS_SESSION, ACCESS_ALLOW or ACCESS_DEFAULT
	useCookiesManagerPlus: true, // https://addons.mozilla.org/firefox/addon/cookies-manager-plus/
	reusePermissionsWindow: false, // Use any already opened permissions window
	// E.g. "Show Exceptions" may convert "Allowed Sites - Add-ons Installation" to "Exceptions - Cookies"
	prefillMode: 1, // 0 - move caret to start, 1 - select all, 2 - move caret to end
	confirmRemoval: true,
	moveToStatusBar: {
		// Move button to Status Bar, only for SeaMonkey or Firefox < 4.0
		// Be careful, has some side-effects and button can't be edited w/o restart
		enabled: false,
		insertAfter: "download-monitor,popupIcon,statusbar-progresspanel"
		// Like https://developer.mozilla.org/en-US/docs/XUL/Attribute/insertafter
		// Also looks for nodes with "cb_id" attribute
	}
};

function _localize(sid) {
	var strings = {
		en: {
			defaultTooltiptext: "Cookies: Default",
			denyTooltiptext: "Cookies: Block",
			allowSessionTooltiptext: "Cookies: Allow for Session",
			allowTooltiptext: "Cookies: Allow",
			notAvailableTooltiptext: "Cookies: n/a",
			unknownTooltiptext: "Cookies: ???",
			errorTooltiptext: "Cookies: Error!",

			defaultDenyTooltiptext: "Cookies: Block (Default)",
			defaultAllowSessionTooltiptext: "Cookies: Allow for Session (Default)",
			defaultAllowTooltiptext: "Cookies: Allow (Default)",

			defaultLabel: "Default",
			defaultAccesskey: "D",
			denyLabel: "Block",
			denyAccesskey: "B",
			denyTempLabel: "Temporarily Block",
			denyTempAccesskey: "k",
			allowSessionLabel: "Allow for Session",
			allowSessionAccesskey: "S",
			allowSessionTempLabel: "Temporarily Allow for Session",
			allowSessionTempAccesskey: "e",
			allowLabel: "Allow",
			allowAccesskey: "A",
			allowTempLabel: "Temporarily Allow",
			allowTempAccesskey: "w",

			showPermissionsLabel: "Show Exceptions…",
			showPermissionsAccesskey: "x",
			showCookiesLabel: "Show Cookies…",
			showCookiesAccesskey: "h",
			removeTempPermissionsLabel: "Remove Temporary Permissions",
			removeTempPermissionsAccesskey: "T",
			autoRemoveUnprotectedCookiesLabel: "Automatically Remove Unprotected Cookies",
			autoRemoveUnprotectedCookiesTip: "Periodically remove unprotected cookies (if checked)",
			autoRemoveUnprotectedCookiesAccesskey: "n",
			removeUnprotectedCookiesLabel: "Remove Unprotected Cookies",
			removeUnprotectedCookiesTip: "Except cookies marked as “Allow” and except cookies from opened sites",
			removeUnprotectedCookiesAccesskey: "U",
			removeUnprotectedCookiesConfirm: "Remove unprotected cookies?",
			removeAllUnprotectedCookiesLabel: "Remove All Unprotected Cookies",
			removeAllUnprotectedCookiesTip: "Except cookies marked as “Allow”; unprotected cookies from opened sites will be removed",
			removeAllUnprotectedCookiesAccesskey: "R",
			removeAllUnprotectedCookiesConfirm: "Remove ALL unprotected cookies?",
			removeCurrentSiteCookiesLabel: "Remove All Current Site Cookies",
			removeCurrentSiteCookiesAccesskey: "C",
			removeCurrentSiteCookiesConfirm: "Remove ALL current site cookies?",
			removeAllCookiesLabel: "Remove ALL Cookies",
			removeAllCookiesAccesskey: "L",
			removeAllCookiesConfirm: "Remove ALL cookies?",

			buttonMenu: "Button Menu",
			buttonMenuAccesskey: "M"
		},
		ru: {
			defaultTooltiptext: "Cookies: По умолчанию",
			denyTooltiptext: "Cookies: Блокировать",
			allowSessionTooltiptext: "Cookies: Разрешить на сессию",
			allowTooltiptext: "Cookies: Разрешить",
			notAvailableTooltiptext: "Cookies: н/д",
			unknownTooltiptext: "Cookies: ???",
			errorTooltiptext: "Cookies: Ошибка!",

			defaultDenyTooltiptext: "Cookies: Блокировать (по умолчанию)",
			defaultAllowSessionTooltiptext: "Cookies: Разрешить на сессию (по умолчанию)",
			defaultAllowTooltiptext: "Cookies: Разрешить (по умолчанию)",

			defaultLabel: "По умолчанию",
			defaultAccesskey: "у",
			denyLabel: "Блокировать",
			denyAccesskey: "Б",
			denyTempLabel: "Временно блокировать",
			denyTempAccesskey: "л",
			allowSessionLabel: "Разрешить на сессию",
			allowSessionAccesskey: "с",
			allowSessionTempLabel: "Временно разрешить на сессию",
			allowSessionTempAccesskey: "е",
			allowLabel: "Разрешить",
			allowAccesskey: "Р",
			allowTempLabel: "Временно разрешить",
			allowTempAccesskey: "ш",

			showPermissionsLabel: "Показать исключения…",
			showPermissionsAccesskey: "и",
			showCookiesLabel: "Показать cookies…",
			showCookiesAccesskey: "П",
			removeTempPermissionsLabel: "Удалить временные исключения",
			removeTempPermissionsAccesskey: "ы",
			autoRemoveUnprotectedCookiesLabel: "Автоматически удалять незащищённые cookies",
			autoRemoveUnprotectedCookiesTip: "Периодически удалять незащищённые cookies (если установлена галочка)",
			autoRemoveUnprotectedCookiesAccesskey: "А",
			removeUnprotectedCookiesLabel: "Удалить незащищённые cookies",
			removeUnprotectedCookiesTip: "Исключая cookies, помеченные как «Разрешить», и исключая cookies из открытых сайтов",
			removeUnprotectedCookiesAccesskey: "н",
			removeUnprotectedCookiesConfirm: "Удалить незащищённые cookies?",
			removeAllUnprotectedCookiesLabel: "Удалить все незащищённые cookies",
			removeAllUnprotectedCookiesTip: "Исключая cookies, помеченные как «Разрешить»; незащищённые cookies из открытых сайтов будут удалены",
			removeAllUnprotectedCookiesAccesskey: "д",
			removeAllUnprotectedCookiesConfirm: "Удалить ВСЕ незащищённые cookies?",
			removeCurrentSiteCookiesLabel: "Удалить все cookies текущего сайта",
			removeCurrentSiteCookiesAccesskey: "в",
			removeCurrentSiteCookiesConfirm: "Удалить все cookies текущего сайта?",
			removeAllCookiesLabel: "Удалить ВСЕ cookies",
			removeAllCookiesAccesskey: "Е",
			removeAllCookiesConfirm: "Удалить ВСЕ cookies?",

			buttonMenu: "Меню кнопки",
			buttonMenuAccesskey: "М"
		}
	};
	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);
}

this.onclick = function(e) {
	if(e.target != this)
		return;
	var btn = e.button;
	if(btn == 1 || btn == 0 && this.permissions.hasModifier(e))
		this.permissions.openPermissions();
	else if(btn == 0) {
		this.permissions.togglePermission(this.permissions.options.toggleMode);
		// Prevent "command" event to use "command" section only from hotkey
		e.preventDefault();
		e.stopPropagation();
	}
};
if(!this.hasOwnProperty("defaultContextId"))
	this.defaultContextId = this.getAttribute("context") || "custombuttons-contextpopup";
this.oncontextmenu = function(e) {
	if(e.target != this)
		return;
	this.permissions.initContextOnce();
	this.setAttribute(
		"context",
		this.permissions.hasModifier(e)
			? this.defaultContextId
			: this.permissions.mpId
	);
};

this.permissions = {
	permissionType: "cookie",
	timerId: "customButtonsCookiesCleanupTimer",
	timer: null,
	popupClass: "cbCookiesPermissionsPopup",

	button: this,
	options: options,

	cp: Components.interfaces.nsICookiePermission,
	PERMISSIONS_NOT_SUPPORTED: -1,
	PERMISSIONS_ERROR:         -2,

	errPrefix: "[Custom Buttons :: Cookies Permissions] ",

	get pm() {
		delete this.pm;
		return this.pm = Components.classes["@mozilla.org/permissionmanager;1"]
			.getService(Components.interfaces.nsIPermissionManager);
	},
	get cm() {
		delete this.cm;
		return this.cm = Components.classes["@mozilla.org/cookiemanager;1"]
			.getService(Components.interfaces.nsICookieManager);
	},
	get io() {
		delete this.io;
		return this.io = Components.classes["@mozilla.org/network/io-service;1"]
			.getService(Components.interfaces.nsIIOService);
	},
	get oSvc() {
		return Components.classes["@mozilla.org/observer-service;1"]
			.getService(Components.interfaces.nsIObserverService);
	},
	get wm() {
		delete this.wm;
		return this.wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
			.getService(Components.interfaces.nsIWindowMediator);
	},
	get tld() {
		delete this.tld;
		return this.tld = Components.classes["@mozilla.org/network/effective-tld-service;1"]
			.getService(Components.interfaces.nsIEffectiveTLDService);
	},
	get app() {
		delete this.app;
		return this.app = Components.classes["@mozilla.org/xre/app-info;1"]
			.getService(Components.interfaces.nsIXULAppInfo);
	},
	get platformVersion() {
		var pv = parseFloat(this.app.platformVersion);
		if(this.app.name == "Pale Moon" || this.app.name == "Basilisk")
			pv = pv >= 4.1 ? 56 : 28;
		delete this.platformVersion;
		return this.platformVersion = pv;
	},

	initialized: false,
	mp: null,
	init: function() {
		if(this.initialized)
			return;
		this.initialized = true;

		if(this.options.moveToStatusBar.enabled)
			this.moveToStatusBar();

		var dummy = function() {};
		this.progressListener = {
			context: this,
			onStateChange: dummy,
			onProgressChange: dummy,
			onLocationChange: function(aWebProgress, aRequest, aLocation) {
				setTimeout(function(_this) {
					_this.context.updButtonState();
				}, 0, this);
			},
			onStatusChange: dummy,
			onSecurityChange: dummy
		};
		gBrowser.addProgressListener(this.progressListener/*, Components.interfaces.nsIWebProgress.NOTIFY_LOCATION*/);

		this.permissionsObserver = {
			context: this,
			observe: function(subject, topic, data) {
				if(topic != "perm-changed")
					return;
				var permission = subject.QueryInterface(Components.interfaces.nsIPermission);
				var type = this.context.permissionType;
				if(permission.type != type)
					return;
				this.context.updButtonState();
				if(data == "deleted") {
					// See chrome://browser/content/preferences/permissions.js
					// observe: function (aSubject, aTopic, aData)
					let win = this.context.wm.getMostRecentWindow("Browser:Permissions");
					if(win && "gPermissionManager" in win && win.gPermissionManager._type == type) {
						let pm = win.gPermissionManager;
						let perms = pm._permissions;
						for(let i = 0, l = perms.length; i < l; ++i) {
							if(this.context.getPermissionHost(perms[i]) == this.context.getPermissionHost(permission)) {
								perms.splice(i, 1);
								--pm._view._rowCount;
								pm._tree.treeBoxObject.rowCountChanged(i, -1);
								pm._tree.treeBoxObject.invalidate();
								break;
							}
						}
					}
				}
			}
		};
		this.oSvc.addObserver(this.permissionsObserver, "perm-changed", false);

		if(this.options.showDefaultPolicy) {
			let po = this.prefsObserver = {
				context: this,
				get prefs() {
					delete this.prefs;
					return this.prefs = Components.classes["@mozilla.org/preferences-service;1"]
						.getService(Components.interfaces.nsIPrefService)
						.getBranch("network.cookie.")
						.QueryInterface(Components.interfaces.nsIPrefBranch2 || Components.interfaces.nsIPrefBranch);
				},
				getIntPref: function(name) {
					var dv = 0;
					try {
						return this.prefs.getIntPref(name, dv);
					}
					catch(e) {
						Components.utils.reportError(e);
					}
					return dv;
				},
				observe: function(subject, topic, data) {
					if(topic != "nsPref:changed")
						return;
					if(data != "cookieBehavior" && data != "lifetimePolicy")
						return;
					this.context.prefs[data] = this.getIntPref(data);
					this.context.updButtonState();
				}
			};
			this.prefs = {
				"cookieBehavior": po.getIntPref("cookieBehavior"),
				"lifetimePolicy": po.getIntPref("lifetimePolicy"),
				__proto__: null
			};
			po.prefs.addObserver("", po, false);
		}

		this.initCleanupTimer();
		this.updButtonState();
	},
	destroy: function() {
		if(!this.initialized)
			return;
		this.initialized = false;

		gBrowser.removeProgressListener(this.progressListener);
		this.oSvc.removeObserver(this.permissionsObserver, "perm-changed");
		if(this.options.showDefaultPolicy)
			this.prefsObserver.prefs.removeObserver("", this.prefsObserver);
		this.progressListener = this.permissionsObserver = this.prefsObserver = null;
	},
	initContextOnce: function() {
		this.initContextOnce = function() {};

		this.mpId = this.button.id + "-context";
		var cp = this.cp;
		var noTempPermissions = !this.options.showTempPermissions || !this.hasTempPermissions;
		var mp = this.mp = this.button.appendChild(this.parseXULFromString('\
			<menupopup xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"\
				id="' + this.mpId + '"\
				class="' + this.popupClass + '"\
				onpopupshowing="\
					if(event.target != this)\
						return true;\
					document.popupNode = this.parentNode;\
					return this.parentNode.permissions.updMenu();"\
				onpopuphidden="if(event.target == this) document.popupNode = null;">\
				<menuitem type="radio" cb_permission="' + cp.ACCESS_DEFAULT + '"\
					oncommand="this.parentNode.parentNode.permissions.removePermission();"\
					label="' + _localize("defaultLabel") + '"\
					accesskey="' + _localize("defaultAccesskey") + '" />\
				<menuseparator />\
				<menuitem type="radio" cb_permission="' + cp.ACCESS_DENY + '"\
					oncommand="this.parentNode.parentNode.permissions.addPermission(Components.interfaces.nsICookiePermission.ACCESS_DENY);"\
					label="' + _localize("denyLabel") + '"\
					accesskey="' + _localize("denyAccesskey") + '" />\
				<menuitem type="radio" cb_permission="' + cp.ACCESS_DENY + '-temp"\
					collapsed="' + noTempPermissions + '"\
					class="cbTempPermission"\
					oncommand="this.parentNode.parentNode.permissions.addPermission(Components.interfaces.nsICookiePermission.ACCESS_DENY, true);"\
					label="' + _localize("denyTempLabel") + '"\
					accesskey="' + _localize("denyTempAccesskey") + '" />\
				<menuitem type="radio" cb_permission="' + cp.ACCESS_SESSION + '"\
					oncommand="this.parentNode.parentNode.permissions.addPermission(Components.interfaces.nsICookiePermission.ACCESS_SESSION);"\
					label="' + _localize("allowSessionLabel") + '"\
					accesskey="' + _localize("allowSessionAccesskey") + '" />\
				<menuitem type="radio" cb_permission="' + cp.ACCESS_SESSION + '-temp"\
					collapsed="' + noTempPermissions + '"\
					class="cbTempPermission"\
					oncommand="this.parentNode.parentNode.permissions.addPermission(Components.interfaces.nsICookiePermission.ACCESS_SESSION, true);"\
					label="' + _localize("allowSessionTempLabel") + '"\
					accesskey="' + _localize("allowSessionTempAccesskey") + '" />\
				<menuitem type="radio" cb_permission="' + cp.ACCESS_ALLOW + '"\
					oncommand="this.parentNode.parentNode.permissions.addPermission(Components.interfaces.nsICookiePermission.ACCESS_ALLOW);"\
					label="' + _localize("allowLabel") + '"\
					accesskey="' + _localize("allowAccesskey") + '" />\
				<menuitem type="radio" cb_permission="' + cp.ACCESS_ALLOW + '-temp"\
					collapsed="' + noTempPermissions + '"\
					class="cbTempPermission"\
					oncommand="this.parentNode.parentNode.permissions.addPermission(Components.interfaces.nsICookiePermission.ACCESS_ALLOW, true);"\
					label="' + _localize("allowTempLabel") + '"\
					accesskey="' + _localize("allowTempAccesskey") + '" />\
				<menuseparator />\
				<menuitem\
					cb_id="openPermissions"\
					oncommand="this.parentNode.parentNode.permissions.openPermissions();"\
					label="' + _localize("showPermissionsLabel") + '"\
					accesskey="' + _localize("showPermissionsAccesskey") + '" />\
				<menuitem\
					cb_id="showCookies"\
					oncommand="this.parentNode.parentNode.permissions.showCookiesEvent(event);"\
					onclick="this.parentNode.parentNode.permissions.showCookiesEvent(event);"\
					label="' + _localize("showCookiesLabel") + '"\
					accesskey="' + _localize("showCookiesAccesskey") + '" />\
				<menuseparator hidden="' + noTempPermissions + '" />\
				<menuitem\
					cb_id="removeTempPermissions"\
					hidden="' + noTempPermissions + '"\
					oncommand="this.parentNode.parentNode.permissions.removeTempPermissions();"\
					label="' + _localize("removeTempPermissionsLabel") + '"\
					accesskey="' + _localize("removeTempPermissionsAccesskey") + '" />\
				<menuseparator />\
				<menuitem\
					cb_id="autoRemoveUnprotectedCookies"\
					type="checkbox"\
					oncommand="this.parentNode.parentNode.permissions.setAutoRemove(this.getAttribute(\'checked\') == \'true\');"\
					label="' + _localize("autoRemoveUnprotectedCookiesLabel") + '"\
					tooltiptext="' + _localize("autoRemoveUnprotectedCookiesTip") + '"\
					accesskey="' + _localize("autoRemoveUnprotectedCookiesAccesskey") + '" />\
				<menuitem\
					cb_id="removeUnprotectedCookies"\
					oncommand="this.parentNode.parentNode.permissions.confirm(\'removeUnprotectedCookiesConfirm\', \'removeUnprotectedCookies\', false);"\
					label="' + _localize("removeUnprotectedCookiesLabel") + '"\
					tooltiptext="' + _localize("removeUnprotectedCookiesTip") + '"\
					accesskey="' + _localize("removeUnprotectedCookiesAccesskey") + '" />\
				<menuitem\
					cb_id="removeAllUnprotectedCookies"\
					oncommand="this.parentNode.parentNode.permissions.confirm(\'removeAllUnprotectedCookiesConfirm\', \'removeUnprotectedCookies\', true);"\
					label="' + _localize("removeAllUnprotectedCookiesLabel") + '"\
					tooltiptext="' + _localize("removeAllUnprotectedCookiesTip") + '"\
					accesskey="' + _localize("removeAllUnprotectedCookiesAccesskey") + '" />\
				<menuseparator />\
				<menuitem\
					cb_id="removeCurrentSiteCookies"\
					oncommand="this.parentNode.parentNode.permissions.confirm(\'removeCurrentSiteCookiesConfirm\', \'removeCurrentSiteCookies\');"\
					label="' + _localize("removeCurrentSiteCookiesLabel") + '"\
					accesskey="' + _localize("removeCurrentSiteCookiesAccesskey") + '" />\
				<menuitem\
					cb_id="removeAllCookies"\
					oncommand="this.parentNode.parentNode.permissions.confirm(\'removeAllCookiesConfirm\', \'removeCookies\');"\
					label="' + _localize("removeAllCookiesLabel") + '"\
					accesskey="' + _localize("removeAllCookiesAccesskey") + '" />\
				<menuseparator />\
				<menu\
					label="' + _localize("buttonMenu") + '"\
					accesskey="' + _localize("buttonMenuAccesskey") + '" />\
			</menupopup>'
		));
		var cbPopup = document.getElementById(this.button.defaultContextId);
		if(!cbPopup)
			Components.utils.reportError(this.errPrefix + "cb menu not found");
		else {
			cbPopup = cbPopup.cloneNode(true);
			let id = "-" + this.button.id.match(/\d*$/)[0] + "-cloned";
			cbPopup.id += id;
			Array.prototype.slice.call(cbPopup.getElementsByAttribute("id", "*")).forEach(function(node) {
				node.id += id;
			});
			cbPopup.setAttribute(
				"onpopupshowing",
				'\
				var btn = document.popupNode = this.parentNode.parentNode.parentNode;\n\
				custombutton.setContextMenuVisibility(btn);'
			);
			let menu = mp.lastChild;
			menu.appendChild(cbPopup);
		}
	},
	setAutoRemove: function(enable) {
		if(enable) {
			this._forceEnableCleanup = true;
			this.initCleanupTimer(); // Ensure initialized
		}
		var timer = this.timer || null;
		if(timer)
			timer.enabled = enable;
	},
	_forceEnableCleanup: false,
	initCleanupTimer: function() {
		if(!this.options.removeUnprotectedCookiesEnabled && !this._forceEnableCleanup)
			return;
		var interval = this.options.removeUnprotectedCookiesInterval;
		if(interval <= 0)
			return;
		var timerId = this.timerId;
		var timer = this.timer = this.storage.get(timerId, null);
		if(timer)
			return;
		timer = this.timer = {
			timerId: timerId,
			interval: interval,
			enabled: true,
			permissions: this,
			get timer() {
				delete this.timer;
				return this.timer = Components.classes["@mozilla.org/timer;1"]
					.createInstance(Components.interfaces.nsITimer);
			},
			init: function() {
				window.addEventListener("unload", this, false);
				this.permissions.oSvc.addObserver(this, "quit-application-granted", false);
				this.timer.init(this, this.interval, this.timer.TYPE_REPEATING_SLACK);
			},
			destroy: function() {
				this.permissions.oSvc.removeObserver(this, "quit-application-granted");
				this.timer.cancel();
				this.permissions.storage.set(this.timerId, null);
				this.permissions = null;
			},
			handleEvent: function(e) {
				if(e.type != "unload")
					return;
				window.removeEventListener("unload", this, false);
				var p = this.permissions;
				p.button = p.mp = null;
			},
			observe: function(subject, topic, data) {
				if(topic == "quit-application-granted")
					this.destroy();
				else if(topic == "timer-callback")
					this.enabled && this.permissions.removeUnprotectedCookies();
			}
		};
		this.storage.set(timerId, timer);
		timer.init();
	},
	moveToStatusBar: function() {
		var insPoint;
		this.options.moveToStatusBar.insertAfter
			.split(/,\s*/)
			.some(function(id) {
				insPoint = document.getElementsByAttribute("cb_id", id)[0]
					|| document.getElementById(id);
				return insPoint;
			});
		if(!insPoint)
			return;

		var btn = this.button;
		// Make <toolbarbutton> looks like <image>, see CSS
		btn.className += " custombuttons-insideStatusbarpanel";
		// And insert it into <statusbarpanel>
		var spId = btn.id + "-statusbarpanel";
		var sp = document.getElementById(spId);
		sp && sp.parentNode.removeChild(sp);
		sp = document.createElement("statusbarpanel");
		sp.id = spId;
		sp.setAttribute("cb_id", "custombuttons-cookiesPermissionsSBPanel");
		sp.appendChild(btn);
		insPoint.parentNode.insertBefore(sp, insPoint.nextSibling);
	},

	get currentHost() {
		return this.getHostFromBrowser(gBrowser);
	},
	get currentHosts() { // returns hosts from all visible tabs in all windows
		var tmp = { __proto__: null };
		var ws = this.wm.getEnumerator("navigator:browser");
		while(ws.hasMoreElements()) {
			let gBrowser = ws.getNext().gBrowser;
			let tabs = gBrowser.visibleTabs || gBrowser.tabs || gBrowser.tabContainer.childNodes;
			for(let i = 0, l = tabs.length; i < l; ++i) {
				let browser = tabs[i].linkedBrowser;
				let host = browser && this.getHostFromBrowser(browser);
				if(!host)
					continue;
				host = this.getHost(this.options.useBaseDomain.preserveCurrentSitesCookies, host);
				tmp[host] = true;
			}
		}
		var hosts = [];
		for(var host in tmp)
			hosts.push(host);
		return hosts;
	},
	getHostFromBrowser: function(browser) {
		try {
			var uri = browser.currentURI;
			if(["chrome", "resource"].indexOf(uri.scheme) != -1)
				return "";
			return uri.host;
		}
		catch(e) {
		}
		return "";
	},
	get currentProtocol() {
		var scheme = gBrowser.currentURI.scheme;
		if(scheme == "https")
			return scheme;
		return "http";
	},
	getHost: function(useBaseDomain, host) {
		if(host === undefined)
			host = this.currentHost;
		switch(useBaseDomain) {
			case 1: return this.stripWww(host);
			case 2: return this.getBaseDomain(host);
		}
		return host;
	},
	getURI: function(host, protocol) {
		if(host.indexOf(":") != -1 && /^[:\da-f.]+$/.test(host)) // IPv6
			host = "[" + host + "]";
		host = host.replace(/^\./, "");
		try {
			return this.io.newURI((protocol || this.currentProtocol) + "://" + host, null, null);
		}
		catch(e) {
			Components.utils.reportError(this.errPrefix + "Invalid host: \"" + host + "\"");
			throw e;
		}
	},
	stripWww: function(host) {
		return host && host.replace(/^www\./i, "");
	},
	getBaseDomain: function(host) {
		if(host) try {
			return this.tld.getBaseDomainFromHost(host);
		}
		catch(e) {
		}
		return host;
	},

	showMenu: function(e, isContext, mp) {
		document.popupNode = this.button.ownerDocument.popupNode = this.button;
		if(!mp) {
			this.initContextOnce();
			mp = this.mp;
		}
		if("openPopupAtScreen" in mp)
			mp.openPopupAtScreen(e.screenX, e.screenY, isContext);
		else
			mp.showPopup(this, e.screenX, e.screenY, isContext ? "context" : "popup", null, null);
	},
	updMenu: function() {
		var permission = this.options.showTempPermissions
			? this.getPermissionEx()
			: this.getPermission();

		var noPermissions = permission == this.PERMISSIONS_NOT_SUPPORTED;
		Array.prototype.forEach.call(
			this.mp.getElementsByAttribute("cb_permission", "*"),
			function(mi) {
				mi.hidden = noPermissions;
				var ns = mi.nextSibling;
				if(ns && ns.localName == "menuseparator")
					ns.hidden = noPermissions;
			}
		);

		if(!noPermissions) {
			let cbPermission = permission.capability || permission;
			if(
				this.options.showTempPermissions
				&& permission instanceof Components.interfaces.nsIPermission
				&& "expireType" in permission
				&& permission.expireType != this.pm.EXPIRE_NEVER
			)
				cbPermission += "-temp";
			let mi = this.mp.getElementsByAttribute("cb_permission", cbPermission)[0] || null;
			mi && mi.setAttribute("checked", "true");
		}

		if(this.hasTempPermissions) {
			let maxItems = 10;
			let removeItem = this.mp.getElementsByAttribute("cb_id", "removeTempPermissions")[0];
			let tempPermissions = this.tempPermissions;
			removeItem.disabled = !tempPermissions.length;
			if(tempPermissions.length > maxItems)
				tempPermissions.splice(maxItems - 2, tempPermissions.length - maxItems + 1, "…");
			let cp = this.cp;
			removeItem.tooltipText = tempPermissions.map(function(permission) {
				if(typeof permission == "string")
					return permission;
				var action = "???";
				switch(permission.capability) {
					case cp.ACCESS_ALLOW:   action = "allowLabel";        break;
					case cp.ACCESS_DENY:    action = "denyLabel";         break;
					case cp.ACCESS_SESSION: action = "allowSessionLabel";
				}
				return (permission.host || permission.principal.URI.spec.replace(/\/$/, ""))
					+ ": " + _localize(action).toLowerCase();
			}, this).join(", \n");
		}

		var removeCurrent = this.mp.getElementsByAttribute("cb_id", "removeCurrentSiteCookies")[0];
		removeCurrent.hidden = noPermissions;
		if(!noPermissions)
			removeCurrent.tooltipText = this.removeCurrentSiteCookiesHost;

		var timer = this.timer || null;
		var autoRemove = this.mp.getElementsByAttribute("cb_id", "autoRemoveUnprotectedCookies")[0];
		autoRemove.setAttribute("checked", timer ? timer.enabled : false);
		autoRemove.hidden = this.options.removeUnprotectedCookiesInterval <= 0;

		return true;
	},

	openPermissions: function() {
		var host = this.getHost(this.options.useBaseDomain.openPermissions);
		if(host && this.platformVersion >= 42)
			host = this.currentProtocol + "://" + host;

		if(this.app.name == "SeaMonkey") {
			this.openPermissionsSM(host);
			return;
		}

		// chrome://browser/content/preferences/privacy.js
		// gPrivacyPane.showCookieExceptions()
		var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
			.getService(Components.interfaces.nsIStringBundleService)
			.createBundle("chrome://browser/locale/preferences/preferences.properties");
		try {
			var cpTitle = bundle.GetStringFromName("cookiepermissionstitle");
			var cpText = bundle.GetStringFromName("cookiepermissionstext");
		}
		catch(e) { // Not used in Firefox 62+
		}
		var params = { blockVisible   : true,
					   sessionVisible : true,
					   allowVisible   : true,
					   prefilledHost  : host,
					   permissionType : this.permissionType,
					   windowTitle    : cpTitle,
					   introText      : cpText };

		var win;
		var ws = this.wm.getEnumerator("Browser:Permissions");
		while(ws.hasMoreElements()) {
			win = ws.getNext();
			if(
				this.options.reusePermissionsWindow
				|| "gPermissionManager" in win && win.gPermissionManager._type == this.permissionType
			)
				break;
			win = null;
		}

		var _this = this;
		var setFilter = function setFilter(e) {
			e && win.removeEventListener("load", setFilter, false);
			setTimeout(function() {
				_this.setTextboxValue(win.document.getElementById("url"), host, !!e);
			}, 0);
		};
		if(win) {
			// See <method name="openWindow"> in chrome://global/content/bindings/preferences.xml#prefwindow
			if("initWithParams" in win)
				win.initWithParams(params);
			win.focus();
			host && setFilter();
		}
		else {
			var ext = this.platformVersion >= 72 ? ".xhtml" : ".xul";
			var sub = this.platformVersion >= 77 ? "dialogs/" : "";
			win = window.openDialog("chrome://browser/content/preferences/" + sub + "permissions" + ext, "_blank", "", params);
			host && win.addEventListener("load", setFilter, false);
		}

		this.tweakWindow(win);
	},
	openPermissionsSM: function(host) {
		var win = this.wm.getMostRecentWindow("mozilla:cookieviewer");
		var _this = this;
		if(!host)
			host = "";
		var setFilter = function setFilter(e) {
			e && win.removeEventListener("load", setFilter, false);
			var doc = win.document;
			doc.getElementById("tabbox").selectedTab = doc.getElementById("permissionsTab");
			_this.setTextboxValue(doc.getElementById("cookie-site"), host);
		};
		if(win) {
			win.focus();
			setFilter();
		}
		else {
			win = window.openDialog("chrome://communicator/content/permissions/cookieViewer.xul", "_blank", "");
			win.addEventListener("load", setFilter, false);
		}
	},
	tweakWindow: function(win) {
		if("__cbPermissionsTweaked" in win)
			return;
		win.__cbPermissionsTweaked = true;
		function keypressHandler(e) {
			if(e.keyCode == e.DOM_VK_ESCAPE)
				win.close();
		}
		win.addEventListener("keypress", keypressHandler, false);
		win.addEventListener("unload", function destroy(e) {
			var win = e.target.defaultView;
			if(win != e.currentTarget)
				return;
			win.removeEventListener(e.type, destroy, false);
			win.removeEventListener("keypress", keypressHandler, false);
		}, false);
	},
	setTextboxValue: function(tb, val, onlySelect) {
		if(!tb)
			return;
		if(!onlySelect)
			tb.value = val;
		tb.focus();
		if(val && "inputField" in tb) {
			let ifi = tb.inputField;
			switch(this.options.prefillMode) {
				case 0: ifi.selectionStart = ifi.selectionEnd = 0;          break;
				case 2: ifi.selectionStart = ifi.selectionEnd = val.length; break;
				default: tb.select();
			}
		}
		if(onlySelect)
			return;
		setTimeout(function() { // For Browser:Cookies in Firefox 14
			tb.doCommand(); // Should be faster than "input" emulation
		}, 0);
		var evt = document.createEvent("UIEvents");
		evt.initUIEvent("input", true, true, tb.ownerDocument.defaultView, 0);
		tb.dispatchEvent(evt);
	},

	get hasTempPermissions() {
		delete this.hasTempPermissions;
		return this.hasTempPermissions = "EXPIRE_SESSION" in this.pm
			&& (!("add" in this.pm) || this.pm.add.length > 3);
	},
	get pmw() {
		delete this.pmw;
		var pm = this.pm;
		if("testPermission" in pm) {
			return this.pmw = {
				testPermission: pm.testPermission.bind(pm),
				add:            pm.add           .bind(pm),
				remove:         pm.remove        .bind(pm),
				__proto__: pm
			};
		}
		// Firefox 71+
		var make = function(fn) {
			return function(uri, permission) {
				var principal = Services.scriptSecurityManager.createContentPrincipal(uri, {});
				var args = Array.from(arguments);
				args[0] = principal;
				return fn.apply(pm, args);
			};
		};
		return this.pmw = {
			_context: this,
			testPermission: make(pm.testPermissionFromPrincipal),
			add:            make(pm.addFromPrincipal),
			remove:         make(pm.removeFromPrincipal),
			get enumerator() { // Firefox 72+
				return pm.enumerator || this._context.arrayToEnumerator(pm.all);
			}
		};
	},
	arrayToEnumerator: function(arr) {
		var i = 0, l = arr.length;
		return {
			hasMoreElements: function() {
				return i < l;
			},
			getNext: function() {
				return arr[i++];
			}
		}
	},
	addPermission: function(capability, temporary) {
		// capability:
		//  this.cp.ACCESS_ALLOW (this.pm.ALLOW_ACTION)
		//  this.cp.ACCESS_SESSION
		//  this.cp.ACCESS_DENY (this.pm.DENY_ACTION)

		var host = this.getHost(this.options.useBaseDomain.addPermission);
		if(!host)
			return;

		if(temporary && !this.hasTempPermissions)
			temporary = false;
		this.updButtonState(capability); // Faster than ProgressListener (70-80 ms for me)

		if(this.hasTempPermissions)
			this.removePermissionForHost(host);

		var pm = this.pm;
		var args = [this.getURI(host), this.permissionType, capability];
		if(temporary) {
			let expire = this.options.tempExpire;
			if(expire < 0)
				args.push(pm.EXPIRE_SESSION);
			else
				args.push(pm.EXPIRE_TIME, expire + Date.now());
		}
		this.pmw.add.apply(this.pmw, args);
	},
	removePermission: function() {
		var host = this.currentHost;
		if(!host)
			return;

		this.updButtonState(this.cp.ACCESS_DEFAULT); // Faster than ProgressListener (70-80 ms for me)

		var uri = this.getURI(host);
		var permission = this.pmw.testPermission(uri, this.permissionType);
		this.removePermissionForHost(host);
		while(this.pmw.testPermission(uri, this.permissionType) == permission) {
			let parentHost = host.replace(/^[^.]*\./, "");
			if(parentHost == host)
				break;
			host = parentHost;
			this.removePermissionForHost(host);
		}
	},
	togglePermission: function(capabilities) {
		var permission = this.getPermissionEx(this.getHost(this.options.useBaseDomain.addPermission), true);
		if(permission instanceof Components.interfaces.nsIPermission)
			permission = permission.capability;
		if(permission == this.PERMISSIONS_NOT_SUPPORTED)
			return;
		var capability = capabilities[(capabilities.indexOf(permission) + 1) % capabilities.length];

		if(capability == this.cp.ACCESS_DEFAULT)
			this.removePermission();
		else
			this.addPermission(capability);
	},
	get tempPermissions() {
		var out = [];
		if(!this.hasTempPermissions)
			return out;
		var pm = this.pm;
		var enumerator = this.pmw.enumerator;
		while(enumerator.hasMoreElements()) {
			let permission = enumerator.getNext()
				.QueryInterface(Components.interfaces.nsIPermission);
			if(
				permission.type == this.permissionType
				&& permission.expireType != pm.EXPIRE_NEVER
			)
				out.push(permission);
		}
		return out;
	},
	removeTempPermissions: function() {
		this.tempPermissions.forEach(this.removeRawPermission, this);
	},
	getPermission: function() {
		var host = this.currentHost;
		return host
			? this.pmw.testPermission(this.getURI(host), this.permissionType)
			: this.PERMISSIONS_NOT_SUPPORTED;
	},
	getPermissionEx: function(host, dontGetInherited) {
		// Unfortunately no API like nsIPermissionManager.testPermission()
		// for temporary permissions
		if(!host)
			host = this.currentHost;
		if(!host)
			return this.PERMISSIONS_NOT_SUPPORTED;
		var pm = this.pm;
		var matchedPermission = pm.UNKNOWN_ACTION;
		var protocol = this.currentProtocol;
		var maxHostLen = -1;
		var enumerator = this.pmw.enumerator;
		while(enumerator.hasMoreElements()) {
			let permission = enumerator.getNext()
				.QueryInterface(Components.interfaces.nsIPermission);
			if(permission.type != this.permissionType)
				continue;
			if("principal" in permission && permission.principal.URI.scheme != protocol) // Firefox 42+
				continue;
			let permissionHost = this.getPermissionHost(permission);
			if(permissionHost == host)
				return permission;
			if(dontGetInherited)
				continue;
			let hostLen = permissionHost.length;
			if(
				hostLen > maxHostLen
				&& host.substr(-hostLen - 1) == "." + permissionHost // ~= checkCookieHost()
			) {
				matchedPermission = permission;
				maxHostLen = hostLen;
			}
		}
		return matchedPermission;
	},
	removePermissionForHost: function(host) {
		try {
			this.pmw.remove(host, this.permissionType);
		}
		catch(e) {
			// See https://bugzilla.mozilla.org/show_bug.cgi?id=1170200
			if("Services" in window) try { // Firefox 42+
				let uri = Services.io.newURI(this.currentProtocol + "://" + host, null, null);
				this.pmw.remove(uri, this.permissionType);
				return;
			}
			catch(e2) {
				Components.utils.reportError(e2);
			}
			Components.utils.reportError(e);
		}
	},
	removeRawPermission: function(permission) {
		if("principal" in permission) // Firefox 42+
			this.pmw.remove(permission.principal.URI, this.permissionType);
		else
			this.removePermissionForHost(permission.host);
	},
	getPermissionHost: function(permission) {
		if("host" in permission)
			return permission.host;
		// See https://bugzilla.mozilla.org/show_bug.cgi?id=1173523
		return permission.principal.URI.host; // Firefox 42+
	},
	get defaultPermission() {
		// http://kb.mozillazine.org/Network.cookie.cookieBehavior
		// http://kb.mozillazine.org/Network.cookie.lifetimePolicy
		if(this.prefs.cookieBehavior == 2)
			return this.cp.ACCESS_DENY;
		if(this.prefs.lifetimePolicy == 2)
			return this.cp.ACCESS_SESSION;
		return this.cp.ACCESS_ALLOW;
	},
	showCookiesEvent: function(e) {
		if(e.type == "command")
			this.showCookies(this.hasModifier(e));
		else if(e.type == "click" && e.button == 1) {
			this.mp.hidePopup();
			this.showCookies(true);
		}
	},
	showCookies: function(showAll) {
		var host = showAll ? "" : this.getHost(this.options.useBaseDomain.showCookies);
		if("coomanPlus" in window && "coomanPlusCore" in window && this.options.useCookiesManagerPlus) {
			// https://addons.mozilla.org/firefox/addon/cookies-manager-plus/
			this.showCookiesCMP(host);
			return;
		}
		if(this.app.name == "SeaMonkey") {
			this.showCookiesSM(host);
			return;
		}
		if(
			(this.app.name == "Firefox" || this.app.name == "Waterfox")
			&& parseFloat(this.app.version) >= 61
		) {
			this.showSiteData(host);
			return;
		}
		var win = this.wm.getMostRecentWindow("Browser:Cookies");
		var _this = this;
		var setFilter = function setFilter(e) {
			e && win.removeEventListener("load", setFilter, false);
			_this.setTextboxValue(win.document.getElementById("filter"), host);
		};
		if(win) {
			win.focus();
			(host || showAll) && setFilter();
		}
		else {
			win = window.openDialog("chrome://browser/content/preferences/cookies.xul", "_blank", "");
			host && win.addEventListener("load", setFilter, false);
		}
		this.tweakWindow(win);
	},
	showCookiesCMP: function(host) {
		// See openCMP() function in resource://cookiesmanagerplus/coomanPlusCore.jsm
		var win = coomanPlusCore.aWindow;
		var _this = this;
		var setFilter = function setFilter(e) {
			e && win.removeEventListener("load", setFilter, false);
			var doc = win.document;
			setTimeout(function() { // Just loaded window aren't ready
				_this.setTextboxValue(doc.getElementById("lookupcriterium"), host);
			}, 0);
		};
		if(win) {
			win.focus();
			host && setFilter();
		}
		else {
			win = window.openDialog(
				"chrome://cookiesmanagerplus/content/cookiesmanagerplus.xul",
				"coomanPlusWindow", "chrome,resizable=yes,toolbar=no,statusbar=no,scrollbar=no,centerscreen"
			);
			host && win.addEventListener("load", setFilter, false);
		}
	},
	showCookiesSM: function(host) {
		var win = this.wm.getMostRecentWindow("mozilla:cookieviewer");
		var _this = this;
		if(!host)
			host = "";
		var setFilter = function setFilter(e) {
			e && win.removeEventListener("load", setFilter, false);
			var doc = win.document;
			doc.getElementById("tabbox").selectedTab = doc.getElementById("cookiesTab");
			_this.setTextboxValue(doc.getElementById("filter"), host);
		};
		if(win) {
			win.focus();
			setFilter();
		}
		else {
			win = window.openDialog("chrome://communicator/content/permissions/cookieViewer.xul", "_blank", "");
			win.addEventListener("load", setFilter, false);
		}
	},
	showSiteData: function(host) {
		var win = this.wm.getMostRecentWindow("Browser:SiteDataSettings");
		var _this = this;
		var setFilter = function setFilter(e) {
			e && win.removeEventListener("load", setFilter, false);
			_this.setTextboxValue(win.document.getElementById("searchBox"), host);
		};
		if(win) {
			win.focus();
			host && setFilter();
		}
		else {
			var {SiteDataManager} = Components.utils.import("resource:///modules/SiteDataManager.jsm", {});
			SiteDataManager.updateSites().then(function() {
				var ext = _this.platformVersion >= 72 ? ".xhtml" : ".xul";
				var sub = _this.platformVersion >= 77 ? "dialogs/" : "";
				win = window.openDialog("chrome://browser/content/preferences/" + sub + "siteDataSettings" + ext, "_blank", "");
				host && win.addEventListener("load", setFilter, false);
			}, Components.utils.reportError);
		}
	},
	confirm: function(msg, method/*, arg1, arg2*/) {
		if(
			!this.options.confirmRemoval
			|| Components.classes["@mozilla.org/prompter;1"]
				.getService(Components.interfaces.nsIPromptService)
				.confirm(window, _localize("Cookies Permissions"), _localize(msg))
		)
			this[method].apply(this, Array.prototype.slice.call(arguments, 2));
	},
	removeUnprotectedCookies: function(removeAll) {
		if(removeAll == undefined)
			removeAll = this.options.removeAllUnprotectedCookies;
		var cp = this.cp;
		var checkCookieHosts;
		if(!removeAll) {
			let hosts = this.currentHosts;
			let checkCookieHost = this.checkCookieHost;
			checkCookieHosts = function(cookieHost) {
				return !hosts.some(function(host) {
					return checkCookieHost(cookieHost, host);
				});
			};
		}
		this.removeCookies([
			cp.ACCESS_DEFAULT,
			/*cp.ACCESS_ALLOW,*/
			cp.ACCESS_DENY,
			cp.ACCESS_SESSION
		], checkCookieHosts);
	},
	get removeCurrentSiteCookiesHost() {
		return this.getHost(this.options.useBaseDomain.removeCurrentSiteCookies);
	},
	removeCurrentSiteCookies: function() {
		var host = this.removeCurrentSiteCookiesHost;
		var checkCookieHost = this.checkCookieHost;
		this.removeCookies(null, function(cookieHost) {
			return checkCookieHost(cookieHost, host);
		});
	},
	get checkCookieHost() {
		delete this.checkCookieHost;
		return this.checkCookieHost = "endsWith" in String.prototype // Firefox 17+
			? function(cookieHost, host) {
				return host == cookieHost
					|| cookieHost.endsWith("." + host);
			}
			: function(cookieHost, host) {
				return host == cookieHost
					|| cookieHost.substr(-host.length - 1) == "." + host;
			};
	},
	removeCookies: function(types, checkHost) {
		var cm = this.cm;
		var pm = this.pm;
		var cookies = cm.enumerator || this.arrayToEnumerator(cm.cookies); // Firefox 73+
		while(cookies.hasMoreElements()) {
			let cookie = cookies.getNext()
				.QueryInterface(Components.interfaces.nsICookie);
			let cookieHost = cookie.host;
			if(checkHost && !checkHost(cookieHost))
				continue;
			if(types) {
				// Trick for Firefox 42+, assumed pm.UNKNOWN_ACTION == 0
				let permission = this.pmw.testPermission(this.getURI(cookieHost, "http"), this.permissionType)
					|| this.pmw.testPermission(this.getURI(cookieHost, "https"), this.permissionType);
				if(types.indexOf(permission) == -1)
					continue;
			}
			if("testPermission" in pm)
				cm.remove(cookieHost, cookie.name, cookie.path, false, cookie.originAttributes || undefined);
			else // Firefox 71+
				cm.remove(cookieHost, cookie.name, cookie.path, cookie.originAttributes || undefined);
		}
	},

	updButtonState: function(permission) {
		var ttAdd = "";
		if(permission === undefined) try {
			permission = this.getPermission();
		}
		catch(e) { // See this.getURI()
			Components.utils.reportError(e);
			ttAdd = " \n" + e;
			permission = this.PERMISSIONS_ERROR;
		}
		var cp = this.cp;
		var key;
		switch(permission) {
			case cp.ACCESS_DEFAULT:
				key = "default";
				if(this.options.showDefaultPolicy) switch(this.defaultPermission) {
					case cp.ACCESS_ALLOW:        key = "defaultAllow";        break;
					case cp.ACCESS_DENY:         key = "defaultDeny";         break;
					case cp.ACCESS_SESSION:      key = "defaultAllowSession";
				}
			break;
			case cp.ACCESS_ALLOW:                key = "allow";               break;
			case cp.ACCESS_DENY:                 key = "deny";                break;
			case cp.ACCESS_SESSION:              key = "allowSession";        break;
			case this.PERMISSIONS_NOT_SUPPORTED: key = "notAvailable";        break;
			case this.PERMISSIONS_ERROR:         key = "error";               break;
			default:                             key = "unknown";
		}
		var btn = this.button;
		if(btn.getAttribute("cb_cookies") == key)
			return;
		btn.disabled = permission == this.PERMISSIONS_NOT_SUPPORTED;
		btn.setAttribute("cb_cookies", key);
		btn.tooltipText = _localize(key + "Tooltiptext") + ttAdd;
	},

	hasModifier: function(e) {
		return e.ctrlKey || e.shiftKey || e.altKey || e.metaKey;
	},
	parseXULFromString: function(xul) {
		xul = xul.replace(/>\s+</g, "><");
		try {
			return new DOMParser().parseFromString(xul, "application/xml").documentElement;
		}
		catch(e) {
			// See http://custombuttons.sourceforge.net/forum/viewtopic.php?f=5&t=3720
			// + https://forum.mozilla-russia.org/viewtopic.php?pid=732243#p732243
			var dummy = document.createElement("dummy");
			dummy.innerHTML = xul.trimLeft();
			return dummy.firstChild;
		}
	},

	get storage() {
		delete this.storage;
		if(!("Services" in window)) // Firefox 3.6 and older
			return this.storage = Application.storage;
		// Simple replacement for Application.storage
		// See https://bugzilla.mozilla.org/show_bug.cgi?id=1090880
		//var global = Components.utils.getGlobalForObject(Services);
		// Ensure, that we have global object (because window.Services may be overwritten)
		var global = Components.utils.import("resource://gre/modules/Services.jsm", {});
		var ns = "_cbCookiesPermissionsStorage";
		var storage = global[ns] || (global[ns] = Components.utils.getGlobalForObject(global).Object.create(null));
		return this.storage = {
			get: function(key, defaultVal) {
				if(key in storage)
					return storage[key];
				return defaultVal;
			},
			set: function(key, val) {
				if(key === null)
					delete storage[key];
				else
					storage[key] = val;
			}
		};
	}
};

//===================
// Styles
// Used Fugue and Diagona icons (http://p.yusukekamiyamane.com/)

// Styles can't override hardcoded icon
var icon = this.icon
	|| this.ownerDocument.getAnonymousElementByAttribute(this, "class", "toolbarbutton-icon");
if(icon)
	// icon.src = ""; Firefox 112+
	icon.removeAttribute("src");
else
	this.image = "";

var cssStr = ('\
	@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");\n\
	@-moz-document url("' + window.location.href + '") {\n\
		%button% {\n\
			list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAC6klEQVQ4T42Ta0iTYRTHz7vru1tubuomFjkLUVHT5swbNlKjUqgPmmBQEZillFZkBInfvISZkIVBSKBgGhRogRqk6LLI6+Y0p27SzG05L9Ntzs1t7X3FtbSgA+fL85zzP8/vOecg8A/7VBJEs63rRABIjNsDtsNcerePUFj8wcTa+Q3sBPlbft81H47Nar0SEJaQyo9KPYJyeP5YnHXF8FMn6x3VTw70UlD0Rcoz48oeAazy+orupjAlN0cQmRSDMplAIJNBKpVCglgMVpMJtHLpiKqvpZXF4dftEWjPI53wCxWVhkpy01k8HlRWPITiogIgoyi4nE4gUamwbjDA1MeW7sWpwSqPwA6z1Q6lfsHRqSx/AZNE2wcs/kEg0bmAEEk47dchGSQmx8PC5Jh+rL3hKS7gzcwLj5cwuEEMl8sFdosRVjVKsJnX4FWnAopuFQDKYADRjaSdUdoHWmuakf9hXpqVg2V5AdjCWHcyFbB/0c+pt/pbaluR3cxbm5uwZbPtYZ4f7QUynQ3jM6uQIhGDVjW1/OVd00vk9XlSWXTW1euBYdEBGE91VR0U38j3dHeHWascB4NaASHiDDAZjTDc0y7TqifKkeZsYqPkUlme/NscOU4UCWQaDTbNZqiteQ4lt/M9zAtKJaiHu0AYdwpmFcMambS7C/XhFiONZ4nNaZfv53AEgSTL2hreKsxQOh2sFgsgBMI2s1oF8p639g0Cqvo+o/hMJDPu3X1v1iENWaRH8WcuXBQIQ32xxMqyerjz4DfCQP8IzqyZnrBLO5omTTZXBdsXOgrbwISP8pNM4jlBcHh57PGsKKr7+WQKBTbcCPglVt195s1c1OF44z3+SH22H9NqXHoclZSeERIRu59AJOIL0vdhEJLTROB0OP5gLmxbxCvvGD5I1acZfIfdXHngUMSxwxFHBWwuj0FDaaD9oTFPK4a03sy7l88zyvXZwFxdhkwXwEmnC4KxQAICandApzfzboFfzENQQBtpnroAAAAASUVORK5CYII=") !important;\n\
		}\n\
		%button%[cb_cookies="default"]             { list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAC6klEQVQ4T42Ta0iTYRTHz7vru1tubuomFjkLUVHT5swbNlKjUqgPmmBQEZillFZkBInfvISZkIVBSKBgGhRogRqk6LLI6+Y0p27SzG05L9Ntzs1t7X3FtbSgA+fL85zzP8/vOecg8A/7VBJEs63rRABIjNsDtsNcerePUFj8wcTa+Q3sBPlbft81H47Nar0SEJaQyo9KPYJyeP5YnHXF8FMn6x3VTw70UlD0Rcoz48oeAazy+orupjAlN0cQmRSDMplAIJNBKpVCglgMVpMJtHLpiKqvpZXF4dftEWjPI53wCxWVhkpy01k8HlRWPITiogIgoyi4nE4gUamwbjDA1MeW7sWpwSqPwA6z1Q6lfsHRqSx/AZNE2wcs/kEg0bmAEEk47dchGSQmx8PC5Jh+rL3hKS7gzcwLj5cwuEEMl8sFdosRVjVKsJnX4FWnAopuFQDKYADRjaSdUdoHWmuakf9hXpqVg2V5AdjCWHcyFbB/0c+pt/pbaluR3cxbm5uwZbPtYZ4f7QUynQ3jM6uQIhGDVjW1/OVd00vk9XlSWXTW1euBYdEBGE91VR0U38j3dHeHWascB4NaASHiDDAZjTDc0y7TqifKkeZsYqPkUlme/NscOU4UCWQaDTbNZqiteQ4lt/M9zAtKJaiHu0AYdwpmFcMambS7C/XhFiONZ4nNaZfv53AEgSTL2hreKsxQOh2sFgsgBMI2s1oF8p639g0Cqvo+o/hMJDPu3X1v1iENWaRH8WcuXBQIQ32xxMqyerjz4DfCQP8IzqyZnrBLO5omTTZXBdsXOgrbwISP8pNM4jlBcHh57PGsKKr7+WQKBTbcCPglVt195s1c1OF44z3+SH22H9NqXHoclZSeERIRu59AJOIL0vdhEJLTROB0OP5gLmxbxCvvGD5I1acZfIfdXHngUMSxwxFHBWwuj0FDaaD9oTFPK4a03sy7l88zyvXZwFxdhkwXwEmnC4KxQAICandApzfzboFfzENQQBtpnroAAAAASUVORK5CYII=") !important; }\n\
		%button%[cb_cookies="allow"]               { list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADAUlEQVQ4T42TXUiTURjH/6/bdHObuZy6iUXqQlT8zDQ10eFHlh/UhdMwqRDMQtIiEIKsm0jNPoQsvAgvRNQV3XihM2UTMS+y/EYd0xl+zPm5qdM5zbX3hFJZ0AOHc87D//mf83vf51D4R3y648mxrM+HA1Sobbj/lFn1ttFnzxf1Rr+Y2aIz1N/qu24eEVjM5jx3v6g4UVBcCFsgdKN15tWlhfnBzn79aE+nPZv9NvaNcfWQAX3y+up8kXdstkwcGBPK5vFgx2Khu7sbURERMG9sQDfU3TfZ1SjnC0RVhwyac5gJrr7hJb7S7CS+UIiyJ09RXFgAFpsN694emA4OWF9awriy8ePieG/5gcE+s3kHJa5ewXF8NzGPyXECX3QCTEcXUAwmof38ZRDRZyMxNzqgH2iueU0MfmUW+kdKuS6eXKvVip1NIwzTalhMa2hSjKDwbgHYXC4YNiSdRr3TI39WT/0P8/LEEDZX5uDsHWYrdgD9XfRT2t1Kbcso9Sfz7vY2di2WQ8wz/Z1gOTpjWGNArDQCOYYOgkS9z2KWBqffuOXhF+xO81SUV6H4dj4aDKO47Ox3wKxTD2NJOwKfiGRkLrQgJSUFra2toOozGbXSa6U5Q2NTrNPhgWBxONg2mZDx7QM5oc0/lzDPqdXQfm1DqZ8jMjIyYLHdkhjUXmTUJ16/LxOIPZiba2vkV9FxfvIdZDIZ5HI5VCF50GsnkWVUkpzRaCQahUIBqiad+Twy9cpVsbfvUTpZVlqNew/ykaxpQmJCIsQeYtTV1ZGC3Nxc6OZ0ZN3e0Y6RohGKepXGuCT28n8UFp8e5GC7PsveHls2BOlYPaRSKRFLJBIyazQaMiuVSkyUTJAWoKozXXlm4/LLoJikZJ+AsGN2DAZ5IF3tvShxG0J8fDwp2g+VSoXZh7MHDUgWFRe4ou87prLjkoAzJwNOiZ1dhFwOmwPd7LQpVdfitG9CFy8+Xvyt/Q821ZngGVaQZgXO7VnhRRvbUdDaBIrKcEEDvV8tP/z4fgAyxDtBpHZ35gAAAABJRU5ErkJggg==") !important; }\n\
		%button%[cb_cookies="allowSession"]        { list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADJElEQVQ4T4WTC0jTQRzHv+c23dzmI2duUZFWTh1qPsrSzMx8YA4qsCylJ5iFaEURvSQoSI0yQ7MJFUWSSUSoiFpRYSbiK42lk7CX1WbzMXXtmf/2/0crs+jguLvf/b7fuw/3O4J/tOcH5vLME+pwgITYutePNEpj612OQnF7ZNGggY6Qv+mb9rq6m43G3V7+K2LEQTFLuO6i2XSecVQ7pO55+kLT2/LUkcu9Gl2mG51hQJ88MarO9YlO2yQJjArhCgRw4HDQ3NyMFcuWwTg5ic8vm7sGmiqrhO7i4hkGNensOE9p+BFpbFq8UCRC/tlz2J+dBQ6XC2pqCmwnJ0xotVA9rnzwRdVeYDf4yWy04Iind3CMcLZEwOa5QCheALazBwiLzdC2dfQgcmUEPvV2a7prFJcZg9+ZRQERsXyPuXyKomD5qsPYh36Y9eO406BE9sEscPl8sGxIn1/3W1qqzleQ/zH3vZ+E6uMktFYX5gZezhb4iBzA0w1Yn1UWVZE/ma0mE6xmM8Pc/sYEtdUTMpkMUqmUMVCpVFAqlWCpOw2a+oIr5O5mdl6wfM++Of7BXjRPYUEx9udkYmCYQr9BgviERLi6uqKzswOhoWGMiU6nw4PGBmi6aopIRSrreuyOvPSXfW85S8MDweHxYNLroWh4i+QtWfALkDGim9fKsW1Xpr1s+l4p8bC+toFcX8+qWLvz2CZ3yRz21/Fx5qnoVt5qRc7hE3ZB5Y1ypG3/ZUBvXDp3BkQhZ1+IWJexXeIjnUUH8/NKcehkJspazMg9etpucPzAHvt8TWIK4pLkKD57EqQkhbVB4h1wKnS1PMjJdn2OoyMMNoRqpQl+q1LhHxSGJ401WJ0gn1b1vT0daKyuqiOlqZ4Co274YlBUfMJCWeg8BxaL+SD3H6lgWBCJpI0ZcJslmiYeG9Gi/t4tqAffbWUKqTCZL/5m0efPXyRbvlgWJnHzEPF5XB5qO4esw3xfp+Cl0QgIiWBMXnW1orutiRafLikpybOXcmkqBGMjSKGAxCkK3nSyA8GbEVHMhN7F15ciJJGOEULqbMMthUJxm15/B71yOwKx0czLAAAAAElFTkSuQmCC") !important; }\n\
		%button%[cb_cookies="deny"]                { list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADN0lEQVQ4T4VTa0hTYRh+zs6ZO2s75dzWNlmhdpmXmmWWXTErCzKhC5ZdoCLohpVFEASNoB+ZUSZkF6IbZJlGBlphF8JqFaSVmdksSrTM5eZ0c+7s4k7nnEiiC73wwXd53+d7nu95PwL/iCc7jfKApzMVICbyQ/cjjbPz42UEo6+bXvTZJ+wQf6t/tGWYKsCyG3QJ09L15vQJtEozXMhjXY5vna9rX9mbn9ZG0PTZWSd7XX8ACDd7XJ074mblLjeMnzGRViohkUphtVoxbcoUsH19+NpoffnxUVk5o9IX/wFQtZqaqzWl7jFl5GYyGg0KDh5Gft5mSGkaXDgMSiaDx+GA7UHZ3S5b3aFBgJ+a2SD2aGOT05nhBiUlHwpGHwNqiBoESYlqn9e/xvSZaehobrA3VJ0+IQL8qlmTmJahUBsVHMch2N+LnvYWBLxuXK1pQt6uzaAVCpC8pK8fWoJPy4+UEv/THGxoBtfQBHm3V2Tg12sQNsXgCxkKPS4rKid+1xzy+xEKBETNsL6A795jODs64LLzDvKh0ukwMj4eXYZIX1XjzVPEtRWUJTl709bohGSdoKfwUDHyt2+E5H0rQjfuwf65HYw5Cez8SXB8akJaK4EgRSHU04MPAUcRUZpDns9YZ1nd+K5VOjl1PKRyOfxeL9qKL0Ld7QI1JgZReevQ0dKCuPsveAoq1FdUQGs0gtGoa4jzi8nSeev3LlcZoql+t1u0SoyiC2B5ILllG4ReYM5VDhbfHYWLq/zGtcKDEqezqaNpWWvWGuJMUUJdgaUEu/dtxEDhGfHFHyYnYJnTM1hcE4uVkVGozvHGe4QLiOOLyCWG2MT9KbOzzTKevjQiAj7+IFhWDaa3X6T6k/azRHJpXvVApSMr4U6Y4zLdTuctoiRHq2R7ncfMMzLnj0pKGSEhSfGDvLl8GzE2G7TxJrTV1aN2tOQsPUydn+vXX5fR9Bx7exsZYH2rxEYqXKjQDwS9BSNHJ00dkzTJEKnWKOS0HF0V1SFJ/VuZYJtgnxCCnYKtPrfngNkWsAy2ckkOlD3dWMQBC8IcYoVkCYFP4xzwRPdhrITDAhGBwC1+finlI64Iy+/RPFbh6B52nAAAAABJRU5ErkJggg==") !important; }\n\
		%button%[cb_cookies="unknown"],\n\
		%button%[cb_cookies="error"]               { list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADEElEQVQ4T42Te0iTURjGn89d/Oa2pjl1E0ttlelK85bdZElaUEoN0hYKFUI3pLyFEDQUAi9hJmShYBa0WhYJWVT0h0mZRcpyak5zKlZOpzl1XuY017dvJFYGvXDgnJf3fc7745yHwD/ibYYPx2oejACIUGp5OcpsQ9TSsPmipu0lX2fsGWK5/tenBW5WiyXVK3CbTBQs20y6CT3tdRbTiHFQW/9xqKOxnk2SldE3xk1/CdhvNpsGz62JViSJN+0IJXk8OLFYaGhowLYtW2CZnIShtUHT81pdzXcTlf4lUJvM3O0REJETEKOI4wuFKMi/jPS0U2CRJGwLC2A6O8M8MoLOOvXL4c6mwkWBX8yWOeR4+IfI+J5iHpOzAnyRH5gu7iAYTJr2Q7MW23dGYaCjZailtvw6LbCUWRgUFcN19+HabDbMTY9j7EsXrFMTuP+iHWmZp0ByuWBQSIburrnG6mIV8T/Mxp5K2Jya6AnYZCwEnnIM9fXOv1GXVBN/Ms/PzmLeav2NWa9Jwfojelqg654ErsJ8GHo6R98/vXObeHiYqQxJOHnGOzDEy85TVFiK9LMnFl+3o/0WJJHh8NiYSueG2yph0unQ1jiuNfR+yiVUiYyqmGPK5FZdHysyYhNYHA5mp6ZQUlyBjKwT6O/ORqhCjea7CpysCEfTq/PQqBWoe+BUSQrc04mqgwxV7PELSW5ib+b0xAT9VPYgXVww0P8YPPECfKQxaK5ROgSeHcDX9jr0aOqKZZnIJsoTmFei9qccFa8JWGlvLFCWIfuiA+GzTgnZoWR63/xc5RB4tIE+1z9UYVcWCOJaPEMu9g/KDduVEOxMjc9iszFDIQwbX0Eg1EMS6E03mMfM6DLwEB7o+Dr6jgHodd/yiLJED55l/PvV4B1xeyTSsFVODAZtEG3LJcTLaQs4JnhndExw88ti7kmN0WGmon1c0Y+5qYLVa6Vb10nDxa7uQm5b2xWGXL5Yu+ympmaJG8sSwRsbRbwN2Ltgg7+XL/y8feFLeQl8PkDR0TFDmdhsBihPwWJB3k8XVTr9Yr7r6AAAAABJRU5ErkJggg==") !important; }\n\
		%button%[cb_cookies="notAvailable"]        { list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACm0lEQVQ4T41TXUiaURh+jyj+RmjhtotBQhhZjCVSwwIbYxuYgrswL7xQ2JWzmF61q9HdJtTcCNbVGLsIoi52Y8E2kISCCauGpFL4U1i0dqFE/oSO2vsepkhusA8O5+N8532e93ne52Pwj8fv90vPzs4M+HkA17U/105w325ra/sWDAYrdMb+Vu/xeJTn5+ePe3t7Tf39/bfb29vVdO/09PTnzs7O92QyGZFIJO/m5+cLLQDEXCgUno6MjIzrdLoBuVwOQqEQNjY2YGhoCEqlEiQSie319fUlpVL5pgXA6XTe02q1UyaT6T5egEAgABMTEyAWi+Hy8hJEIhEgAUQikS97e3uBBkBdc61Wm9JoNKbOzk6FVCoFtVoNCoUCBAIBV7u1tQVGoxGw+CQUCr3lAM2ae3p67nZ0dMiJrVwuw+HhId/D4TDvhECpi2w2W1teXl5g/6N5f38f8vk8YGe8WCaTEfCvxcXFJXZVM0qAarXaojkWiwEZSmDDw8O051dWVj4wh8Px3GKxPEHj+KxnZ2fB6/U2plvXnEql4ODgAAwGA2A+YG1tLYYyppndbn/vcrmcu7u7Ir1ez5krlQrMzc3B5ORkQ3Mmk4HNzU0YHByEeDyew7F+xnz4mM1mW3C73ePotrBYLMLFxQVnJ51kHrlP77lcjkZXY4xlsJuv6MWz1dXVH8xqtb4aGxtzdXV1qahwZmYGfD5fQ0I0GuWa0+l0DceWRH9eqFSqEE6gyKOM+h+hu9Ojo6O3MJ7cZWKmh9jprFkzgnxsjj95oMCMv0aWB319fTepCNvk0aXAkKRmzXXmOggPktlsvo7je9nd3X0HQW5QkIj56OiohMXHzZqv/nyNKFMnGBYLJvAhLg3Xx1gW16dmzVcBfgN5FlQ7XXON/wAAAABJRU5ErkJggg==") !important; }\n\
		%button%[cb_cookies="defaultAllow"]        { list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADMUlEQVQ4T42Ta0hTYRzGn+M5c2e3crm1rYu2WQ2TadrStMSkG1RCfdCCgoqiG90pgiApCLKiK1n0IQzKMOlbUFarJksttDJdLZe2oLnt6K666TxT184iqSzohf+X9/0/z/v/vS8PgX+sxoPTBGy/Sw8Q2bFS/GiLMrF6lyhRthRctA9yO8Tf9KZdE6VsOLxVkZ5fpMwsmktLZZO5vrDP3eNqq29lLE31iTR9s/B6wDfOgLu53+farylcX6bSLcymxWIk8HhoaGhAfm4uwsEgnO0N776YamolUuXlcQYPNlBL5Fr9UW3x+mUSmQwVp8/hwJ6d4NE0oqOjoPh89Lvd6HhR87S3o+XMmMFP5nAER+XqrCLJZJWYEkyARDkDlDAZBEnFaZvftKFgUR4clvfM+wc3rsUNfmWWzckrFiVPE0WjUUQGAvB/s4IN9eHe4w/Yc2gnaJEIZAzJ2WmNNNWeryb+h9nT1Y4BrwNJmpyYmA/uXZivtuG7TXfqiT+Zh4eGMMyy45jtrfXgCZNg7vSjsDgXVc7mwc+uz63E/XVUeVbJjt1T0rMUHM/ZM5dxYN92tId7oaPlY8xOqxlu2wek5S7HHY8ZQmECY+hqMxLVpWRV8ebyDe2fvvLm63XgCQQYCoWw7+Ft5BfosWWqPs7ssFphe/sErVnpkMknBrp9TFddwFlHVK0hq5duOVYmVU2hBvr64l/FrZqgFdpZs/HR8hHbUhaAsX3B1Y66EW12to/p99mHdWmGR69eBokbJdSFvFUbN6k02kmcsKK8EoePb8dtrxkatQZ+XxD+Pg/83t6RZCnf7RTyTZFUhfVZo4k17zWfJK6uJteq1HNO5CwuyeTHxuclJmIwhnDL3QZ1zICiKIhFQjgcNsYy6DEG1UqL0WhE55HOk/EsVJbKxeGA51LmwmXL0zJypieQZDwgJkMLOnQkUlNS4fa4At1+Z1cgfXrd86ZG1n7cHhePhensSpFyJBKqSJmZsWBWxjxVUrJMJKAFcHZ/C12wGVnpVIU9oFEaDC2vgz2nesbEv6WxshRivxero8CK0SjU3GECAVtsmsdXcqS6CEmw3grvb2Ku5zvxg2tkeIR+owAAAABJRU5ErkJggg==") !important; }\n\
		%button%[cb_cookies="defaultAllowSession"] { list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADaElEQVQ4T4WTfUxbZRTGn/vV3ktboHALLR0E1pGG4cAho2OMINFtiQ51yZhLppnGBKdZFI3JEpMR/zFjM4ojYzKDITGSIFGzuMRss8uGUJd9uEG3tSsFJ7bYdkDLbW+/S69t1cU4jSc5f7xvznme95f3HAL/ET++tYZLhLyNALExk6V/lEm+TN6UqbTXt/S5o9kb4t/6J14rUCdisVdKa5rbtHVtj7JqviRbFwss3fdax6d89svjMpb9rPUTIfCQQNY5FPC+ubZ17x7dhpaNrFIJkmFgsVjQ3NSEmCjCc8ty8+eJ0TGVWnv8IYEz++gnNMbGQ8b2vdtUPI/eIx+g++ABMCwLKZ0GLZcjtLQEx8XR7xcd148+EPiLOZbEIU1VfZuqRKekuXyotJWg84pBUHSO9tpPVmzZasJv9mnf9JlTJ3MCf2fm15vaFcVrFJIkIRkRsOKaQSIcxJfn7uDg2wfAKhSgMkie2Znk5bEPR4j/Y/YuinDNuyCICbBFOqjkBDSFcsR991KTo31jxD+ZU/E4UolEjnnBn0SEzEdBxpVJihlnFjbnAvIUDMLuOyHHdyeHiK+ep3vqO159vaymvjTLc+zocXS/0YVAVMJyUgk5p0J1tQHO21PI52gU6Q0ICgIsl8w+390rR4iRTmq4/aWefbfu/sJsatwAhuMQD4dx4vMLeLGrC1q9HiRJYfLCeVSUFkKtXwfBvyw4Z2fn7N7UADH8HDXy5Mvv7lHryuhIMJj7qmxM+yg0bNoMgiBAy2S4Mm7OsKtWJUYRSKYld2XTs+ahoU9F4lQH/ZHp6Rf269Yai7KNvT0DeOdwF665VmHa2g73rx5UVOlxemR4dX7OviRS/ERzx/6Z7c/sTvS9fxjEiZ3ULl3V+vcaHu+ok2eez2TcohkEx/0U+Mpa6PQVmLFZwXF5PpnGcKmkptWeNbJZb+D8t2NOYqBTo4wJyx/XtWzbbqhtKCcpKrcg58xWlDWYYDA+gmg0KoTE6Jy+ZfdZRq5MrPj9OPvNF1j0uL7ODdKxpxTa1WS4t2Jd7ebq2sd0hcW8gmM53HB44q5gKqLSlLubdnWb2QJetE1dxdTVSfgW5n/o7++/+GCUBzqhXPFjpwTsSEuoygqTBO5F8o02P29aThNs+Z+b6yRJ0jo4OHg7e/4dGhFl3RS3wJwAAAAASUVORK5CYII=") !important; }\n\
		%button%[cb_cookies="defaultDeny"]         { list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADYElEQVQ4T4WTa2hTZxjH/2/PJeeYpG2a1FzUsTYbXa1NWq3W6qR2mwqbhcloJ3PiRHAqRes2EAYr+2Z1bJ2wbggTPxW6og7Rgbtg6WoUaVy1F5vGa9cu7WmT5nJyOTm5nOVEJmNu7IHnw/vyPP/n/fH+H4L/iOtHl/OyOFcHkNpcmp+UKUIuh1m9xb2hayah3pB/6x88WGSQJWmfubKh0eJorOEMpqVqnRT0z8+NDNwWJm4MsBx3ZtM34eAzAupkMTh3pHzTzlZr9cZaTqdDAcPA5XKhYd06SNEoZkddww8He/v0BsupZwQu7aJfLa2oO1bRtHOL3mRC5/HP0N52AAzHQclmQWs0EP1+TPb3/rww6T7xVOAvZimFY6Vlzkb9UquO5guhtzwPeokRhKLztEO3RrDh5Xr4Ju4Idy6d/jov8Hdm08r6Jq1xuVZRFKTiYYSmvZBjEXz34zjaPjgATqsFlUOave9N3ej7vIf8H3Py9z8Q94xBCSyCM1ihFOlB2cyYDQfS13q7+sg/mdPJJNKy/IR5yodsTiAkCBDuj+cmc4jINKrrnBDSoth/7cK35NzbdIez+f1DtkqnWeU5eeIU2g/vBwmEkPU8hHfSC/vaWoSKafgfjWOV1g5JTmHOMyL4AjPHSU8LdbbpvY5do57HzNq6ajA8j2QshitdZ/BKTRVYSym0DWvg83oB1yAMdgfuXv0pnBFDDyoMy7rJ2Tepntf2ftxqsNroeCSS/yo1aPc4pHgMzOb1UL0gX72OBWEqMzPqCbop/w9vJW0LBl1hlJxupr+of+PdPdbyihK1sbOjGx99sh9Z1y3QDAuXnMY2swliXMy4L/T6R4vQXlyCy62xlz6U4nGQr7ZTO6xlKz9dvbnZock9n2FZJHIImTEvNMk0Co0lkAnB8MXzwgQfPNh2OfO9v7lyt5JRyiPB4D3S3VKqk8KBLx0bt2y1V61eUUBR+QUZujgAR6EGS3ICj38bCt9MTJ3jiozt76RsO1gNWzY/PU0S0eT5vJFOvq61ZFKxzudeqFr/YtUaa7HRpOU5HsJNdzLsvh3nNfRMjcX+C0+x0dD8PBZ9PiTC0V9XTUr9T63c3QJdaBHbFWBbVkGZKlxA8GiZiLuViwgwWazILzRwjyEYcT7AmHr+E5EUd77R7OXNAAAAAElFTkSuQmCC") !important; }\n\
		/* "moveToStatusBar" option */\n\
		%button%.custombuttons-insideStatusbarpanel {\n\
			-moz-appearance: none !important;\n\
			border: none !important;\n\
			margin: 0 !important;\n\
			padding: 0 !important;\n\
			min-width: 0 !important;\n\
			max-width: none !important;\n\
		}\n\
		%button%.custombuttons-insideStatusbarpanel > .toolbarbutton-icon {\n\
			margin: 0 !important;\n\
			padding: 0 !important;\n\
		}\n\
		%button%.custombuttons-insideStatusbarpanel > .toolbarbutton-text {\n\
			display: none !important;\n\
		}\n\
		%button% .cbTempPermission {\n\
			font-style: italic !important;\n\
			/*-moz-padding-start: 0.7em !important;*/\n\
		}\n\
	}')
	.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) {
	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.permissions.timer)
			this.permissions.timer.destroy();
	}
	this.permissions.destroy();
};
this.permissions.init();


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

Отсутствует

 

№1706431-10-2023 13:41:48

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

Re: Custom Buttons

ВВП пишет

при добавлении в прейлист пропадает предыдущая ссылка, в хроме через расширение -нет

Так какая там командная строка, когда запущено через хром?
В смысле если в диспетчере задач виндовс или в Process Explorer'е посмотреть.

Отсутствует

 

№1706531-10-2023 13:46:13

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

Re: Custom Buttons

Здравствуйте. В 102.15.1esr настроил нужное, кроме кнопки "Quick Toggle Быстрое переключение параметров about:config", которая работала в FF100. Если возможно, подправьте код. Спасибо.

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

Выделить код

Код:

/*Initialization Code*/// Quick Toggle Быстрое переключение параметров about:config для custom_script.js

(async (name, id, func) => { // https://forum.mozilla-russia.org/viewtopic.php?pid=789824#p789824
	if (name == "Object") return CustomizableUI.createWidget(func());
	var win = name == "Window", g = Cu.import("resource://gre/modules/Services.jsm", {});
	if (g[id]) {if (win) return;} else g[id] = func(); if (win) return CustomizableUI.createWidget(g[id]);
	addDestructor(r => r[5] == "e" && delete g[id]); g[id].onCreated(this);	// BEGIN QuickToggle…
})(this.constructor.name, "ToggleAboutConfig", () => { var help =

`ПКМ	Меню быстрых настроек 
։нажать	Краткая справка ✍
…+Alt	Опции about:config\n
ЛКМ	Боковая панель: Журнал
։нажать	Антизапрет proxy
…+Alt	Пипетка: захват цвета
…Shift	★ Библиотека закладок\n
СКМ	± Zoom Текст/Страница
։нажать	Консоль браузера\n
- тире ⟳ Обновить ↯ Перезапуск
СКМ ролик мыши, :нажать ≥ 1 сек`, // :нажать - удержание кнопки мыши около секунды. свободные hotkeys: ЛКМ+Alt+⇧

help_ucf = ['chrome://user_chrome_files/content/help.html', 'http://forum.puppyrus.org/index.php?topic=22762'],

// Ctrl+Click или правый клик - сброс параметра по-умолчанию
// клик по параметру с Shift блокирует авто-закрытие меню
// строки с userAlt имеют шрифт italic
//	refresh: false - reload current tab,	true - reload current tab skip cache
//	restart: false - restart browser,		true - restart browser with confirm
// Разделитель: Имя меню "—,⟳,↯" Опция, ⟳ обновить страницу, ↯ перезапуск браузера
// иконки равны ключам: userChoice:зелёный, userAlt:жёлтый, userPro:серый, нет userChoice:серый, ни один:красный

	{prefs, dirsvc} = Services, db = prefs.getDefaultBranch(""), my_vpn = "https://antizapret.prostovpn.org/proxy.pac", icon_vpn = "hue-rotate(270deg) brightness(95%)", menuactive = (AppConstants.platform == "macosx") ? '#e8e8e8' : '#124', // текст, подсвеченный курсором
	xul_ns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
	fonts = ["Arial","Cantarell","DejaVu Sans","Roboto","PT Serif","Segoe UI","Ubuntu","Cambria","Fira Sans","Georgia","Noto Sans","Calibri","Times","системный"],
	font_pref = (font) => { return font.map(function(name) { // массив с вложениями
		return (name == font[font.length -1]) ? ["", name,,, `prefs.setIntPref("browser.display.use_document_fonts", 1)`] : [name, name,,, `prefs.setIntPref("browser.display.use_document_fonts", 0)`]; });
	},
	fontserif = font_pref(fonts), fontsans = [["PT Sans","PT Sans"], ...fontserif], dw; // путь загрузки
	try {dw = prefs.getComplexValue("browser.download.dir",Ci.nsIFile);} catch {dw = dirsvc.get("DfltDwnld", Ci.nsIFile);};

	var secondary = [{ // pref … [apref, lab, akey, hint, js-code]
			pref: ["dom.disable_open_during_load", "Блокировать всплывающие окна"], userChoice: 2, userAlt: true,
	},{
			pref: ["browser.safebrowsing.downloads.remote.block_dangerous", "Опасные файлы, сайты",,"browser.safebrowsing.downloads.remote.block_dangerous_host"], userChoice: true, userAlt: false,
			values: [[true, "Запретить",,,`prefs.setBoolPref('browser.safebrowsing.downloads.remote.block_dangerous_host',true)`], [false, "Загружать",,,`prefs.setBoolPref('browser.safebrowsing.downloads.remote.block_dangerous_host',false)`]]
	},{
			pref: ["permissions.default.image", "Загрузка графики"], userChoice: 1, userAlt: 3, refresh: true,
			values: [[1, "Разрешена"], [3, "Только с сайта"], [2, "Отключить"]]
	},{
			pref: ["ucf_save.dirs", `Сайт|Графика`,,`\nПути сохранения страниц | графики\n[Загрузки] — папка по-умолчанию${dw ? ":\n"+ dw.path : ""}`], userChoice: "_Сайты||_Картинки|1", userAlt: "", userPro: "_Web||_Images|1",
			values: [
				["", "папка [Загрузки]"], // subdir: пусто | 0 заголовок | 1 домен
				[`_Сайты||_Картинки|1`, "_Сайты|_Картинки/имя"], // _Web/host|_Pics/title
				[`_Web||_Images|`, "_Web|_Images"],
				[`_Web||_Images|1`, "_Web|_Images/имя"],
				[`_Web||_Pics|1`, "_Web|_Pics/имя"],
				[`_Web|1|_Pics|0`, "_Web/сайт|_Pics/имя"],
				[`_Web|1|_Pics|`, "_Web/сайт|_Pics"],
				[`_Web|1|_Images|0`, "ввести свои пути"]] // здесь нужно открыть about:config
	},null,{
			pref: ["network.proxy.autoconfig_url", "Прокси (VPN) URL", "п"],
			userChoice: my_vpn, userAlt: "127.0.0.1", userPro: "", refresh: true,
			values: [
				["", "сброшен", ""],
				[my_vpn, "АнтиЗапрет", "1", "\nНадёжный доступ на заблокированные сайты\n«Режим прокси» меняется на 2", `prefs.setIntPref('network.proxy.type', 2); node.parentNode.parentNode.style.filter = icon_vpn;`],
				["https://git.io/ac-anticensority-pac", "ac-anticensority", "2"],
				// ["localhost", "Tor Browser", "4", "Только для Linux, MacOS\nУстановите сервис: «tor»"],
				[prefs.getStringPref("user.pacfile", "file:///etc/proxy.pac"), "user .pac файл", "3"], // нужен диалог выбора pac-файла
				["127.0.0.1", "local host", "0",, `prefs.setIntPref('network.proxy.type', 0); node.parentNode.parentNode.style.filter = '';`]]
	},{
			pref: ["network.proxy.type", "Режим прокси", "р"], userChoice: 0, userAlt: 2, refresh: true,
			values: [
				[0, "Без прокси", "0", "по-умолчанию"],
				[5, "Системные (из IE)", "5"],
				[2, "Автонастройка", "2", "about:config - user.pacfile"],
				[1, "Ручная настройка", "1", "Используется network.proxy.autoconfig_url"],
				[4, "Автоопределение", "4"] ]
	},{
			pref: ["network.proxy.share_proxy_settings", "Все протоколы через прокси"], userAlt: true, refresh: true,
			values: [[true, "Да", "", "Прокси для всех протоколов при ручной настройке"], [false, "Нет"]]
	},{
			pref: ["network.trr.mode", "DNS поверх HTTPS",, "\nШифрование DNS-трафика для\nзащиты персональных данных"], userChoice: 1, userAlt: 2, userPro: 5, refresh: true,
			values: [
				[0, "по-умолчанию", "0"], [1, "автоматически", "1", "используется DNS или DoH, в зависимости от того, что быстрее"], [2, "DoH, затем DNS", "2"], [3, "только DoH", "3"], [4, "DNS и DoH", "4"], [5, "отключить DoH", "5"] ]
	},null,{
			pref: ["browser.zoom.full", "Масштабировать"], userChoice: false, userAlt: true,
			values: [[true, "всю страницу"], [false, "только текст"]]
	},{
			pref: ["font.name.sans-serif.x-cyrillic", "Шрифт без засечек ",,"\nТакже влияет на всплывающие подсказки\nСистемный: загрузка шрифтов документа"], userAlt: "", values: fontsans
	},{
			pref: ["font.name.serif.x-cyrillic", "Шрифт с засечками"], userAlt: "", values: fontserif
	},{
			pref: ["image.animation_mode", "Анимация изображений"], userChoice: "none", userAlt: "normal", refresh: true,
			values: [["none", "Выключена"], ["normal", "По циклу"], ["once", "Единожды"]]
	},null,{
			pref: ["media.autoplay.default", "Авто-play аудио/видео"], userChoice: 0, userAlt: 2, userPro: 5, refresh: true,
			values: [
				[0, "Разрешить", "0"], [2, "Спрашивать", "2"], [1, "Запретить", "1"], [5, "Блокировать", "5"]]
	},{
			pref: ["media.autoplay.blocking_policy", "Автозапуск (политика)"], userChoice: 1, userAlt: 2, refresh: true,
			values: [[1, "Временная", "1"], [2, "По действию", "2"], [0, "Постоянная", "0"]]
	},{
			pref: ["gfx.webrender.all", "Аппаратное ускорение графики"], userChoice: true, refresh: true,
			values: [[true, "Да"], [false, "Нет"]]
	},{
			pref: ["gfx.webrender.force-disabled", "Web render disabled", , "gfx.webrender.compositor.force-enabled\n\nАппаратная отрисовка страниц видеокартой.\nотключите при разных проблемах с графикой"],
			userChoice: false, restart: true, values: [
			[true, "Да",,, `prefs.setBoolPref("gfx.webrender.compositor.force-enabled", false)`],
			[false, "Нет",,, `prefs.setBoolPref("gfx.webrender.compositor.force-enabled", true)`]]
	},null,{
			pref: ["network.cookie.cookieBehavior", "Получать куки",, "\nПерсональные настройки посещённых сайтов"], userChoice: 3, userAlt: 0, userPro: 4, refresh: false,
			values: [[0, "со всех сайтов"], [3, "кроме не посещённых"], [4, "кроме трекеров"], [1, "кроме сторонних"], [2, "никогда"]]
	},{
			pref: ["network.http.sendRefererHeader", "Referer: для чего"], userChoice: 2, userAlt: 1,
			values: [[0, "Ни для чего", "0"], [1, "Только ссылки", "1"], [2, "Ссылки, графика", "2"]]
	},{
			pref: ["dom.storage.enabled", "Локальное хранилище",, "\nСохранение персональных данных, по\nкоторым вас можно идентифицировать"],
			userChoice: false, userAlt: true,
			values: [[true, "Разрешить"], [false, "Запретить"]]
	},{
			pref: ["privacy.resistFingerprinting", "Изоляция Firstparty-Fingerprint", ,"privacy.firstparty.isolate\n\nЗащита данных пользователя также\nзапрещает запоминать размер окна"], userChoice: false,
			values: [[true, "Да", , "Защита от слежки",`prefs.setBoolPref('privacy.firstparty.isolate', true);`], [false, "Нет", , "Защита от слежки",`prefs.setBoolPref('privacy.firstparty.isolate', false);`]]
	},{
			pref: ["media.peerconnection.enabled", "WebRTC ваш реальный IP"], userChoice: false,
			values: [[true, "Выдать"], [false, "Скрыть"]]
	},null,{
			pref: ["browser.tabs.remote.force-enable", "Многопоточный режим вкладок"], userChoice: null, userAlt: true, userPro: false,
			values: [[true, "Да"], [false, "Нет"]]
	},{
			pref: ["javascript.enabled", "Выполнять скрипты Java",,"\nПоддержка интерактивных сайтов (и рекламы)"], userChoice: true, refresh: true,
			values: [[true, "Да"], [false, "Нет"]]
	},{
			pref: ["browser.cache.disk.capacity", "Кэш браузера",,"browser.cache.memory.enable"], userChoice: 1048576, userAlt: 0,
			values: [
			[1048576, "Диск и Память",,, `prefs.setBoolPref("browser.cache.memory.enable", true); prefs.setBoolPref("browser.cache.disk.enable", true)`],
			[0, "только Память",,, 		`prefs.setBoolPref("browser.cache.memory.enable", true); prefs.setBoolPref("browser.cache.disk.enable", false)`],
			[2097152, "только Диск",,, `prefs.setBoolPref("browser.cache.memory.enable", false); prefs.setBoolPref("browser.cache.disk.enable", true)`]]
	},{
			pref: ["dom.enable_performance", "Статус загрузки страницы",,"\nПередача данных разрешит определять\nфакт использования прокси-сервера"], userAlt: true
	},{
			pref: ["general.useragent.override", "User Agent"],
			userChoice: null, userAlt: "Mozilla/5.0 (Android 9; Mobile; rv:68.0) Gecko/68.0 Firefox/68.0", userPro: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:68.0) Gecko/20100101 Firefox/68.0", refresh: true,
			values: [
				(arr => {
					var pref = "general.useragent.override";
					var has = prefs.prefHasUserValue(pref);
					if (has) {
						var val = prefs.getStringPref(pref);
						prefs.clearUserPref(pref);
					}
					var ua = Cc["@mozilla.org/network/protocol;1?name=http"]
						.getService(Ci.nsIHttpProtocolHandler).userAgent; // текущий юзерагент
					has && prefs.setStringPref(pref, val);

					var find = node => node.pref && node.pref.pref == pref;
					var redef = (doc, hint) => {
						var popup = doc.getElementById("ToggleAboutConfig-secondaryPopup");
						var menuitem = Array.from(popup.children).find(find).menupopup.firstChild;
						menuitem.tooltipText = hint ? ua + "\n" + hint : ua;
						menuitem.setAttribute("oncommand",
							`event.stopPropagation();
							this.closest("toolbarbutton").linkedObject.contextmenu({
								preventDefault: Boolean,
								target: this.parentNode.parentNode
							});`
						);
					}
					Object.defineProperty(arr, "0", {enumerable: true, get() {
						if (Components.stack.formattedStack.includes("createRadios")) {
							var win = Services.wm.getMostRecentWindow("navigator:browser");
							win.setTimeout(redef, 0, win.document, this[3]);
						}
						else return "";
					}});
					return arr;
				})([null, "По-умолчанию"]),
				["Mozilla/5.0 (Android 9; Mobile; rv:68.0) Gecko/68.0 Firefox/68.0", "Firefox Android9"],
				["Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:68.0) Gecko/20100101 Firefox/68.0", "Firefox 68 MacOSX"],
				["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", "Chrome61 Win10"],
				["Mozilla/5.0 (Windows NT 6.1; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0", "Firefox 56"],
				["Mozilla/5.0 (X11; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0", "Firefox 56 Linux"],
				["Mozilla/5.0 (Windows; U; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)", "MSIE 6.0 Windows"],
				["Mozilla/5.0 (Linux; Android 7.0; PLUS Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", "Chrome61 Android7"],
				["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.1 Safari/603.1.30", "Safari 6 MacOSX"],
				["Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12 Version/12.16", "Opera12 W8"],
				["Mozilla/5.0 (Linux; Android 5.1.1; SM-G928X Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.83 Mobile Safari/537.36", "Samsung Galaxy S6"],
				["Mozilla/5.0 (PlayStation 4 3.11) AppleWebKit/537.73 (KHTML, like Gecko)", "Playstation 4"],
				["Xbox (Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586", "Xbox One (mobile)"],
				["Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586", "Microsoft Lumia 950"],
				["Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; GT-I8350)", "Windows Phone"],
				["Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", "GoogleBot"]]
	},{
			pref: ["browser.sessionstore.restore_on_demand", "Загружать неактивные вкладки", , "\nПри запуске загружаются все вкладки,\nэто может замедлить работу браузера."], userAlt: false,
			values: [[false, "Да"], [true, "Нет"]]
	}];
	return {
		label: "Quick Toggle Settings",
		id: "ToggleAboutConfig",
		tooltiptext: help, localized: false,
		image: "data:image/x-icon;base64,AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAABMLAAATCwAAAAAAAAAAAAD///8A////AFhYWAJYWFgHWFhYDlhYWBNYWFgVWFhYFVhYWBVYWFgVWFhYFVhYWBVYWFgVWFhYFVhYWBVYWFgVWFhYFVhYWBVYWFgVWFhYFVhYWBVYWFgVWFhYFVhYWBVYWFgVWFhYE1hYWA5YWFgHWFhYAv///wD///8A////AP///wD///8AWFhYB1hYWBVYWFgrWFhYOVhYWEBYWFhAWFhYQFhYWEBYWFhAWFhYQFhYWEBYWFhAWFhYQFhYWEBYWFhAWFhYQFhYWEBYWFhAWFhYQFhYWEBYWFhAWFhYQFhYWEBYWFg5WFhYK1hYWBVYWFgH////AP///wD///8A////AP///wBYWFgOWFhYK1hYWFVYWFhxWFhYf1hYWH9YWFh/WFhYf1hYWH9YWFh/WFhYf1hYWH9YWFh/WFhYf1hYWH9YWFh/WFhYf1hYWH9YWFh/WFhYf1hYWH9YWFh/WFhYf1hYWHFYWFhVWFhYK1hYWA7///8A////AP///wD///8A////AFhYWBN5eXqtfn5//35+f/9+fn//fn5//35+f/9+fn//fn5//35+f/9+fn//fn5//35+f/9+fn//fn5//35+f/9+fn//fn5//35+f/9+fn//fn5//35+f/9+fn//fn5//35+f/95eXqtWFhYE////wD///8A////AP///wD///8AWFhYFX9/gP/T09P/0tLS/9LS0v/T09P/09PT/9TU1P/U1NT/1NTU/9TU1P/U1NT/1NTU/9TU1P/U1NT/1NTU/9TU1P/U1NT/1NTU/9TU1P/T09P/09PT/9LS0v/S0tL/09PT/39/gP9YWFgV////AP///wD///8A////AP///wBYWFgVgYGC/9vb2//Kysr/y8vL/8zMzP/MzMz/zc3N/87Ozv/Ozs7/z8/P/8/Pz//Pz8//0NDQ/8/Pz//Pz8//z8/P/87Ozv/Ozs7/zc3N/8zMzP/MzMz/y8vL/8rKyv/b29v/gYGC/1hYWBX///8A////AP///wD///8A////AFhYWBWDg4P/39/f/9HR0f+ZmZn/kZGR/3l5ef+Kior/o6Oj/5ubm/+bm5v/enp6/9fX1/+kpKT/ra2t/5ubm/9xcXH/vb29/8TExP/Dw8P/s7Oz/9PT0//S0tL/0dHR/9/f3/+Dg4P/WFhYFf///wD///8A////AP///wD///8AWFhYFYSEhf/g4OD/09PT/4qKiv+rq6v/m5ub/4qKiv+cnJz/nJyc/5ycnP+Dg4P/2dnZ/8jIyP+Dg4P/nZ2d/3Jycv/Gxsb/19fX/9bW1v/W1tb/1dXV/9TU1P/T09P/4ODg/4SEhf9YWFgV////AP///wD///8A////AP///wBYWFgVhoaH/+Hh4f/V1dX/k5OT/6SkpP/Y2Nj/2NjY/9nZ2f/a2tr/2tra/9vb2//b29v/3Nzc/5WVlf/S0tL/2tra/9ra2v/Z2dn/2NjY/9jY2P/X19f/1tbW/9XV1f/h4eH/hoaH/1hYWBX///8A////AP///wD///8A////AFhYWBWIiIn/4uLi/9fX1//Y2Nj/2dnZ/9ra2v/b29v/29vb/9zc3P/c3Nz/3d3d/93d3f/e3t7/3d3d/93d3f/c3Nz/3Nzc/9vb2//b29v/2tra/9nZ2f/Y2Nj/19fX/+Li4v+IiIn/WFhYFf///wD///8A////AP///wD///8AWFhYFYuLi//k5OT/2tra/52dnf+VlZX/e3t7/42Njf/Ly8v/fHx8/5+fn/98fHz/39/f/+Dg4P/f39//39/f/97e3v/e3t7/3d3d/93d3f/c3Nz/29vb/9ra2v/a2tr/5OTk/4uLi/9YWFgV////AP///wD///8A////AP///wBYWFgVjY2O/+bm5v/c3Nz/jY2N/7Gxsf+goKD/jo6O/6Ghof/FxcX/oaGh/4aGhv/i4uL/4uLi/+Li4v/h4eH/4eHh/+Dg4P/g4OD/39/f/9/f3//e3t7/3d3d/9zc3P/m5ub/jY2O/1hYWBX///8A////AP///wD///8A////AFhYWBWPj5D/5+fn/9/f3/+Xl5f/qqqq/+Hh4f/i4uL/4uLi/+Pj4//j4+P/5OTk/+Tk5P/k5OT/5OTk/+Tk5P/j4+P/4+Pj/+Li4v/i4uL/4eHh/+Dg4P/g4OD/39/f/+fn5/+Pj5D/WFhYFf///wD///8A////AP///wD///8AWFhYFZKSkv/p6en/4uLi/+Li4v/j4+P/5OTk/+Tk5P/l5eX/5eXl/+bm5v/m5ub/5+fn/+fn5//n5+f/5ubm/+bm5v/l5eX/5eXl/+Tk5P/k5OT/4+Pj/+Li4v/i4uL/6enp/5KSkv9YWFgV////AP///wD///8A////AP///wBYWFgVlJSV/+vr6//Hx8f/yMjI/8jIyP/IyMj/ycnJ/8nJyf/Jycn/ycnJ/8nJyf/Kysr/ysrK/8rKyv/Jycn/ycnJ/8nJyf/Jycn/ycnJ/8jIyP/IyMj/yMjI/8fHx//r6+v/lJSV/1hYWBX///8A////AP///wD///8A////AFhYWBWWlpf/7Ozs/+fn5//n5+f/6Ojo/+jo6P/p6en/6urq/+rq6v/q6ur/6+vr/+vr6//r6+v/6+vr/+vr6//q6ur/6urq/+rq6v/p6en/6Ojo/+jo6P/n5+f/5+fn/+zs7P+Wlpf/WFhYFf///wD///8A////AP///wD///8AWFhYFZmZmf/u7u7/6enp/+rq6v/q6ur/6+vr/7CwsP/s7Oz/7Ozs/+zs7P/t7e3/7e3t/+3t7f/t7e3/7e3t/+zs7P/s7Oz/7Ozs/+vr6//r6+v/6urq/+rq6v/p6en/7u7u/5mZmf9YWFgV////AP///wD///8A////AP///wBYWFgVm5ub//Dw8P/s7Oz/sbGx/6enp/+xsbH/np6e/5SUlP+oqKj/gICA/9HR0f+pqan/qamp/8fHx//Hx8f/x8fH/+7u7v/u7u7/7u7u/+3t7f/t7e3/7e3t/+zs7P/w8PD/m5ub/1hYWBX///8A////AP///wD///8A////AFhYWBWdnZ7/8fHx/+7u7v+pqan/7+/v/6mpqf+fn5//lZWV/6qqqv+BgYH/3d3d/4uLi/+fn5//8fHx//Hx8f/x8fH/8fHx//Dw8P/w8PD/8PDw/+/v7//v7+//7u7u//Hx8f+dnZ7/WFhYFf///wD///8A////AP///wD///8AWFhYFaCgoP/z8/P/8PDw/8jIyP+qqqr/ycnJ//Ly8v/y8vL/8vLy//Ly8v/z8/P/8/Pz//Pz8//z8/P/8/Pz//Ly8v/y8vL/8vLy//Ly8v/y8vL/8fHx//Hx8f/w8PD/8/Pz/6CgoP9YWFgV////AP///wD///8A////AP///wBYWFgVoqKi//X19f/z8/P/9PT0//T09P/19fX/9fX1//X19f/19fX/9fX1//X19f/19fX/9vb2//X19f/19fX/9fX1//X19f/19fX/9fX1//X19f/09PT/9PT0//Pz8//19fX/oqKi/1hYWBX///8A////AP///wD///8A////AFhYWBWkpKT/9/f3//f39/+tra3/4+Pj/42Njf+NjY3/o6Oj/62trf+YmJj/ubm5/87Ozv/Ozs7/zs7O//n5+f/5+fn/+Pj4//j4+P/4+Pj/+Pj4//j4+P/4+Pj/9/f3//f39/+kpKT/WFhYFf///wD///8A////AP///wD///8AWFhYE6Wlpv/5+fn/+fn5/66urv+kpKT/rq6u/46Ojv+vr6//r6+v/46Ojv+vr6//+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//r6+v/6+vr/+vr6//r6+v/5+fn/+fn5/6Wlpv9YWFgT////AP///wD///8A////AP///wBYWFgOp6en//r6+v/7+/v/urq6/9vb2/+6urr//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//v7+//6+vr/p6en/1hYWA7///8A////AP///wD///8A////AFhYWAepqan//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v+pqan/WFhYB////wD///8A////AP///wD///8AWFhYAqqqqv///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////6qqqv9YWFgC////AP///wD///8A////AP///wCrq6sAtZNx/6urq/+rq6v/q6ur/6urq/+rq6v/q6ur/6urq/+rq6v/q6ur/6urq/+rq6v/q6ur/6urq/+rq6v/q6ur/6urq/+rq6v/q6ur/6urq/+rq6v/q6ur/6urq/+rq6v/q6urllhYWAD///8A////AP///wD///8A////AKurqwDJeSD/679v/+axTv/msU7/5rFO/+axTv/msU7/5rFO/+axTv/msU7/5rFO/+u/b//JeSD/WFhYAFhYWABYWFgAWFhYAFhYWABYWFgAWFhYAFhYWABYWFgAWFhYAFhYWABYWFgAWFhYAP///wD///8A////AP///wD///8Aq6urAM+CJP/vzYL/7MJl/+zCZf/swmX/7MJl/+zCZf/swmX/7MJl/+zCZf/swmX/782C/8+CJP////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wCrq6sA1Isn//Tak//z1IL/89WE//PVhP/z1YT/89WE//PVhP/z1YT/89WE//PUgv/02pP/1Isn/////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wDZkyr/+eWn//nnrP/5567/+eeu//nnrv/5567/+eeu//nnrv/5567/+ees//nlp//Zkyr/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ANyYLJbcmCz/3Jgs/9yYLP/cmCz/3Jgs/9yYLP/cmCz/3Jgs/9yYLP/cmCz/3Jgs/9yYLJb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfgAAAP4AD//+AA///gAP//4AD//+AA//8=",
		onCreated(btn) {
			btn.setAttribute("image", this.image);
			var doc = btn.ownerDocument;

			btn.btn = true;
			btn.domParent = null;
			btn.popups = new btn.ownerGlobal.Array();
			this.createPopup(doc, btn, "secondary", secondary);
			this.createCloseMenusOption(doc, btn);

			if (prefs.getIntPref('network.proxy.type') == 2)
				btn.style.filter = icon_vpn; // btn.style.cssText = "background-image: -moz-linear-gradient(#c0c8c0, #c0c8c0, #c0c8c0) !important";

			btn.linkedObject = this;
			for(var type of ["command", "contextmenu", "mousedown", "auxclick"]) // события
				btn.setAttribute("on" + type, `linkedObject.${type}(event)`);
			this.addSheet(btn);
		},
		addSheet(btn) {
			var cb = Array.isArray(btn._destructors);
			var id = cb ? btn.id : "ToggleAboutConfig";
			var css = `#${id} menu[_moz-menuactive] {
				color: ${menuactive} !important;
			}`;
			var args = [
				"data:text/css;charset=utf-8," + encodeURIComponent(css),
				Ci.nsIDOMWindowUtils.USER_SHEET
			];
			if (cb) var destructor = function() {
				this.removeSheetUsingURIString(...args);
			}
			var add = b => b.ownerGlobal.windowUtils.loadSheetUsingURIString(...args);
			(this.addSheet = !cb ? add : btn => {
				add(btn);
				btn._destructors.push({destructor, context: btn.ownerGlobal.windowUtils});
			})(btn);
		},
		createPopup(doc, btn, name, data) {
			var popup = doc.createElementNS(xul_ns, "menupopup");
			var prop = name + "Popup";
			btn.popups.push(btn[prop] = popup);
			popup.id = this.id + "-" + prop;
			for (var type of ["popupshowing", "click"])
				popup.setAttribute("on" + type, `parentNode.linkedObject.${type}(event)`);
			for(var obj of data) popup.append(this.createElement(doc, obj));
			btn.append(popup);
		},
		map: {b: "Bool", n: "Int", s: "String"},
		createElement(doc, obj) {
			if (!obj) return doc.createElementNS(xul_ns, "menuseparator");
			var pref = doc.ownerGlobal.Object.create(null), node, img, bool;
			for(var [key, val] of Object.entries(obj)) {
				if (key == "pref") {
					var [apref, lab, akey, hint] = val;
					pref.pref = apref; pref.lab = lab || apref;
					if (hint) pref.hint = hint;
				}
				else if (key == "image") img = val, pref.img = true;
				else if (key != "values") pref[key] = val;
				else pref.hasVals = true;
			}
			var type = prefs.getPrefType(pref.pref);
			var str = this.map[type == prefs.PREF_INVALID
				? obj.values ? (typeof obj.values[0][0])[0] : "b"
				: type == prefs.PREF_BOOL ? "b" : type == prefs.PREF_INT ? "n" : "s"
			];
			pref.get = prefs[`get${str}Pref`];
			var map, set = prefs[`set${str}Pref`];
			if (pref.hasVals) {
				for(var [val, , , , code] of obj.values)
					code && (map || (map = new Map())).set(val, code);
				if (map) pref.set = (key, val) => {
					set(key, val);
					map.has(val) && eval(map.get(val)); // выполнить код
				}
			}
			if (!map) pref.set = set;

			node = doc.createElementNS(xul_ns, "menu");
			node.className = "menu-iconic";
			node.setAttribute("closemenu", "none");
			img && node.setAttribute("image", img);
			akey && node.setAttribute("accesskey", akey);
			(node.pref = pref).vals = doc.ownerGlobal.Object.create(null);
			this.createRadios(doc,
				str.startsWith("B") && !pref.hasVals ? [[true, "true"], [false, "false"]] : obj.values,
				node.appendChild(doc.createElementNS(xul_ns, "menupopup"))
			);
			if ("userChoice" in obj) pref.noAlt = !("userAlt" in obj);
			return node;
		},
		createCloseMenusOption(doc, btn) {
			var pn = this.closePref = "ToggleAboutConfig.closeMenus";
			var data = [null, {
				pref: [pn, "Закрывать меню этой кнопки"], values: [[true, "Да"], [false, "Нет"]]
			}];
			var setCloseMenus = (e, trg = e.target) => {
				e.stopPropagation();
				var {pref, val} = trg, updPopup = true, clear;
				switch(e.type) {
					case "command": pref = (trg = trg.closest("menu")).pref; updPopup = false; break;
					case "click": if (e.button) return; break;
					case "contextmenu": e.preventDefault(); clear = pref;
				}
				if (!pref) return;
				if (clear) prefs.clearUserPref(pn);
				else if (!updPopup && val === pref.val) return;
				else pref.set(pn, val !== undefined ? val : !pref.val);
				this.upd(trg);
				updPopup && this.popupshowing(null, trg.querySelector("menupopup"));
			}
			(this.createCloseMenusOption = (doc, btn) => {
				for(var obj of data)
					btn.secondaryPopup.append(this.createElement(doc, obj));
				var m = btn.secondaryPopup.lastChild;
				m.style.cssText = "fill: lightblue !important; list-style-image: url(chrome://browser/skin/menu.svg) !important;";
				m.setAttribute("oncommand", "setCloseMenus(event)");
				m.onclick = m.oncontextmenu = m.setCloseMenus = setCloseMenus;
			})(doc, btn);
		},
		UserImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAe1BMVEUAAAB1dXV1dXV1dXV1dXV1dXV1dXV1dXV8fHyRkZGfn5+oqKipqamqqqqysrKzs7O6urq8vLy9vb3ExMTFxcXHx8fNzc3Ozs7Pz8/Q0NDY2NjZ2dna2tre3t7g4ODi4uLj4+Pk5OTl5eXn5+fs7Ozv7+/w8PDx8fHy8vLK4aRZAAAACHRSTlMAGFiAiNDw+LBTincAAACRSURBVBgZBcFBTsMADAAwJ20pqjgM+P8TgQua2Nok2AAAAiIzdfcgkOv2/ub357yaIF8+jwgz969nS7He9pnumf22hrSse1d1V/W+LlIc3d1V3d1HCPsHkWjj+5FUTVdVTdcQtmMNkXrMdT/Dur0KYYy/8wqx7QugHucE+bIFmPPZArkuS+qqqwmIzNTdAwAA/zI6Uy+Vzu5KAAAAAElFTkSuQmCC", // серый
		UserChoiceImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABGElEQVR4AWKgPgAQSmbgEsNQFB53GHz43GGcioPF4mCxGCwWi8FiMBgMBoPFYOzOPWf2/cv3Z/3P7Wo2W2VQolIJ59zb/grvlfLnO1lWJ7lmwDn2cEbnY3jciF0XSTUqSfKZRCLP4NB9c9tlyrOE4iXUwMAd2OMZHLiPj2O0uUZcWcQXp3jKsQTAuSeODlxm7grEIRmxZZal2EuhOxjEGR24yNwXqHOe5MQsdtVCq72He+DiIfNQYMxGwJRHhdIzPLs4zwViGw4ypF5MGsiYIBLML/t04D49gja7kz4eyEB6yiQCnhG4zDx/xsa30sUL3RMtgXP5jO9+JApt2L+DZ3C+/o2sbv9l5xsNtYBz7B0HS8qUZSZqAwCSaKMMRS9J3wAAAABJRU5ErkJggg==", // зелёный
		notUserChoiceImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABDElEQVR4Aa2TK3CEQBBEt6JwdxKJRJ48GRkZiURGxqt4dV5FnkQikSdXIpHIweE6+8KKyf+7Va92qqe770v493MOoUw8JGJizcSslV+Fm3NRWLxrZUMnzaOAGY0dng/DXVnK+kdpGhKXFI4CZjR2ePC+edu0W3eSYieNPQEPGjvhwUuG7FXuuK+b691uX4Sw2obBmkHbwIOXjC+4qY61D+d5Bq89g5eML6hpxvQd8JLxBXk5uxsM3p05vmBcJhfmnrkzbmaHl4wv6KfL5IKuZHbFecZLxhecxiEuiwVX4nBhPHjJvP0j7QtZe5TaWmqqdG8wo7HD8+m/MWHxUMluDym0wYzGDs/fHqb/Pk9WVkDcHStz1AAAAABJRU5ErkJggg==", // красный
		UserAltImg: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABAklEQVR4Aa2TKVDEQBREx3sRiUQi8Wpl5MqVSCQyMhIZGYlciVy5cmQkEhk5runHNQf3kapX9ev36w97hX9/xk3ozGCiScDMjuyr8va6D+syd9LdIOkgYGZHhvNhed4FyxdSmswsaQ/M7MiEg9uWO65r6aV1MCOFCnZkOLh0ygPjMgXpvjc7i5f50HORHRkOLp3yQNSR131uYZMPFbAjw8GlUx5IWk5kLJwiGeQMOzIcoFMfiEEFz+IZMHsHOW8PRO0dHMyxIEK9w8FtX8IYBwe3gPQeOcel0377Vt1w/XNwcOm8/SJtLcxI70OG8+m3kevxKihNucjMjgznbz+m/34eAEg4sZItNtjUAAAAAElFTkSuQmCC", // жёлтый
		regexpRefresh: /^(?:view-source:)?(?:https?|ftp)/,
		upd(node) {
			var {pref} = node, def = false, user = false, val;
			if (prefs.getPrefType(pref.pref) != prefs.PREF_INVALID) {
				var pn = pref.pref;
				try {val = pref.defVal = db[pref.get.name](pn); def = true}
				catch(ex) {def = false;}
				var user = prefs.prefHasUserValue(pn);
				if (user) try {val = pref.get(pn, undefined);} catch(ex) {}
			}
			if (val == pref.val && def == pref.def && user == pref.user) return;
			pref.val = val; pref.def = def; pref.user = user;
			var exists = def || user;

			var hint = exists ? val : "Эта опция не указана";
			if (hint === "") hint = "[ пустая строка ]";
			hint += "\n" + pref.pref;
			if (pref.hint) hint += "\n" + pref.hint;
			node.tooltipText = hint;

			var img, alt = "userAlt" in pref && val == pref.userAlt, pro = "userPro" in pref && val == pref.userPro;
			if (alt) img = this.UserAltImg;
			if (pro) img = this.UserImg;
			if ("userChoice" in pref)
				if (val == pref.userChoice)
					node.style.removeProperty("color"),
					img = this.UserChoiceImg;
				else {
					node.style.setProperty("color", "#804040", "important");
					if (!alt && !pro) img = this.notUserChoiceImg;
				}
			node.nextSibling && node.setAttribute("image", img || this.UserImg); // серый значок, если нет userChoice
			user
				? node.style.setProperty("font-style", "italic", "important")
				: node.style.removeProperty("font-style");

			var {lab} = pref;
			if (exists && pref.hasVals) {
				if (val in pref.vals) var sfx = pref.vals[val] || val;
				else var sfx = user ? "другое" : "стандарт";
				lab += ` ${"restart" in pref ? "↯-" : "refresh" in pref ? "-⟳" : "—"} ${sfx}`;
			}
			lab = exists ? lab : '['+ lab +']'; // имя = [имя] если преф не существует
			node.setAttribute("label", lab);
		},
		createRadios(doc, vals, popup) {
			for(var arr of vals) {
				if (!arr) {
					popup.append(doc.createElementNS(xul_ns, "menuseparator"));
					continue;
				}
				var [val, lab, key, hint] = arr;
				var menuitem = doc.createElementNS(xul_ns, "menuitem");
				menuitem.setAttribute("type", "radio");
				menuitem.setAttribute("closemenu", "none");
				menuitem.style.setProperty("font-style", "italic", "important"),
				menuitem.setAttribute("label", popup.parentNode.pref.vals[val] = lab);
				key && menuitem.setAttribute("accesskey", key);
				var tip = menuitem.val = val;
				if (hint) tip += "\n" + hint;
				menuitem.tooltipText = tip;
				popup.append(menuitem);
			}
		},
		openPopup(popup) {
			var btn = popup.parentNode;
			if (btn.domParent != btn.parentNode) {
				btn.domParent = btn.parentNode;
				if (btn.matches(".widget-overflow-list > :scope"))
					var pos = "after_start";
				else var win = btn.ownerGlobal, {width, height, top, bottom, left, right} =
					btn.closest("toolbar").getBoundingClientRect(), pos = width > height
						? `${win.innerHeight - bottom > top ? "after" : "before"}_start`
						: `${win.innerWidth - right > left ? "end" : "start"}_before`;
				for(var p of btn.popups) p.setAttribute("position", pos);
			}
			popup.openPopup(btn);
		},
		maybeRestart(node, conf) {
			if (conf && !Services.prompt.confirm(null, this.label, "Перезапустить браузер?")) return;
			var cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
			Services.obs.notifyObservers(cancel, "quit-application-requested", "restart");
			return cancel.data ? Services.prompt.alert(null, this.label, "Запрос на выход отменён.") : this.restart();
		},
		async restart() {
			var meth = Services.appinfo.inSafeMode ? "restartInSafeMode" : "quit";
			Services.startup[meth](Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
		},
		maybeRe(node, fe) {
			var {pref} = node;
			if ("restart" in pref) {
				if (this.maybeRestart(node, pref.restart)) return;
			}
			else this.popupshowing(fe, node.parentNode);
			if ("refresh" in pref) {
				var win = node.ownerGlobal;
				if (this.regexpRefresh.test(win.gBrowser.currentURI.spec)) pref.refresh
					? win.BrowserReloadSkipCache() : win.BrowserReload();
			}
		},
		maybeClosePopup(e, trg) {
			!e.shiftKey && prefs.getBoolPref(this.closePref, undefined)
				&& trg.parentNode.hidePopup();
		},
		eyedropper(trg) { // Пипетка - захват цвета
			var obj = ChromeUtils.import("resource://devtools/shared/Loader.jsm")
				.require("devtools/client/menus").menuitems
				.find(menuitem => menuitem.id == "menu_eyedropper");
			(this.eyedropper = target => obj.oncommand({target}))(trg);
		},
		auxclick(e) { // CKM
			if (e.button != 1 || !e.target.btn) return;
			PlacesUtils.history.clear();
 var closedTabCount = SessionStore.getClosedTabCount(window);
 while(closedTabCount--) SessionStore.forgetClosedTab(window, 0);
      
       alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
       alertsService.showAlertNotification("chrome://global/skin/icons/cpd_OK.png", "PrivateData", "История Очищена" );
       setTimeout(()=> alertsService.closeAlert(), 2000);
		},
		command(e) { // нажатия левой кнопки мыши
			var trg = e.target, win = e.view;
			if (trg.btn) { // LMB
				if (e.shiftKey) e.altKey
					? e.view.alert("Press Alt+Shift") // Alt+Shift
					: e.view.PlacesCommandHook.showPlacesOrganizer("BookmarksToolbar"); // Shift Библиотека Панель закладок
				else if (e.altKey)
					this.eyedropper(trg); // Alt Пипетка
				else {  // LMB Click
					var bar = trg.ownerDocument.getElementById("add-additional-vertical-bar");
					if (bar) {
						win.setToolbarVisibility(bar, bar.collapsed);
						bar.collapsed ? win.SidebarUI.hide() : win.SidebarUI.show("viewHistorySidebar");
					} else
						win.SidebarUI.toggle("viewHistorySidebar");
				}
				return;
			}
			var menu = trg.closest("menu"), newVal = trg.val;
			this.maybeClosePopup(e, menu);
			if (newVal != menu.pref.val)
				menu.pref.set(menu.pref.pref, newVal),
				this.maybeRe(menu, true);
		},
		popupshowing(e, trg = e.target) {
			if (trg.state == "closed") return;
			if (trg.id) {
				for(var node of trg.children) {
					if (node.nodeName.endsWith("r")) continue;
					this.upd(node);
					!e && node.open && this.popupshowing(null, node.querySelector("menupopup"));
				}
				return;
			}
			var {pref} = trg.closest("menu"), findChecked = true;

			var findDef = "defVal" in pref;
			var checked = trg.querySelector("[checked]");
			if (checked) {
				if (checked.val == pref.val) {
					if (findDef) findChecked = false;
					else return;
				}
				else checked.removeAttribute("checked");
			}
			if (findDef) {
				var def = trg.querySelector("menuitem:not([style*=font-style]");
				if (def)
					if (def.val == pref.defVal) {
						if (findChecked) findDef = false;
						else return;
					}
					else def.style.setProperty("font-style", "italic", "important");
			}
			for(var node of trg.children) if ("val" in node) {
				if (findChecked && node.val == pref.val) {
					node.setAttribute("checked", true);
					if (findDef) findChecked = false;
					else break;
				}
				if (findDef && node.val == pref.defVal) {
					node.style.removeProperty("font-style");
					if (findChecked) findDef = false;
					else break;
				}
			}
		},
		contextmenu(e) { // RMB
			var trg = e.target, win = e.view;
			if (trg.btn) {
				if (e.ctrlKey || e.shiftKey) return;
				if (e.detail == 2) return trg.secondaryPopup.hidePopup(); // меню быстрых настроек
				! e.altKey ? this.openPopup(trg.secondaryPopup) : this.switchToTab("about:config", e);
			}
			else if ("pref" in trg) {
				this.maybeClosePopup(e, trg);
				if (trg.pref.user)
					prefs.clearUserPref(trg.pref.pref),
					this.maybeRe(trg);
			}
			e.preventDefault();
		},
		click(e) {
			if (e.button) return;
			var trg = e.target, {pref} = trg;
			if (!pref) return;
		},
		mousedown(e) {
			var reset = e => e.target.linkedObject = this;
			var id, lo = {command: reset, mousedown: reset, auxclick: e => e.button != 1 || reset(e)};
			var lin = /macos|linux/.test(e.view.AppConstants.platform);
			var stop = e => reset(e) && e.preventDefault();
			lo.contextmenu = lin
				? e => e.ctrlKey || e.shiftKey ? dsp(e) : stop(e) : stop;
			var context = lin
				? e => e.button == 2 && e.type.endsWith("p") && this.contextmenu(e) : () => {};
			var dsp = (e, timeout) => {
				var trg = e.target;
				trg.onmouseup = trg.onmouseleave = null;
				if (timeout) return this.londPress(e);
				e.view.clearTimeout(id);
				reset(e);
				context(e);
			}
			(this.mousedown = e => { var trg = e.target;
				if (!trg.btn) return;
				trg.linkedObject = lo;
				trg.onmouseup = trg.onmouseleave = dsp;
				id = e.view.setTimeout(dsp, 500, e, true);
			})(e);
		},
		showInStatusPanel(info, ms = 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, ms);
			StatusPanel._label = info;
		},
		Notify(title, text, ms = 3000){
			Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService).showAlertNotification(null, title, text, false, '', null, ms);
		},
		switchToTab(url, e = this) { // открыть вкладку | закрыть, если открыта
			for(var tab of e.view.gBrowser.tabs)
				if ( tab.linkedBrowser.currentURI.spec == url ) {e.view.gBrowser.removeTab(tab); return;}; // вкладка найдена, закрыть
			e.view.switchToTabHavingURI(url, true, {relatedToCurrent: true, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()});
		},
		switchProxy(e, pac) {
			if (prefs.getIntPref('network.proxy.type') == 2) { // выключить
				prefs.setIntPref('network.proxy.type', 0);
				prefs.setStringPref("network.proxy.autoconfig_url", "127.0.0.1");
				e.target.style.removeProperty("filter");
				this.showInStatusPanel("\u{1F6A6} Настройки сети - работа без прокси"); // символ Светофор
			} else {
				prefs.setIntPref('network.proxy.type', 2);
				prefs.setStringPref("network.proxy.autoconfig_url", pac);
				e.target.style.setProperty("filter", icon_vpn, "important");
				this.showInStatusPanel("\u{1F6A6} Заблокированные сайты через «АнтиЗапрет»");
				// this.Notify('Proxy', 'Работаем через VPN Антизапрет');
			}
		},
		londPress(e) { // удержание кнопки мыши. на второй долгий клик при отпускании сработает действие на обычный клик этой кнопки
			var trg = e.target, win = e.view;
			if (e.button == 0) this.switchProxy(e, my_vpn);
			if (e.button == 1) trg.ownerDocument.getElementById("key_browserConsole").doCommand(); // Консоль браузера
			if (e.button == 2) { // RMB Long
				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()) ? this.switchToTab(help_ucf[0], e) : this.switchToTab(help_ucf[1], e);
			}
		}
	};
}); // END ToggleAboutConfig

Отредактировано manuk (31-10-2023 13:54:37)

Отсутствует

 

№1706631-10-2023 15:04:10

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

Re: Custom Buttons

Dumby
Через Хром тоже /add , но там это Custom Arguments , плюс там Node.exe  используется.  А у самого GOM  не понятно ком.строку где найти , в других плеерах - норм.
Можно в фокс аддон такой же типа In VLC , так при закрытии браузера и плеер закрывается , там Node.exe - как вкладка,зараза...

Отредактировано ВВП (31-10-2023 18:04:47)

Отсутствует

 

№1706731-10-2023 18:03:07

_backup
Участник
 
Группа: Members
Зарегистрирован: 12-02-2007
Сообщений: 25
UA: Firefox 78.0

Re: Custom Buttons

Есть у кого Cookies Permissions под версию FF78? А то Infocatcher пишет "удаляет все незащищённые (то есть все, кроме разрешенных в списке исключений) куки". А у меня на FF78 остаются куки от google и прочих сайтов, которые не включены в исключение.

Отсутствует

 

№1706801-11-2023 23:07:03

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

Re: Custom Buttons

manuk пишет

Если возможно, подправьте код

Сколько раз повторять, что Cu.import() больше не возвращает NSVO.
Перенеси в SystemGlobal. Замени Cu.import("resource://gre/modules/Services.jsm", {})
на Cu.getGlobalForObject(Cu)


ВВП пишет

Через Хром тоже /add

Хмм, потыкал я этот GOM Player, и, похоже,
что если ставить /add после урла, то плейлист очищается,
а если ставить /add перед урлом, то ссылка добавляется к имеющемуся.
Вобщем, попробуй заменить push на unshift

Отсутствует

 

№1706902-11-2023 09:03:05

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

Re: Custom Buttons

Dumby пишет

Сколько раз повторять, что Cu.import() больше не возвращает NSVO.

Спасибо.

Отсутствует

 

№1707002-11-2023 10:09:43

xrun1
Участник
 
Группа: Members
Зарегистрирован: 12-12-2013
Сообщений: 1165
UA: Firefox 119.0

Re: Custom Buttons

Dumby
А ты сам не пользуешься? Похоже, окончательно умерла Session Bookmarks. Хорошая была кнопка...

Отсутствует

 

№1707102-11-2023 10:19:09

rubel
Участник
 
Группа: Members
Откуда: г.Самара
Зарегистрирован: 10-05-2005
Сообщений: 559
UA: Firefox 115.0

Re: Custom Buttons

Farby

cookiesPermissions.js

А возможно выровнять контекстное меню на кнопке, а то оно как-то разъехалось местами.

скрытый текст
2f4f6579c23110cc740948f3ee352025.png

Отсутствует

 

№1707202-11-2023 13:13:36

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

Re: Custom Buttons

Dumby

Dumby пишет

Вобщем, попробуй заменить push на unshift

Круто...Rastaman Vibration ! Сам GOM - гадость редкостная, но уломать можно, без рекламы и ютуб берет. Но HLS - берет, но не перематывает, Lav spliter нужен.Осталась одна поганка. При новом запуске из браузера - плейлист новый , если заранее запустить Gom , а потом из браузера, тогда норм. Нельзя подрихтовать ?

Выделить код

Код:

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%u0412%u0438%u0434%u0435%u043E%20%u0432%20GomPlayer%3C/name%3E%0A%20%20%3Cimage%3E%3C%21%5BCDATA%5Bdata%3Aimage/x-icon%3Bbase64%2CAAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAAAYLOoAGCzqYRYr6tAWK+rrEyfp7ggd5+4AEeTuAAPj7gAB5u4AAePuAADj7hAG5e4dAOLuHwDg6R8A4cceAOFVJADgABgs6m8WK+rtFivp/xQo6f8KIej/ABTm/wAH4/8BGOf/LUDq/yMm5/8ANen/AP///wD///8A////AP///wCj9uUYCuNXGCzq4BYr6v8VKOn/DiPo/wAW5/9BTe7/09L5////////////o5jy/wBo7v8A////DGru/wD///8A////AP///xgR5c4YLOryFCjq/xMn5/8FG+f/VWHu/+fl+/////////////////+sn/X/AGHu/wD///8eAOL/FiLn/w9N7P8A///+HQDk6xgs6vAWK+n/DyXo/xIk5v/Z1/n//////////////////////6KT9P8AWO7/AP///xQx6f8A////Fhrm/wD//v8eAOLuGCzq7xYr5/8NI+j/Ym3w////////////////////////////oZXz/wBe7v8A////FwTl/xBB6v8WHef/AP///xwF5e4YLOrvFivp/w4j6P+pq/f///////////////////////////+so/T/AD/p/wD///8A////AP///wD///8A////Fxjm7hgs6u8WK+n/ECTo/7Gy9///////3d76/19q7v9MVO3/zc34//rt/P9Rae//AETr/wB07/8Ae/D/AIPy/wBH6v8YDuTuFivp7xQo6f8KIej/a3Xw//////9reO//AADh/wAA4P9TYe3///////bn/P+VhfD/lXzw/4hp7f8LAOH/EQDi/xsM5O4VKOfvDSHo/wAP5v8AFOX/3dz8/5id9P8AEeX/AADj/3B68f//////////////////////zsv5/wIM5v8GEef/Fh/n7hQo6e8IH+j/RlTr/1Vj7v++vvj/+fL9/6Gm9f+AifL/7+39/////////////////+7t/P+QmPT/ABbm/wAY6P8UKenuFivp7xEm6P/z7vz///////z6/f+1uPf/5uT8//////////////////v2/f/f3vr/v7/3/9nY+/8ZLOf/Bhzo/xYq6e4WK+nwFyzo/////////////////3V/7/94g/D/pqn1/7y99//ExPf/qaz0/8TF9//R0Pj/kpr0/xUp6P8JIOj/FCjp7hUo6fILIej/t7r3//75/v+3ufX////9///////X1/v/4t/8////////////9vP+/8TI+P8AC+T/Axnn/wgf6P4TJ+jrFivp4Ace6P8AFub/AA3m/wAA4/+7vPf//////8jJ+P/Nzfj//////62y9/8ADeP/Bhzm/wAV5/8IH+f/Eibp/xUp6c0WK+lvDyPo7Qgf6P8DGej/AA3m/wAS5v8iNen/ABfm/wAA4/8AD+X/AAnl/wAB4/8AEOb/Bx3o/xAk6f4WKunlFyzpVhYr6QAXLOlhFyzpzhgt6esNI+fuABbn7gAO5O4AAubuAADj7gAE5u4ADeTuABXk7gwi5+4WKunpFirpxxcs6VUZLeoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%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%0A%28func%20%3D%3E%20%7B%0A%09var%20sysPlayerName%20%3D%20%22Gomplayer%22%3B%0A%09var%20path%20%3D%20%22D%3A%5C%5CGOM%5C%5CGOMPlayer%5C%5CGOM.exe%22%3B%0A%09var%20videoMoved%20%3D%20%22%u0412%u0438%u0434%u0435%u043E%20%u043F%u0435%u0440%u0435%u043D%u0435%u0441%u0435%u043D%u043E%20%u0432%20%22%20+%20sysPlayerName%3B%0A%09var%20noFound%20%3D%20%22%u041D%u0435%20%u043D%u0430%u0439%u0434%u0435%u043D%u043E%20%u0432%u0438%u0434%u0435%u043E%20%u043D%u0430%20%u0441%u0442%u0440%u0430%u043D%u0438%u0446%u0435%2C%20%u0434%u043E%u0441%u0442%u0443%u043F%u043D%u043E%u0435%20%u0434%u043B%u044F%20%u043F%u0435%u0440%u0435%u043D%u043E%u0441%u0430%20%u0432%20%22%20+%20sysPlayerName%3B%0A%09%0A%09this.label%20%3D%20%22%u041E%u0442%u043A%u0440%u044B%u0442%u044C%20%u0432%u0438%u0434%u0435%u043E%20%u0432%20%22%20+%20sysPlayerName%3B%0A%09this.tooltipText%20%3D%20%22%u041B%3A%20%u0412%u0438%u0434%u0435%u043E%20%u0432%20%u043F%u043B%u0435%u0435%u0440%5Cn%u041F%3A%20%u0412%u0438%u0434%u0435%u043E%20%u0438%u0437%20Clipboar%5Cn%u0421%3A%20%u0417%u0430%u043A%u0440%u044B%u0442%u044C%20GomPlayer%22%3B%0A%0A%09this._handleClick%20%3D%20%28%29%20%3D%3E%20%7B%0A%09%09var%20msgName%20%3D%20_id%20+%20%22%3APlayer%22%3B%0A%09%09var%20listener%20%3D%20%28%7Bdata%7D%29%20%3D%3E%20data%20%3F%20run%28%5Bdata%5D%29%20%3A%20notify%28%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20listener%20%3D%20%28%7Bdata%7D%29%20%3D%3E%20data%20%3F%20run%28%5Bdata%5D%2C%20true%29%20%3A%20notify%28%29%3B%0A%09%09messageManager.addMessageListener%28msgName%2C%20listener%29%3B%0A%09%09addDestructor%28%28%29%20%3D%3E%20messageManager.removeMessageListener%28msgName%2C%20listener%29%29%3B%0A%0A%09%09var%20url%20%3D%20%22data%3Acharset%3Dutf-8%2C%22%20+%20encodeURIComponent%28%0A%09%09%09%60%28%24%7Bfunc%7D%29%28%29%60.replace%28%22MSG_NAME%22%2C%20msgName%29%0A%09%09%09%09.replace%28%22VIDEO_MOVED%22%2C%20encodeURIComponent%28videoMoved%29%29%0A%09%09%09%09.replace%28%22CONFIRM%22%2C%20encodeURIComponent%28%22%20%20%20%20%20%20%20%u041E%u0442%u043A%u0440%u044B%u0442%u044C%20%u0441%u0441%u044B%u043B%u043A%u0443%20%u0432%20%u043F%u043B%u0435%u0435%u0440%u0435%20%3F%22%29%29%0A%09%09%29%3B%0A%09%09%28this._handleClick%20%3D%20%28%29%20%3D%3E%20gBrowser.selectedBrowser.messageManager.loadFrameScript%28url%2C%20false%29%29%28%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%09%7D%0A%09this.onclick%20%3D%20e%20%3D%3E%20e.button%20%21%3D%201%20%7C%7C%20gShowPopup%28this%29%3B%20%0A%09this.oncontextmenu%20%3D%20e%20%3D%3E%20%7B%0A%09%09if%20%28e.ctrlKey%20%7C%7C%20e.shiftKey%20%7C%7C%20e.altKey%29%20return%3B%0A%09%09e.preventDefault%28%29%3B%0A%09%09custombuttons.confirmBox%28null%2C%20%22%20%20%20%20%20%20%20%20%20%20%u0417%u0430%u043F%u0443%u0441%u0442%u0438%u0442%u044C%20%u043F%u043B%u0435%u0435%u0440%20%u0438%u0437%20%u0431%u0443%u0444%u0435%u0440%u0430%20%u043E%u0431%u043C%u0435%u043D%u0430%20%3F%22%2C%20%22%u0414%u0430%22%2C%20%22%u041D%u0435%u0442%22%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%26%26%20run%28%5BgClipboard.read%28%29%2C%20%22/add%22%5D%29%3B%0A%09%09gBrowser.selectedBrowser.browsingContext.mediaController.pause%28%29%3B%09%0A%09%7D%0A%0A%0A%0A%09var%20popup%20%3D%20document.getElementById%28%22contentAreaContextMenu%22%29%3B%0A%09addEventListener%28%22popupshowing%22%2C%20%7B%0A%09%09get%20hidden%28%29%20%7B%0A%09%09%09return%20%21%28gContextMenu.onLink%20%7C%7C%20gContextMenu.onVideo%20%7C%7C%20gContextMenu.onPlainTextLink%29%3B%0A%09%09%7D%2C%0A%09%09handleEvent%28%29%20%7B%0A%09%09%09if%20%28this.hidden%29%20return%3B%0A%09%09%09var%20menuitem%20%3D%20document.createXULElement%28%22menuitem%22%29%3B%0A%09%09%09for%28var%20args%20of%20Object.entries%28%7B%0A%09%09%09%09image%3A%20self.image%2C%0A%09%09%09%09oncommand%3A%20%22play%28%29%3B%22%2C%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%0A%09%09%09%09class%3A%20%22menuitem-iconic%22%2C%0A%09%09%09%09label%3A%20%22%u041E%u0442%u043A%u0440%u044B%u0442%u044C%20%u0432%20%22%20+%20sysPlayerName%0A%09%09%09%7D%29%29%0A%09%09%09%09menuitem.setAttribute%28...args%29%3B%0A%09%09%09menuitem.play%20%3D%20%28%29%20%3D%3E%20play%28gContextMenu.linkURL%20%7C%7C%20gContextMenu.mediaURL%29%3B%0A%09%09%09document.getElementById%28%22context-savelink%22%29.before%28menuitem%29%3B%0A%09%09%09addDestructor%28%28%29%20%3D%3E%20menuitem.remove%28%29%29%3B%0A%09%09%09this.handleEvent%20%3D%20e%20%3D%3E%20%7B%0A%09%09%09%09if%20%28e.target%20%3D%3D%20popup%29%20menuitem.hidden%20%3D%20this.hidden%3B%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D%2C%20false%2C%20popup%20%7C%7C%201%29%3B%0A%0A%09var%20play%20%3D%20link%20%3D%3E%20custombuttons.confirmBox%28null%2C%20%22%20%20%20%20%20%20%20%20%20%20%u041E%u0442%u043A%u0440%u044B%u0442%u044C%20%u0441%u0441%u044B%u043B%u043A%u0443%20%u0432%20%u043F%u043B%u0435%u0435%u0440%u0435%20%3F%22%2C%20%22%u0414%u0430%22%2C%20%22%u041E%u0442%u043C%u0435%u043D%u0430%22%29%20%26%26%20run%28%5Blink%5D%29%3B%0A%09%0A%09var%20run%20%3D%20%28...a%29%20%3D%3E%20%7B%0A%09%09var%20file%20%3D%20FileUtils.File%28path%29%3B%0A%09%09%28run%20%3D%20%28args%2C%20quit%29%20%3D%3E%20%7B%0A%09%09%09if%20%28%21file.exists%28%29%29%20return%20custombuttons.alertBox%28%22File%20not%20exists%21%22%2C%20path%29%3B%0A%09%09%09var%20process%20%3D%20Cc%5B%22@mozilla.org/process/util%3B1%22%5D.createInstance%28Ci.nsIProcess%29%3B%0A%09%09%09%0A%09%09%09process.init%28file%29%3B%0A%09%09%09gBrowser.selectedBrowser.browsingContext.mediaController.pause%28%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20args.unshift%28%22/add%22%29%3B%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%20window.minimize%28%29%3B%0A%09%09%09process.runwAsync%28args%2C%20args.length%29%3B%0A%09%09%09%0A%09%09%7D%29%28...a%29%3B%0A%09%7D%0A%09var%20notify%20%3D%20%28%29%20%3D%3E%20%7B%0A%09%09var%20name%20%3D%20_id%20+%20%22-noFound%22%3B%0A%09%09var%20as%20%3D%20Cc%5B%22@mozilla.org/alerts-service%3B1%22%5D.getService%28Ci.nsIAlertsService%29%3B%0A%09%09%28notify%20%3D%20%28%29%20%3D%3E%20setTimeout%28as.closeAlert%2C%201150%2C%20name%2C%20as.showAlertNotification%28%0A%09%09%09%22chrome%3A//global/skin/icons/question-48.png%22%2C%20%22%22%2C%20noFound%2C%20false%2C%20%22%22%2C%20null%2C%20name%0A%09%09%29%29%29%28%29%3B%0A%09%7D%0A%0A%7D%29%28%28%29%20%3D%3E%20%7B%0A%0A%09var%20found%2C%20videoMoved%2C%20SEND%20%3D%20msg%20%3D%3E%20%7B%0A%09%09found%20%3D%20true%3B%0A%09%09if%20%28%21msg%20%7C%7C%20Cc%5B%22@mozilla.org/embedcomp/prompt-service%3B1%22%5D%0A%09%09%09.getService%28Ci.nsIPromptService%29%0A%09%09%09.confirm%28content%2C%20null%2C%20decodeURIComponent%28%22CONFIRM%22%29%29%0A%09%09%29%20%7B%0A%09%09%09if%20%28msg%29%20videoMoved%20%3D%20decodeURIComponent%28%22VIDEO_MOVED%22%29%3B%0A%09%09%09sendAsyncMessage%28%22MSG_NAME%22%2C%20msg%29%3B%0A%09%09%7D%0A%09%09else%20return%20true%3B%0A%09%7D%0A%0A%09var%20YoutubeID%20%3D%20/%28%3F%3Ayoutube%28%3F%3A-nocookie%29%3F%5C.com%5C/%28%3F%3A%5B%5E%5C/%5Cn%5Cs%5D+%5C/%5CS+%5C/%7C%28%3F%3Av%7Ce%28%3F%3Ambed%29%3F%29%5C/%7C%5CS*%3F%5B%3F%26%5Dv%3D%29%7Cyoutu%5C.be%5C/%29%28%5Ba-zA-Z0-9_-%5D%7B11%7D%29%28%3F%3A%5CW%7C%24%29/%3B%0A%0A%09var%20tmp%20%3D%20%27%27%2C%0A%09tmpp%20%3D%20%27%27%2C%0A%09innerA%20%3D%20%27%3Cdiv%20style%3D%22display%3Ablock%21important%3Bcolor%3A%2300ff00%21important%3Bwidth%3A250px%21important%3Bfont%3Abold%2016px%20serif%21important%3Bz-index%3A999%21important%3Bopacity%3A1%21important%3Bvisibility%3A%20visible%21important%3B%27%2C%0A%09innerB%20%3D%20%27left%3A5px%21important%3Bposition%3Aabsolute%21important%3Bheight%3Aauto%21important%3Bbox-sizing%3Aborder-box%21important%3Bpadding%3A5px%21important%3Bmargin%3A5px%21important%3B%27%2C%0A%09//stopPl%20%3D%20%22javascript%3A%28function%28%29%7Bv%3Ddocument.getElementById%28%27movie_player%27%29%3Bif%28v%29%7Bv.stopVideo%28%29%7Delse%7Bv%3Ddocument.getElementsByTagName%28%27video%27%29%3Bif%28v%29%7Bv%5B0%5D.src%3D%27%27%3Btry%7Bv%5B0%5D.load%28%29%7Dcatch%28e%29%7B%7D%7D%3B%7D%7D%29%28%29%3B%22%2C%0A%09ytIMGouter%20%3D%20function%20%28ytID%29%20%7B%0A%09%09return%20%27%3Cdiv%20width%3D%22100%25%22%3E%3Cbr%20/%3E%3Ca%20target%3D%22_blank%22%20href%3D%22https%3A//www.youtube.com/watch%3Fv%3D%27%20+%20ytID%20+%20%27%22%3E%3Cimg%20src%3D%22https%3A//i.ytimg.com/vi/%27%20+%20ytID%20+%20%27/hqdefault.jpg%22%3E%3C/a%3E%3Cbr%20/%3E%27%20+%20innerA%20+%20%27background-color%3Ablack%21important%3Bposition%3Arelative%21important%3Bbottom%3A20px%21important%3B%22%3E%26nbsp%3B%26nbsp%3B%27%20+%20videoMoved%20+%20%27%3C/div%3E%3Cbr%20/%3E%3C/div%3E%3Cbr%20/%3E%27%0A%09%7D%2C%0A%09handlWin%20%3D%20function%20%28currentWin%29%20%7B%0A%09%09tmp%20%3D%20%27%27%3B%0A%09%09var%20elem%20%3D%20currentWin.document.getElementsByTagName%28%27video%27%29%2C%0A%09%09currLoc%20%3D%20currentWin.location%3B%0A%09%09if%20%28elem.length%20%3E%200%29%20%7B%0A%09%09%09if%20%28currLoc.hostname.indexOf%28%27youtu%27%29%20%21%3D%20-1%20%26%26%20%28tmp%20%3D%20currLoc.toString%28%29.match%28YoutubeID%29%29%20%26%26%20tmp%5B1%5D.length%20%3D%3D%2011%29%20%7B%0A%0A%09%09%09%09if%20%28SEND%28%27https%3A//www.youtube.com/watch%3Fv%3D%27%20+%20tmp%5B1%5D%29%29%20return%3B%0A%0A%09%09%09%09videoMovedbox%20%3D%20currentWin.document.createElement%28%27videoMoved%27%29%3B%0A%09%09%09%09videoMovedbox.innerHTML%20%3D%20innerA%20+%20innerB%20+%20%27top%3A-15px%21important%3B%22%3E%3Cb%3E%27%20+%20videoMoved%20+%20%27%3C/b%3E%3C/div%3E%27%3B%0A%0A%09%09%09%09//loadURI%28stopPl%29%3B%0A%09%09%09%09%28function%28d%29%7Bvar%20v%3Dd.getElementById%28%27movie_player%27%29%3Bif%28v%29%7Btry%7Bv.stopVideo%28%29%7Dcatch%7B%7D%7D%0A%09%09%09%09%09else%7Bv%3Dd.getElementsByTagName%28%27video%27%29%3Bif%28v%5B0%5D%29%7Bv%5B0%5D.src%3D%27%27%3Btry%7Bv%5B0%5D.load%28%29%7Dcatch%7B%7D%7D%3B%7D%7D%29%28currentWin.document%29%3B%0A%0A%09%09%09%09currentWin.document.getElementById%28%27eow-title%27%29.appendChild%28videoMovedbox%29%3B%0A%09%09%09%09return%20true%3B%0A%09%09%09%7D%3B%0A%09%09%09for%20%28i%20%3D%200%3B%20i%20%3C%20elem.length%3B%20i++%29%20%7B%0A%09%09%09%09if%20%28%28%28tmp%20%3D%20getSrc%28elem%5Bi%5D.parentNode%2C%20currLoc%29%29%20%26%26%20tmp.length%20%3E%202%29%20%7C%7C%20%28i%20%3D%3D%200%20%26%26%20currentWin.document.body.innerHTML.substring%280%2C%207%29%20%3D%3D%20%27%3Cvideo%20%27%20%26%26%20%28tmp%20%3D%20currLoc.toString%28%29%29%29%29%20%7B%0A%0A%09%09%09%09%09if%20%28SEND%28tmp%29%29%20return%3B%0A%0A%09%09%09%09%09videoMovedbox%20%3D%20currentWin.document.createElement%28%27videoMoved%27%29%3B%0A%09%09%09%09%09videoMovedbox.innerHTML%20%3D%20innerA%20+%20innerB%20+%20%27top%3A20px%21important%3Bbackground-color%3Ablack%21important%3B%22%3E%27%20+%20videoMoved%20+%20%27%3C/div%3E%27%3B%0A%0A%09%09%09%09%09if%20%28currLoc.hostname%20%3D%3D%20%27www.youtube.com%27%29%20%7B%0A%09%09%09%09%09%09elem%5Bi%5D.parentNode.parentNode.appendChild%28videoMovedbox%29%3B%0A%09%09%09%09%09%7D%20else%20%7B%0A%09%09%09%09%09%09elem%5Bi%5D.parentNode.appendChild%28videoMovedbox%29%3B%0A%09%09%09%09%09%7D%3B%0A%09%09%09%09%09elem%5Bi%5D.src%20%3D%20%27%27%3B%0A%09%09%09%09%09try%20%7B%0A%09%09%09%09%09%09elem%5Bi%5D.load%28%29%0A%09%09%09%09%09%7D%20catch%20%28e%29%20%7B%7D%3B%0A%09%09%09%09%09return%20true%3B%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%3B%0A%0A%09%09currentWin._elems%20%3D%20currentWin.document.getElementsByTagName%28%27iframe%27%29%3B%0A%09%09if%20%28currentWin._elems.length%20%3E%200%29%20%7B%0A%09%09%09for%20%28currentWin._iCounter%20%3D%200%3B%20currentWin._iCounter%20%3C%20currentWin._elems.length%3B%20currentWin._iCounter++%29%20%7B%0A%09%09%09%09if%20%28%28currentWin._elems%5BcurrentWin._iCounter%5D.src.indexOf%28%27youtube.com%27%29%20%3E%20-1%29%20%26%26%20%28tmp%20%3D%20currentWin._elems%5BcurrentWin._iCounter%5D.src.match%28YoutubeID%29%29%20%26%26%20%28tmp%5B1%5D.length%20%3D%3D%2011%29%29%20%7B%0A%0A%09%09%09%09if%20%28SEND%28%27https%3A//www.youtube.com/watch%3Fv%3D%27%20+%20tmp%5B1%5D%29%29%20return%3B%0A%0A%09%09%09%09currentWin._elems%5BcurrentWin._iCounter%5D.outerHTML%20%3D%20ytIMGouter%28tmp%5B1%5D%29%3B%0A%09%09%09%09%09return%20true%3B%0A%09%09%09%09%7D%3B%0A%09%09%09%09if%20%28currentWin._elems%5BcurrentWin._iCounter%5D.clientWidth%20%3E%2080%20%26%26%20currentWin._elems%5BcurrentWin._iCounter%5D.clientHeight%20%3E%2040%20%26%26%20handlWin%28currentWin._elems%5BcurrentWin._iCounter%5D.contentWindow%29%29%0A%09%09%09%09%09return%20true%3B%0A%09%09%09%7D%0A%09%09%7D%3B%0A%0A%09%09elem%20%3D%20currentWin.document.getElementsByTagName%28%27object%27%29%3B%0A%09%09currLoc%20%3D%20currentWin.location%3B%0A%09%09if%20%28elem.length%20%3D%3D%200%29%20%7B%0A%09%09%09elem%20%3D%20currentWin.document.getElementsByTagName%28%27embed%27%29%0A%09%09%7D%3B%0A%09%09if%20%28elem.length%20%3E%200%29%20%7B%0A%09%09%09for%20%28i%20%3D%200%3B%20i%20%3C%20elem.length%3B%20i++%29%20%7B%0A%09%09%09%09if%20%28elem%5Bi%5D.innerHTML.indexOf%28%27youtu%27%29%20%21%3D%20-1%20%26%26%20%28tmp%20%3D%20elem%5Bi%5D.innerHTML.match%28YoutubeID%29%29%20%26%26%20tmp%5B1%5D.length%20%3D%3D%2011%29%20%7B%0A%0A%09%09%09%09%09if%20%28SEND%28%27https%3A//www.youtube.com/watch%3Fv%3D%27%20+%20tmp%5B1%5D%29%29%20return%3B%0A%0A%09%09%09%09%09elem%5Bi%5D.outerHTML%20%3D%20ytIMGouter%28tmp%5B1%5D%29%3B%0A%09%09%09%09%09return%20true%3B%0A%09%09%09%09%7D%20else%20%7B%0A%09%09%09%09%09if%20%28elem%5Bi%5D.clientWidth%20%3E%2080%20%26%26%20elem%5Bi%5D.clientHeight%20%3E%2040%29%20%7B%0A%09%09%09%09%09%09if%20%28%28%28tmp%20%3D%20getSrc%28elem%5Bi%5D.parentNode%2C%20currLoc%29%29%20%7C%7C%20%28tmp%20%3D%20getLink%28elem%5Bi%5D%2C%20currLoc%29%29%29%20%26%26%20tmp.length%20%3E%202%29%20%7B%0A%0A%09%09%09%09%09%09%09if%20%28SEND%28tmp%29%29%20return%3B%0A%0A%09%09%09%09%09%09%09elem%5Bi%5D.outerHTML%20%3D%20innerA%20+%20%27background-color%3Ablack%21important%3Bbottom%3A20px%21important%3B%22%3E%26nbsp%3B%26nbsp%3B%27%20+%20videoMoved%20+%20%27%3C/div%3E%27%3B%0A%09%09%09%09%09%09%09return%20true%3B%0A%09%09%09%09%09%09%7D%3B%0A%09%09%09%09%09%7D%3B%0A%09%09%09%09%7D%0A%09%09%09%7D%3B%0A%09%09%7D%3B%0A%09%09return%20false%3B%0A%09%7D%3B%0A%0A%09function%20restProtHost%28lnkR%2C%20curLoc%29%20%7B%0A%09%09if%20%28lnkR.length%20%3D%3D%200%29%0A%09%09%09return%20%27%27%3B%0A%09%09let%20tr%20%3D%20lnkR.replace%28/%5E%3A%5C/%5C//%2C%20curLoc.protocol%20+%20%22//%22%29%3B%0A%09%09if%20%28%21tr.match%28/%5Ehttps%3F%3A%5C/%5C//i%29%29%20%7B%0A%09%09%09lnkR%20%3D%20tr.replace%28/%5E%5C/+/%2C%20%27%27%29%3B%0A%09%09%09if%20%28lnkR.split%28%27/%27%29%5B0%5D.split%28%27%3F%27%29%5B0%5D.split%28%27%23%27%29%5B0%5D.toLowerCase%28%29.match%28/%5E%28%3F%3A%5B-a-z%5Cd%5D+%5C.%29+%5Ba-z%5Cd%5D%7B2%2C6%7D%24/%29%29%20%7B%0A%09%09%09%09tr%20%3D%20curLoc.protocol%20+%20%27//%27%20+%20lnkR%3B%0A%09%09%09%7D%20else%20%7B%0A%09%09%09%09tr%20%3D%20curLoc.protocol%20+%20%27//%27%20+%20curLoc.host%20+%20%22/%22%20+%20lnkR%3B%0A%09%09%09%7D%0A%09%09%7D%3B%0A%09%09return%20tr%3B%0A%09%7D%3B%0A%0A%09function%20getSrc%28vobj%2C%20currentLoc%29%20%7B%0A%09%09var%20t%20%3D%20%27%27%2C%0A%09%09tt%20%3D%20%27%27%3B%0A%09%09if%20%28%28%28%28t%20%3D%20vobj.innerHTML.match%28/%3Cvideo.*%3F%5Cssrc%3D%28%3F%3A%28%3F%3A%27%28%5B%5E%27%5D*%29%27%29%7C%28%3F%3A%22%28%5B%5E%22%5D*%29%22%29%7C%28%5B%5E%5Cs%5D*%29%29/i%29%29%20%26%26%20%28t%29%20%26%26%20%28tt%20%3D%20t%5B1%5D%20%7C%7C%20t%5B2%5D%20%7C%7C%20t%5B3%5D%29%20%26%26%20tt.indexOf%28%27blob%3A%27%29%20%3D%3D%20-1%29%20%7C%7C%20%28%28t%20%3D%20vobj.innerHTML.match%28/%3Csource.*%3F%5Cssrc%3D%28%3F%3A%28%3F%3A%27%28%5B%5E%27%5D*%29%27%29%7C%28%3F%3A%22%28%5B%5E%22%5D*%29%22%29%7C%28%5B%5E%5Cs%5D*%29%29.*%3F%5Cstype%3D%5B%27%22%5D%3Fvideo%5C//i%29%29%20%26%26%20%28t%29%20%26%26%20%28tt%20%3D%20t%5B1%5D%20%7C%7C%20t%5B2%5D%20%7C%7C%20t%5B3%5D%29%29%29%20%26%26%20tt.length%20%3E%202%20%26%26%20tt.indexOf%28%27blob%3A%27%29%20%3D%3D%20-1%29%20%7B%0A%09%09%09if%20%28tt.indexOf%28%22.mp4/%3F%22%29%20%3D%3D%20-1%29%20%7B%0A%09%09%09%09tt%20%3D%20tt.replace%28/%26amp%3B/g%2C%20%22%26%22%29%0A%09%09%09%7D%3B%0A%09%09%09t%20%3D%20restProtHost%28tt%2C%20currentLoc%29%3B%0A%09%09%09return%20t%3B%0A%09%09%7D%3B%0A%09%09return%20%27%27%3B%0A%09%7D%3B%0A%0A%09function%20getLink%28obj%2C%20curLocation%29%20%7B%0A%0A%09%09if%20%28%21obj%20%7C%7C%20%21obj.tagName%29%0A%09%09%09return%20%27%27%3B%0A%09%09q%20%3D%20obj.tagName.toLowerCase%28%29%3B%0A%0A%09%09var%20getParam%20%3D%20function%20%28e%2C%20n%29%20%7B%0A%09%09%09var%20v%20%3D%20%27%27%2C%0A%09%09%09r%20%3D%20new%20RegExp%28%27%5E%28%27%20+%20n%20+%20%27%29%24%27%2C%20%27i%27%29%2C%0A%09%09%09param%20%3D%20e.getElementsByTagName%28%27param%27%29%3B%0A%09%09%09for%20%28var%20igp%20%3D%200%2C%20p%3B%20p%20%3D%20param%5Bigp%5D%3B%20igp++%29%20%7B%0A%09%09%09%09if%20%28p.hasAttribute%28%27name%27%29%20%26%26%20p.getAttribute%28%27name%27%29.match%28r%29%29%20%7B%0A%09%09%09%09%09v%20%3D%20p.getAttribute%28%27value%27%29%3B%0A%09%09%09%09%09break%0A%09%09%09%09%7D%3B%0A%09%09%09%7D%3B%0A%09%09%09return%20v%3B%0A%09%09%7D%3B%0A%0A%09%09var%20restPath%20%3D%20function%20%28f%2C%20s%29%20%7B%0A%09%09%09return%20%28f.substring%280%2C%204%29%20%3D%3D%20%27http%27%29%20%3F%20f%20%3A%20s.replace%28/%5B%23%3F%5D.*%24/%2C%20%27%27%29.replace%28/%5B%5E%5C/%5D*%24/%2C%20f%29%0A%09%09%7D%3B%0A%0A%09%09function%20videoLinkExtract%28fl%29%20%7B%0A%09%09%09alert%28fl%29%3B%0A%09%09%09var%20linkArr%20%3D%20%5B%5D%2C%0A%09%09%09outLinks%20%3D%20%5B%5D%2C%0A%09%09%09jj%20%3D%200%2C%0A%09%09%09lba%20%3D%20%27%27%2C%0A%09%09%09lbb%20%3D%20%27%27%2C%0A%09%09%09decodeURL%20%3D%20gBrowser.currentURI.spec%3B%20%7B%0A%09%09%09%09try%20%7B%0A%09%09%09%09%09return%20decodeURIComponent%28s%29%0A%09%09%09%09%7D%20catch%20%28e%29%20%7B%0A%09%09%09%09%09return%20unescape%28s%29%0A%09%09%09%09%7D%0A%09%09%09%7D%3B%0A%0A%09%09%09for%20%28var%20ij%20%3D%200%3B%20ij%20%3C%203%3B%20ij++%29%20%7B%0A%09%09%09%09lba%20%3D%20lba%20+%20String.fromCharCode%28parseInt%28%28Math.random%28%29%20*%2015%20+%201%29%20+%20%27%27%2C%2010%29%29%3B%0A%09%09%09%09lbb%20%3D%20lbb%20+%20String.fromCharCode%28parseInt%28%28Math.random%28%29%20*%2015%20+%2016%29%20+%20%27%27%2C%2010%29%29%3B%0A%09%09%09%7D%3B%0A%0A%09%09%09function%20pushWithMerit%28lnk%29%20%7B%0A%0A%09%09%09%09var%20merit%20%3D%20-11%3B%0A%09%09%09%09if%20%28lnk.match%28/%5Ehttps%3F%3A%5C/%5C//i%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%2040%3B%0A%09%09%09%09if%20%28outLinks.length%20%3D%3D%200%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%201%3B%0A%09%09%09%09if%20%28lnk.match%28/%5E%5C//%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%207%3B%0A%09%09%09%09if%20%28lnk.match%28/%5E%5C/%5C//%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%2030%3B%0A%09%09%09%09if%20%28lnk.match%28/240p%28%5B%5Ea-z%5D%7C%24%29/i%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%201%3B%0A%09%09%09%09if%20%28lnk.match%28/%5B%5Ea-z%5D240%28%5B%5Ea-z0-9%5D%7C%24%29/i%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%201%3B%0A%09%09%09%09if%20%28lnk.match%28/360p%28%5B%5Ea-z%5D%7C%24%29/i%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%203%3B%0A%09%09%09%09if%20%28lnk.match%28/%5B%5Ea-z%5D360%28%5B%5Ea-z0-9%5D%7C%24%29/i%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%203%3B%0A%09%09%09%09if%20%28lnk.match%28/480p%28%5B%5Ea-z%5D%7C%24%29/i%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%205%3B%0A%09%09%09%09if%20%28lnk.match%28/%5B%5Ea-z%5D480%28%5B%5Ea-z0-9%5D%7C%24%29/i%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%205%3B%0A%09%09%09%09if%20%28lnk.match%28/720p%28%5B%5Ea-z%5D%7C%24%29/i%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%207%3B%0A%09%09%09%09if%20%28lnk.match%28/%5B%5Ea-z%5D720%28%5B%5Ea-z0-9%5D%7C%24%29/i%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%207%3B%0A%09%09%09%09if%20%28lnk.match%28/%5C.mp4%28%5B%5Ea-z%5D%7C%24%29/i%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%208%3B%0A%09%09%09%09if%20%28lnk.match%28/_hd%28%5B%5Ea-z%5D%7C%24%29/i%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20+%206%3B%0A%09%09%09%09if%20%28lnk.match%28/%5C.%28jpg%7Cxml%29%28%5B%5Ea-z%5D%7C%24%29/i%29%29%0A%09%09%09%09%09merit%20%3D%20merit%20-%2040%3B%0A%09%09%09%09if%20%28merit%20%3E%200%29%0A%09%09%09%09%09outLinks.push%28merit%20+%20lba%20+%20lnk%29%3B%0A%09%09%09%09Services.console.logStringMessage%28%27merit%3A%27%20+%20merit%20+%20%27%20lnk-%3E%27%20+%20lnk%29%3B%0A%09%09%09%7D%3B%0A%0A%09%09%09linkArr.push%28fl%29%3B%0A%09%09%09while%20%28linkArr.length%20%3E%20jj%20%26%26%20jj%20%3C%2030%29%20%7B%0A%0A%09%09%09%09var%20testPaths%20%3D%20%5B%5D%3B%0A%09%09%09%09testPaths%20%3D%20linkArr%5Bjj%5D.split%28/%28%5C.%28%3F%3Aflv%7Cmp4%7Cm3u8%29%29/i%29%3B%0A%09%09%09%09if%20%28testPaths%5BtestPaths.length%20-%201%5D%20%3D%3D%20%27%27%29%0A%09%09%09%09%09testPaths.pop%28%29%3B%0A%0A%09%09%09%09for%20%28k%20%3D%201%3B%20k%20%3C%20testPaths.length%3B%20k%20%3D%20k%20+%202%29%20%7B%0A%0A%09%09%09%09%09if%20%28testPaths%5Bk%20-%201%5D.indexOf%28lba%29%20%3E%20-1%29%20%7B%0A%09%09%09%09%09%09pref%20%3D%20testPaths%5Bk%20-%201%5D%3B%0A%09%09%09%09%09%7D%20else%20%7B%0A%09%09%09%09%09%09var%20testAboutDom%20%3D%20testPaths%5Bk%20-%201%5D.toLowerCase%28%29.split%28/%28https%3F%3A%5C/%5C/%29/%29%3B%0A%09%09%09%09%09%09if%20%28testAboutDom%5BtestAboutDom.length%20-%201%5D%20%3D%3D%20%27%27%29%0A%09%09%09%09%09%09%09testAboutDom.pop%28%29%3B%0A%09%09%09%09%09%09var%20pTest%20%3D%20testAboutDom%5BtestAboutDom.length%20-%201%5D.split%28/%28%5C%3F%5B%5E%5C%3F%5D*%3F%26%29/%29%3B%0A%09%09%09%09%09%09if%20%28pTest.length%20%3E%202%29%20%7B%0A%09%09%09%09%09%09%09pTest.pop%28%29%3B%0A%09%09%09%09%09%09%09pTest.pop%28%29%3B%0A%09%09%09%09%09%09%7D%3B%0A%09%09%09%09%09%09testAboutDom%5BtestAboutDom.length%20-%201%5D%20%3D%20pTest.join%28%27%27%29%3B%0A%09%09%09%09%09%09pref%20%3D%20testPaths%5Bk%20-%201%5D.substring%28testAboutDom.join%28%27%27%29.lastIndexOf%28%22%26%22%29%20+%201%29%3B%0A%09%09%09%09%09%7D%3B%0A%0A%09%09%09%09%09t2%20%3D%20pref.lastIndexOf%28lbb%29%3B%0A%09%09%09%09%09if%20%28t2%20%3E%20-1%29%20%7B%0A%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%203%29%3B%0A%09%09%09%09%09%7D%20else%20%7B%0A%0A%09%09%09%09%09%09t2%20%3D%20pref.lastIndexOf%28%27%7B%22%27%29%3B%0A%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%202%29%3B%0A%09%09%09%09%09%09t2%20%3D%20pref.lastIndexOf%28%27%5B%22%27%29%3B%0A%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%202%29%3B%0A%09%09%09%09%09%09t2%20%3D%20pref.lastIndexOf%28%27%2C%22%27%29%3B%0A%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%202%29%3B%0A%09%09%09%09%09%09t2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27%22http%3A//%27%29%3B%0A%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0A%09%09%09%09%09%09t2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27%22https%3A//%27%29%3B%0A%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0A%09%09%09%09%09%09t2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27%2Chttp%3A//%27%29%3B%0A%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0A%09%09%09%09%09%09t2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27%2Chttps%3A//%27%29%3B%0A%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0A%09%09%09%09%09%09t2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27%3Bhttp%27%29%3B%0A%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0A%09%09%09%09%09%09t2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27*https%3A//%27%29%3B%0A%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0A%09%09%09%09%09%09t2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27%20or%20%27%29%3B%0A%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%204%29%3B%0A%0A%09%09%09%09%09%09pref%20%3D%20pref.substring%28pref.split%28%27/%27%29%5B0%5D.toLowerCase%28%29.split%28%27%252f%27%29%5B0%5D.lastIndexOf%28%27%3D%27%29%20+%201%29%3B%0A%0A%09%09%09%09%09%7D%0A%0A%09%09%09%09%09if%20%28pref.length%20%3E%200%29%20%7B%0A%0A%09%09%09%09%09%09if%20%28pref.split%28%27%3F%27%29%5B0%5D.toLowerCase%28%29.match%28/%25%5B2-3%5D%5B0-9a-f%5D/%29%29%20%7B%0A%0A%09%09%09%09%09%09%09t2%20%3D%20pref.indexOf%28%27%22%27%29%0A%09%09%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0A%09%09%09%09%09%09%09%09suff%20%3D%20testPaths%5Bk%20+%201%5D%20%3F%20testPaths%5Bk%20+%201%5D.split%28%27%26%27%29%5B0%5D.split%28%27%22%27%29%5B0%5D.split%28%27%3B%27%29%5B0%5D.split%28/%2Chttp/i%29%5B0%5D%20%3A%20%27%27%3B%0A%09%09%09%09%09%09%09if%20%28%28suff%20%21%3D%20testPaths%5Bk%20+%201%5D%29%20%7C%7C%20%28testPaths.length%20%3C%20k%20+%203%29%29%20%7B%0A%09%09%09%09%09%09%09%09if%20%28testPaths.length%20%3E%20k%20+%201%29%20%7B%0A%09%09%09%09%09%09%09%09%09testPaths%5Bk%20+%201%5D%20%3D%20%28%28pref%20%3D%3D%20testPaths%5Bk%20-%201%5D%29%20%3F%20%27%27%20%3A%20%27%26%27%29%20+%20testPaths%5Bk%20+%201%5D.substr%28suff.length%29%0A%09%09%09%09%09%09%09%09%7D%3B%0A%09%09%09%09%09%09%09%09t2%20%3D%20pref.lastIndexOf%28lba%29%3B%0A%09%09%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%203%29%0A%09%09%09%09%09%09%09%09%09%09linkArr.push%28decodeURL%28pref%20+%20testPaths%5Bk%5D%20+%20suff%29%29%3B%0A%0A%09%09%09%09%09%09%09%7D%20else%20%7B%0A%09%09%09%09%09%09%09%09testPaths%5Bk%20+%201%5D%20%3D%20%28pref%20%3D%3D%20testPaths%5Bk%20-%201%5D%20%3F%20%27%27%20%3A%20lbb%29%20+%20pref%20+%20testPaths%5Bk%5D%20+%20suff%0A%09%09%09%09%09%09%09%7D%0A%09%09%09%09%09%09%7D%20else%20%7B%0A%09%09%09%09%09%09%09suff%20%3D%20testPaths%5Bk%20+%201%5D%20%3F%20testPaths%5Bk%20+%201%5D.split%28%27%3B%27%29%5B0%5D.split%28%27%22%5D%27%29%5B0%5D.split%28%27%22%7D%27%29%5B0%5D.split%28%27%22%2C%27%29%5B0%5D.split%28/%2Chttps%3F%3A%5C/%5C//i%29%5B0%5D.split%28%27*https%3A//%27%29%5B0%5D.split%28%27%20or%20%27%29%5B0%5D%20%3A%20%27%27%3B%0A%09%09%09%09%09%09%09t2%20%3D%20suff.indexOf%28%27%26%27%29%3B%0A%09%09%09%09%09%09%09if%20%28%28t2%20%3E%20-1%29%20%26%26%20%28pref%20%21%3D%20testPaths%5Bk%20-%201%5D%29%29%20%7B%0A%09%09%09%09%09%09%09%09if%20%28t2%20%3D%3D%200%29%0A%09%09%09%09%09%09%09%09%09suff%20%3D%20%27%27%3B%0A%09%09%09%09%09%09%09%09if%20%28suff.charAt%280%29%20%21%3D%20%27%3F%27%29%0A%09%09%09%09%09%09%09%09%09suff%20%3D%20suff.split%28/%28%26%5B%5E%26%5D+%3Dhttps%3F%3A%5C/%5C/%29/i%29%5B0%5D%3B%0A%09%09%09%09%09%09%09%7D%3B%0A%09%09%09%09%09%09%09if%20%28%28suff%20%21%3D%20testPaths%5Bk%20+%201%5D%29%20%7C%7C%20%28testPaths.length%20%3C%20k%20+%203%29%29%20%7B%0A%09%09%09%09%09%09%09%09if%20%28testPaths.length%20%3E%20k%20+%201%29%20%7B%0A%09%09%09%09%09%09%09%09%09testPaths%5Bk%20+%201%5D%20%3D%20%28%28pref%20%3D%3D%20testPaths%5Bk%20-%201%5D%29%20%3F%20%27%27%20%3A%20%27%26%27%29%20+%20testPaths%5Bk%20+%201%5D.substr%28suff.length%29%0A%09%09%09%09%09%09%09%09%7D%3B%0A%09%09%09%09%09%09%09%09t2%20%3D%20pref.lastIndexOf%28lba%29%3B%0A%09%09%09%09%09%09%09%09if%20%28t2%20%3E%20-1%29%0A%09%09%09%09%09%09%09%09%09pref%20%3D%20pref.substring%28t2%20+%203%29%3B%0A%09%09%09%09%09%09%09%09pushWithMerit%28pref%20+%20testPaths%5Bk%5D%20+%20suff%29%3B%0A%0A%09%09%09%09%09%09%09%7D%20else%20%7B%0A%09%09%09%09%09%09%09%09testPaths%5Bk%20+%201%5D%20%3D%20lba%20+%20%28pref%20%3D%3D%20testPaths%5Bk%20-%201%5D%20%3F%20%27%27%20%3A%20lbb%29%20+%20pref%20+%20testPaths%5Bk%5D%20+%20suff%0A%09%09%09%09%09%09%09%7D%0A%09%09%09%09%09%09%7D%0A%09%09%09%09%09%7D%0A%09%09%09%09%7D%3B%0A%09%09%09%09jj%20%3D%20jj%20+%201%3B%0A%09%09%09%7D%3B%0A%0A%09%09%09if%20%28outLinks.length%20%3D%3D%200%29%0A%09%09%09%09return%20%27%27%3B%0A%09%09%09function%20srt%28a%2C%20b%29%20%7B%0A%09%09%09%09a%20%3D%20parseInt%28a.substr%280%2C%20a.indexOf%28lba%29%29%2C%2010%29%3B%0A%09%09%09%09b%20%3D%20parseInt%28b.substr%280%2C%20b.indexOf%28lba%29%29%2C%2010%29%3B%0A%09%09%09%09if%20%28a%20%3C%20b%29%0A%09%09%09%09%09return%201%3B%0A%09%09%09%09if%20%28a%20%3E%20b%29%0A%09%09%09%09%09return%20-1%3B%0A%09%09%09%09return%200%0A%09%09%09%7D%3B%0A%09%09%09outLinks.sort%28srt%29%3B%0A%09%09%09outLinks%5B0%5D%20%3D%20outLinks%5B0%5D.substr%28outLinks%5B0%5D.indexOf%28lba%29%20+%203%29%0A%09%09%09%09if%20%28outLinks%5B0%5D.indexOf%28%27_hq.mp4/%3Ftime%3D%27%29%20%3E%200%29%0A%09%09%09%09%09outLinks%5B0%5D%20%3D%20outLinks%5B0%5D.replace%28/%26/g%2C%20%27%26amp%3B%27%29%3B%0A%09%09%09%09return%20outLinks%5B0%5D%3B%0A%09%09%7D%3B%0A%0A%09%09if%20%28%21ol%29%0A%09%09%09return%20%27%27%3B%0A%09%09//ol%20%3D%20ol.replace%28/%5E%3A%3F%5C/%5C//%2C%20curLocation.protocol%20+%20%22//%22%29%3B%0A%09%09//return%20restPath%28ol%2C%20src%29%3B%0A%09%09return%20restProtHost%28ol%2C%20curLocation%29%3B%0A%09%7D%3B%0A%0A%09try%20%7BhandlWin%28content%29%3B%7D%20finally%20%7Bfound%20%7C%7C%20SEND%28%29%3B%7D%0A%7D%29%3B%0Athis.onclick%20%3D%20function%28e%29%20%7B%0A%20%20%20%20if%28e.target%20%21%3D%20this%29%0A%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20if%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%0A%20%20%20%7B%20%20%0A%09if%28Services.prompt.confirm%28null%2C%20null%2C%20%22%20%20%20%20%20%20%20%20%20%20%u0417%u0430%u043A%u0440%u044B%u0442%u044C%20Gom%20Player%20%3F%22%29%29%20%7B%0A%09%09var%20file%20%3D%20Services.dirsvc.get%28%27ProfD%27%2C%20Ci.nsIFile%29%3B%0A%20%20%20%20%20%20%20%20%20file.initWithPath%28file.path%20+%20%22%5C%5Cmemory%5C%5Cgom.vbs%22%29%3B%20%20file.launch%28%29%3B%20%0A%0A%09%7D%0A%7D%0A%7D%3B%0A%5D%5D%3E%3C/initcode%3E%0A%20%20%3Ccode%3E%3C%21%5BCDATA%5B%0A%09%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%23navigator-toolbox%20%23nav-bar%20%3E%20hbox%20toolbarbutton%5Bis%3D%22custombuttons-button%22%5D%23id%7Bmargin%3A%200px%20-3px%200px%20-2px%20%21important%3B%7D%5D%5D%3E%3C/help%3E%0A%20%20%3Cattributes/%3E%0A%3C/custombutton%3E

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

Отсутствует

 

№1707306-11-2023 09:52:22

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

Re: Custom Buttons

Боюсь, что Dumby заругает, но спрошу. В кнопке PotPlayer

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

Выделить код

Код:

(func => {
	var sysPlayerName = "Pot Player";
	var path = "R:\\PotPlayer\\PotPlayerMini.exe";
	var videoMoved = "Видео перенесено в " + sysPlayerName;
	var noFound = "Не найдено видео на странице, доступное для переноса в " + sysPlayerName;

	
	this.label = "Открыть видео в " + sysPlayerName;
	this.tooltipText = "Л: Добавить в плейлист\nП: Воспроизведение";

	var rmb;
	this._handleClick = arg => {
		var msgName = _id + ":Player";
		var listener = ({data}) => data ? run([data]) : notify();
		messageManager.addMessageListener(msgName, listener);
		addDestructor(() => messageManager.removeMessageListener(msgName, listener));

		var url = "data:charset=utf-8," + encodeURIComponent(
			`(${func})()`.replace("MSG_NAME", msgName)
				.replace("VIDEO_MOVED", encodeURIComponent(videoMoved))
				.replace("CONFIRM", encodeURIComponent("Открыть ссылку в плеере ?"))
		);
		(this._handleClick = arg => {
			rmb = arg;
			gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false);
		})(arg);
	}
	this.oncontextmenu = e => {
		if (e.ctrlKey || e.shiftKey || e.altKey) return;
		e.preventDefault();
		this._handleClick(true);
	}
	var popup = document.getElementById("contentAreaContextMenu");
	addEventListener("popupshowing", {
		get hidden() {
			return !(gContextMenu.onLink || gContextMenu.onVideo || gContextMenu.onPlainTextLink);
		},
		handleEvent() {
			if (this.hidden) return;
			var menuitem = document.createXULElement("menuitem");
			for(var args of Object.entries({
				image: self.image,
				oncommand: "play(event)",
				class: "menuitem-iconic", 
				label: "  В плейлист " + sysPlayerName
			}))
				menuitem.setAttribute(...args);
			menuitem.play = e => {
				rmb = e.button == 2;
				play(gContextMenu.linkURL || gContextMenu.mediaURL);
			}
			document.getElementById("context-savelink").before(menuitem);
			addDestructor(() => menuitem.remove());
			this.handleEvent = e => {
				if (e.target == popup) menuitem.hidden = this.hidden;
			}
		}
	}, false, popup || 1);

	var play = link => custombuttons.confirmBox(null, "Открыть ссылку в плеере ?", "Да", "Отмена") && run([link]);
	var run = args => {
		var file = FileUtils.File(path);
		(run = args => {
			if (!file.exists()) return custombuttons.alertBox("File not exists!", path);
			var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
			process.init(file);
			rmb || args.push("/add");
			process.runwAsync(args, args.length);
		})(args);
	}
	var notify = () => {
		var name = _id + "-noFound";
		var as = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
		(notify = () => setTimeout(as.closeAlert, 1150, name, as.showAlertNotification(
			"chrome://global/skin/icons/question-48.png", "", noFound, false, "", null, name
		)))();
	}

})(() => {

	var found, videoMoved, SEND = msg => {
		found = true;
		if (!msg || Cc["@mozilla.org/embedcomp/prompt-service;1"]
			.getService(Ci.nsIPromptService)
			.confirm(content, null, decodeURIComponent("CONFIRM"))
		) {
			if (msg) videoMoved = decodeURIComponent("VIDEO_MOVED");
			sendAsyncMessage("MSG_NAME", msg);
		}
		else return true;
	}

	var YoutubeID = /(?:youtube(?:-nocookie)?\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})(?:\W|$)/;

	var tmp = '',
	tmpp = '',
	innerA = '<div style="display:block!important;color:#00ff00!important;width:250px!important;font:bold 16px serif!important;z-index:999!important;opacity:1!important;visibility: visible!important;',
	innerB = 'left:5px!important;position:absolute!important;height:auto!important;box-sizing:border-box!important;padding:5px!important;margin:5px!important;',
	//stopPl = "javascript:(function(){v=document.getElementById('movie_player');if(v){v.stopVideo()}else{v=document.getElementsByTagName('video');if(v){v[0].src='';try{v[0].load()}catch(e){}};}})();",
	ytIMGouter = function (ytID) {
		return '<div width="100%"><br /><a target="_blank" href="https://www.youtube.com/watch?v=' + ytID + '"><img src="https://i.ytimg.com/vi/' + ytID + '/hqdefault.jpg"></a><br />' + innerA + 'background-color:black!important;position:relative!important;bottom:20px!important;">&nbsp;&nbsp;' + videoMoved + '</div><br /></div><br />'
	},
	handlWin = function (currentWin) {
		tmp = '';
		var elem = currentWin.document.getElementsByTagName('video'),
		currLoc = currentWin.location;
		if (elem.length > 0) {
			if (currLoc.hostname.indexOf('youtu') != -1 && (tmp = currLoc.toString().match(YoutubeID)) && tmp[1].length == 11) {

				if (SEND('https://www.youtube.com/watch?v=' + tmp[1])) return;

				videoMovedbox = currentWin.document.createElement('videoMoved');
				videoMovedbox.innerHTML = innerA + innerB + 'top:-15px!important;"><b>' + videoMoved + '</b></div>';

				//loadURI(stopPl);
				(function(d){var v=d.getElementById('movie_player');if(v){try{v.stopVideo()}catch{}}
					else{v=d.getElementsByTagName('video');if(v[0]){v[0].src='';try{v[0].load()}catch{}};}})(currentWin.document);

				currentWin.document.getElementById('eow-title').appendChild(videoMovedbox);
				return true;
			};
			for (i = 0; i < elem.length; i++) {
				if (((tmp = getSrc(elem[i].parentNode, currLoc)) && tmp.length > 2) || (i == 0 && currentWin.document.body.innerHTML.substring(0, 7) == '<video ' && (tmp = currLoc.toString()))) {

					if (SEND(tmp)) return;

					videoMovedbox = currentWin.document.createElement('videoMoved');
					videoMovedbox.innerHTML = innerA + innerB + 'top:20px!important;background-color:black!important;">' + videoMoved + '</div>';

					if (currLoc.hostname == 'www.youtube.com') {
						elem[i].parentNode.parentNode.appendChild(videoMovedbox);
					} else {
						elem[i].parentNode.appendChild(videoMovedbox);
					};
					elem[i].src = '';
					try {
						elem[i].load()
					} catch (e) {};
					return true;
				}
			}
		};

		currentWin._elems = currentWin.document.getElementsByTagName('iframe');
		if (currentWin._elems.length > 0) {
			for (currentWin._iCounter = 0; currentWin._iCounter < currentWin._elems.length; currentWin._iCounter++) {
				if ((currentWin._elems[currentWin._iCounter].src.indexOf('youtube.com') > -1) && (tmp = currentWin._elems[currentWin._iCounter].src.match(YoutubeID)) && (tmp[1].length == 11)) {

				if (SEND('https://www.youtube.com/watch?v=' + tmp[1])) return;

				currentWin._elems[currentWin._iCounter].outerHTML = ytIMGouter(tmp[1]);
					return true;
				};
				if (currentWin._elems[currentWin._iCounter].clientWidth > 80 && currentWin._elems[currentWin._iCounter].clientHeight > 40 && handlWin(currentWin._elems[currentWin._iCounter].contentWindow))
					return true;
			}
		};

		elem = currentWin.document.getElementsByTagName('object');
		currLoc = currentWin.location;
		if (elem.length == 0) {
			elem = currentWin.document.getElementsByTagName('embed')
		};
		if (elem.length > 0) {
			for (i = 0; i < elem.length; i++) {
				if (elem[i].innerHTML.indexOf('youtu') != -1 && (tmp = elem[i].innerHTML.match(YoutubeID)) && tmp[1].length == 11) {

					if (SEND('https://www.youtube.com/watch?v=' + tmp[1])) return;

					elem[i].outerHTML = ytIMGouter(tmp[1]);
					return true;
				} else {
					if (elem[i].clientWidth > 80 && elem[i].clientHeight > 40) {
						if (((tmp = getSrc(elem[i].parentNode, currLoc)) || (tmp = getLink(elem[i], currLoc))) && tmp.length > 2) {

							if (SEND(tmp)) return;

							elem[i].outerHTML = innerA + 'background-color:black!important;bottom:20px!important;">&nbsp;&nbsp;' + videoMoved + '</div>';
							return true;
						};
					};
				}
			};
		};
		return false;
	};

	function restProtHost(lnkR, curLoc) {
		if (lnkR.length == 0)
			return '';
		let tr = lnkR.replace(/^:\/\//, curLoc.protocol + "//");
		if (!tr.match(/^https?:\/\//i)) {
			lnkR = tr.replace(/^\/+/, '');
			if (lnkR.split('/')[0].split('?')[0].split('#')[0].toLowerCase().match(/^(?:[-a-z\d]+\.)+[a-z\d]{2,6}$/)) {
				tr = curLoc.protocol + '//' + lnkR;
			} else {
				tr = curLoc.protocol + '//' + curLoc.host + "/" + lnkR;
			}
		};
		return tr;
	};

	function getSrc(vobj, currentLoc) {
		var t = '',
		tt = '';
		if ((((t = vobj.innerHTML.match(/<video.*?\ssrc=(?:(?:'([^']*)')|(?:"([^"]*)")|([^\s]*))/i)) && (t) && (tt = t[1] || t[2] || t[3]) && tt.indexOf('blob:') == -1) || ((t = vobj.innerHTML.match(/<source.*?\ssrc=(?:(?:'([^']*)')|(?:"([^"]*)")|([^\s]*)).*?\stype=['"]?video\//i)) && (t) && (tt = t[1] || t[2] || t[3]))) && tt.length > 2 && tt.indexOf('blob:') == -1) {
			if (tt.indexOf(".mp4/?") == -1) {
				tt = tt.replace(/&amp;/g, "&")
			};
			t = restProtHost(tt, currentLoc);
			return t;
		};
		return '';
	};

	function getLink(obj, curLocation) {

		if (!obj || !obj.tagName)
			return '';
		q = obj.tagName.toLowerCase();

		var getParam = function (e, n) {
			var v = '',
			r = new RegExp('^(' + n + ')$', 'i'),
			param = e.getElementsByTagName('param');
			for (var igp = 0, p; p = param[igp]; igp++) {
				if (p.hasAttribute('name') && p.getAttribute('name').match(r)) {
					v = p.getAttribute('value');
					break
				};
			};
			return v;
		};

		var restPath = function (f, s) {
			return (f.substring(0, 4) == 'http') ? f : s.replace(/[#?].*$/, '').replace(/[^\/]*$/, f)
		};

		function videoLinkExtract(fl) {
			alert(fl);
			var linkArr = [],
			outLinks = [],
			jj = 0,
			lba = '',
			lbb = '',
			decodeURL = gBrowser.currentURI.spec; {
				try {
					return decodeURIComponent(s)
				} catch (e) {
					return unescape(s)
				}
			};

			for (var ij = 0; ij < 3; ij++) {
				lba = lba + String.fromCharCode(parseInt((Math.random() * 15 + 1) + '', 10));
				lbb = lbb + String.fromCharCode(parseInt((Math.random() * 15 + 16) + '', 10));
			};

			function pushWithMerit(lnk) {

				var merit = -11;
				if (lnk.match(/^https?:\/\//i))
					merit = merit + 40;
				if (outLinks.length == 0)
					merit = merit + 1;
				if (lnk.match(/^\//))
					merit = merit + 7;
				if (lnk.match(/^\/\//))
					merit = merit + 30;
				if (lnk.match(/240p([^a-z]|$)/i))
					merit = merit + 1;
				if (lnk.match(/[^a-z]240([^a-z0-9]|$)/i))
					merit = merit + 1;
				if (lnk.match(/360p([^a-z]|$)/i))
					merit = merit + 3;
				if (lnk.match(/[^a-z]360([^a-z0-9]|$)/i))
					merit = merit + 3;
				if (lnk.match(/480p([^a-z]|$)/i))
					merit = merit + 5;
				if (lnk.match(/[^a-z]480([^a-z0-9]|$)/i))
					merit = merit + 5;
				if (lnk.match(/720p([^a-z]|$)/i))
					merit = merit + 7;
				if (lnk.match(/[^a-z]720([^a-z0-9]|$)/i))
					merit = merit + 7;
				if (lnk.match(/\.mp4([^a-z]|$)/i))
					merit = merit + 8;
				if (lnk.match(/_hd([^a-z]|$)/i))
					merit = merit + 6;
				if (lnk.match(/\.(jpg|xml)([^a-z]|$)/i))
					merit = merit - 40;
				if (merit > 0)
					outLinks.push(merit + lba + lnk);
				Services.console.logStringMessage('merit:' + merit + ' lnk->' + lnk);
			};

			linkArr.push(fl);
			while (linkArr.length > jj && jj < 30) {

				var testPaths = [];
				testPaths = linkArr[jj].split(/(\.(?:flv|mp4|m3u8))/i);
				if (testPaths[testPaths.length - 1] == '')
					testPaths.pop();

				for (k = 1; k < testPaths.length; k = k + 2) {

					if (testPaths[k - 1].indexOf(lba) > -1) {
						pref = testPaths[k - 1];
					} else {
						var testAboutDom = testPaths[k - 1].toLowerCase().split(/(https?:\/\/)/);
						if (testAboutDom[testAboutDom.length - 1] == '')
							testAboutDom.pop();
						var pTest = testAboutDom[testAboutDom.length - 1].split(/(\?[^\?]*?&)/);
						if (pTest.length > 2) {
							pTest.pop();
							pTest.pop();
						};
						testAboutDom[testAboutDom.length - 1] = pTest.join('');
						pref = testPaths[k - 1].substring(testAboutDom.join('').lastIndexOf("&") + 1);
					};

					t2 = pref.lastIndexOf(lbb);
					if (t2 > -1) {
						pref = pref.substring(t2 + 3);
					} else {

						t2 = pref.lastIndexOf('{"');
						if (t2 > -1)
							pref = pref.substring(t2 + 2);
						t2 = pref.lastIndexOf('["');
						if (t2 > -1)
							pref = pref.substring(t2 + 2);
						t2 = pref.lastIndexOf(',"');
						if (t2 > -1)
							pref = pref.substring(t2 + 2);
						t2 = pref.toLowerCase().lastIndexOf('"http://');
						if (t2 > -1)
							pref = pref.substring(t2 + 1);
						t2 = pref.toLowerCase().lastIndexOf('"https://');
						if (t2 > -1)
							pref = pref.substring(t2 + 1);
						t2 = pref.toLowerCase().lastIndexOf(',http://');
						if (t2 > -1)
							pref = pref.substring(t2 + 1);
						t2 = pref.toLowerCase().lastIndexOf(',https://');
						if (t2 > -1)
							pref = pref.substring(t2 + 1);
						t2 = pref.toLowerCase().lastIndexOf(';http');
						if (t2 > -1)
							pref = pref.substring(t2 + 1);
						t2 = pref.toLowerCase().lastIndexOf('*https://');
						if (t2 > -1)
							pref = pref.substring(t2 + 1);
						t2 = pref.toLowerCase().lastIndexOf(' or ');
						if (t2 > -1)
							pref = pref.substring(t2 + 4);

						pref = pref.substring(pref.split('/')[0].toLowerCase().split('%2f')[0].lastIndexOf('=') + 1);

					}

					if (pref.length > 0) {

						if (pref.split('?')[0].toLowerCase().match(/%[2-3][0-9a-f]/)) {

							t2 = pref.indexOf('"')
								if (t2 > -1)
									pref = pref.substring(t2 + 1);
								suff = testPaths[k + 1] ? testPaths[k + 1].split('&')[0].split('"')[0].split(';')[0].split(/,http/i)[0] : '';
							if ((suff != testPaths[k + 1]) || (testPaths.length < k + 3)) {
								if (testPaths.length > k + 1) {
									testPaths[k + 1] = ((pref == testPaths[k - 1]) ? '' : '&') + testPaths[k + 1].substr(suff.length)
								};
								t2 = pref.lastIndexOf(lba);
								if (t2 > -1)
									pref = pref.substring(t2 + 3)
										linkArr.push(decodeURL(pref + testPaths[k] + suff));

							} else {
								testPaths[k + 1] = (pref == testPaths[k - 1] ? '' : lbb) + pref + testPaths[k] + suff
							}
						} else {
							suff = testPaths[k + 1] ? testPaths[k + 1].split(';')[0].split('"]')[0].split('"}')[0].split('",')[0].split(/,https?:\/\//i)[0].split('*https://')[0].split(' or ')[0] : '';
							t2 = suff.indexOf('&');
							if ((t2 > -1) && (pref != testPaths[k - 1])) {
								if (t2 == 0)
									suff = '';
								if (suff.charAt(0) != '?')
									suff = suff.split(/(&[^&]+=https?:\/\/)/i)[0];
							};
							if ((suff != testPaths[k + 1]) || (testPaths.length < k + 3)) {
								if (testPaths.length > k + 1) {
									testPaths[k + 1] = ((pref == testPaths[k - 1]) ? '' : '&') + testPaths[k + 1].substr(suff.length)
								};
								t2 = pref.lastIndexOf(lba);
								if (t2 > -1)
									pref = pref.substring(t2 + 3);
								pushWithMerit(pref + testPaths[k] + suff);

							} else {
								testPaths[k + 1] = lba + (pref == testPaths[k - 1] ? '' : lbb) + pref + testPaths[k] + suff
							}
						}
					}
				};
				jj = jj + 1;
			};

			if (outLinks.length == 0)
				return '';
			function srt(a, b) {
				a = parseInt(a.substr(0, a.indexOf(lba)), 10);
				b = parseInt(b.substr(0, b.indexOf(lba)), 10);
				if (a < b)
					return 1;
				if (a > b)
					return -1;
				return 0
			};
			outLinks.sort(srt);
			outLinks[0] = outLinks[0].substr(outLinks[0].indexOf(lba) + 3)
				if (outLinks[0].indexOf('_hq.mp4/?time=') > 0)
					outLinks[0] = outLinks[0].replace(/&/g, '&amp;');
				return outLinks[0];
		};

		if (!ol)
			return '';
		//ol = ol.replace(/^:?\/\//, curLocation.protocol + "//");
		//return restPath(ol, src);
		return restProtHost(ol, curLocation);
	};

	try {handlWin(content);} finally {found || SEND();}
});

 var style = custombutton.buttonGetHelp(self).replace(/id/g, _id);
var uri = makeURI('data:text/css,'+ encodeURIComponent(style));
var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
sss.loadAndRegisterSheet(uri, 0);


в FF 115 не появляетя предупреждение, т.е. кнопка частично не работает.
скрытый текст
Screen-513.jpg

Что исправить в коде?

Отсутствует

 

№1707406-11-2023 13:17:20

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

Re: Custom Buttons

xrun1 пишет

А ты сам не пользуешься? Похоже, окончательно умерла Session Bookmarks. Хорошая была кнопка...

Нет, сам не пользуюсь.
Кнопку пробовал править, но бесполезно.
Подправишь одно — вылезает другое, затем третье, пятое, десятое...
Расписался в неспособности.


ВВП пишет

При новом запуске из браузера - плейлист новый , если заранее запустить Gom , а потом из браузера, тогда норм.

У меня, даже если и не из браузера запустить — плейлист всегда новый.
Не смог понять где это настраивается,
ну кроме как явно указать в командной строке /playlist "бла-бла.asx"


manuk пишет

Боюсь, что Dumby заругает

С чего бы? Я никого не ругаю, хотелось бы думать.
А здесь будет просто недоумение, типа багу уже месяцев десять,
и давно пора менять embedcomp/prompt-service на prompter

Отсутствует

 

№1707506-11-2023 14:03:28

xrun1
Участник
 
Группа: Members
Зарегистрирован: 12-12-2013
Сообщений: 1165
UA: Firefox 119.0

Re: Custom Buttons

Dumby пишет

Расписался в неспособности.

Ну и ладно, всё и все когда-то умирают. Данные вытяну через какую-нибудь старую версию браузера. Спасибо за попытку.:beer:

Отсутствует

 

Board footer

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