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

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

№1485131-07-2020 15:44:57

Baron_
Забанен
 
Группа: Members
Зарегистрирован: 13-08-2013
Сообщений: 71
UA: Firefox 79.0

Re: Custom Buttons

Dumby пишет

«Merge Day»custom_buttons-0.0.7.0.0.16-fx-paxmod.xpicustom_buttons-0.0.7.0.0.16-fx-bootstrap.xpi
                    Отредактировано Dumby (27-07-2020 18:07:44)

А как его поставить? Ругается, что расширение не было проверено и не может быть установлено. Нашел какой-то способ, описанный ранее, но он не работает. Проверка подписей отключена, FF79

Отсутствует

 

№1485231-07-2020 16:10:17

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

Re: Custom Buttons

Baron_ пишет

Dumby пишет«Merge Day»custom_buttons-0.0.7.0.0.16-fx-paxmod.xpicustom_buttons-0.0.7.0.0.16-fx-bootstrap.xpi                    А как его поставить? Ругается, что расширение не было проверено и не может быть установлено. Нашел какой-то способ, описанный ранее, но он не работает. Проверка подписей отключена, FF79

Значит что то не так сделали, проверьте ещё раз...: https://forum.mozilla-russia.org/viewtopic.php?id=70326


И попробуйте установить custom_buttons-0.0.7.0.0.16-fx-paxmod, может в этом дело:

скрин
4f74f1aff68c.png

Отредактировано kokoss (31-07-2020 16:12:35)


Win7

Отсутствует

 

№1485331-07-2020 16:33:49

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

Re: Custom Buttons

sandro79 пишет

хотелось бы так

Вот так, вроде, похоже на картинку

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

Выделить код

Код:

@-moz-document url(chrome://browser/content/downloads/contentAreaDownloadsView.xhtml) {
	#downloadsListEmptyDescription {
		-moz-box-flex: 1 !important;
		margin: 0 !important;
		padding: 1px 0 0 6px !important;
		background-color: white !important;
	}
}

Baron_ пишет

Ругается, что расширение не было проверено
Проверка подписей отключена

Определись.


Baron_ пишет

как его поставить?

Если никогда не устанавливал расширения после их запрета,
а теперь вот, от скуки, захотелось, то нет, не советую.

Отсутствует

 

№1485431-07-2020 17:04:27

sandro79
Участник
 
Группа: Members
Зарегистрирован: 15-11-2017
Сообщений: 1750
UA: Firefox 78.0

Re: Custom Buttons

Dumby пишет

Вот так, вроде, похоже на картинку

Да-да, отлично, вообще один в один. Благодарю! :beer:

Отсутствует

 

№1485501-08-2020 00:31:52

Baron_
Забанен
 
Группа: Members
Зарегистрирован: 13-08-2013
Сообщений: 71
UA: Firefox 79.0

Re: Custom Buttons

Dumby пишет
Baron_ пишет

Ругается, что расширение не было проверено
Проверка подписей отключена

Определись.

Baron_ пишет

как его поставить?

Если никогда не устанавливал расширения после их запрета,
а теперь вот, от скуки, захотелось, то нет, не советую.

Чего определяться, когда-то делал. В about:config проверка подписей отключена, и два файлика в папке pref.  Из-за того, что большинство кнопок перестали работать, удалил расширение. Было давно, с тех пор что-то поменялось, устанавливать не хочет.

kokoss, спасибо, все работает. А я в этой ветке искал решение, так и не раскопал.

Отсутствует

 

№1485601-08-2020 16:03:29

Duche
Участник
 
Группа: Members
Зарегистрирован: 07-02-2016
Сообщений: 208
UA: unknown 0.0

Re: Custom Buttons

Добрый день. По моему , осталась одна рабочая ветка на форуме . Почините кто сможет пожалуйста три кода , два кода часов  "цифра"и "аналог", оба варианта часов "цифра" и "аналог" отстают на один час от системных на FF71, как на 32 так и 64, хотя на FF38.0 ESR  , FF60.0 ESR ходят нормально,синхронно с системными. Не пойму откуда и как эти коды синхронизируется с системными часами . Крутил "синхрон" по интернету и без ,менял часовой пояс , включал и отключал службы времени ,нет "синхрона" с системными часами. Третий код это переключатель "Proxy", мало того
не переключает выбранный режим прокси на кнопке , сами режимы "без прокси", "Ручная настройка прокси", "URL автоматической настройки прокси" переключаются ,но на кнопке это не видно. Она "кнопка" после перетаскивания на панель рвёт интерфейс панелей в хлам. Хочу завершить переход на FF71 с  FF38 .Заранее спасибо.


Код "Аналоговые часы"

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

Выделить код

Код:

/*Initialization Code*/


// Аналоговые часы, от 08.02.2016. ............... 
(()=> {
   var dia = 30; // диаметр аналоговых часов

   var canvas = document.createElementNS(xhtmlns, 'canvas');
   canvas.setAttribute("width", dia+"px;");
   canvas.setAttribute("height", dia+"px;");
   //canvas.style.cssText = "position: fixed !important; top: 30px; right: 218px; min-width: diapx; min-height: diapx; max-width: diapx; max-height: diapx".replace(/dia/g, dia);
   canvas.style.cssText = "min-width: diapx; min-height: diapx; max-width: diapx; max-height: diapx".replace(/dia/g, dia);
   var ctx = canvas.getContext("2d");
   ctx.scale(dia/122, dia/122);
   self.parentNode.insertBefore(canvas, self);
   addDestructor(()=> canvas.remove() );
   
   self.hidden = true;
   canvas.onclick =()=> self.hidden = !self.hidden;

   var interval = setInterval(()=> {
      var ctx = canvas.getContext("2d");
      ctx.save();
      ctx.clearRect(0, 0, 150, 150);
      ctx.translate(61, 61);
      ctx.scale (0.4, 0.4);
      ctx.fillStyle = "white";
      ctx.arc(0, 0, 142, 0, Math. PI * 2, true);
      ctx.fill();
      ctx.rotate(-Math. PI / 2);
      ctx.strokeStyle = "black";
      ctx.fillStyle = "white";
      ctx.lineWidth = 12;
      ctx.lineCap = "round";
      ctx.save();
      ctx.beginPath();
      for ( var i = 0; i < 12; i++ ) {
            ctx.rotate(Math. PI / 6);
            ctx.moveTo(100, 0);
            ctx.lineTo(120, 0);
            }
      ctx.stroke();
      ctx.restore();
      ctx.save();
      ctx.lineWidth = 5;
      ctx.beginPath();
      for ( var i = 0; i < 60; i++ ) {
            if ( i % 5 != 0 ) {
                 ctx. moveTo (117, 0);
                 ctx. lineTo (120, 0);
                 }
            ctx.rotate(Math. PI / 30);
            }
      ctx.stroke();
      ctx.restore();
      var now = new Date();
      var sec = now.getSeconds();
      var min = now.getMinutes();
      var hr = now.getHours();
      self.tooltipText = [hr, min > 9? min: "0" + min, sec > 9? sec: "0" + sec]. join (" : ");
      hr = hr >= 12? hr - 12: hr;
      ctx.fillStyle = "black";
      ctx.save();
      ctx.strokeStyle = "black";
      ctx.rotate(hr * (Math. PI / 6) + (Math. PI / 360) * min + (Math. PI / 21600) * sec)
      ctx.lineWidth = 14;
      ctx.beginPath();
      ctx.moveTo(-20, 0);
      ctx.lineTo(80, 0);
      ctx.stroke();
      ctx.restore();
      ctx.save();
      ctx.rotate((Math. PI / 30) * min + (Math. PI / 1800) * sec)
      ctx.lineWidth = 10;
      ctx.beginPath();
      ctx.moveTo(-28, 0);
      ctx.lineTo(112, 0);
      ctx.stroke();
      ctx.restore();
      ctx.save();
      ctx.rotate(sec * Math. PI / 30);
      ctx.strokeStyle = "#ee0000";
      ctx.fillStyle = "#ee0000";
      ctx.lineWidth = 6;
      ctx.beginPath();
      ctx.moveTo(-30, 0);
      ctx.lineTo(93, 0);
      ctx.stroke();
      ctx.fillStyle = "#555";
      ctx.arc(0, 0, 3, 0, Math. PI * 2, true);
      ctx.fill();
      ctx.restore();
      ctx.beginPath();
      ctx.lineWidth = 14;
      ctx.strokeStyle = '#1581e6';
      ctx.arc(0, 0, 142, 0, Math. PI * 2, true);
      ctx.stroke();
      ctx.restore();
   }, 1000);
   addDestructor(()=> clearInterval(interval) );
   
})();




/*CODE*/

this.leftclick(event);

Код "цифра"

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

Выделить код

Код:

/*Initialization Code*/


this.setAttribute("style", " -moz-appearance: none; font-size: 11pt !important; color: #000000 !important; background-color:  !important; border-width: 0px !important; border-color: #4444aa !important;-moz-border-radius: 4px;  margin-left: 1px !important; margin-top: 1px !important; margin-bottom: 1px !important; padding-bottom: 0px !important; padding-left: 1px !important; padding-right: 1px !important; padding-top: 0px !important; ");

this.style.opacity = "0.99";

this.onmouseover = function(event)
{
  var ttTime = new Date();
  
		var p = (ttTime. getHours () < 12)? "AM": "PM";
		var time = ttTime. toLocaleFormat ("%I:%M:%S ") + p;
		var date = ttTime. toLocaleFormat ("%A, %B %d, %Y");
		this.tooltipText =  date ;  
  
  /*
  var mydatestr = ttTime.toDateString();
  var myday = mydatestr.substring(0,3);
  var mymonth = mydatestr.substring(4,7);
  var mydate = mydatestr.substring(7,11);
  var myyear = mydatestr.substring(10,mydatestr.length);    
  this.tooltipText = myday + mydate + mymonth + myyear;
  */
}  

// Comment out these next two lines to start as a twelve hour clock
 var TwelveHourClock = 0;

var timesign = ":";
var timetick = ";"
var timetick1 = ":";
var timetick2 = ".";

this.leftclick = function(event)
{
  if(TwelveHourClock == 0)
  {
     TwelveHourClock = 12;
  }
  else
  {
     TwelveHourClock = 0;
  }
}


var beginTime = new Date();

var now = new Date();
var offset = now.getTimezoneOffset();
var myGMToffset = (offset/60)*-1;


function count(t) {

  var millisecond = t.getTime();
  var hour = Math.floor(millisecond % 86400000 / 3600000) + myGMToffset;
  if(TwelveHourClock == 12)
  {  
    if(hour >= 13)
    {
      hour = hour - TwelveHourClock ; 
    }
    else
    {
      morneve = "AM";
    }
    
    if(hour >= 12) 
    {morneve = "PM"; 
    };
  }
  else
  { 
    if(hour >= 24) {hour = hour - 24}
  }  
  var minute = Math.floor(millisecond % 3600000 / 60000);
  var second = Math.floor(millisecond % 3600000 % 60000 / 1000);
  hour = (hour < 10 ? "0" : "") + hour;
  minute = (minute < 10 ? "0" : "") + minute;
  second = (second < 10 ? "0" : "") + second;
  if(TwelveHourClock == 0){timesign = timetick1}else{timesign = timetick2}
  return hour + timesign + minute + timesign + second;
}
setInterval(function(that) {

  
  var currentTime = new Date();
  that.label = count(currentTime);
}, 10, this);
var ios = Components.classes["@mozilla.org/network/io-service;1"].
  getService(Components.interfaces.nsIIOService);
var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"].
  getService(Components.interfaces.nsIStyleSheetService);
var css = new String();
css += "#" + this.id + " .toolbarbutton-icon { display: none !important; }\n";
css += "#" + this.id + " .toolbarbutton-text { display: -moz-box !important; }\n";
css += "#" + this.id + "                     { -moz-box-orient: horizontal !important; }";
var uss = ios.newURI("data:text/css," + encodeURIComponent(css), null, null);
// comment out the next line to disable style
if (!sss.sheetRegistered(uss, sss.USER_SHEET)) sss.loadAndRegisterSheet(uss, sss.USER_SHEET);
this.onDestroy = function(reason) {
  if (reason == "update") {
    var uss = ios.newURI("data:text/css," + encodeURIComponent(css), null, null);
    if (sss.sheetRegistered(uss, sss.USER_SHEET)) sss.unregisterSheet(uss, sss.USER_SHEET);
  }
  if (reason == "delete") {
    var uss = ios.newURI("data:text/css," + encodeURIComponent(css), null, null);
    if (sss.sheetRegistered(uss, sss.USER_SHEET)) sss.unregisterSheet(uss, sss.USER_SHEET);
  }
}



  this. onclick = function (event) { custombuttons. gQuot. mHandler (event); }
  this. ondblclick = function (event) { custombuttons. gQuot. mHandler (event); }
  


this.setAttribute('author','squeaky,Barbiegirl,morat');
this.setAttribute('version','20110408.2.5');
this.setAttribute('homepage', 'http://custombuttons.mozdev.org/drupal/content/button-clock');

/*CODE*/

this.leftclick(event);


Код "Proxy"

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

Выделить код

Код:

// Proxy, от 25.02.2016.


// Настройка функций кликов мыши для кнопки ...................
this.onmousedown =e=> {
   
   this.onmouseup =e=>{                  // левый клик
        if ( e.button ) return;
        clearTimeout(self.timer);           

        switch( cbu.getPrefs("network.proxy.type") ) {
           case 0:  var data = 1; break;            
           case 1:  var data = 2; break; 
           case 2:  var data = 0; break;
           default: var data = 0; 
        }
        cbu.setPrefs("network.proxy.type", data);  
   }

   if ( e.button == 0 )                  // длинный левый клик
        self.timer = setTimeout(()=>{     
           self.onmouseup = '';
           cbu.getPrefs("CB.Proxy.connectionsInTab") ? openConnectionsInTab() : openConnections();
        }, 500);
   
   if ( e.button == 2 )                  // правый клик
        menuPopup.showPopup(self, -1, -1, "popup", "bottomleft", "topleft");
};
self.onclick =e=> e.preventDefault();



// Подсказка для кнопки ...................
this.onmouseover =()=> {
   this.tooltipText = "Proxy \nЛ: Переключить прокси \nДЛ: Открыть настройки прокси"
                    + "\nП: Mеню кнопки \n\nТекущие настройки прокси: " 
                    + "\nIP: " + Services.prefs.getComplexValue("network.proxy.http", Ci.nsISupportsString).data
                    + "\nПорт: "+ cbu.getPrefs("network.proxy.http_port");                                                    
};



// Создать меню для кнопки ...................
var array = [
   { label: "Добавление прокси в контекстом меню", value: 'CB.Proxy.inContextMenu' },
   { label: "Открывать настройки прокси как вкладку", value: 'CB.Proxy.connectionsInTab' },
   { label: "Переключать на режим 'Без прокси' при закрытии браузера ", value: 'CB.Proxy.reset' }    
];

var menuPopup = document.getElementById('mainPopupSet').appendChild(document.createElement("menupopup"));
array.forEach((m)=> {
   var mItem = document.createElement("menuitem");
   mItem.setAttribute("label", m.label);
   mItem.setAttribute('type', 'checkbox');
   mItem.setAttribute('checked', cbu.getPrefs(m.value) );
   mItem.onclick =()=> cbu.setPrefs(m.value, !cbu.getPrefs(m.value));  
   menuPopup.appendChild(mItem);
});
addDestructor(()=> menuPopup.remove() );

// добавить стандартное контекстное меню 
menuPopup.appendChild(document.createElement("menuseparator"));
menuPopup.appendChild(document.createElement("menu")).setAttribute("label", "Меню кнопки");
var clone = menuPopup.lastChild.appendChild(document.getElementById("custombuttons-contextpopup").cloneNode(true));
clone.setAttribute("onpopupshowing", "document.popupNode = document.getElementById('" + _id + "')");



// Функция открывает настройки прокси в окне ...................
function openConnections() {
   for ( var win, nm = Services.wm.getEnumerator(null); win = nm.getNext(); ) 
         if ( win.name == 'Proxy') {
              win.focus();  
              break;
              }
   var win = openDialog("chrome://browser/content/preferences/connection.xul", "Proxy", "centerscreen");

   // добавить атрибут "prefwindow"
   win.addEventListener("load", function f(e) {
       this.removeEventListener("load", f, true); 
       e.target.documentElement.setAttribute("type", "prefwindow");
   }, true );
   
   // закрыть настройки прокси по клику на странице 
   gBrowser.addEventListener("click", function c() {
      this.removeEventListener("click", c );
      try { win.close() } catch(e) {}; 
   }, true );
};



// Функция открывает настройки прокси в вкладке ...................
function openConnectionsInTab() { 
   var connections = gBrowser.getBrowserForTab( gBrowser.selectedTab = gBrowser.addTab("chrome://browser/content/preferences/connection.xul") ); 
          
   // oбработчик ждет пока откроется прокси, удаляет себя и добавляет атрибут
   connections.addEventListener("pageshow", function c(e) {         
      this.removeEventListener(e.type, c);         
      e.originalTarget.documentElement.setAttribute("type", "prefwindow");
   })   
};



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



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



// Создаем меню для добавление прокси в контекстном меню выделенного текста на странице ...................
((contextMenu)=> {

  // создать новый пункт меню
  var menuitem = contextMenu.appendChild( document.createElement("menuitem") );      
  menuitem.setAttribute("label", "Добавить прокси"); 
  menuitem.setAttribute("class", "menuitem-iconic");
  menuitem.setAttribute("image", self.image);
  menuitem.onclick =()=> addNewProxy();
  addDestructor(()=> menuitem.remove() );
  
  // устанавливаем где показывать пункт меню 
  addEventListener("popupshowing", ()=>{
     menuitem.hidden = !cbu.getPrefs("CB.Proxy.inContextMenu") || !gContextMenu.isContentSelected; // !gContextMenu.isTextSelected;
  }, false, contextMenu);
  
  
  // добавление прокси
  function addNewProxy(sel) {  
     var selection = document.commandDispatcher.focusedWindow.getSelection().toString();
     var sel = ( sel == undefined ) ? selection : sel.toString();
     sel = sel.replace(/^\s+|\s+$/g, ""); // удалить пробелы, слева и справа от строки
     sel = sel.replace(/\s+/g,":"); // заменить пробелы внутри строки

     // если только порт ...
     if ( sel.length < 6 && isFinite(sel) ) { 
          sel = sel.replace(/:/g, "");
          var lab = 'порт';
          cbu.setPrefs("network.proxy.http_port", +sel);                    
          }
     
     // если только адрес ...
     if ( sel.length > 5 && !/:/.test(sel) && sel.split(".").length == 4 ) {   
          var lab = 'адрес';
          cbu.setPrefs("network.proxy.http", convertFromUnicode("UTF-8", sel));  
          }   
     
     // если адрес и порт ...    
     if ( sel.length > 5 && /:/.test(sel) && sel.split(":").length == 2 && sel.split(".").length == 4 ) {
          var lab = 'адрес и порт';
          var array = sel.split(":");  
          array.forEach((str)=> addNewProxy(str) );          
          }     

     if ( lab == undefined ) return;

     // всплывающая подсказка рядом с выделенным текстом ...     
     function showTooltip() {
        var tooltip = gBrowser.appendChild( document.createElement("tooltip") );
        tooltip.style.cssText = "color: red !important; font-weight: bold !important; font-size: 14px !important; -moz-box-orient: horizontal; text-align: center;";
   
        var image = tooltip.appendChild( document.createElement("image") );
        image.setAttribute("src", self.image);
   
        var label = tooltip.appendChild( document.createElement("label"));
        label.setAttribute("value", "Установлен " + lab + " прокси: " + sel);
    
        var focused = document.commandDispatcher.focusedWindow;
        var selection = focused.getSelection().getRangeAt(0).getBoundingClientRect();
        var posX = focused.mozInnerScreenX + selection.left;
        var posY = focused.mozInnerScreenY + selection.bottom - 5;   

        tooltip.showPopup(gBrowser, posX, posY);
        setTimeout(()=> gBrowser.removeChild(tooltip), 3000[firefox]);
     };
     showTooltip();    
  };
   
})(document.getElementById("contentAreaContextMenu"));

Отсутствует

 

№1485701-08-2020 21:10:43

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

Re: Custom Buttons

Duche пишет

отстают на один час от системных

Может это RFP так выкрутасничает.
В любом случае, можно подвести на час вперёд

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

аналог

Выделить код

Код:

...
      var now = new Date();
      now.setHours(now.getHours() + 1);

цифра

Выделить код

Код:

//var myGMToffset = (offset/60)*-1;
var myGMToffset = (offset/60)*-1 + 1;

Duche пишет

Код "Proxy"

Не души тёмнозелёным, возьми лучше какой-нибудь такой.
Иконки, надеюсь, сам сможешь заменить.

Отсутствует

 

№1485802-08-2020 13:21:23

Duche
Участник
 
Группа: Members
Зарегистрирован: 07-02-2016
Сообщений: 208
UA: unknown 0.0

Re: Custom Buttons

Dumby.  Спасибо большое за отзывчивость и реальную помощь. Всё заработало.
Еще одна хотелочка и можно отказаться от расширений и полностью переходить на FF71

Три кода: Первые два не работают на FF71 а третий код "Двойным левым кликом на папке закладок добавлять закладку в папку закладок" работает но долго 15 секунд висит "транспарант" что закладка добавлена.

Первый "CB drag and go"

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

Выделить код

Код:

// CB drag and go, от 09.01.2017.перетаскивая выделенного текста левой клавишей на странице. ..................

({

  link: 
        {
        U: {
            name: "Открыть ссылку в новой активной странице", cmd: ()=> {
               gBrowser.selectedTab = gBrowser.addTab(self.link);
           }},
        //D: {
            //name: "Открыть ссылку в новой активной странице", cmd: ()=> {
               //gBrowser.selectedTab = gBrowser.addTab(self.link);
           //}}, 
        D: {
            name: "Открыть ссылку в новой фоновой странице", cmd: ()=> {
               gBrowser.addTab(self.link);
           }},      
        },
           
  text: 
        {
                U: {
            name: "Поиск текста поисковиком по умолчанию в новой активной странице", cmd: ()=> {
               var submission = Services.search.currentEngine.getSubmission(self.text, null);
               gBrowser.loadOneTab(submission.uri.spec, null, null, submission.postData, false, false);
               
           }},
        D: {
            name: "Поиск текста поисковиком по умолчанию в новой фоновой странице", cmd: ()=> {
               var submission = Services.search.currentEngine.getSubmission(self.text, null);
               gBrowser.loadOneTab(submission.uri.spec, null, null, submission.postData, false, false);
           }},
        },
        
  init: function() {
     self.this = this;

     // создать подсказку у кнопки
     
     var arr = [];
     ["link", "text"].forEach(ob=> {
        arr.push("\n" + ob);
        for (var key in this[ob]) arr.push(key + ':' + ["     ", "   ", " "][key.length-1] + this[ob][key].name);
     });
     self.tooltipText = self.label + "\n" + arr.join("\n");
     
     ["dragstart", "dragover", "drop"].forEach(type=> addEventListener(type, this, false, gBrowser));
  },
  
  convertFromUnicode: function(charset, str) {
     var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
     converter.charset = charset;
     str = converter.ConvertFromUnicode(str);
     return str + converter.Finish();
  },

  handleEvent: function(e) {
     if ( !content.location.protocol.startsWith("http") ) return; // если не http(s) страница

     switch (e.type) {
        
        case "dragstart": {
           self.lastDirection = "";
           self.currentPoint = [e.screenX, e.screenY];
     
            
           // получить перетаскиваемый элемент, текст или адрес ссылки или изображения
           self.el = e.target;
           self.text = e.dataTransfer.getData("text/unicode");
           self.img = e.dataTransfer.getData("application/x-moz-file-promise-url").split("\n")[0];
           var textLink = /^([a-z]+:\/\/)?([a-z]([a-z0-9\-]*\.)+([a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel)|(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(:[0-9]{1,5})?(\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(\?[a-z0-9+_\-\.%=&amp;]*)?)?(#[a-z][a-z0-9_]*)?$|^custombutton:\/\/\S+$/.test(self.text);
           self.link = textLink ? self.text : e.dataTransfer.getData("text/x-moz-url").split("\n")[0];
           
           // получить и обявить тип перетаскиваемого элемента
           self.type = (self.img || self.link) ? "link" : "text";
           
           break;
           }
           
    case "dragover": {
           Cc["@mozilla.org/widget/dragservice;1"].getService(Ci.nsIDragService).getCurrentSession().canDrop = true;
           
           // получить направление перетаскивания, L налево, R направо, U верх, D вниз
           var [subX, subY] = [e.screenX - self.currentPoint[0], e.screenY - self.currentPoint[1]];
           var [distX, distY] = [(subX > 0 ? subX : (-subX)), (subY > 0 ? subY : (-subY))];
           if ( distX < 10 && distY < 10 ) return;
           var direction = distX > distY ? (subX < 0 ? "L" : "R") : (subY < 0 ? "U" : "D");
           self.currentPoint = [e.screenX, e.screenY];
                      
           // получить весь жест, указать код жеста и показать подсказку жеста
           if ( direction != self.lastDirection.split('').pop() ) {
                self.lastDirection += direction;
                var dir = self.lastDirection, ob = this[self.type][dir];
                
                this.cmd = ob ? ob.cmd : "";
                XULBrowserWindow.statusTextField.label = ob ? "Жест мыши: " + dir + "   " + ob.name : "Неизвестный жест мыши: " + dir;
                }

           break;
           }
        
    case "drop": {
           // если перетаскивается в поле текстового ввода или из-за пределов окна браузера
           if ( !self.currentPoint || e.target instanceof Ci.nsIDOMNSEditableElement ) return;
           e.preventDefault();

           // запустить код жеста и сбросить подсказку жеста
           this.cmd && this.cmd();
           XULBrowserWindow.statusTextField.label = "";
           }
    }
   }
}).init();



Второй Autocopy+3


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

Выделить код

Код:

// Autocopy+3 от 26.12.2013.

// Настройка функций кликов мыши для кнопки ................................
this.onclick = function(e) {
   if ( e.button == 0 ) cbu.setPrefs("Autocopy", !cbu.getPrefs("Autocopy") ); 
       
   if ( e.button == 2 ) { 
        e.preventDefault();  
        menuPopup.showPopup( this, -1, -1, "popup", "bottomleft", "topleft");
        }     
}; 



// Проверить наличие строк в 'about:config' и создать если не существует ................................
if ( !cbu.isPref("Autocopy.saveWithDoubleClick") ) {
     ["Autocopy", "Autocopy.reset", "Autocopy.selectingTextBlink", "Autocopy.selectWithDoubleClick",
      "Autocopy.copyWithDoubleClick", "Autocopy.saveWithDoubleClick"].forEach(function(pref) { cbu.setPrefs( pref, false ) });
};



// Создать меню ................................
var array = [
    { label: 'Выключать автокопирование при выходе из браузера', value: 'Autocopy.reset' },
    { label: 'Выделенный текст мигает при автокопировании', value: 'Autocopy.selectingTextBlink' },
    { separator: ''},
    { label: 'Двойной правый клик мыши копирует выделенный текст', value: 'Autocopy.copyWithDoubleClick' },
    { label: 'Двойной левый клик мыши выделяет все в текстовых полях', value: 'Autocopy.selectWithDoubleClick' },
    { label: 'Двойной правый клик мыши сохраняет изображение без запроса', value: 'Autocopy.saveWithDoubleClick' }, 
    { label: 'Средним кликом вставлятъ текст с заменой выделенного текста', value: 'middlemouse.paste' }
];

var menuPopup = self.appendChild( document.createElement("menupopup") );
array.forEach(function( m ) {
    if ( "separator" in m ) { menuPopup.appendChild( document.createElement("menuseparator") ); return };
    var mItem = document.createElement("menuitem");
    mItem.setAttribute("label", m.label);
    mItem.setAttribute('type', 'checkbox');
    mItem.setAttribute('checked', custombuttons.getPrefs( m.value ) );
    mItem.setAttribute('onclick', 'custombuttons.setPrefs("' + m.value + '", !custombuttons.getPrefs("' + m.value + '"))');  
    menuPopup.appendChild( mItem );
});
menuPopup.setAttribute("onclick", "event.stopPropagation()");

// добавить стандартное контекстное меню ....
menuPopup.appendChild( document.createElement("menuseparator") );
menuPopup.appendChild( document.createElement("menu") ).setAttribute("label", "Меню кнопки");
var clone = menuPopup.lastChild.appendChild( document.getElementById("custombuttons-contextpopup").cloneNode(true) );
clone.setAttribute("onpopupshowing", "document.popupNode = document.getElementById('" + _id + "')");



// Установить нужную иконку кнопки при старте браузера или при изменениях настроек в 'about:config' ................................
const s = "Autocopy";
function toggleImage() {  
    self.image = cbu.getPrefs(s)
    ? "data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QA/wD/AP+gvaeTAAAAB3RJTUUH1gUCFysoMPbyDwAABE5JREFUOI2NlV1sFFUUx39z73S/6C67s6UsQisWAgZBKRTUhBhDJAhEoyQ2QqMlhjcSP158MMYHoo+YGF5MjNCHqkmJKJpgaYAEFYhalWio2EWXpZgIS3G3uzu783Hn+tAPW2zRk5zcySTnd//nf+fMNfr6+qK1Wq1Fa50BWoCMlLJNSrkUWBIEwUKlVFJKWRZCDPu+3+O67sd79+69xR3C6Onp0alUyrYsSyeTSdHY2BiKxWIyEokQCoVoaGhgdHSUQqGAEALXdf1sNuvX6/WD4XB4f2dnZ2VWcG9vb6mrqyvheR5aa4IgmFonn33fx/O8qfR9H9u2g6Ghoeu2ba+eTb1pGEZJKZWwbRut9axtpVIpgiCY2sBxHJLJpIhGo5nBwcGXgTdurxGGYYz6vo9hGHP6FQQBUkrK5TK5XI5qtUosFiOdThuGYSyfrcYECq7r3hHsOA6u6zI2NkZLSwsAWmtM06Rx9MLKi7sj+UCqpBf1ztg+XZsOURZa6/8Eu64LgGVZU++01ri/n+NRZbWveun71tVbjiWWRNq3zWvgHQAhhFBBEMwJnSuql04j3RrRrdsN74lXKR88QqRpp6k8dgEIpZQ316HNFfalUxh/ZZm/PIrHm1x/aw038yPYbhEhGAUQeoJ6JytmKB0aQJav0LR+FfLas0Sv96GXVTBe6OBG8aijFPsmwbbv+/8LWvn5OGZ1hKZ1K5HXdkFxDOoWSQlF2e84tdyeDYc5BmBKKRuFEHN+wzB+UJWfPiPs3yK9fiXyaheUxsBJ44a2MXL881pQyO/ZcIi+yRpTax2fC6y1Hode+JQIZdLty5FXd0OpDE4TrrmVX0+cw72Z7+44xJHptUJKmbjd3+mjXfnxCFEqpNe2IfO7oVgGZwGu+TiXT33Dbwu2qY73Z0IBBDBPSjmlbnqODX5EVDhYa5eOQ0sV8Jpxza1kT54ntX0/lYUP1WezTwRBkJi0YvrPZ+zbXuaFNNYDrdOgC8ehA2eJbH6N2OrtBEHgAPJ2sAlEDcNAKfVP+4MfMj+VInnvAkTuGShVwc3gNGwhe+IrQptfRy99hGKxiO/79QmOBqYmTWito4ZhzLDAufgJ1sZORHwVXvg58BbhmI+R/eJL3I2vUEyuoVqtUq/XUUrVJiwV/1IshCAUCqGUwisXiLdtBKOOU7xJPbaTsKwx3H+a0v37MJrXIZVCa02tVgMoTKidMQym7/tWf3+/a1mWE4/HzUhuILJi01OGcmoEQRhcn+H+M5TbX0S0PsykiHg8ju/7BEEwCqQBeyIdALO7u1scOHCgNZ/PrwiFQm0dv7y9/4e7Hmy+r3SeP08e5sbwd2Sbn/ak16wW1+sik8mEEokEsViMfD5PoVAoAhngyiQUxm8QDeSBq4A8+7zxbum9Jy8fvVX74MRlBr6uLCns2KEXtYiRxcVisSWXyy0Lh8MrDMO4Wyl1j23bfwCXgOp0K/4GqDBYgeGFbWEAAAAASUVORK5CYII="
    : "data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAEj0lEQVR42n2Vf0xbVRTHv49HSwsFSvmxmtLBmMOZ6TYYcyNbYoQAMUAIRFEoyJxEidOYLP6jC8ZgImpCTGb8wwiMAS0bxD8WI4FGDIOamYBi9odaysY6wIGlBVqgfa+/PO+5kraAN7npu/f2fu4533Puuczg4KDc7XZrg8GgGoCWuppl2Rzq2fSdGQgEDvj9fiWNXTExMbM+n6+H5/nvmpubHfifxvT09ARTUlK2VSpVUKlUxigUCml8fDwrk8kglUohkUhgt9ths9lAYBDUZ7FYfB6P56u4uLi22trazT3B/f39G7qGhqTQhMftBlkPslTswjdZCa/Xu9OF8ZHcXPH/XZ2dqXtZz+j1+of1Op02NLG+trbr9OTkZPGQ0AGKxMSdNYNe/4lOp/toF9hgMMzU1NScjCPX94MnEog0xurqKtLS03fm7TQ2Go0D9dT2AhsrKipKEpOSotd2DhC0Jm2hTEmJWN9YX8dE36e/Hb5zNS3A+pVeuff2tg+6891wCVLoy8rK6ikQES5GWx4NdTmd8MyZIJu4G0wsrGRgtsI2fcW3xM305X2Di8zAwEBvcXFxo1wuFzWMhgjw6LEYZMttSAN+JCUfQfD5D+DJygAqczD7oNVT0A25kBVdJSUlFynF9gTv5cH2X2NgnfNIO3UMvK0HdlMOvFemEf/mCfy93LGU34lMpq+vr7O0tPSNhIQEMeL7uR6Cbv1hROzWAtLynwa7WEcLTiwE3oHfqIBr8ybHbc2/cvoabjG9vb1XSYp3hZQKgfezeHFCD4nnEUGfIqhOhMKjgktej3tGE+db/v3C6S7cCOVxd1FR0et040Qp9oOGmt/+PdiHBN0gKJcKXvIi5kYn3R6b9cKpbgzupBtpPEQavyQELzrl1hwO8eapUlMj6ePUuTTwsWUwG++AX71fW9CFoYg8pqwYJSlK0zMyIvY6qD4IbXNmiELMIb34vYh1fqwBc2O/YFZV5q9+/+vYXReEwKZX6+rORUMFS12/3kCCxA/ViWywVnI/P7LePDIZMDbv32psbFTsApPGd6lWPBuaEK6pCJ3SQyFnoTqeSdAG0nQL8B4ASlciAL3XrzuampoEd/3RYAuBnxQGq1QaBejmtAHJFETl0XTEzL/8H5RXg5OUwDI6iWc+fxBpHSAUGiGlAuHBW6ysrNQIqRYqk47eWhy9PAIEV+A1fwbJ0i1wbDEsI5Pgz16GL/MsnjtzJhwc/xjsCwfbq6qqVAKQXgp4XTbwU99CU/0huLV78DgdiLuvx+zIT9g4fglM9jmx0glZdDIvLwSW048nwgvhBaFbx9MLwlF5jJXNG2W5519gYlWHwG/awTsWYO18G668S8DBQvEVEaodvTZi3o+Pj//Q0tLyFrG2H3dOBJOlTEdHx0H6zqUNOQV/ftyG+psZx1KdWP7xGv6ZnYIlo9rLZhX6NRpNjFqtliZRvgu1xWq1Ynh4WN/a2vol7ReEt4fJEy4V2J9fY7wbkM2tONz60TkYTZuZtvLy8ie0Wq2GPNIS8DCV2FyGYbJIukNms/mL9vb2Ntq7FS7Fv/ChKzVwIHr3AAAAAElFTkSuQmCC";
    
};  
toggleImage();
gPrefService.addObserver( s, toggleImage, false );
addDestructor(function() { gPrefService.removeObserver( s, toggleImage, false ) });  



// Выключать кнопку при закрытии браузера если это разрешено в 'about:config' ................................
var turnOffButton = {
    observe: function(subject, topic, data) {
       if ( cbu.getPrefs("Autocopy.reset") && data == "shutdown" ) cbu.setPrefs("Autocopy", false );  
    }
};
Services.obs.addObserver( turnOffButton, "quit-application", false);
addDestructor(function() { Services.obs.addObserver( turnOffButton, "quit-application", false ) });  



// Функции автоматически копирует выделенный текст на странице, если это разрешено в 'about:config' ................................
function autocopy(e) {
   if ( e.button == 2 ) return;

   if ( /input|password|textarea|textbox|searchbar|findbar|tabbrowser/.test( e.target.localName.toLowerCase() ) ) return;
   
   if ( e.type == 'mousedown' ) var lastSelection = getBrowserSelection();
   
   if ( e.type !== 'mouseup' ) return; 
   
   var selection = getBrowserSelection();
   if ( cbu.getPrefs("Autocopy") && selection && selection !== lastSelection ) {
        goDoCommand('cmd_copy');
         
        // выделенный текст мигает ....
        if ( !cbu.getPrefs("Autocopy.selectingTextBlink") ) return;
             document.activeElement.blur();  
             setTimeout(function() { window.content.focus() }, 300);
        }
};
addEventListener("mouseup", autocopy, false, gBrowser );
addEventListener("mousedown", autocopy, false, gBrowser );



// Cредней кнопкой мыши вставить текст из буфера обмена в текстовые поля с заменой выделенного текста ................................
function middleMousePaste(e) { 
    if ( e.button == 1 && cbu.getPrefs('middlemouse.paste') ) {

         if ( /input|password|textarea|textbox|searchbar|findbar|cbeditor/.test( e.target.localName.toLowerCase() ) 
              && document.commandDispatcher.getControllerForCommand("cmd_paste") ) {
      
              e.preventDefault();
              e.stopPropagation();
               
              // вставить текст ....
              var cmd = "cmd_insertText"; 
              var commandDispatcher = ( this.document || document ).commandDispatcher; 
              var controller = commandDispatcher.getControllerForCommand(cmd);
  
              if ( controller && controller.isCommandEnabled(cmd) ) {
                   controller = controller.QueryInterface(Components.interfaces.nsICommandController);
                   var params = Components.classes["@mozilla.org/embedcomp/command-params;1"]
                                          .createInstance(Components.interfaces.nsICommandParams);
                   params.setStringValue("state_data", gClipboard.read() );    
                   controller.doCommandWithParams(cmd, params);
                   }
              }              
         }
};
addEventListener("click", middleMousePaste, true, document.documentElement );



// Дополнительные возможности для значка идентификации сайта в строке адреса ................................
addEventListener("click", function(e) { 
   e.preventDefault();
   e.stopPropagation();
   
   // ЛКМ без запроса открывает информацию о странице в вкладке 'Разрешения' ....
   if ( e.button == 0 ) {
        var doc = content.document;
        BrowserPageInfo( doc, ( (doc.location.protocol).slice(0,4) == "http") ? "permTab" : "generalTab" );
        }
        
   // ПКМ копирует текущий адрес ....     
   if ( e.button == 2) { 
        gClipboard.write( content.location );
                 
        // значок идентификации сайта мигает красным ....
        document.getElementById("identity-box").setAttribute("style", "background: red;");
        setTimeout(function() { document.getElementById("identity-box").removeAttribute("style") }, 500);
        }
}, true, document.getElementById("identity-box") );

   
   
// Дополнительные возможности для двойного клика мыши, если это разрешено в 'about:config' ................................
function handleDblClick(e) {

  var node = e.target;
  var editor = node.editor;
  
  // выделить все в текстовых полях ....
  if ( e.button == 0 && custombuttons.getPrefs("Autocopy.selectWithDoubleClick") ) {    
       e.preventDefault();

       if ( /input|textbox|textarea/.test( node.localName ) ) !editor ? node.select() : editor.selectAll();
       }
           
  // сохранить изображение без запроса ....    
  if ( e.button == 2 && cbu.getPrefs("Autocopy.saveWithDoubleClick") && node.localName == 'img' ) {
       saveImageURL( gContextMenu.imageURL, 0, 0, 0, 1, null, content.document );
       setTimeout(function() { document.getElementById("contentAreaContextMenu").hidePopup() }, 20);
       }      
       
  // скопировать выделенный текст ....
  if ( e.button == 2 && cbu.getPrefs("Autocopy.copyWithDoubleClick") && !/findbar|tabbrowser/.test( node.localName ) ) { 
       e.preventDefault();
       !editor ? goDoCommand("cmd_copy") : editor.copy();       
       try {        
           var box = ( node.textbox || node ).inputField.parentNode;
           var popup = box.ownerDocument.getAnonymousElementByAttribute( box, "anonid", "input-box-contextmenu");
           setTimeout(function() popup.hidePopup(), 50);
           }
       catch(e) { document.getElementById("contentAreaContextMenu").hidePopup() }; 
       }        
};
addEventListener("dblclick", handleDblClick, false, gBrowser );



// Наблюдатель следит за открытием окон адреса которых указанны в коде и добавляет им обработчики ................................
var observer = {  
       observe: function(subject, topic, data) {
          subject.addEventListener("load", this, false);
          },
      
       handleEvent: function(e) {
          var doc = e.target;
          var win = doc.defaultView;
          var href = doc.location.href; 
          win.removeEventListener("load", this, false);
         
          // закрывать 'Информацию о странице' или 'Библиотеку' двойным кликом на ней ....            
          if ( /pageInfo.xul|places.xul/.test( href ) ) {
          
               win.addEventListener("dblclick", function close() { this.close() }, true);
                         
               win.addEventListener("unload", function(e) {
                   win.removeEventListener(e.type, arguments.callee, false);
                             
                   win.removeEventListener("dblclick", close, true);
                   }, false);                  
               };
    
          // добавлять и удалять обработчики клика для редактора Custom Buttons ....
          if ( href.substring(0, 41) == "chrome://custombuttons/content/editor.xul" ) { 

               win.addEventListener("click", middleMousePaste, true );
               win.addEventListener("dblclick", handleDblClick, false );
          
               win.addEventListener("unload", function(e) {
                   win.removeEventListener(e.type, arguments.callee, false );
          
                   win.removeEventListener("click", middleMousePaste, true );
                   win.removeEventListener("dblclick", handleDblClick, false );
                   }, false);
               };
      }
};
Services.obs.addObserver(observer, "domwindowopened", false);
addDestructor(function() { Services.obs.removeObserver(observer, "domwindowopened", false) }); 



// Подсказка для кнопки ................................
this.tooltipText = "Autocopy \nЛ: Переключить автоматическое копирование \nП: Меню + CB меню";



Третий "Двойным левым кликом на папке закладок добавлять закладку в папку закладок"


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

Выделить код

Код:

// Двойным левым кликом на папке закладок добавлять закладку в папку закладок, от 06.06.2019. ......................
addEventListener("dblclick", (e, targ = e.originalTarget)=> {     
   if ( e.button || !targ._placesNode || !PlacesUtils.nodeIsFolder(targ._placesNode) ) return;          
   
   var docTitle = gBrowser.selectedTab.label.substr(0, 50);
   var folderId = PlacesUtils.getConcreteItemId(targ._placesNode);
   var folderTitle = PlacesUtils.bookmarks.getItemTitle(folderId);
   var currentURI = Services.io.newURI(gBrowser.currentURI.spec, null, null);
   PlacesUtils.bookmarks.insertBookmark(folderId, currentURI, 0, docTitle);  

   // всплывающая подсказка ....
   var favicon = gBrowser.selectedTab.image || "chrome://global/skin/icons/Portrait.png";
   Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService)
   .showAlertNotification(favicon, "Добавил в папку " + folderTitle + ":", docTitle);

   setTimeout(()=> { document.getElementById("bookmarksMenuPopup").hidePopup() }, 50);
  
});

Отредактировано Duche (02-08-2020 16:27:27)

Отсутствует

 

№1485902-08-2020 19:08:32

Vitaliy V.
Участник
 
Группа: Members
Зарегистрирован: 19-09-2014
Сообщений: 2186
UA: Firefox 79.0

Re: Custom Buttons

egorsemenov06 пишет

две кнопки

Вместо ваших двух кнопок достаточно одной в расширении Async Run Applications https://github.com/VitaliyVstyle/Vitali … xperiments

Отсутствует

 

№1486002-08-2020 20:23:00

Vitaliy V.
Участник
 
Группа: Members
Зарегистрирован: 19-09-2014
Сообщений: 2186
UA: Firefox 80.0

Re: Custom Buttons

egorsemenov06
Это расширение подписать нельзя, только отключать проверку подписи или использовать Firefox Developer Edition.
Актуальный код спросите подскажут для этого.

Отсутствует

 

№1486102-08-2020 20:44:34

Vitaliy V.
Участник
 
Группа: Members
Зарегистрирован: 19-09-2014
Сообщений: 2186
UA: Firefox 80.0

Re: Custom Buttons

egorsemenov06
Ну для user_chrome_files наподобие этого https://forum.mozilla-russia.org/viewto … 54#p782454
можно сделать только с кнопкой, или можете использовать contextmenuopenwith. Ну а с интерфейсом для добавления приложений как в расширении увольте.

Отредактировано Vitaliy V. (02-08-2020 20:45:40)

Отсутствует

 

№1486203-08-2020 10:29:36

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

Re: Custom Buttons

Duche

Duche пишет

Третий "Двойным левым кликом на папке закладок добавлять закладку в папку закладок"

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

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

Выделить код

Код:

// Двойным левым кликом на папке закладок добавлять закладку в папку закладок, от 06.06.2019. .............................................................
addEventListener("dblclick", (e, targ = e.originalTarget)=> {     
   if ( e.button || !targ._placesNode || !PlacesUtils.nodeIsFolder(targ._placesNode) ) return;          
   
   var docTitle = gBrowser.selectedTab.label.substr(3, 50);
   var folderId = PlacesUtils.getConcreteItemId(targ._placesNode);
   var folderTitle = PlacesUtils.bookmarks.getItemTitle(folderId);
   var currentURI = Services.io.newURI(gBrowser.currentURI.spec, null, null);
   PlacesUtils.bookmarks.insertBookmark(folderId, currentURI, 0, docTitle);  

   // всплывающая подсказка ....
Components.utils.import('resource://gre/modules/PopupNotifications.jsm');
var notify  = new PopupNotifications(gBrowser,
                    document.getElementById("notification-popup"),
                    document.getElementById("notification-popup-box"));

var notification =  notify.show(
// browser
gBrowser.selectedBrowser,
// popup id
"PDES-popup",
// message
"Добавил в папку " + folderTitle + ":",
// anchor id
null,
// main action
null,
// secondary action
null,
// options
{ 
  // Alternative way to set the popup icon
  popupIconURL: gBrowser.selectedTab.image || "chrome://global/skin/icons/Portrait.png"
}
);

setTimeout(function(){
  notification.remove();
}, 2000); // Time in milliseconds to disappear the door-hanger popup.
});

Насчет Autocopy+3, где-то здесь Dumby выкладывал

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

Выделить код

Код:

/*Initialization Code*/
this.closest("toolbarpaletteitem") || (script => {
    var id = `CB${_id.slice(20)}:Autocopy`, pid = id + "Parent";
    var nsvoStr = `Components.utils.import("resource://gre/modules/Services.jsm", {})`;
    var nsvo = eval(nsvoStr), {Services} = nsvo, parent = nsvo[pid];
    if (!parent) {
        var cid = id + "Child", u = code => "data:," + encodeURIComponent(code);
        var pref = "CB.Autocopy.settings", topic = "quit-application-granted";
        var PREF_ENABLED = 1, PREF_BLINK = 2, PREF_RESET = 4;

        (parent = nsvo[pid] = {
            init() {
                this.readSettings();
                if (!this[PREF_ENABLED]) return;
                this.initChild();
                if (this[PREF_RESET]) this.setObserver(true);
            },
            destroy(reason) {
                var ud = reason[5] == "e";
                if (ud || !this.obsAdded) this.saveSettings();
                delete nsvo[pid];
                if (reason == "delete") Services.prefs.clearUserPref(pref);
                if (!this[PREF_ENABLED]) return;

                this.destroyChild();
                if (ud && this[PREF_RESET]) this.setObserver(false);
            },
            get processURL() {
                delete this.processURL;
                this.frameURL = u(`${nsvoStr}["${cid}"].init(this);`);
                return this.processURL = u(script.replace(/%ID%/g, cid)
                    .replace("%NSVO%", nsvoStr)
                    .replace("%PREF%", pref)
                    .replace("%PREF_BLINK%", PREF_BLINK)
                );
            },
            get frameURLDestroy() {
                delete this.frameURLDestroy;
                this.processURLDestroy = u(`${nsvoStr}["${cid}"].forget();`);
                return this.frameURLDestroy = u(`${nsvoStr}["${cid}"].destroy(this);`);
            },
            initChild() {
                Services.ppmm.loadProcessScript(this.processURL, true);
                Services.mm.loadFrameScript(this.frameURL, true);
            },
            destroyChild() {
                Services.mm.removeDelayedFrameScript(this.frameURL);
                Services.mm.loadFrameScript(this.frameURLDestroy, false);
                Services.ppmm.removeDelayedProcessScript(this.processURL);
                Services.ppmm.loadProcessScript(this.processURLDestroy, false);
            },
            readSettings() {
                var val = Services.prefs.getIntPref(pref, 3);
                for(var setting of [PREF_ENABLED, PREF_BLINK, PREF_RESET])
                    this[setting] = Boolean(val & setting);
            },
            saveSettings() {
                var settings = 0;
                for(var setting of [PREF_ENABLED, PREF_BLINK, PREF_RESET])
                    if (this[setting]) settings += setting;
                Services.prefs.setIntPref(pref, settings);
            },
            btns: new Set(),
            register(btn) {
                this.btns.add(btn);
                btn._handleClick = this.click;
                btn.oncontextmenu = this.context;
                this.setImg(btn, this[PREF_ENABLED]);
            },
            unregister(btn, reason) {
                this.btns.delete(btn);
                if (!this.btns.size) this.destroy(reason);
            },
            setImg(btn, state) {
                (btn.icon || btn.ownerDocument.getAnonymousElementByAttribute(
                    btn, "class", "toolbarbutton-icon"
                )).src = state
                    ? "data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAgMBAAQIAAcEBwAIBAcACAQHAAgEBwAIBAcACAQHAAgEBwAIBAcACAMEAQEAAAAAAAAAAAAAAAACAwADAAAAABUnAB9cqgC3a7wB4Gq5Ad1qugHearoB3mq6Ad5qugHearoB3mi4AN1qugHgYrMAxR43AC8AAAAAAAEAAAECAAQAAAQAV6AAprP9Vv/W/qn80/+f/9T/ov/U/6L/1P+i/9T/ov/U/6L/1/+n/9X+pfy3/WL/Y7QAvwEAAQAAAAAAFSgAH1ehAKlyzwD1htgf/YzcJ/2K2yP9i9sk/YvbJf2L2yX9i9sm/YnaIv2b4kP92/21/Nf+qv9quwHdBQkACAAAAQBeqwCzr/tR/8X0j/u+8X//vvJ//77ygP++8oD/vvKA/77yf/+98n7/wvSH/4zcKv+e4kv93v+0/2i5AN0DBwAIBQkACGu8AdzV/af/4v/B/d//u//h/7//4f+//+H/v//h/7//4f+//9/+u//n/8n/w/GK/4zaK/3g/7r/aroC3gMHAAgEBwAIarkC3dX/pf/g/sD93v67/9/+vv/g/r//4P6//+D+v//f/r7/3f66/+T/xv/B8Yb/j9st/eT/w/9qugPeAwcACAQHAAhqugLe2v+w/+j/z/3l/8r/5//N/+f/zv/n/87/5//O/+f/zf/l/sj/7P/W/8Xyj/+Q2y/96f/N/2q6A94DBwAIBAcACGq6At7f/7n/7v/c/ev/1v/t/9n/7f/a/+3/2v/t/9r/7f/Z/+r+1f/y/+P/yPKW/5DbMf3s/9X/aroE3gMHAAgEBwAIaroC3uP/wf/z/+j98P/h//L/5P/z/+X/8//l//P/5f/y/+T/8P7g//j/7v/L8p3/kdsy/fD/3P9rugTeAwcACAQHAAhqugLe5v/J//j/8v31/+r/9v/t//f/7v/3/+//9//u//b/7f/0/un//f/4/87yo/+R2zL98f/f/2q5Bd0DBwAIBAcACGq6At7p/8///P/6/fj/8f/6//T/+v/1//r/9f/6//X/+v/0//f+8P//////0fGo/5PbNf30/+f/a7wE3AQJAAgEBwAIabkC3er/0f/+//79+v/0//v/9//8//j//P/4//z/+P/7//f/+f70///////T8qz/i9go+8P9ef9dqwCzAAACAAUJAAhquwHd7f7a//////z+//39/////f////3////9/////f////39/vz9/////dzzvv5v0AD1VqECqRUnAB8AAAAAAQACAGK0AL/J/Yf/8v7k/O3/1//u/9n/7v/Z/+7/2f/u/9n/7v/Z/+3/1//x/eP8vfxu/1WgAKYAAAUAAQIABAABAAAAAAAAHjcALmGzAMVquwLgarkC3Wq6At5qugLearoC3mq6At5qugLearkC3Wu8AeBbqgC3FScAHwAAAAACAwADAAAAAAAAAAAAAAAAAwQCAQQIAAgEBwAIBAcACAQHAAgEBwAIBAcACAQHAAgEBwAIBAgABwMDAgAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
                    : "data:image/x-icon;base64,AAABAAEAEREAAAEAIADwBAAAFgAAACgAAAARAAAAIgAAAAEAIAAAAAAAyAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAgEDAAQACAcEAAcIBAAHCAQABwgEAAcIBAAHCAQABwgEAAcIBAAHCAMBBAEAAAAAAAAAAAAAAAACAAMDAAAAABUAJx9cAKq3awG84GoBud1qAbreagG63moBut5qAbreagG63mgAuN1qAbrgYgCzxR4ANy8AAAAAAAABAAEAAgQABAAAVwCgprNW/f/Wqf7805///9Si///Uov//1KL//9Si///Uov//16f//9Wl/vy3Yv3/YwC0vwEBAAAAAAAAFQAoH1cAoalyAM/1hh/Y/Ywn3P2KI9v9iyTb/Ysl2/2LJdv9iybb/Yki2v2bQ+L927X9/Neq/v9qAbvdBQAJCAABAABeAKuzr1H7/8WP9Pu+f/H/vn/y/76A8v++gPL/voDy/75/8v+9fvL/wof0/4wq3P+eS+L93rT//2gAud0DAAcIBQAJCGsBvNzVp/3/4sH//d+7///hv///4b///+G////hv///4b///9+7/v/nyf//w4rx/4wr2v3guv//agK63gMABwgEAAcIagK53dWl///gwP793rv+/9++/v/gv/7/4L/+/+C//v/fvv7/3br+/+TG///BhvH/jy3b/eTD//9qA7reAwAHCAQABwhqArre2rD//+jP//3lyv//583//+fO///nzv//587//+fN///lyP7/7Nb//8WP8v+QL9v96c3//2oDut4DAAcIBAAHCGoCut7fuf//7tz//evW///t2f//7dr//+3a///t2v//7dn//+rV/v/y4///yJby/5Ax2/3s1f//agS63gMABwgEAAcIagK63uPB///z6P/98OH///Lk///z5f//8+X///Pl///y5P//8OD+//ju///LnfL/kTLb/fDc//9rBLreAwAHCAQABwhqArre5sn///jy//316v//9u3///fu///37///9+7///bt///06f7//fj//86j8v+RMtv98d///2oFud0DAAcIBAAHCGoCut7pz////Pr//fjx///69P//+vX///r1///69f//+vT///fw/v//////0ajx/5M12/305///awS83AQACQgEAAcIaQK53erR///+/v/9+vT///v3///8+P///Pj///z4///79///+fT+///////TrPL/iyjY+8N5/f9dAKuzAAIAAAUACQhqAbvd7dr+//////z+/f/9/////f////3////9/////f////39/P79/////dy+8/5vAND1VgKhqRUAJx8AAAAAAQIAAGIAtL/Jh/3/8uT+/O3X///u2f//7tn//+7Z///u2f//7tn//+3X///x4/38vW78/1UAoKYABQAAAQACBAAAAQAAAAAAHgA3LmEAs8VqArvgagK53WoCut5qArreagK63moCut5qArreagK53WsBvOBbAKq3FQAnHwAAAAACAAMDAAAAAAAAAAAAAAAAAwIEAQQACAgEAAcIBAAHCAQABwgEAAcIBAAHCAQABwgEAAcIBAAIBwMCAwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
            },
            click() {
                var newState = parent[PREF_ENABLED] = !parent[PREF_ENABLED];
                for(var btn of parent.btns) parent.setImg(btn, newState);
                newState ? parent.initChild() : parent.destroyChild();
                if (parent[PREF_RESET]) parent.setObserver(newState);
            },
            context(e) {
                if (e.ctrlKey || e.shiftKey) return;
                var btn = e.target;
                if (btn.btnPopup && e.detail > 1) return btn.btnPopup.hidePopup();
                e.preventDefault();
                (btn.btnPopup || parent.getPopup(btn)).openPopup(btn, "after_start");
            },
            getPopup(btn) {
                var win = btn.ownerGlobal, doc = win.document;
                var popup = doc.createElementNS(xulns, "menupopup");
                popup.setAttribute("onclick", "event.stopPropagation();");
                popup.setAttribute("oncommand", "handleCommand(event.target);");
                popup.setAttribute("onpopupshowing", "handlePopupshowing();");
                popup.menuitems = [];
                for(var [lab, pref] of win.Object.entries({
                    "Выделенный текст мигает при автокопировании": PREF_BLINK,
                    "Выключать автокопирование при выходе из браузера": PREF_RESET
                })) {
                    var menuitem = popup.appendChild(doc.createElementNS(xulns, "menuitem"));
                    menuitem.setAttribute("label", lab);
                    menuitem.setAttribute("type", "checkbox");
                    menuitem.pref = pref;
                    popup.menuitems.push(menuitem);
                }
                popup.handleCommand = menuitem => {
                    var newState = this[menuitem.pref] = menuitem.hasAttribute("checked");
                    if (!this[PREF_ENABLED]) return;

                    if (menuitem.pref == PREF_BLINK)
                        this.saveSettings(),
                        Services.ppmm.broadcastAsyncMessage(cid + ":FromParent", {blink: newState});
                    else if (menuitem.pref == PREF_RESET)
                        this.setObserver(newState);
                }
                popup.handlePopupshowing = () => {
                    for(var menuitem of popup.menuitems) this[menuitem.pref]
                        ? menuitem.setAttribute("checked", true)
                        : menuitem.removeAttribute("checked");
                }
                return btn.appendChild(btn.btnPopup = popup);
            },
            obsAdded: false,
            setObserver(set) {this.obsAdded = set
                ? Services.obs.addObserver(this, topic, false)
                : Services.obs.removeObserver(this, topic);
            },
            observe() {
                Services.obs.removeObserver(this, topic);
                this[PREF_ENABLED] = false;
                this.saveSettings();
            }
        }).init();
    }
    parent.register(this);
    addDestructor(reason => parent.unregister(this, reason), parent);

})(`(nsvo => (nsvo["%ID%"] = {
    x: -1, y: -1, down: false,
    handleEvent(e) {e.button || this[e.type](e);},
    mousedown(e) {this.x = e.screenX; this.y = e.screenY, this.down = true;},
    mouseup(e) {
        var {down} = this; this.down = false; if (!down) return;
        if (e.screenX == this.x && e.screenY == this.y && (e.detail == 1 || e.target.matches(
            "textarea[disabled],input[disabled],button,select,summary"
        )))
            return;
        var name = e.originalTarget.nodeName;
        if (/^(?:(?:xul:)?(?:slider|scrollbarbutton)|resizer)$/.test(name))
            return;
        this.x = this.y = -1;
        var win = this.getFocusedWin(e.target.ownerGlobal);
        var sel = win.getSelection();
        if (sel.toString()) {
            (win.docShell || win.document.docShell).doCommand("cmd_copy", null, win);
            this.blinkEnabled && this.blink(win, e.detail > 1);
        }
    },
    blinkEnabled: Boolean(
        Components.classes["@mozilla.org/preferences-service;1"]
            .getService(Components.interfaces.nsIPrefService)
            .getIntPref("%PREF%", 3) & %PREF_BLINK%
    ),
    blink(win, pause) {
        if (pause) return win.setTimeout(() => this.blink(win), 100);
        var sc = (win.docShell || win.document.docShell)
            .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
            .getInterface(Components.interfaces.nsISelectionDisplay)
            .QueryInterface(Components.interfaces.nsISelectionController);
        sc.setDisplaySelection(sc.SELECTION_OFF);
        sc.repaintSelection(sc.SELECTION_NORMAL);
        win.setTimeout(() => {
            sc.setDisplaySelection(sc.SELECTION_ON);
            sc.repaintSelection(sc.SELECTION_NORMAL);
        }, 150);
    },
    getFocusedWin(win) {
        var focusedWin = {};
        var elm = this.fm.getFocusedElementForWindow(win.top, true, focusedWin);
        return focusedWin.value;
    },
    get fm() {
        delete this.fm;
        return this.fm = Components.classes["@mozilla.org/focus-manager;1"]
            .getService(Components.interfaces.nsIFocusManager);
    },
    count: 0,
    init(cfmm) {
        this.count += 1;
        cfmm.addEventListener("mousedown", this);
        cfmm.addEventListener("mouseup", this);
        cfmm.addEventListener("unload", this);
        if (this.count == 1)
            this.cpmm.addMessageListener("%ID%:FromParent", this);
    },
    destroy(cfmm) {
        this.count -= 1;
        cfmm.removeEventListener("mousedown", this);
        cfmm.removeEventListener("mouseup", this);
        cfmm.removeEventListener("unload", this);
        if (!this.count)
            this.cpmm.removeMessageListener("%ID%:FromParent", this);
    },
    receiveMessage(msg) {
        if ("blink" in msg.data) this.blinkEnabled = msg.data.blink;
    },
    unload(e) {this.destroy(e.target);},
    forget: () => delete nsvo["%ID%"]

}).cpmm = this)(%NSVO%);`);

а насчет всплывающих подсказок - вверху -там  больше возможностей https://developer.mozilla.org/en-US/doc … ifications

Отредактировано Andrey_Krropotkin (03-08-2020 10:34:20)

Отсутствует

 

№1486303-08-2020 11:31:40

Duche
Участник
 
Группа: Members
Зарегистрирован: 07-02-2016
Сообщений: 208
UA: unknown 0.0

Re: Custom Buttons

Andrey_Krropotkin пишет

Andrey_Krropotkin

Большое спасибо за "Autocopy+3" и "Двойным левым". Меня волновали не столько место всплывающих подсказок (их расположение), сколько время которое оно висит перед главами ,в старом коде 15-20 секунд это перебор. А так и в верху хорошо и в низу хорошо. В Вашем коде интереснее, на мой взгляд.

Ещё бы починить "CB drag and go"  и можно окончательно переходить на FF71.

Отсутствует

 

№1486403-08-2020 16:48:13

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

Re: Custom Buttons

egorsemenov06 пишет

Обратите пожалуйста внимание на пост

Да видел. Хорошо, попробую. Один код на обе.
Во второй, передвиг пунктов заменил с колеса на перетаскивание.

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

Выделить код

Код:

try {((ext, data) => data.forEach(([id, impl]) => {
	impl.id = "ucf-cbbtn-" + id;
	CustomizableUI.createWidget(Object.assign(impl, ext))
}))({
	localized: false,
	onCreated(btn) {
		btn.owner = this;
		btn.type = "menu";
		btn.setAttribute("image", this.image);
		btn.openPopup = btn.openMenu;
		btn.openMenu = this.openMenu;

		var popup = btn.appendChild(btn.ownerDocument.createXULElement("menupopup"));
		popup.setAttribute("context", "");
		popup.setAttribute("oncommand", "owner.command(event)");

		this.init(btn, popup);
		var {openDelay, closeDelay} = this;
		this.autoOpenCloseFeature(btn.ownerGlobal, btn, openDelay, closeDelay);
	},
	file: Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile),
	openMenu(...args) {
		if (this.parentNode != this.domParent) {
			this.domParent = this.parentNode;
			this.owner.setPopupPosition(this);
		}
		this.openPopup(...args);
	},
	setPopupPosition(node) {
		if (node.matches(".widget-overflow-list > :scope"))
			var pos = "after_start";
		else var win = node.ownerGlobal, {width, height, top, bottom, left, right} =
			node.closest("toolbar").getBoundingClientRect(), pos = width > height
				? `${win.innerHeight - bottom > top ? "after" : "before"}_start`
				: `${win.innerWidth - right > left ? "end" : "start"}_before`;
		node.firstChild.setAttribute("position", pos);
	},
	// https://github.com/Infocatcher/Custom_Buttons/blob/master/code_snippets/autoOpenCloseMenu.js
	// Automatically open menu on mouse over (and hide it on mouse out)
	autoOpenCloseFeature(win, btn, openDelay = 200, closeDelay = 350) {
		var _openTimer = 0;
		var _closeTimer = 0;
		btn.onmouseover = function(e) {
			win.clearTimeout(_closeTimer);
			if(e.target == btn && closeOtherMenus()) {
				btn.open = true;
				return;
			}
			_openTimer = win.setTimeout(function() {
				btn.open = true;
			}, openDelay);
		};
		btn.onmouseout = function(e) {
			win.clearTimeout(_openTimer);
			_closeTimer = win.setTimeout(function() {
				if(!isContextOpened())
					btn.open = false;
			}, closeDelay);
		};
		function closeOtherMenus() {
			return win.Array.prototype.some.call(
				btn.parentNode.getElementsByTagName("*"),
				function(node) {
					if(
						node != btn
						&& win.XULElement.isInstance(node)
						// See https://github.com/Infocatcher/Custom_Buttons/issues/28
						//&& node.boxObject
						//&& node.boxObject instanceof Components.interfaces.nsIMenuBoxObject
						&& "open" in node
						&& node.open
						&& node.getElementsByTagName("menupopup").length
					) {
						node.open = false;
						return true;
					}
					return false;
				}
			);
		}
		function isContextOpened() {
			return inBtn(win.document.popupNode);
		}
		function inBtn(node) {
			for(; node; node = node.parentNode)
				if(node == btn)
					return true;
			return false;
		}
	}
}, Object.entries({

	OpenPageInOtherBrowser: {
		label: "Открыть страницу в другом браузере",
		image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAACXBIWXMAAAsSAAALEgHS3X78AAAEgUlEQVQ4jU2TW2yTZQCG3+/7v/79266HraN1G8cNVoERNhk42BBmghiQBF3IMJnghYcbxUPEREiYF0bgihBREyNRQ4wENCwkBjlsyIA5WclWOe3ANrq2W1u6reu5/f//+7xQI8/tmzx5bx4yMjKCgYEByLIMAYBTirymEUYpbIrimkslzKXOpwLrV3NNceTAhZERNVfFC1mnNifGjO6i8NB4grCOjg7s378foBSVNju+3b6D+NUC/d43oGeK7dXLFlfu9BhKr244XObntvuvkPDURszNGiSjkhKTaYAtPO7tT15iQggAAASHVZJIs8sFlDqx69l1O4Lh+EeVddXPidrZN2XeZcDvswrGqnhBXXXowK2rRxtXGF0vy4XWzvOhG4wQ8o+IUCIAkYcoYrr+pXlqdo+nwQXR6BUk1WP13qhE5pRZX2cDMRRpn9U/LK870/egrfkZ66WCqir/P4IQakGHIad/LUaDbWrLIs2w+TbFyB16J75PDNg3I9V8XbKdO4GaEiffXWpqmZ8tN01Oq20ffLwuTv+1SOACvM7S+hcLtknbyzR56z0p2T9If3nYjmtTtSQV9BF51RqML1yOlP8hiQUfqU00va33RGD3a69fEZRQQgDoJmaAceu8t+/tWwxsDxK9o5OcOduICxE3ykvSSBUvhR66D1W/heyyGDG/GJLwxgSWb4q8NXh3xkgBEABQi6WqxvUr6neVzwHXbtJQO8dgQEWJG4gqZfDM3URZVzuml21DyRYdhk0JwutzWN0CT2OttJY6HApxWICG5uqad6qZVRry8s8j88j9YAJJi4JR5kZvnxfV1w+id8EupBreA1m5CNSVJZxRYTYT04JyuoTt2bNGb939KQjXthUNX8DJqAU/Oi1IbnFiY0UFgots2Onx4BQ/iC6sRX0sCclTBuR8EIQAnEAiRGYyM4MZ3PV06trz/Y81nM4UwZXOYLhlIbKPFdTHIzjh8+G3+FLkC1nU1uiQ2AMUIAlGOclnZR6OIcI4MTGiJzfoY4OlP0zbM1mJmx2KhHSxBe6KOKKBIdyOOFBpIHjaY8SOJV8AGT9ALKCEIDDBogODWj8DrBpJB+smxjPdV84Xeua3LjjCZUmzaBbmjffAVNGPl6pWIJGVYNW9KFE7IJgZah6abDYbfvq18HNsjocoVD8QuOWyrWzqyT1Qj4b/CPsU2cSy+bSWt+YwU4ihO9mJ7vhlNCndsBiMSGaYbmFWg7fX4D92OnEEACjJ+iEyYatTqI9qXBJ8x3yt492ROxQyQ07S5QLTcxmb/oKS0TebVS2dtOpWUSz19Rn9be2xV2eTPEQJqHTow70Q8T/X0vjjpuaaeRdnptPR/gujPekEXyOZjfN1JhOH0Ogn9gi15BTyKKDQ785lR949Htk7EVV7KAHlApyok5ehDn9lZdnJ9yU9l6Ys03X4ZMR/4GzCqtjleqnCXu1xs+IGU56MRrX43bHcWGimcJsQhADkhYAOAESdvIj80Dcw5vMYGQ7i4KlBdN4tIJEVIBD4L+knoRSAAPgT49/cEBl9hsIr+QAAAABJRU5ErkJggg==",
		tooltiptext: [
			"Л: Открыть меню с браузерами",
			"С: Добавить в меню новый браузер",
			"\nФункции кликов мыши для меню:",
				"\tЛ: Открыть страницу",
				"\tС: Добавить разделитель",
				"\tП: Удалить пункт меню или разделитель",
				"\tCtrl+П: Изменить название пункта меню",
			"Перетаскиванием можно передвигать пункты меню или разделители"
		].join("\n"),

		init(btn, popup) {
			btn.onauxclick = this.auxclick;
			popup.setAttribute("onpopupshowing", "this.shouldRebuild && owner.rebuild(this)");
			popup.ondragstart = this.dragstart;
			popup.shouldRebuild = true;
		},
		get markup() {
			try {var data = Cu.readUTF8URI(Services.io.newURI(
				`chrome://user_chrome_files/content/custom_scripts/${this.id}-data.txt`
			)).split("\n").filter(line => /\S/.test(line));}
			catch {var data = [
				"D:\\Програмное обеспечение\\Флешка загрузочная\\Windows 7 SP1\\Программы\\ChromePortable\\ChromePortable.exe>Chrome",
				"D:\\Програмное обеспечение\\Флешка загрузочная\\Windows 7 SP1\\Программы\\Opera_1217\\Opera\\launcher.exe>Opera",
				"C:\\Program Files (x86)\\Maxthon5\\Bin\\Maxthon.exe",
				"C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe",
				"D:\\Програмное обеспечение\\Флешка загрузочная\\Windows 7 SP1\\Программы\\Microsoft Edge\\ProgramFiles\\msedge.exe",
			];}
			delete this.markup;
			return this.markup = this.dataToMarkup(data);
		},
		setMarkup(popup) {
			this.markup = popup.innerHTML;
			for(var {node} of CustomizableUI.getWidget(this.id).instances)
				if (node.firstChild != popup) node.firstChild.shouldRebuild = true;
			this.write(Array.from(popup.children,
				node => node.hasAttribute("value")
					? node.tooltipText + (node.value == "true" ? ">" + node.label : "")
					: "separator"
			).join("\n"));
		},
		dataToMarkup(data) {
			var markup = "";
			for(var str of data) markup += str == "separator"
				? "<menuseparator/>" : this.strToMenuitem(str);
			return markup;
		},
		repl: [/^./, c => c.toUpperCase()],
		strToMenuitem(str, ind = str.lastIndexOf(">")) {
			var name, val, path = str;
			if ((val = ind != -1))
				path = str.slice(0, ind),
				name = str.slice(ind + 1);
			else
				this.file.initWithPath(path),
				name = this.file.leafName.split(".")
					.shift().replace(...this.repl);

			return `<menuitem label="${name}" tooltiptext="${path}" value="${val}"`
				+ ` class="menuitem-iconic" image="moz-icon://file://${path}"/>`;
		},
		append(popup, xul = this.markup) {
			popup.append(popup.ownerGlobal.MozXULElement.parseXULToFragment(xul));
		},
		rebuild(popup) {
			popup.textContent = "";
			this.append(popup);
			delete popup.shouldRebuild;
		},
		auxclick(e) {
			var trg = e.target, popup = this.firstChild;
			if (trg == this && e.button == 1)
				return this.owner.addMenuitem(popup);

			else if (trg.parentNode != popup) return;

			if (e.button == 1) {
				var up = e.screenY < trg.screenY + trg.clientHeight/2;
				up = up ? trg.previousSibling : !trg.nextSibling;
				trg[up ? "before" : "after"](
					trg.ownerDocument.createXULElement("menuseparator")
				);
			} else {
				if (e.ctrlKey) {
					if (trg.nodeName.endsWith("r")) return;

					var name = this.owner.prompt(
						"Введите другое название пункта",
						trg.label, trg.ownerGlobal
					);
					if (name && name != trg.label)
						trg.label = name,
						trg.value = true;
				}
				else trg.remove();
			}
			this.owner.changeMarkup(popup);
		},
		prompt(msg, value, domWin) {
			var res = {value};
			return Services.prompt.wrappedJSObject.pickPrompter({
				domWin, modalType: Ci.nsIPrompt.MODAL_TYPE_WINDOW
			}).nsIPrompt_prompt(this.label, msg, res, null, {})
				? res.value : null;
		},
		addMenuitem(popup) {
			var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
			fp.appendFilters(fp.filterApps);
			fp.init(popup.ownerGlobal, "Укажите путь к программе", fp.modeOpen);
			fp.open(res => {
				if (res == fp.returnOK)
					this.append(popup, this.strToMenuitem(fp.file.path, -1)),
					this.setMarkup(popup);
			});
		},
		changeMarkup(popup) {
			popup.state == "open"
				? popup.addEventListener("popuphidden", this, {once: true})
				: this.setMarkup(popup);
		},
		handleEvent(e) {
			this[e.type](e);
		},
		popuphidden(e) {
			this.setMarkup(e.target);
		},
		dragstart(e) {
			var trg = e.target;
			if (trg.parentNode.nodeName != "menupopup") return;

			var {owner} = this.parentNode;
			var pn = trg.flattenedTreeParentNode;
			owner.dragData = {trg, pn, ns: trg.nextSibling};

			trg.style.cssText = "font-weight: bold; color: red;"
				+ "outline: 2px solid red; outline-offset: -2px;"
					.replace(/;/g, " !important;");
			var win = trg.ownerGlobal;
			win.setCursor("grabbing");
			pn.addEventListener("mousemove", owner);
			win.addEventListener("mouseup", owner, {once: true});
		},
		mousemove(e) {
			var trg = e.target, dtrg = this.dragData.trg;
			if (trg == dtrg) return;

			e.movementY > 0
				? trg.nextSibling != dtrg && trg.after(dtrg)
				: trg.previousSibling != dtrg && trg.before(dtrg);
		},
		mouseup(e) {
			e.preventDefault();
			var {trg, pn, ns} = this.dragData;
			delete this.dragData;
			trg.removeAttribute("style");
			trg.ownerGlobal.setCursor("auto");
			pn.removeEventListener("mousemove", this);
			trg.nextSibling != ns && this.changeMarkup(trg.parentNode);
		},

		command(e) {
			this.file.initWithPath(e.target.tooltipText);
			if (this.file.exists()) {
				var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
				process.init(this.file);
				return process.run(false, [e.view.gBrowser.currentURI.spec], 1);
			}
			Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService)
				.showAlertNotification(this.image, this.label, "Файл не существует");
		},
		write(txt) {
			var file = Services.dirsvc.get("UChrm", Ci.nsIFile), CC = Components.Constructor;
			["user_chrome_files", "custom_scripts", this.id + "-data.txt"].forEach(file.append);
			var te = new (Cu.getGlobalForObject(Cu).TextEncoder)();
			var fos = CC("@mozilla.org/network/file-output-stream;1", "nsIFileOutputStream", "init")
				// MODE_{WRONLY, CREATE, TRUNCATE}, PERMS_FILE
				.bind(null, file, 0x02 | 0x08 | 0x20, 0o644, 0);
			var bos = CC("@mozilla.org/binaryoutputstream;1", "nsIBinaryOutputStream", "setOutputStream");

			(this.write = txt => {
				var stream = new fos();
				try {new bos(stream).writeByteArray(te.encode(txt));}
				catch(ex) {Cu.reportError(ex);}
				finally {stream.close();}
			})(txt);
		}
	},

	openExternalWinApplication: {
		label: "Открыть внешнее win приложение",
		image: "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAMAAwQAKCImDyo4IWkYaBzFQ6xI8FG/V/VCq0jcGGQbkwAQACQAAAAAAAIAAwAAAAAAAAAAAAAAAAEAAAIAAgIAQy4iYp9YOuZUah3/QMJQ/nfxgP97+Yb/f/+L/m/7ev87v0L1BzwIawAAAAAAAgADAAAAAAEAAAIAAAAAQR4Ki7pwNP//tG79aXQg/CGwM/tL3lP+SeJU/krmVf5I5lT8ROZQ/SjIMf8DQgWFAAAAAAACAAMAAAAAMRoKX5hKHP/qoVT69JtU/WVsGP8RmyP/LMAz/ynHM/4ozTP8Jc4w+x/KK/sbxyn7Daoa/wAlA1QAAAEAAgAAA2o5G9GhVyT/z305/N54Nv9eWxTyAnMR6Qp+DvsIig//CpQR/wucE/8KnQ//CpkG/QedAf8FZADWAwIACigYIklrMln7h0VB/6dcJPvBaCz/XC8RlgABAAACDgAlABUANAAfAUsAKABeAz8RlAhfUvkDZnP/CFtw+gcXKklSLEeVlUiB/6VamPykYGD7o1wl/2A4H5YAAAAAAgEBBAAAAAAAAQMEAAAAAAUoVmcHcfT/AIL5+QCK//8BOZ2rXjJRsJtOhf/SgLr9zoK++5hbW/9AKhaGAAAAAAICAQYAAQACAAMDBwAAAAABLlprD4///wqh9/oJsf//Al7M1FsxT6ucUYf/1Iq//Oyd1vzYkMf/X0FVhQAAAAADAgMEAAAAAAACBAQBAAAAAC1aYRSQ//8lpPr6Irj//wtt1t5GJT2DmlCF/82Juvz2reH/8Kbb/eej1P9jR1t+AAAAAAMCAwQBAwUGAAAAAAYkV2wjkv//PLP7+jzE//8VaMXMHhAaP5FLff+4d6b++rno//iz5P/3suP88rLg/2hPYn8AAAAAAQAAAAgPYW1bXeD/PJL0/1DB/fxSy///EkiRlwAAAABqOFzBp16S/+ev2Pz/we///b7s//u86vr7wev/dFxfcgAJYmhxeP//lJH+/juS+/5q0f/+V7n4/AASODwAAAAAHA4YP5NMgP+6fKj9/Mzw/f3H8/7/y/X/7LvU811Ywd54gPv8r6z//puZ/P1Akff5g+L//y5hmZ8AAAAAAgECAwAAAAA1Gy5vmlGG/8iOuP3/1vX/8sfe811YxNZ6g/f5ubb9/a6u+/uvrfz8TZPt/1GFvMcAAQwNAQAAAAAAAAACAQEDAAAAACoVJVh/QW3umWuP7V5fzeSMk/j9zcn//7+//v7Av///o6Pz+yU2XH0AAwYKAQAAAAAAAQEAAAAAAAAAAAEBAQMAAAAADwkHFAcCKUsJGb3VO0vn9lRf5/RdZMzXRkmTmw4OKTUAAAAAAgIDAwABAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
		data: [
			["IE", "C:\\Program files\\Internet Explorer\\iexplore.exe"],
			["Explorer", "C:\\windows\\explorer.exe"],
			null,
			["Cmd Prompt", "C:\\windows\\system32\\cmd.exe"],
			["Media Player", "C:\\Program Files\\Windows Media Player\\wmplayer.exe"],
			["Task Manager", "C:\\windows\\system32\\taskmgr.exe"],
			["Control Panel", "C:\\windows\\system32\\control.exe"],
			null,
			["Notepad", "C:\\windows\\notepad.exe"],
			["Calculator", "C:\\windows\\system32\\calc.exe"],
			["Virtual Keyboard", "C:\\windows\\system32\\OSK.exe"],
			["Character table", "C:\\windows\\system32\\charmap.exe"]
		],
		init(btn) {
			btn.tooltipText = btn.label;
			btn.ownerGlobal.Object.defineProperty(btn, "domParent", this);
		},
		configurable: true,
		get() {
			delete this.domParent;
			var doc = this.ownerDocument, df = doc.createDocumentFragment();
			for(var arr of this.owner.data) {
				if (!arr) {
					df.append(doc.createXULElement("menuseparator"));
					continue;
				}
				var menuitem = df.appendChild(doc.createXULElement("menuitem"));
				menuitem.className = "menuitem-iconic";
				menuitem.setAttribute("label", arr[0]);
				menuitem.setAttribute("image", "moz-icon://file://" + arr[1]);
			}
			this.firstChild.append(df);
		},
		command(e) {
			this.file.initWithPath(e.target.getAttribute("image").slice(18));
			this.file.launch();
		}
	}
}))} catch(ex) {Cu.reportError(ex);}

egorsemenov06 пишет

можно Вас попросить пожалуйста адаптировать для user_chrome_files вот эту кнопку

Ещё не легче, совсем поперёк ситуации.

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

Выделить код

Код:

try {CustomizableUI.createWidget(({
	label: "XXXXX XXXXXXX",
	image: "data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAewQAAHsEBw2lUUwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABYSURBVDiNY2CgEjjKwMDwHw0fwaIOJgcHjEgS2AAjGv8/ujgLkS5EtwBuEBORBuAExLoA3atwL8BccBSLJmyBOIgBoXSAU57YdIBTnuJoHDwGEEoHtEsnALmSHj9YVKEQAAAAAElFTkSuQmCC",
	defaultFavicon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAABh0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjIyt5EXfQAAAmZJREFUOE91k1tIVFEUhj/v0l0LHyoiqoemKHowKaywMm9EIhVJRFl01aBIuphYliKNWqIv5pOgZWGGdHspJUtCSkW6vBRYb4EIEWJhzTSr/8xMg1ke+Nh7r73Ot9feZ58wKgGf8IjvYvwTRiO/FBhj/19x7wz4NAJeJ+oIrogycU4UhYilPGqIi5FDnCBWwBFxUhRIkKU2baLAHQVngqJzHKN1gY8Wl48C9fMVH26CQ8qZVHA1GmrjApIi+hjKNj7nmAR9lChuXXBQOZMKqjV5PQEKSaIuzoMvxfyUz/FQlpCD9f9XUEA55zkrSmmjemYbF6a+5t1mw5IC9GcZhfGDNKTdZ4dy9sY0skX5aaoNNx3cmG8MbB5lINF4myxcxo9Nhnd1gLEtxsulxtNlxnONO9ca+dNNkg5HkEVDQjc9WsmXqRdV8tgq4+ty48uKAE7/p2LedcZoqtGsBfKmdJPqfAu3DqyYlSqok0dzjfcLjI+L/+XDEqN3kVE321R6Jyl6J9X5jBWiRJzCxaWYFzRP03YkmkiPtlkRZ2TyRKW7BAFBvU69VlSJRtcBVWJ0xRvPxuGMH2vlPWHOvhNJD14iR0JLEtwSt8Wd5BoqI4wHqqJdtAbbh2rvieORjmCrf/U/cDOZENfmvaFGgsYYo0oURXu4HOWhPtpo0vi0BBupFYTAenXD/IRTqlLd4cZ5kccw2bSTIXapX6pYseQbeMV6Cf7AyF2CxHNUezysfzKXQV2YbLYrcZtIV3+jYjs1t4FvuqcRAj/+HzXAQvbpAHfrPuYyS8mEBBnqpyi2TnNrlJOk3KDgN9P8GjD3yqukAAAAAElFTkSuQmCC",
	id: "ucf-cbbtn-LnkCreator",
	localized: false,
	onCreated(btn) {
		btn.owner = this;
		btn.tooltipText = this.label;
		btn.setAttribute("image", this.image);
		btn.setAttribute("oncommand", "owner.createLnk(this)");
	},
	init() {
		this.widget.parent = this;
		this.widget.contextmenu.destroy = id => {
			CustomizableUI.destroyWidget(id);
			delete this.data[id.slice(8)];
			this.save();
		}
		try {this.data = JSON.parse(Cu.readUTF8URI(Services.io.newURI(
			`chrome://user_chrome_files/content/custom_scripts/${this.id}-data.json`
		)))}
		catch {this.data = {}; return this;}
		for(var [id, inf] of Object.entries(this.data))
			this.createWidget(id, inf.url, inf.name);
		return this;
	},
	get fs() {
		delete this.fs;
		return this.fs = Cc["@mozilla.org/browser/favicon-service;1"]
			.getService(Ci.nsIFaviconService);
	},
	createLnk(btn) {
		var id = Date.now();
		var gb = btn.ownerGlobal.gBrowser;
		var uri = gb.currentURI;
		var label = gb.contentTitle.slice(0, 75);

		var widget = this.createWidget(id, uri, label);
		var {area, position} = CustomizableUI.getPlacementOfWidget(this.id);
		CustomizableUI.addWidgetToArea(widget.id, area, position + 1);

		this.data[id] = {name: label, url: uri.spec};
		this.save();
	},
	createWidget(id, url, label) {
		var obj = {
			uri: url.spec ? url : Services.io.newURI(url),
			id: "ucf-lnk-" + id, label, ...this.widget
		};
		var widget = obj.widget = CustomizableUI.createWidget(obj);
		this.fs.getFaviconDataForPage(obj.uri, obj);
		return widget;
	},
	tip: "\nShift+ПКМ - Удалить кнопку",
	widget: {
		localized: false,
		onCreated(btn) {
			btn.uri = this.uri;
			btn.addTab = this.addTab;
			btn.oncontextmenu = this.contextmenu;
			btn.setAttribute("oncommand", "addTab(this)");
			btn.tooltipText = this.label + this.parent.tip;
			this.image && btn.setAttribute("image", this.image);
		},
		addTab(btn) {
			var gb = btn.ownerGlobal.gBrowser;
			gb.selectedTab = gb.addTrustedTab(btn.uri.spec, {userContextId: 1});
		},
		contextmenu: function checkShift(e) {
			if (e.shiftKey)
				e.preventDefault(),
				checkShift.destroy(e.target.id);
		},
		onComplete(uri, len, arr, mmt) {
			this.image = len
				? `data:${mmt};base64,${btoa(String.fromCharCode(...arr))}`
				: this.parent.defaultFavicon
			for(var {node} of this.widget.instances)
				node.hasAttribute("image") || node.setAttribute("image", this.image);
			delete this.widget;
		}
	},
	save() {
		var file = Services.dirsvc.get("UChrm", Ci.nsIFile), CC = Components.Constructor;
		["user_chrome_files", "custom_scripts", this.id + "-data.json"].forEach(file.append);
		var te = new (Cu.getGlobalForObject(Cu).TextEncoder)();
		var fos = CC("@mozilla.org/network/file-output-stream;1", "nsIFileOutputStream", "init")
			// MODE_{WRONLY, CREATE, TRUNCATE}, PERMS_FILE
			.bind(null, file, 0x02 | 0x08 | 0x20, 0o644, 0);
		var bos = CC("@mozilla.org/binaryoutputstream;1", "nsIBinaryOutputStream", "setOutputStream");

		(this.write = () => {
			var stream = new fos();
			try {new bos(stream).writeByteArray(
				te.encode(JSON.stringify(this.data))
			);} catch(ex) {Cu.reportError(ex);}
			finally {stream.close();}
		})();
	}
}).init())} catch(ex) {Cu.reportError(ex);}

Duche пишет

15-20 секунд это перебор

Можно точно так же закрыть по таймауту.

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

Выделить код

Код:

...
   // всплывающая подсказка ....
   var favicon = gBrowser.selectedTab.image || "chrome://global/skin/icons/Portrait.png";
   var as = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
   var name = "bookmarks-alert-" + Date.now();
   as.showAlertNotification(
   	favicon, "Добавил в папку " + folderTitle + ":", docTitle, false, null, null, name
   );
   setTimeout(() => as.closeAlert(name), 2e3);

Duche пишет

Ещё бы починить "CB drag and go"  и можно окончательно переходить на FF71.

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

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

Выделить код

Код:

addEventListener("dragstart", ({
	link: {
		U: {
			name: "Открыть ссылку в новой активной странице", cmd() {
				openUILinkIn(this.val, "tab", this.opts);
			}
		},
		D: {
			name: "Открыть ссылку в новой фоновой странице", cmd() {
				openUILinkIn(this.val, "tabshifted", this.opts);
			}
		}
	},
	text: {
		U: {
			name: "Поиск текста поисковиком по умолчанию в новой активной странице", cmd() {
				this.search("tab");
			}
		},
		D: {
			name: "Поиск текста поисковиком по умолчанию в новой фоновой странице", cmd() {
				this.search("tabshifted");
			}
		}
	},
	search(where) {
		var engine = Services.search[`default${this.opts.private ? "Private" : ""}Engine`];
		var submission = engine.getSubmission(this.val, null, "");
		openUILinkIn(submission.uri.spec, where, {postData: submission.postData, ...this.opts});
	},
	opts: {
		//relatedToCurrent: true,
		triggeringPrincipal: document.nodePrincipal,
		get userContextId() {
			return parseInt(gBrowser.selectedBrowser.getAttribute("usercontextid"));
		},
		get private() {
			return PrivateBrowsingUtils.isWindowPrivate(window);
		}
	},
	init() {
		var arr = [];
		for(var type of ["link", "text"]) arr.push(
			type + "\n" + Object.entries(this[type]).map(a => a[0] + ":\t" + a[1].name).join("\n")
		);
		self.tooltipText = (self.label ? self.label + "\n\n" : "") + arr.join("\n\n");

		this.drop = () => this.drag();
		this.handleEvent = e => this[e.type](e);
		return this;
	},
	dragstart(e) {
		//if (!gBrowser.currentURI.spec.startsWith("http")) return;
		if (!e.dataTransfer.mozItemCount || !gBrowser.selectedBrowser.matches(":hover"))
			return;

		var dt = e.dataTransfer;
		this.type = this.link;
		this.dir = this.val = "";

		
		var url = dt.getData("text/x-moz-url-data");
		if (url) this.val = url;
		else {
			var txt = dt.getData("text/plain");
			if (txt) {
				this.val = txt;
				if (!this.textLinkRe.test(txt)) this.type = this.text;
			}
			else return;
		}
		this.x = e.screenX; this.y = e.screenY;
		this.drag(true);
	},
	drag(init) {
		var meth = `${init ? "add" : "remove"}EventListener`;
		for(var type of this.events) window[meth](type, this, true);
		init || StatusPanel.panel.setAttribute("inactive", true);
	},
	events: ["dragover", "drop", "dragend"],
	dragover(e) {
		var {x, y} = this, cx = e.screenX, cy = e.screenY;
		var dx = cx - x, ax = Math.abs(dx), dy = cy - y, ay = Math.abs(dy);
		if (ax < 10 && ay < 10) return;

		this.x = cx; this.y = cy;
		var dir = ax > ay ? dx > 0 ? "R" : "L" : dy > 0 ? "D" : "U";
		if (this.dir.endsWith(dir)) return;

		dir = this.dir += dir;
		var obj = this.type[dir];
		var txt = `${
			obj ? "Ж" : "Неизвестный ж"
		}ест мыши: ${dir + (obj ? "  " + obj.name : "")}`;

		StatusPanel._labelElement.value = txt;
		StatusPanel.panel.removeAttribute("inactive");
	},
	dragend(e) {
		var dt = e.dataTransfer;
		this.drag();

		var obj = this.type[this.dir];
		if (!obj || dt.mozUserCancelled) return;

		var x = e.screenX, y = e.screenY;
		var wx = mozInnerScreenX, wy = mozInnerScreenY;
		x > wx && y > wy && x < wx + innerWidth && y < wy + innerHeight
			&& obj.cmd.call(this);
	},
	textLinkRe: /^([a-z]+:\/\/)?([a-z]([a-z0-9\-]*\.)+([a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel)|(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(:[0-9]{1,5})?(\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(\?[a-z0-9+_\-\.%=&amp;]*)?)?(#[a-z][a-z0-9_]*)?$|^custombutton:\/\/\S+$/
}).init(), true, gBrowser.tabpanels || 1);

Отсутствует

 

№1486504-08-2020 00:00:11

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

Re: Custom Buttons

Dumby
как блокировать всегда? если смысл ? летит шняга в storage c youtube и яндекса
la4shnet.jpg

Отсутствует

 

№1486604-08-2020 07:45:18

Duche
Участник
 
Группа: Members
Зарегистрирован: 07-02-2016
Сообщений: 208
UA: unknown 0.0

Re: Custom Buttons

Dumby .       Спасибо большое за  реальную помощь.

Отсутствует

 

№1486704-08-2020 09:09:36

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

Re: Custom Buttons

solombala пишет

как блокировать всегда?

Видимо, создать числовую настройку permissions.default.persistent-storage со значением 2

Отсутствует

 

№1486804-08-2020 10:56:23

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

Re: Custom Buttons

Dumby

Dumby пишет

Видимо, создать числовую настройку permissions.default.persistent-storage со значением 2

Уй,шикардос! А, "иметь доступ к экрану" ? тоже заблокировать на глушняк.

Отредактировано solombala (04-08-2020 11:10:15)

Отсутствует

 

№1486904-08-2020 13:47:44

Duche
Участник
 
Группа: Members
Зарегистрирован: 07-02-2016
Сообщений: 208
UA: unknown 0.0

Re: Custom Buttons

Добрый день. Поправьте пожалуйста кнопку "Закрыть все вкладки и перейти на домашнюю."  Вкладки закрывает а на домашнюю не переходит.


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

Выделить код

Код:

/*CODE*/


[...gBrowser.tabs].forEach((tab)=> !tab.pinned && gBrowser.removeTab(tab));   /*закрыть все вкладки*/

 getBrowser (). selectedTab = getBrowser (). addTab ("https://yandex.ru");  /*Закрытие всех вкладок приводило к открытию домашней страницы*/

Отсутствует

 

№1487004-08-2020 13:58:47

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

Re: Custom Buttons

Duche пишет

Добрый день. Поправьте пожалуйста кнопку "Закрыть все вкладки и перейти на домашнюю."  Вкладки закрывает а на домашнюю не переходит.

:/

Выделить код

Код:

/*CODE*/

[...gBrowser.tabs].forEach((tab)=> !tab.pinned && gBrowser.removeTab(tab)); /*закрыть все вкладки*/
  var url = "https://yandex.ru";
  openUILinkIn(url, 'current', { triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal() }); /*Закрытие всех вкладок приводило к открытию домашней страницы*/

«The Truth Is Out There»

Отсутствует

 

№1487104-08-2020 14:55:54

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

Re: Custom Buttons

Dumby
Возможно ли реализовать такую штуку.

Заходя на любую страницу любого сайта получить массив ссылок.
И, если какие-то из них ссылаются на youtube.com или на youtu.be, то при клике на такие ссылки происходил редирект на invidio.us.


Например:
https://www.youtube.com/watch?v=MdGDMFuT8vU  --->  https://invidio.us/watch?v=MdGDMFuT8vU
https://youtu.be/336Z5BhM7h0  --->  https://invidio.us/336Z5BhM7h0


P.S. Желательно, чтобы код работал как на FF52 ESR, так и на FF78 ESR.


«The Truth Is Out There»

Отсутствует

 

№1487204-08-2020 15:11:06

Duche
Участник
 
Группа: Members
Зарегистрирован: 07-02-2016
Сообщений: 208
UA: unknown 0.0

Re: Custom Buttons

unter_officer 

Спасибо большое.

Отсутствует

 

№1487304-08-2020 20:20:57

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

Re: Custom Buttons

solombala пишет

А, "иметь доступ к экрану" ?

То же самое, только persistent-storage заменить на screen


unter_officer пишет

Возможно ли реализовать такую штуку.

Странно, мне казалось ты повнимательнее, и, в отличие от некоторых,
понимаешь, что меня бесполезно спрашивать про контентские дела.


Может попробуй какую-нибудь обезьяну ({Tamper, Grease, Violent}monkey)
под это дело подрядить. Например, чтобы href по клику подменялся, типа

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

Выделить код

Код:

((re, ret) => {
	var listener = e => {
		if (e.button > 1) return;
		var link = e.target.closest("a[href]");
		if (link && re.test(link.href)) {
			var was = link.getAttribute("href");
			link.href = "https://invidio.us/" + RegExp.rightContext;
			setTimeout(ret, 200, link, was);
		}
	}
	addEventListener("click", listener, true);
	"onauxclick" in document && addEventListener("auxclick", listener, true);
})(
	/^https:\/\/(?:www\.)?youtu(?:be\.com|\.be)\//,
	(link, href) => link.setAttribute("href", href)
);

Отсутствует

 

№1487405-08-2020 03:14:23

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

Re: Custom Buttons

Dumby пишет

Может попробуй какую-нибудь обезьяну ({Tamper, Grease, Violent}monkey)
под это дело подрядить. Например, чтобы href по клику подменялся, типа

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

Выделить код

Код:

((re, ret) => {
	var listener = e => {
		if (e.button > 1) return;
		var link = e.target.closest("a[href]");
		if (link && re.test(link.href)) {
			var was = link.getAttribute("href");
			link.href = "https://invidio.us/" + RegExp.rightContext;
			setTimeout(ret, 200, link, was);
		}
	}
	addEventListener("click", listener, true);
	"onauxclick" in document && addEventListener("auxclick", listener, true);
})(
	/^https:\/\/(?:www\.)?youtu(?:be\.com|\.be)\//,
	(link, href) => link.setAttribute("href", href)
);

Собственно, у меня Tampermonkey установлен. Однако скрипт не срабатывает.


«The Truth Is Out There»

Отсутствует

 

№1487505-08-2020 08:50:11

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

Re: Custom Buttons

unter_officer пишет

Однако скрипт не срабатывает.

Ну да, я же говорю — бесполезно :).
Но, всё таки, немного любопытно почему не срабатывает.


Вот, провёл такой эксперимент на Firefox 78.0
Открыл новую пустую вкладку и скормил адресной строке
data: адрес (простая html'ка с двумя ссылками, которые ты предоставил).


Открыл веб-консоль (Ctrl+Shift+K) и запустил с js-терминала код.


ЛКМ по ссылке на странице — GET-запрос на invidio.us есть,
и в адресной строке, в конце концов, invidio.us тоже появляется.
А Ctrl+ЛКМ или СКМ — новая вкладка, и снова с invidio.us
Так же и на Firefox 52.0.


Попробуй повторить, если интересно. Лучше на чистом, по возможности.
В смысле, если так работает, то дело не в самом коде, а в чём-то другом, наверно.

url

Выделить код

Код:

data:text/html;charset=utf-8,%3C!DOCTYPE%20html%3E%0A%3Chtml%3E%0A%09%3Chead%3E%0A%09%09%3Ctitle%3ETest%20yt%20links%3C%2Ftitle%3E%0A%09%09%3Cmeta%20http-equiv%3D%22Content-Type%22%20content%3D%22text%2Fhtml%3B%20charset%3Dutf-8%22%3E%0A%09%3C%2Fhead%3E%0A%09%3Cbody%3E%0A%09%09%3Ccenter%3E%0A%09%09%09%3Cbr%2F%3E%3Cbr%2F%3E%0A%09%09%09%3Ca%20href%3D%22https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DMdGDMFuT8vU%22%3Ewww.youtube.com%2Fwatch%3Fv%3DMdGDMFuT8vU%3C%2Fa%3E%0A%09%09%09%3Cbr%2F%3E%3Cbr%2F%3E%0A%09%09%09%3Ca%20href%3D%22https%3A%2F%2Fyoutu.be%2F336Z5BhM7h0%22%3Eyoutu.be%2F336Z5BhM7h0%3C%2Fa%3E%0A%09%09%3C%2Fcenter%3E%0A%09%3C%2Fbody%3E%0A%3C%2Fhtml%3E

Отсутствует

 

Board footer

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