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

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

№1300117-12-2018 18:20:34

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

Re: Custom Buttons

drage2 пишет

какую поганку завернули в FF64 ?

В FF64, здесь, никакую. showPopup() выпилен в FF61.
Остальное — создай кнопку и убедись что работает.

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

Выделить код

Код:

this.append(MozXULElement.parseXULToFragment(`

    <menupopup context="bla">
        <menuitem label="menuitem 1"/>
        <menuitem label="menuitem 2"/>
        <menuitem label="menuitem 3"/>
    </menupopup>

    <menupopup id="bla">
        <menuitem label="context"/>
    </menupopup>
`));

var menu = this.firstChild;

this.oncontextmenu = e => e.target != this ? menu.hasAttribute("context")
    : e.ctrlKey || e.shiftKey || e.altKey || e.metaKey || (
        e.detail != 1 ? menu.hidePopup() : !!menu.openPopup(this, "after_start")
    );


custombuttons.alertSlide1 = function(sTitle) {
var as = Components.classes["@mozilla.org/alerts-service;1"].getService(Components.interfaces.nsIAlertsService);
as.showAlertNotification('chrome://global/skin/icons/information-16.png', "", sTitle, false, "", null);
setTimeout(() => as.closeAlert(), 999);
};
for(var menuitem of menu.children) menuitem.setAttribute(
    "oncommand", "custombuttons.alertSlide1(this.label);"
);

Отсутствует

 

№1300217-12-2018 19:23:01

Karn
Участник
 
Группа: Members
Зарегистрирован: 11-12-2018
Сообщений: 45
UA: Firefox 64.0

Re: Custom Buttons

Dumby
Возможно ли встроить Вашу кнопку youtube-dl в контекстное меню по ПКМ? Т.е. нажимаешь ПКМ на ссылке / ссылке с графикой (миниатюры YouTube) или просто при выделении текстовой ссылки и по нажатию на пункт контекстного меню, автоматически копируется ссылка или текст и нажимается кнопка youtube-dl. Благодаря Vitaliy V., она теперь работает с любыми ссылками. :)

Код

Выделить код

Код:

/*CODE*/
var url = gClipboard.read();
if (!url.startsWith("http://") && !url.startsWith("https://")) return;

var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
process.init(FileUtils.File(String.raw`D:\YouTube\youtube-dl.exe`));

var args = ["-o", "D:\\YouTube\\%(title)s.%(ext)s", "--no-check-certificate", "--no-call-home", url];
process.runw(false, args, args.length);

Отсутствует

 

№1300317-12-2018 20:57:56

drage2
Забанен
 
Группа: Members
Откуда: Донецк
Зарегистрирован: 23-11-2017
Сообщений: 392
UA: Firefox 64.0

Re: Custom Buttons

Dumby
Не, это не для меня, не помню не фига, эта кнопка всю душу вынула и в 63 работает. От какого теперь  в этой версии надломилась?

Выделить код

Код:

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%20PotPlayer%3C/name%3E%0A%20%20%3Cimage%3E%3C%21%5BCDATA%5Bmoz-icon%3A//file%3A//C%3A%5CPotplayer%5Cpotplayer.exe%5D%5D%3E%3C/image%3E%0A%20%20%3Cmode%3E0%3C/mode%3E%0A%20%20%3Cinitcode%3E%3C%21%5BCDATA%5B/*Initialization%20Code*/%0A%0Avar%20path%20%3D%20%27C%3A%5C%5CPotplayer%5C%5Cpotplayer.exe%27%0Avar%20addToPlaylistKey%20%3D%20%22/add%22%3B%0A%0Avar%20sysPlayerName%20%3D%20%22Potplayer%22%3B%0Avar%20openIn%20%3D%20%22%u041E%u0442%u043A%u044B%u0442%u044C%20%u0432%20%22+sysPlayerName%3B%0Avar%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+sysPlayerName%3B%0Avar%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+sysPlayerName%3B%0A%0Avar%20Menu_n_TooltipTxts%20%3D%20%5B%7B%0Alabel%3A%20%22%u0414%u0435%u0439%u0441%u0442%u0432%u0438%u0435%20%u043A%u043D%u043E%u043F%u043A%u0438%3A%20%u0417%u0430%u043F%u0443%u0441%u0442%u0438%u0442%u044C%20%u0432%u0438%u0434%u0435%u043E%20%u0441%u0440%u0430%u0437%u0443%20%u0432%20%22+sysPlayerName%2C%0Aradio%3A%20%27%27%2C%0Avalue%3A%20%27videotoplayer%27%2C%0AtooltipTxt%3A%20%27%u0417%u0430%u043F%u0443%u0441%u0442%u0438%u0442%u044C%20%u0432%u0438%u0434%u0435%u043E%20%u0441%u0440%u0430%u0437%u0443%20%u0432%20%27+sysPlayerName%0A%7D%2C%0A%7B%0Alabel%3A%20%22%u0414%u0435%u0439%u0441%u0442%u0432%u0438%u0435%20%u043A%u043D%u043E%u043F%u043A%u0438%3A%20%u041F%u0435%u0440%u0435%u043D%u0435%u0441%u0442%u0438%20%u0432%u0438%u0434%u0435%u043E%20%u0432%20%u043F%u043B%u0435%u0439%u043B%u0438%u0441%u0442%20%22+sysPlayerName%2C%0Aradio%3A%20%27%27%2C%0Avalue%3A%20%27videotoplaylist%27%2C%0AtooltipTxt%3A%20%27%u041F%u0435%u0440%u0435%u043D%u0435%u0441%u0442%u0438%20%u0432%u0438%u0434%u0435%u043E%20%20%u0432%20%u043F%u043B%u0435%u0439%u043B%u0438%u0441%u0442%20%27+sysPlayerName%0A%7D%2C%0A%5D%3B%0A%0Avar%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%0A%0Aif%28%21%28cbu.getPrefs%28%22CB.video%22%29%29%20%7C%7C%20cbu.getPrefs%28%22CB.video%22%29.length%20%3C%209%29%20cbu.setPrefs%28%22CB.video%22%2C%20%22videotoplayer%22%29%3B%0Avar%20tmp%20%3D%20%27%27%2C%0Atmpp%20%3D%20%27%27%2C%0AinnerA%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%0AinnerB%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%0AstopPl%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%0AytIMGouter%20%3D%20function%28ytID%29%20%7Breturn%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%7D%2C%0AhandlWin%20%3D%20function%28currentWin%29%20%7B%0Atmp%20%3D%20%27%27%3B%0Avar%20elem%20%3D%20currentWin.document.getElementsByTagName%28%27video%27%29%2C%20currLoc%20%3D%20currentWin.location%3B%0Aif%28elem.length%20%3E%200%29%20%7B%0Aif%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%0Aplay%28cbu.getPrefs%28%22CB.video%22%29%20%3D%3D%20%22videotoplaylist%22%20%3F%20%27https%3A//www.youtube.com/embed/%27%20+%20tmp%5B1%5D%20%3A%20%27https%3A//www.youtube.com/watch%3Fv%3D%27%20+%20tmp%5B1%5D%29%3B%0AvideoMovedbox%20%3D%20currentWin.document.createElement%28%27videoMoved%27%29%3B%0AvideoMovedbox.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%0AloadURI%28stopPl%29%3B%0AcurrentWin.document.getElementById%28%27eow-title%27%29.appendChild%28videoMovedbox%29%3B%0Areturn%20true%3B%0A%7D%3B%0Afor%28i%20%3D%200%3B%20i%20%3C%20elem.length%3B%20i++%29%20%7B%0Aif%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%0AvideoMovedbox%20%3D%20currentWin.document.createElement%28%27videoMoved%27%29%3B%0AvideoMovedbox.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%0Aplay%28tmp%29%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0Aif%28currLoc.hostname%20%3D%3D%20%27www.youtube.com%27%29%20%7B%0Aelem%5Bi%5D.parentNode.parentNode.appendChild%28videoMovedbox%29%3B%0A%7D%20else%20%7B%0Aelem%5Bi%5D.parentNode.appendChild%28videoMovedbox%29%3B%0A%7D%3B%0Aelem%5Bi%5D.src%20%3D%20%27%27%3B%0Atry%20%7B%0Aelem%5Bi%5D.load%28%29%0A%7D%20catch%28e%29%20%7B%7D%3B%0Areturn%20true%3B%0A%7D%0A%7D%0A%7D%3B%0A%0AcurrentWin._elems%20%3D%20currentWin.document.getElementsByTagName%28%27iframe%27%29%3B%0Aif%28currentWin._elems.length%20%3E%200%29%20%7B%0Afor%28currentWin._iCounter%20%3D%200%3B%20currentWin._iCounter%20%3C%20currentWin._elems.length%3B%20currentWin._iCounter++%29%20%7B%0Aif%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%0Aplay%28cbu.getPrefs%28%22CB.video%22%29%20%3D%3D%20%22videotoplaylist%22%20%3F%20%27https%3A//www.youtube.com/embed/%27%20+%20tmp%5B1%5D%20%3A%20%27https%3A//www.youtube.com/watch%3Fv%3D%27%20+%20tmp%5B1%5D%29%3B%0AcurrentWin._elems%5BcurrentWin._iCounter%5D.outerHTML%20%3D%20ytIMGouter%28tmp%5B1%5D%29%3B%0Areturn%20true%3B%0A%7D%3B%0Aif%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%29return%20true%3B%0A%7D%0A%7D%3B%0A%0Aelem%20%3D%20currentWin.document.getElementsByTagName%28%27object%27%29%3B%0AcurrLoc%20%3D%20currentWin.location%3B%0Aif%28elem.length%20%3D%3D%200%29%20%7B%0Aelem%20%3D%20currentWin.document.getElementsByTagName%28%27embed%27%29%0A%7D%3B%0Aif%28elem.length%20%3E%200%29%20%7B%0Afor%28i%20%3D%200%3B%20i%20%3C%20elem.length%3B%20i++%29%20%7B%0Aif%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%0Aplay%28cbu.getPrefs%28%22CB.video%22%29%20%3D%3D%20%22videotoplaylist%22%20%3F%20%27https%3A//www.youtube.com/embed/%27%20+%20tmp%5B1%5D%20%3A%20%27https%3A//www.youtube.com/watch%3Fv%3D%27%20+%20tmp%5B1%5D%29%3B%0Aelem%5Bi%5D.outerHTML%20%3D%20ytIMGouter%28tmp%5B1%5D%29%3B%0Areturn%20true%3B%0A%7D%20else%20%7B%0Aif%28elem%5Bi%5D.clientWidth%20%3E%2080%20%26%26%20elem%5Bi%5D.clientHeight%20%3E%2040%29%20%7B%0Aif%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%0Aplay%28tmp%29%3B%0Aelem%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%0Areturn%20true%3B%0A%7D%3B%0A%7D%3B%0A%7D%0A%7D%3B%0A%7D%3B%0Areturn%20false%3B%0A%7D%3B%0A%0Athis.onclick%20%3D%20this.oncontextmenu%20%3D%20e%20%3D%3E%20%7B%0Aif%20%28e.target%20%21%3D%20this%29%20return%3B%0Aif%28e.button%20%3D%3D%200%29%20%7B%0Aif%28cbu.getPrefs%28%22CB.video%22%29.substring%280%2C6%29%20%3D%3D%20%22videom%22%29%7B%0Aelem%20%3D%20content.document.getElementsByTagName%28%27object%27%29%3B%0Aif%28elem.length%20%3D%3D%200%29%20%7B%0Aelem%20%3D%20content.document.getElementsByTagName%28%27embed%27%29%0A%7D%3B%0A%0AresizeObjs%28elem%29%3B%0AresizeObjs%28content.document.getElementsByTagName%28%27iframe%27%29%29%3B%0AresizeObjs%28content.document.getElementsByTagName%28%27video%27%29%29%3B%0A%7D%20else%20%7B%0Aif%28%21handlWin%28content%29%29custombuttons.alertSlide1%28noFound%29%3B%0A%7D%0A%7D%3B%0A%0Aif%28e.button%20%3D%3D%201%29%0AgShowPopup%28self%29%3B%0A%0Aif%28e.button%20%3D%3D%202%20%26%26%20%21e.ctrlKey%20%26%26%20%21e.shiftKey%20%26%26%20%21e.altKey%20%26%26%20%21e.metaKey%29%20%7B%0Ae.preventDefault%28%29%3B%0Amenu.showPopup%28self%2C%20-1%2C%20-1%2C%20%22popup%22%2C%20%22bottomleft%22%2C%20%22topleft%22%29%3B%0A%7D%0A%7D%3B%0Athis.oncontextmenu%20%3D%20e%20%3D%3E%20e.target%20%21%3D%20this%20%3F%20menu.hasAttribute%28%22context%22%29%0A%20%20%20%20%3A%20e.ctrlKey%20%7C%7C%20e.shiftKey%20%7C%7C%20e.altKey%20%7C%7C%20e.metaKey%20%7C%7C%20%28%0A%20%20%20%20%20%20%20%20e.detail%20%21%3D%201%20%3F%20menu.hidePopup%28%29%20%3A%20%21%21menu.openPopup%28this%2C%20%22after_start%22%29%0A%20%20%20%20%29%3B%0Acustombuttons.alertSlide1%20%3D%20function%28sTitle%29%20%7B%0Avar%20as%20%3D%20Components.classes%5B%22@mozilla.org/alerts-service%3B1%22%5D.getService%28Components.interfaces.nsIAlertsService%29%3B%0Aas.showAlertNotification%28%27chrome%3A//global/skin/icons/information-16.png%27%2C%20%22%22%2C%20sTitle%2C%20false%2C%20%22%22%2C%20null%29%3B%0AsetTimeout%28%28%29%20%3D%3E%20as.closeAlert%28%29%2C%20999%29%3B%0A%7D%3B%0A%0Afunction%20resizeObjs%28objs%29%20%7B%0Aif%28%21objs%29%20return%3B%0ALEVELS%20%3D%203%3B%0Adir%20%3D%20%28cbu.getPrefs%28%22CB.video%22%29%20%3D%3D%20%22videomaximize%22%29%20%3F%201%20%3A%20-1%3B%0Afor%28i%20%3D%200%3B%20i%20%3C%20objs.length%3B%20i++%29%20%7B%0Avar%20Width%20%3D%20new%20Array%28LEVELS%29%0Avar%20Height%20%3D%20new%20Array%28LEVELS%29%0AWidth%5B0%5D%20%3D%20objs%5Bi%5D.clientWidth%3B%0AHeight%5B0%5D%20%3D%20objs%5Bi%5D.clientHeight%3B%0Aif%28%28Width%5B0%5D%20%3E%20%28-20%20*%20dir%20+%20100%29%29%20%26%26%20%28Height%5B0%5D%20%3E%20%28-20%20*%20dir%20+%2060%29%29%29%20%7B%0Aobj%20%3D%20objs%5Bi%5D%3B%0Afor%28var%20k%20%3D%201%3B%0A%28%28k%20%3C%20LEVELS%29%20%26%26%20%28obj.parentNode%29%29%3B%20k++%29%20%7B%0Aobj%20%3D%20obj.parentNode%0AWidth%5Bk%5D%20%3D%20obj.clientWidth%3B%0AHeight%5Bk%5D%20%3D%20obj.clientHeight%3B%0A%7D%3B%0AWidth%5B0%5D%20%3D%20Width%5B0%5D%20+%20dir%20*%20%28Width%5B0%5D%20/%205%20%7C%200%29%3B%0AHeight%5B0%5D%20%3D%20Height%5B0%5D%20+%20dir%20*%20%28Height%5B0%5D%20/%205%20%7C%200%29%3B%0Aobjs%5Bi%5D.style.width%20%3D%20Width%5B0%5D%20+%20%22px%22%3B%0Aobjs%5Bi%5D.width%20%3D%20Width%5B0%5D%3B%0Aobjs%5Bi%5D.style.height%20%3D%20Height%5B0%5D%20+%20%22px%22%3B%0Aobjs%5Bi%5D.height%20%3D%20Height%5B0%5D%3B%0Aobj%20%3D%20objs%5Bi%5D%3B%0Afor%28var%20k%20%3D%201%3B%0A%28%28k%20%3C%20LEVELS%29%20%26%26%20%21%28objs%5Bi%5D.tagName%20%3D%3D%20%27IFRAME%27%29%20%26%26%20%28obj.parentNode%29%20%26%26%20%28Width%5Bk%5D%29%20%26%26%20%28Height%5Bk%5D%29%20%26%26%20%28Width%5Bk%5D%20%3E%20%28-20%20*%20dir%20+%20100%29%29%20%26%26%20%28Height%5Bk%5D%20%3E%20%28-20%20*%20dir%20+%2060%29%29%29%3B%20k++%29%20%7B%0Aobj%20%3D%20obj.parentNode%0AWidth%5Bk%5D%20%3D%20Width%5Bk%5D%20+%20dir%20*%20%28Width%5Bk%5D%20/%205%20%7C%200%29%3B%0AHeight%5Bk%5D%20%3D%20Height%5Bk%5D%20+%20dir%20*%20%28Height%5Bk%5D%20/%205%20%7C%200%29%3B%0Aobj.style.width%20%3D%20Width%5Bk%5D%20+%20%22px%22%3B%0Aobj.width%20%3D%20Width%5Bk%5D%3B%0Aobj.style.height%20%3D%20Height%5Bk%5D%20+%20%22px%22%3B%0Aobj.height%20%3D%20Height%5Bk%5D%3B%0A%7D%0A%7D%0A%7D%3B%0A%7D%3B%0A%0Afunction%20restProtHost%28lnkR%2C%20curLoc%29%20%7B%0Aif%28lnkR.length%3D%3D0%29return%20%27%27%3B%0Alet%20tr%20%3D%20lnkR.replace%28/%5E%3A%5C/%5C//%2C%20curLoc.protocol%20+%20%22//%22%29%3B%0Aif%28%21tr.match%28/%5Ehttps%3F%3A%5C/%5C//i%29%29%7B%0AlnkR%20%3D%20tr.replace%28/%5E%5C/+/%2C%20%27%27%29%3B%0Aif%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%7B%0Atr%20%3D%20curLoc.protocol%20+%20%27//%27%20+%20lnkR%3B%0A%7Delse%7B%0Atr%20%3D%20curLoc.protocol%20+%20%27//%27%20+%20curLoc.host%20+%20%22/%22%20+%20lnkR%3B%0A%7D%0A%7D%3B%0Areturn%20tr%3B%0A%7D%3B%0A%0Afunction%20getSrc%28vobj%2C%20currentLoc%29%20%7B%0Avar%20t%20%3D%20%27%27%2C%0Att%20%3D%20%27%27%3B%0Aif%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%20%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%20%29%20%7B%0Aif%28tt.indexOf%28%22.mp4/%3F%22%29%20%3D%3D%20-1%29%20%7B%0Att%20%3D%20tt.replace%28/%26amp%3B/g%2C%20%22%26%22%29%0A%7D%3B%0At%20%3D%20restProtHost%28tt%2C%20currentLoc%29%3B%0Areturn%20t%3B%0A%7D%3B%0Areturn%20%27%27%3B%0A%7D%3B%0A%0Afunction%20getLink%28obj%2C%20curLocation%29%20%7B%0A%0A%0Aif%28%21obj%20%7C%7C%20%21obj.tagName%29%20return%20%27%27%3B%0Avar%20flashvars%20%3D%20%27%27%2C%0A//%20%20%20%20%20%20%20%20src%20%3D%20%27%27%2C%0Aq%20%3D%20obj.tagName.toLowerCase%28%29%3B%0A%0Avar%20getParam%20%3D%20function%28e%2C%20n%29%20%7B%0Avar%20v%20%3D%20%27%27%2C%0Ar%20%3D%20new%20RegExp%28%27%5E%28%27%20+%20n%20+%20%27%29%24%27%2C%20%27i%27%29%2C%0Aparam%20%3D%20e.getElementsByTagName%28%27param%27%29%3B%0Afor%28var%20igp%20%3D%200%2C%20p%3B%20p%20%3D%20param%5Bigp%5D%3B%20igp++%29%20%7B%0Aif%28p.hasAttribute%28%27name%27%29%20%26%26%20p.getAttribute%28%27name%27%29.match%28r%29%29%20%7B%0Av%20%3D%20p.getAttribute%28%27value%27%29%3B%0Abreak%0A%7D%3B%0A%7D%3B%0Areturn%20v%3B%0A%7D%3B%0A%0A%0Aif%28q%20%3D%3D%20%27object%27%29%20%7B%0A//%20%20%20%20%20%20%20%20src%20%3D%20obj.getAttribute%28%27data%27%29%20%7C%7C%20obj.getAttribute%28%27src%27%29%20%7C%7C%20getParam%28obj%2C%20%27movie%7Cdata%7Csrc%7Ccode%7Cfilename%7Curl%27%29%20%7C%7C%20%28obj.getElementsByTagName%28%27embed%27%29.length%20%3E%200%20%3F%20obj.getElementsByTagName%28%27embed%27%29%5B0%5D.getAttribute%28%27src%27%29%20%3A%20%27%27%29%3B%0Aflashvars%20%3D%20getParam%28obj%2C%20%27flashvars%27%29%3B%0A%7D%20else%20if%28q%20%3D%3D%20%27embed%27%29%20%7B%0A//%20%20%20%20%20%20%20%20src%20%3D%20obj.getAttribute%28%27src%27%29%3B%0Aflashvars%20%3D%20obj.getAttribute%28%27flashvars%27%29%3B%0A%7D%20else%20return%20%27%27%3B%0A%0A%0Aif%28%21flashvars%29%20return%20%27%27%3B%0A//%20%20%20src%20%3D%20restProtHost%28src%2C%20curLocation%29%3B%0A%0Avar%20restPath%20%3D%20function%28f%2C%20s%29%20%7B%0Areturn%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%7D%3B%0A%0Afunction%20videoLinkExtract%28fl%29%20%7B%0A//alert%28fl%29%3B%0Avar%20linkArr%20%3D%20%5B%5D%2C%0AoutLinks%20%3D%20%5B%5D%2C%0Ajj%20%3D%200%2C%0Alba%20%3D%20%27%27%2C%0Albb%20%3D%20%27%27%2C%0AdecodeURL%20%3D%20function%28s%29%20%7B%0Atry%20%7B%0Areturn%20decodeURIComponent%28s%29%0A%7D%20catch%28e%29%20%7B%0Areturn%20unescape%28s%29%0A%7D%0A%7D%3B%0A%0Afor%28var%20ij%20%3D%200%3B%20ij%20%3C%203%3B%20ij++%29%20%7B%0Alba%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%0Albb%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%7D%3B%0A%0Afunction%20pushWithMerit%28lnk%29%20%7B%0A%0Avar%20merit%20%3D%20-11%3B%0Aif%28lnk.match%28/%5Ehttps%3F%3A%5C/%5C//i%29%29%20merit%20%3D%20merit%20+%2040%3B%0Aif%28outLinks.length%20%3D%3D%200%29%20merit%20%3D%20merit%20+%201%3B%0Aif%28lnk.match%28/%5E%5C//%29%29%20merit%20%3D%20merit%20+%207%3B%0Aif%28lnk.match%28/%5E%5C/%5C//%29%29%20merit%20%3D%20merit%20+%2030%3B%0Aif%28lnk.match%28/240p%28%5B%5Ea-z%5D%7C%24%29/i%29%29%20merit%20%3D%20merit%20+%201%3B%0Aif%28lnk.match%28/%5B%5Ea-z%5D240%28%5B%5Ea-z0-9%5D%7C%24%29/i%29%29%20merit%20%3D%20merit%20+%201%3B%0Aif%28lnk.match%28/360p%28%5B%5Ea-z%5D%7C%24%29/i%29%29%20merit%20%3D%20merit%20+%203%3B%0Aif%28lnk.match%28/%5B%5Ea-z%5D360%28%5B%5Ea-z0-9%5D%7C%24%29/i%29%29%20merit%20%3D%20merit%20+%203%3B%0Aif%28lnk.match%28/480p%28%5B%5Ea-z%5D%7C%24%29/i%29%29%20merit%20%3D%20merit%20+%205%3B%0Aif%28lnk.match%28/%5B%5Ea-z%5D480%28%5B%5Ea-z0-9%5D%7C%24%29/i%29%29%20merit%20%3D%20merit%20+%205%3B%0Aif%28lnk.match%28/720p%28%5B%5Ea-z%5D%7C%24%29/i%29%29%20merit%20%3D%20merit%20+%207%3B%0Aif%28lnk.match%28/%5B%5Ea-z%5D720%28%5B%5Ea-z0-9%5D%7C%24%29/i%29%29%20merit%20%3D%20merit%20+%207%3B%0Aif%28lnk.match%28/%5C.mp4%28%5B%5Ea-z%5D%7C%24%29/i%29%29%20merit%20%3D%20merit%20+%208%3B%0Aif%28lnk.match%28/_hd%28%5B%5Ea-z%5D%7C%24%29/i%29%29%20merit%20%3D%20merit%20+%206%3B%0Aif%28lnk.match%28/%5C.%28jpg%7Cxml%29%28%5B%5Ea-z%5D%7C%24%29/i%29%29%20merit%20%3D%20merit%20-%2040%3B%0Aif%28merit%20%3E%200%29%20outLinks.push%28merit%20+%20lba%20+%20lnk%29%3B%0AServices.console.logStringMessage%28%27merit%3A%27+merit+%27%20lnk-%3E%27+lnk%29%3B%0A%7D%3B%0A%0AlinkArr.push%28fl%29%3B%0Awhile%28linkArr.length%20%3E%20jj%20%26%26%20jj%20%3C%2030%29%20%7B%0A%0Avar%20testPaths%20%3D%20%5B%5D%3B%0AtestPaths%20%3D%20linkArr%5Bjj%5D.split%28/%28%5C.%28%3F%3Aflv%7Cmp4%7Cm3u8%29%29/i%29%3B%0Aif%28testPaths%5BtestPaths.length%20-%201%5D%20%3D%3D%20%27%27%29%20testPaths.pop%28%29%3B%0A%0Afor%28k%20%3D%201%3B%20k%20%3C%20testPaths.length%3B%20k%20%3D%20k%20+%202%29%20%7B%0A%0Aif%28testPaths%5Bk%20-%201%5D.indexOf%28lba%29%20%3E%20-1%29%20%7B%0Apref%20%3D%20testPaths%5Bk%20-%201%5D%3B%0A%7D%20else%20%7B%0Avar%20testAboutDom%20%3D%20testPaths%5Bk%20-%201%5D.toLowerCase%28%29.split%28/%28https%3F%3A%5C/%5C/%29/%29%3B%20%0Aif%28testAboutDom%5BtestAboutDom.length%20-%201%5D%3D%3D%27%27%29%20testAboutDom.pop%28%29%3B%0Avar%20pTest%20%3D%20testAboutDom%5BtestAboutDom.length%20-%201%5D.split%28/%28%5C%3F%5B%5E%5C%3F%5D*%3F%26%29/%29%3B%0Aif%28pTest.length%3E2%29%7B%0ApTest.pop%28%29%3B%0ApTest.pop%28%29%3B%0A%7D%3B%0AtestAboutDom%5BtestAboutDom.length%20-%201%5D%20%3D%20pTest.join%28%27%27%29%3B%0Apref%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%7D%3B%0A%0At2%20%3D%20pref.lastIndexOf%28lbb%29%3B%0Aif%28t2%20%3E%20-1%29%20%7B%0Apref%20%3D%20pref.substring%28t2%20+%203%29%3B%0A%7D%20else%20%7B%0A%0At2%20%3D%20pref.lastIndexOf%28%27%7B%22%27%29%3B%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%202%29%3B%0At2%20%3D%20pref.lastIndexOf%28%27%5B%22%27%29%3B%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%202%29%3B%0At2%20%3D%20pref.lastIndexOf%28%27%2C%22%27%29%3B%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%202%29%3B%0At2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27%22http%3A//%27%29%3B%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0At2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27%22https%3A//%27%29%3B%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0At2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27%2Chttp%3A//%27%29%3B%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0At2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27%2Chttps%3A//%27%29%3B%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0At2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27%3Bhttp%27%29%3B%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0At2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27*https%3A//%27%29%3B%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0At2%20%3D%20pref.toLowerCase%28%29.lastIndexOf%28%27%20or%20%27%29%3B%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%204%29%3B%0A%0Apref%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%7D%0A%0Aif%28pref.length%20%3E%200%29%20%7B%0A%0Aif%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%0At2%20%3D%20pref.indexOf%28%27%22%27%29%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%201%29%3B%0Asuff%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%0Aif%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%0Aif%28testPaths.length%20%3E%20k%20+%201%29%20%7B%0AtestPaths%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%7D%3B%0At2%20%3D%20pref.lastIndexOf%28lba%29%3B%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%203%29%0AlinkArr.push%28decodeURL%28pref%20+%20testPaths%5Bk%5D%20+%20suff%29%29%3B%0A%0A%7D%20else%20%7B%0AtestPaths%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%7D%0A%7D%20else%20%7B%0Asuff%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%0At2%20%3D%20suff.indexOf%28%27%26%27%29%3B%0Aif%28%28t2%20%3E%20-1%29%20%26%26%20%28pref%20%21%3D%20testPaths%5Bk%20-%201%5D%29%29%20%7B%0Aif%28t2%20%3D%3D%200%29%20suff%20%3D%20%27%27%3B%0Aif%28suff.charAt%280%29%20%21%3D%20%27%3F%27%29%20suff%20%3D%20suff.split%28/%28%26%5B%5E%26%5D+%3Dhttps%3F%3A%5C/%5C/%29/i%29%5B0%5D%3B%0A%7D%3B%0Aif%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%0Aif%28testPaths.length%20%3E%20k%20+%201%29%20%7B%0AtestPaths%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%7D%3B%0At2%20%3D%20pref.lastIndexOf%28lba%29%3B%0Aif%28t2%20%3E%20-1%29%20pref%20%3D%20pref.substring%28t2%20+%203%29%3B%0ApushWithMerit%28pref%20+%20testPaths%5Bk%5D%20+%20suff%29%3B%0A%0A%7D%20else%20%7B%0AtestPaths%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%7D%0A%7D%0A%7D%0A%7D%3B%0Ajj%20%3D%20jj%20+%201%3B%0A%7D%3B%0A%0Aif%28outLinks.length%20%3D%3D%200%29%20return%20%27%27%3B%0Afunction%20srt%28a%2C%20b%29%20%7B%0Aa%20%3D%20parseInt%28a.substr%280%2C%20a.indexOf%28lba%29%29%2C%2010%29%3B%0Ab%20%3D%20parseInt%28b.substr%280%2C%20b.indexOf%28lba%29%29%2C%2010%29%3B%0Aif%28a%20%3C%20b%29%20return%201%3B%0Aif%28a%20%3E%20b%29%20return%20-1%3B%0Areturn%200%0A%7D%3B%0AoutLinks.sort%28srt%29%3B%0AoutLinks%5B0%5D%20%3D%20outLinks%5B0%5D.substr%28outLinks%5B0%5D.indexOf%28lba%29%20+%203%29%0Aif%28outLinks%5B0%5D.indexOf%28%27_hq.mp4/%3Ftime%3D%27%29%20%3E%200%29%20outLinks%5B0%5D%20%3D%20outLinks%5B0%5D.replace%28/%26/g%2C%20%27%26amp%3B%27%29%3B%0Areturn%20outLinks%5B0%5D%3B%0A%7D%3B%0Aol%20%3D%20videoLinkExtract%28flashvars%29%3B%0Aif%28%21ol%29%20return%20%27%27%3B%0A//%20%20%20%20ol%20%3D%20ol.replace%28/%5E%3A%3F%5C/%5C//%2C%20curLocation.protocol%20+%20%22//%22%29%3B%0A//%20%20%20%20return%20restPath%28ol%2C%20src%29%3B%0Areturn%20restProtHost%28ol%2C%20curLocation%29%3B%0A%7D%3B%0A%0A%0Avar%20menu%20%3D%20self.appendChild%28document.createElement%28%22menupopup%22%29%29%3B%0Aself.image%20%3D%20%22moz-icon%3A//file%3A//%22%20+%20path%3B%0Avar%20playerName%20%3D%20path.split%28%22%5C%5C%22%29.pop%28%29.replace%28%22.exe%22%2C%22%22%29%3B%0Aself.label%20%3D%20%22%u041E%u0442%u043A%u0440%u044B%u0442%u044C%20%u0432%u0438%u0434%u0435%u043E%20%u0432%20%22%20+sysPlayerName%3B%0AsetTimeout%28%28%29%20%3D%3E%20%7B%0AMenu_n_TooltipTxts.forEach%28%28m%29%20%3D%3E%20%7B%0Aif%28%22separator%22%20in%20m%29%20%7B%0Amenu.appendChild%28document.createElement%28%22menuseparator%22%29%29%3B%0Areturn%0A%7D%3B%0Avar%20mItem%20%3D%20document.createElement%28%22menuitem%22%29%3B%0AmItem.setAttribute%28%22label%22%2C%20m.label%29%3B%0A%0Aif%28%22radio%22%20in%20m%29%20%7B%0AmItem.setAttribute%28%22type%22%2C%20%22radio%22%29%3B%0AmItem.setAttribute%28%27checked%27%2C%20cbu.getPrefs%28%22CB.video%22%29%20%3D%3D%20m.value%29%3B%0Aif%28cbu.getPrefs%28%22CB.video%22%29%20%3D%3D%20m.value%29%20%7B%0Aself.tooltipText%20%3D%20m.tooltipTxt%3B%0A%7D%0AmItem.onclick%20%3D%20%28%29%20%3D%3E%20%7B%0Acbu.setPrefs%28%22CB.video%22%2C%20m.value%29%3B%0Atmp%20%3D%20%28self.image%20%3D%3D%20imgFlashToPlayer%20%7C%7C%20self.image%20%3D%3D%20imgFlashMinimize%20%7C%7C%20%20self.image%20%3D%3D%20imgFlashMaximize%29%3B%0Aif%28m.value.substring%280%2C9%29%3D%3D%27videotopl%27%29%7B%0Aself.image%20%3D%20tmp%20%3F%20imgFlashToPlayer%20%3A%20imgHTML5ToPlayer%3B%0A%7D%20else%20if%28m.value%3D%3D%27videominimize%27%29%20%7B%0Aself.image%20%3D%20tmp%20%3F%20imgFlashMinimize%20%3A%20imgHTML5Minimize%3B%0A%7D%20else%20self.image%20%3D%20tmp%20%3F%20imgFlashMaximize%20%3A%20imgHTML5Maximize%3B%0Aself.tooltipText%20%3D%20m.tooltipTxt%3B%0A%7D%3B%0A%7D%0Aif%28%22checkbox%22%20in%20m%29%20%7B%0AmItem.setAttribute%28%27type%27%2C%20%27checkbox%27%29%3B%0AmItem.setAttribute%28%27checked%27%2C%20%28self.image%20%3D%3D%20imgFlashToPlayer%20%7C%7C%20self.image%20%3D%3D%20imgFlashMinimize%20%7C%7C%20%20self.image%20%3D%3D%20imgFlashMaximize%20%29%29%3B%0AmItem.onclick%20%3D%20function%28e%29%20%7B%0Ae.stopPropagation%28%29%3B%0Ae.preventDefault%28%29%3B%0Aif%28e.button%20%3D%3D%200%29%20toggleFlash%28%29%3B%0A%7D%0A%7D%0Amenu.appendChild%28mItem%29%3B%0A%7D%29%3B%0Amenu.onclick%20%3D%20function%28e%29%20%7B%0Ae.stopPropagation%28%29%3B%0Aif%28e.button%20%3E%200%29%20e.preventDefault%28%29%3B%0A%7D%3B%0A%7D%2C%20100%29%3B%0Avar%20contextMenu%20%3D%20document.getElementById%28%22contentAreaContextMenu%22%29%3B%20%0Avar%20menuitem%20%3D%20contextMenu.insertBefore%28document.createElement%28%22menuitem%22%29%2C%20document.getElementById%28%22context-sep-open%22%29%29%3B%0Amenuitem.setAttribute%28%22label%22%2C%20%22%u041E%u0442%u043A%u0440%u044B%u0442%u044C%20%u0432%20%22%20+sysPlayerName%29%3B%20%20%20%20%20%20%0Amenuitem.setAttribute%28%22class%22%2C%20%22menuitem-iconic%22%29%3B%0Amenuitem.setAttribute%28%22image%22%2C%20%22moz-icon%3A//file%3A//%22%20+%20path%29%3B%20%0Amenuitem.onclick%20%3D%20%28%29%20%3D%3E%20play%28gContextMenu.linkURL%29%3B%0AaddEventListener%28%22popupshowing%22%2C%20%28%29%3D%3E%20menuitem.hidden%20%3D%20%21gContextMenu.onLink%2C%20false%2C%20contextMenu%29%3B%0AaddDestructor%28%28%29%3D%3E%20menuitem.remove%28%29%20%29%3B%0Avar%20contextMenu%20%3D%20document.getElementById%28%22contentAreaContextMenu%22%29%3B%0Avar%20mItem%20%3D%20contextMenu.insertBefore%28document.createElement%28%22menuitem%22%29%2C%20document.getElementById%28%22context-copyvideourl%22%29%29%3B%0AmItem.setAttribute%28%22label%22%2C%20openIn%29%3B%0AmItem.onclick%20%3D%20%28%29%20%3D%3E%20%7B%0Avar%20vurl%20%3D%20gContextMenu.mediaURL%2C%20videoelem%20%3D%20gContextMenu.target%3B%0Aif%28videoelem%20%26%26%20videoelem.nodeName.toLowerCase%28%29%20%3D%3D%20%27video%27%29%20%7B%0Aif%28content.location.hostname.indexOf%28%27youtu%27%29%20%21%3D%20-1%20%26%26%20%28tmp%20%3D%20content.location.toString%28%29.match%28YoutubeID%29%29%20%26%26%20tmp%5B1%5D.length%20%3D%3D%2011%29%20%7B%0Aplay%28vurl%29%3B%0AvideoMovedbox%20%3D%20content.document.createElement%28%27videoMoved%27%29%3B%0AvideoMovedbox.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%0AloadURI%28stopPl%29%3B%0Acontent.document.getElementById%28%27eow-title%27%29.appendChild%28videoMovedbox%29%3B%0Areturn%3B%0A%7D%3B%0A%0Aif%28content.location.hostname%20%3D%3D%20%27www.youtube.com%27%29%20%7B%0Avideoelem.parentNode.parentNode.appendChild%28videoMovedbox%29%3B%0A%7D%20else%20%7B%0Avar%20inFrameHref%20%3D%20inFrameWin.location.href%2C%20found%20%3D%20false%3B%0Aif%28inFrameWin.location.hostname%20%3D%3D%20%27www.youtube.com%27%20%26%26%20%28tmp%20%3D%20inFrameHref.match%28YoutubeID%29%29%20%26%26%20tmp%5B1%5D.length%20%3D%3D%2011%29%7B//%u0438%20%u0437%u043D%u0430%u0447%u0438%u0442%20%u0432%u043E%20%u0444%u0440%u0435%u0439%u043C%u0435%0Aelem%20%3D%20inFrameWin.parent.document.getElementsByTagName%28%27iframe%27%29%3B%0Aif%28elem.length%20%3E%200%29%20%7B%0Afor%28i%20%3D%200%3B%20i%20%3C%20elem.length%3B%20i++%29%20%7B%0Aif%28elem%5Bi%5D.contentWindow%20%3D%3D%20inFrameWin%29%20%7B%0Aelem%5Bi%5D.outerHTML%20%3D%20ytIMGouter%28tmp%5B1%5D%29%3B%0Afound%20%3D%20true%3B%0Abreak%3B%0A%7D%3B%0A%7D%3B%0A%7D%3B%0Aif%28%21found%29inFrameWin.document.body.innerHTML%20%3D%20ytIMGouter%28tmp%5B1%5D%29%3B%0Areturn%3B%0A%7D%3B%0Avideoelem.parentNode.appendChild%28videoMovedbox%29%3B%0A%7D%3B%0Avideoelem.src%20%3D%20%27%27%3B%0Atry%20%7B%0Avideoelem.load%28%29%0A%7D%20catch%28e%29%20%7B%7D%3B%0A%7D%20else%20play%28vurl%29%3B%0A%7D%3B%0A%0A%0AaddEventListener%28%22popupshowing%22%2C%20%28%29%20%3D%3E%20%7B%0AmItem.hidden%20%3D%20%21gContextMenu.onVideo%20%7C%7C%20%21gContextMenu.mediaURL%3B%0AmItem2.hidden%20%3D%20%21gContextMenu.linkURL%3B%0AmItem3.hidden%20%3D%20framItem.hidden%20%7C%7C%20gContextMenu.target.ownerDocument.location.hostname.indexOf%28%27youtube.com%27%29%20%3D%3D%20-1%3B%0A%7D%2C%20false%2C%20contextMenu%29%3B%0AaddDestructor%28%28%29%20%3D%3E%20%7BmItem.remove%28%29%3BmItem2.remove%28%29%3BmItem3.remove%28%29%7D%29%3B%0A%0Afunction%20play%28link%29%20%7B%0Avar%20file%20%3D%20Services.dirsvc.get%28%27CurProcD%27%2C%20Ci.nsIFile%29%3B%0Avar%20MozExeDir%20%3D%20file.path.split%28%27%5C%5C%27%29.slice%280%2C-1%29.join%28%27%5C%5C%27%29%3B%0Afile.initWithPath%28path%29%3B%0Aif%28%21file.exists%28%29%29%20%7B%0Acustombuttons.alertBox%28%22File%20not%20found%21%22%2C%20MozExeDir%20+%20Path%29%3B%0Areturn%3B%0A%7D%3B%0Avar%20process%20%3D%20Cc%5B%22@mozilla.org/process/util%3B1%22%5D.createInstance%28Ci.nsIProcess%29%3B%0Aprocess.init%28file%29%3B%0Aprocess.run%28false%2C%20%5Blink%2C%20cbu.getPrefs%28%22CB.video%22%29%20%3D%3D%20%22videotoplaylist%22%20%3F%20addToPlaylistKey%20%3A%20%22%22%5D%2C%202%29%3B%0A%7D%3B%0A%5D%5D%3E%3C/initcode%3E%0A%20%20%3Ccode%3E%3C%21%5BCDATA%5B/*CODE*/%5D%5D%3E%3C/code%3E%0A%20%20%3Caccelkey%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/accelkey%3E%0A%20%20%3Chelp%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/help%3E%0A%20%20%3Cattributes/%3E%0A%3C/custombutton%3E

Отсутствует

 

№1300417-12-2018 21:03:45

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

Re: Custom Buttons

Dumby
Вы бы не могли посмотреть вот эту кнопку (перестала работать на 61 - вообще пропадает из интерфейса, а в консоли ни одной ошибки) или сделать что нибудь на подобие. Смысл этой копки - скопировал текст, нажал на кнопку - в текстовый файл добавил  строку с текстом. Скопировал следующий текст, добавил в файл текст с новой строки. Меню копки считывает из файла эти строки и создает меню в том количестве, сколько строк в файле и название пунктов меню соответственно текст строк  .  Потом в любом текстовом поле при нажатии  пункта меню кнопки вставляются текстовые значения строк. Можно вообще упростить  - только считывать из текстового файла, а в файл вручную вносить. 

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

Выделить код

Код:

function fileName()
{
        let dir = Components.classes["@mozilla.org/file/directory_service;1"]
                   .getService(Components.interfaces.nsIProperties)
                   .get("ProfD", Components.interfaces.nsIFile);
        dir.append("custombuttons");
        if (!dir.exists()) {
            try{
                dir.create(0x01, 0x1ED);
            } catch(e){
                let msg='Custom Buttons error.]'
                    +'[ Event: Creating custombuttons directory]'
                    +'[ '+e;
                Components.utils.reportError(msg);
            }
        }
    return dir.path;
}

function writeFile (sFilePath, sFileContent)
{
   var suc = Cc ["@mozilla.org/intl/scriptableunicodeconverter"]. createInstance (Ci. nsIScriptableUnicodeConverter);
    suc. charset = "UTF-8";
    cbu. writeFile (sFilePath, suc. ConvertFromUnicode (sFileContent)); 
}


function readFile (sFilePath)
{
 var suc = Cc ["@mozilla.org/intl/scriptableunicodeconverter"]. createInstance (Ci. nsIScriptableUnicodeConverter);
    suc. charset = "UTF-8";
        try {
        return suc. ConvertToUnicode (cbu. readFile (sFilePath));
    }
    catch(e) {
    }
    return "";   
}
//********  Read write ******
let mp;
this.removeNode = function( aNode ){
    closeMenus( aNode );
    mp.removeChild( aNode );
 
};

function reAssignId(){
    let NL=mp.childNodes;
    for(let i=0;i<NL.length;i++)
    {
        mp.removeChild(NL[i].id=i+1);
    }
}

function addMenuItem(aNode, aLabel, aContextId, aCommand) {
 var mWid = 55;
   var mi = aNode.appendChild(document.createElement("menuitem"));
  mi.setAttribute("label", aLabel.substr(0,mWid));
   mi.setAttribute("value", aLabel);
   mi.setAttribute("id",aNode.childNodes.length);
  if(aContextId) mi.setAttribute("context", aContextId);
  if(aCommand) mi.setAttribute("oncommand", aCommand);

}
function donoth(){}

let contextId = "popup-item-clipping";
let test = document.getElementById(contextId);
if(test) test.parentNode.removeChild(test);
let mainPopup = document.getElementById("mainPopupSet");
let context = mainPopup.appendChild(document.createElement("menupopup"));
context.id = contextId;
//addMenuItem(context, "Удалить элемент?", null,
addMenuItem(context, "Удалить элемент?",null, "document.popupNode.parentNode.parentNode.removeNode(document.popupNode);");


let filePath=fileName()+"/InFormEnter.txt";
  let data=readFile(filePath);
    let popupItems=data.split('\n');
mp = document.createElement("menupopup");
addMenuItem(mp, "Сохранить", null,"this.parentNode.parentNode.save()");
mp.setAttribute("oncommand", "this.parentNode.paste(event)");

for(var i = 0; i < popupItems.length; i++) {
    popupItems[i].replace(/\\s/g,'');
if(popupItems[i].length>1)
 addMenuItem(mp, popupItems[i], contextId);
}

function getData()
{
    let NL=mp.childNodes;
    let data="";
    for(let i=1;i<NL.length;i++)
    {
        data=data+NL[i].value+"\n";
    }
    return data;
}

this.execute=function(evt)
{
    if(evt.target.value==-1)
    addMenuItem(mp,readFromClipboard(),contextId);
}

this.save=function()
{
writeFile(filePath,getData())
}

this.paste=function(e)
{

var open=e.target.value;
if (open != "Save"){
var theBox = document.commandDispatcher.focusedElement;
var startPos = theBox.selectionStart;
var endPos = theBox.selectionEnd;
var selectionLen = endPos - startPos
var oPosition = theBox.scrollTop;
var oHeight = theBox.scrollHeight;
var text=theBox.value.substring(0,startPos); 
var nHeight = theBox.scrollHeight - oHeight;
text +=open;
text +=theBox.value.substring(endPos, theBox.value.length);
theBox.value = text; 
theBox.selectionStart = endPos + open.length;
theBox.selectionEnd = endPos + open.length - selectionLen;
theBox.scrollTop = oPosition + nHeight;
}
};


this.getSupportedFlavours = function () {
    var flavours = new FlavourSet();
    flavours.appendFlavour("text/unicode");
    return flavours;
  }
 this.onDragOver = function(e,f,s){}
  this.onDrop = function(event,dDat,session){
addMenuItem(mp,dDat.data.split('\n')[0],contextId)
  }

this.setAttribute("ondragover","nsDragAndDrop.dragOver(event,this);");
this.setAttribute("ondragdrop","nsDragAndDrop.drop(event,this);");
this.tooltipText = this.label;
this.appendChild(mp);
this.value=-1;
this.type = "menu-button";
this.setAttribute("oncommand", "this.execute(event);");

this.orient = "horizontal";


А вот похожая по смыслу кнопка работает (она записывает не в текстовый файл, а буфер обмена)
скрытый текст

Выделить код

Код:

/*Initialization Code*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Блок инициализации глоб. переменных и функций
// срок существования - один сеанс браузера
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
bbBBCodeStat=true                                                   // разрешить/включить BBCode
window.arycb_BBCodeClipboardStrings = this.clipboardStrings = [];   // Массив буфера обмена

//
//********************************************************
//--------Общие функции для вставки BBCode----------------
//*********************************************************

//++++++++++++++++++BEGIN DEF++++++++++++++++++++++++++++++
//--------------------------------------------------------
// Функция lb_BBCodePrim 
// [bbCode]выделенный[/bbCode]
//  по умолчанию от ЛКМ)
lb_BBCodePrim = function (open,close){
var theBox = document.commandDispatcher.focusedElement;
var startPos = theBox.selectionStart;
var endPos = theBox.selectionEnd;
var oPosition = theBox.scrollTop;
var oHeight = theBox.scrollHeight;
var text=theBox.value.substring(0,startPos);
text +=open+theBox.value.substring(startPos, endPos)+close;
text +=theBox.value.substring(endPos, theBox.value.length);
theBox.value = text;
var nHeight = theBox.scrollHeight - oHeight;
theBox.scrollTop = oPosition + nHeight;
};

//---------------------------------------------------------
// Функция mb_BBCodePrim 
// Резерв
// по умолчанию от CКМ
mb_BBCodePrim = function (open,close) {};

// -------------------------------------------------------
// Функция rb_BBCodePrim 
// [bbCode]параметр PASTE по умолчанию из буфер обмена[/bbCode]
// по умолчанию от ПКМ
rb_BBCodePrim = function (open,close,paste){
if (paste == undefined)  { open +=close;} //буфер обмена пуст
   else                 { open +=paste+close;}
   
var theBox = document.commandDispatcher.focusedElement;
var startPos = theBox.selectionStart;
var endPos = theBox.selectionEnd;
var selectionLen = endPos - startPos
var oPosition = theBox.scrollTop;
var oHeight = theBox.scrollHeight;
var text=theBox.value.substring(0,startPos); 
var nHeight = theBox.scrollHeight - oHeight;
text +=open;
text +=theBox.value.substring(endPos, theBox.value.length);
theBox.value = text; 
theBox.selectionStart = endPos + open.length;
theBox.selectionEnd = endPos + open.length - selectionLen;
theBox.scrollTop = oPosition + nHeight;
};

// -------------------------------------------------------
// Функция fHLD_Get_ListClipboardPrim 
// получить список сохранёного буфера обмена
//
fnHLD_Get_ListClipboardPrim = function (){
var cs = arycb_BBCodeClipboardStrings; 
return (cs.slice(0)); 
}; 


//++++++++++++++++++END DEF+++++++++++++++++++++++++++++++++++

//Список сохранёного буфера обмена
//Не вызываем это, обработка по таймеру или по событию ЛКМ
//-----Обработчики буфера обмена

this.MAX_ENTRIES = 16;               //Максимальное число записей 16
this.CHECK_INTERVAL = 1000;      //Время опроса буфера 1000 миллисекунд
this.type = "menu";
this.orient = "horizontal";
this._menupopup = this.appendChild(document.createElement("menupopup"));
this._menupopup.setAttribute("oncommand", "this.parentNode.handleCommand(event.target);");



this.checkClipboard = function() {
    var clipStr = readFromClipboard();
    if(clipStr && this.clipboardStrings.indexOf(clipStr) == -1)
        this.storeString(clipStr);
};


this.storeString = function(str) {
    var cs = this.clipboardStrings;
    cs.push(str);
    while(cs.length > this.MAX_ENTRIES)
        cs.shift(); 

    var mi = document.createElement("menuitem");
    mi.setAttribute("label", str);
   
    
    this._menupopup.appendChild(mi);
    while(this._menupopup.childNodes.length > this.MAX_ENTRIES)
        this._menupopup.removeChild(this._menupopup.firstChild);
};


this.handleCommand = function(mi) {
    var indx = Array.indexOf(mi.parentNode.childNodes, mi);
    if(indx != -1)
        this.insertText(this.clipboardStrings[indx]);
};

this.insertText = function(str) {
    var cmd = "cmd_insertText";
    var controller = document.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", str);
        controller.doCommandWithParams(cmd, params);
    }
};

setInterval(function(button) {
    button.checkClipboard();
}, this.CHECK_INTERVAL, this);

this.setAttribute("onpopupshowing", "this.checkClipboard();");

Отредактировано Andrey_Krropotkin (17-12-2018 23:31:49)

Отсутствует

 

№1300517-12-2018 22:12:44

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 316
UA: Firefox 64.0

Re: Custom Buttons

drage2
Походу, у тебя косяк не в кнопке. У меня работает на 64 на твоей сборке.

Отредактировано Garalf (17-12-2018 22:14:43)

Отсутствует

 

№1300617-12-2018 22:20:51

drage2
Забанен
 
Группа: Members
Откуда: Донецк
Зарегистрирован: 23-11-2017
Сообщений: 392
UA: Firefox 64.0

Re: Custom Buttons

Garalf
На какой сборке? 64 ? Контекст на кнопке ПКМ - перенести в плейлист - работает? Не гонишь?

Отсутствует

 

№1300717-12-2018 22:39:03

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 316
UA: Firefox 64.0

Re: Custom Buttons

drage2
ПКМ не работает. Перенести в плейлист у меня по умолчанию установлен, поэтому не заморачиваюсь. Главное - кнопка работает.

Отсутствует

 

№1300817-12-2018 23:39:01

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

Re: Custom Buttons

Karn
Ох, далёк я от всех этих видосов, у меня вообще
скрипты запрещены, так что я как-бы не в теме.
Могу попробовать набросать что-нибудь с твоих слов.

Клик по пункту меню не левой кнопкой — выбор папки,
если не работает, надеюсь найдешь где удалить блок menuitem.onauxclick

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

Выделить код

Код:

(popup => addEventListener("popupshowing", {
    handleEvent(e) {
        if (e.target != popup || this.shouldHide) return;
        var menuitem = document.createElement("menuitem");
        for(var args of Object.entries({
            class: "menuitem-iconic",
            id: "context-sendlinktoytdl",
            label: "Отправить в youtube-dl",
            oncommand: "linkedObject.oncommand();",
            image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAc0lEQVQ4jWNgGB7gvqdtwANP+y8PvOz/E4Pve9m/v+9pG4AwwMv+PLGakQw5DzcAm4Ifty//f5IQhtcQvAb8/fP1/++Pr/6/bKog3wAY/rBuKWUGfNq5kXwvvO5tJs8LP25f/v80O5G4QKQ4GilOSEMbAAAJoGH0pNGWEwAAAABJRU5ErkJggg=="
        }))
            menuitem.setAttribute(...args);
        menuitem.linkedObject = this;
        popup.insertBefore(menuitem, popup.querySelector("#context-sep-open"));
        addDestructor(() => menuitem.remove());
        this.handleEvent = e => {
            if (e.target == popup) menuitem.hidden = this.shouldHide;
        }
        menuitem.onauxclick = e => {
            e.preventDefault();
            var link = gContextMenu.linkURL;
            var fp = makeFilePicker();
            fp.init(window, null, fp.modeGetFolder);
            fp.open(res => {
                if (res != fp.returnOK) return;
                fp.file.append("%(title)s.%(ext)s");
                this.oncommand(fp.file.path, link);
            });
        }
    },
    get shouldHide() {
        return !(gContextMenu.onLink || gContextMenu.onPlainTextLink)
            || !/^https?:\/\//.test(gContextMenu.linkURL);
    },
    args: ["--no-check-certificate", "--no-call-home", "-o"],
    oncommand(path = String.raw`D:\YouTube\%(title)s.%(ext)s`, link = gContextMenu.linkURL) {

        var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
        process.init(FileUtils.File(String.raw`D:\YouTube\youtube-dl.exe`));

        var args = this.args.concat(path, link);
        process.runwAsync(args, args.length);
    }
}, false, popup || 1))(document.getElementById("contentAreaContextMenu"));

Отсутствует

 

№1300918-12-2018 00:11:05

Karn
Участник
 
Группа: Members
Зарегистрирован: 11-12-2018
Сообщений: 45
UA: Firefox 64.0

Re: Custom Buttons

Dumby
Огромное спасибо, всё работает! :beer: По сути, реализована давнишняя мечта всех пользователей браузеров, сохранять видео так же просто, как картинки. :angel: Самое крутое, что не нужно запускать само видео, а потом только скачивать, как это реализовано во всех дополнениях.

А можно окно cmd запускать в фоне, а не на переднем плане?

Отредактировано Karn (18-12-2018 00:15:04)

Отсутствует

 

№1301018-12-2018 14:38:09

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

Re: Custom Buttons

drage2 пишет

какого теперь  в этой версии надломилась?

Без понятия. Но менюшку будет показывать, если выкинешь

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

Выделить код

Код:

if(e.button == 2 && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) {
e.preventDefault();
menu.showPopup(self, -1, -1, "popup", "bottomleft", "topleft");
}

Andrey_Krropotkin пишет

вообще пропадает из интерфейса, а в консоли ни одной ошибки) или сделать что нибудь на подобие

Пропадает потому, что toolbarbutton[type="menu-button"] в Firefox больше нет.
Может что-нибудь более примитивное подойдёт, типа

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

Выделить код

Код:

this.type != "menu" ? this.type = "menu" : (popup => {
    var inserter = {
        get docShell() {
            delete this.docShell;
            return this.docShell = "docShell" in document
                && document.docShell instanceof Ci.nsIDocShell
                ? document.docShell : window.docShell;
        },
        get insertText() {
            delete this.insertText;
            return this.insertText = text => {
                if (!this.docShell.isCommandEnabled("cmd_insertText")) return;
                var params = "createCommandParams" in Components.utils
                    ? Cu.createCommandParams()
                    : Components.classes["@mozilla.org/embedcomp/command-params;1"]
                        .createInstance(Components.interfaces.nsICommandParams);
                params.setStringValue("state_data", text);
                this.docShell.doCommandWithParams("cmd_insertText", params);
            }
        },
        insert(text) {
            var br = document.activeElement;
            !br || br.localName != "browser" || !br.isRemoteBrowser
            ? this.insertText(text) : br.messageManager.loadFrameScript(
                `data:,(${this.insertText})${encodeURIComponent(text.toSource())}`
            , false, true);
        }
    };
    this.onmousedown = e => {
        if (e.button) return;
        this.onmousedown = null;

        var data, save = () => {
            var link = custombuttons.makeButtonLink("update", _id);
            var params = custombuttons.cbService.getButtonParameters(link).wrappedJSObject;
            params.help = JSON.stringify(data, null, "\t");
            custombuttons.cbService.installButton(params.wrappedJSObject = params);
        }
        popup.setAttribute("context", "");
        popup.setAttribute("onpopupshowing", "firstChild.disabled = !gClipboard.read();");

        popup.add = () => save(data.push(gClipboard.read()));

        var menuitem = popup.appendChild(document.createElement("menuitem"));
        menuitem.setAttribute("label", "Добавить из буфера");
        menuitem.setAttribute("oncommand", "parentNode.add();");

        if (!(data = JSON.parse(this.Help || "[]")).length) return;

        popup.insert = ind => inserter.insert(data[ind]);
        popup.delete = ind => save(data.splice(ind, 1));

        var df = document.createDocumentFragment();
        df.append(document.createElement("menuseparator"));

        var menugroup = df.appendChild(document.createElement("menugroup"));
        menugroup.setAttribute("oncommand", "parentNode.insert(event.target.index);");
        menugroup.setAttribute("orient", "vertical");
        menugroup.setAttribute("context", "_child");

        var context = menugroup
            .appendChild(document.createElement("menupopup"))
            .appendChild(document.createElement("menuitem"));
        context.setAttribute("label", "Удалить элемент?");
        context.setAttribute("oncommand", "event.stopPropagation(); menupopup.delete(popupNode.index);");
        context.menupopup = popup;

        data.forEach((text, ind) => {
            var menuitem = menugroup.appendChild(document.createElement("menuitem"));
            menuitem.setAttribute("label", text.trimLeft().replace(/\s+/g, " ").slice(0, 70));
            menuitem.index = ind;
        });
        popup.append(df);
    }
})(this.appendChild(document.createElement("menupopup")));

Отсутствует

 

№1301118-12-2018 15:39:31

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

Re: Custom Buttons

Dumby спасибо работает, то что надо. А не подскажите где находится файл консоли браузера. Если в 61 я нашел по пути chrome://devtools/content/webconsole/browserconsole.xul то в 63 что найти не могу.

Отсутствует

 

№1301218-12-2018 16:53:30

drage2
Забанен
 
Группа: Members
Откуда: Донецк
Зарегистрирован: 23-11-2017
Сообщений: 392
UA: Firefox 64.0

Re: Custom Buttons

Dumby

Dumby пишет

Без понятия. Но менюшку будет показывать, если выкинешь

Мало того, что показывает, но и работает....
Добро је бити професионално!  Срећна Нова Година!

Отсутствует

 

№1301318-12-2018 17:05:21

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

Re: Custom Buttons

Andrey_Krropotkin пишет

найти не могу

Ну, например, Attributes Inspector'ом посмотри (при несвёрнутом Firefox).

Отсутствует

 

№1301418-12-2018 19:31:56

Karn
Участник
 
Группа: Members
Зарегистрирован: 11-12-2018
Сообщений: 45
UA: Firefox 64.0

Re: Custom Buttons

Dumby
А возможно ли восстановить работоспособность Вашей кнопки для незаметного обновления страничек в фоне? Т.е., например, находясь в списке избранного любого форума, нажал её, и возвращаясь обратно на вкладку, всегда получаешь актуальные данные. Находясь на этой вкладке, естественно не происходит авто-обновления, но переключаясь на другие, авто-обновление продолжается.

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

Выделить код

Код:

const checkInterval = 1 * 60 * 1000; //ms
const labelReload = "Перезагружать вкладку";
const labelStopReload = "Остановить перезагрузку вкладки";
const noThrob = true;

const tabContextMenu = document.getElementById("tabContextMenu");
const insertPoint = document.getElementById("context_reloadTab");

var menuitem = document.createElement("menuitem");
menuitem.id = "context_reloadTab_interval";

function setThrobberState(tab, throb) {

    const on = "tab-throbber";
    const off = "tab-throbber-off"
    var throbber = 
        document.getAnonymousElementByAttribute(tab, "class", on) ||
        document.getAnonymousElementByAttribute(tab, "class", off);
    throbber.className = throb ? on : off;
}
function tick(tab) {

    var oldDocs = tab.docs;
    if (!oldDocs) return;
    tab.docs = {};
    function fillTabDocs(tab, win) {

        var frames = win.frames;
        var loc = frames.location;
        if (loc != "about:blank") {
            tab.docs[frames.location] = oldDocs[frames.location] || "";
        }
        if (!frames.length) return;
        for(var i = 0; i < frames.length; i++)
            fillTabDocs(tab, frames[i]);
    }
    var br = tab.linkedBrowser;
    if (!br) return;
    fillTabDocs(tab, br.contentWindow);
    for(var loc in tab.docs) sendRequest(tab, loc);
    setTimeout(tick, checkInterval, tab);
}
function sendRequest(tab, loc) {

    var req = new XMLHttpRequest();
    req.open("GET", loc, true);
    req.responseType = "text";
//    reg.timeout = Math.round(checkInterval / 2);
    req.onloadend = function() {

//        if (req.status != 200) return;
        var res = req.responseText;

        var old = tab.docs[loc];
        if (old && old != res) {
            var wn = tab.linkedBrowser.webNavigation;
            wn.reload(wn.LOAD_FLAGS_BYPASS_CACHE);
        }
        tab.docs[loc] = res;
    }
    req.channel.loadFlags |= req.channel.LOAD_BYPASS_CACHE;
    req.send(null);
}
function onCommand(e) {

    var tab = e.target.parentNode.triggerNode;
    if (tab.docs) {
        delete tab.docs;
        setThrobberState(tab, true);
        return;
    }
    if (noThrob) setThrobberState(tab, false);
    tab.docs = {};
    tick(tab);
}
function insertMenuitem(e) {

    if (e.target != tabContextMenu) return;
    var tab = tabContextMenu.triggerNode;
    var protocol = tab.linkedBrowser.contentDocument.location.protocol;
    if (protocol != "http:" && protocol != "https:") return;

    var label = tab.docs ? labelStopReload : labelReload;
    menuitem.setAttribute("label", label);
    tabContextMenu.insertBefore(menuitem, insertPoint.nextSibling);
}
function removeMenuitem(e) {
    if (e.target != tabContextMenu) return;
    try {
        tabContextMenu.removeChild(menuitem);
    } catch(ex) {}
}
addEventListener("popupshowing", insertMenuitem, false, tabContextMenu);
addEventListener("popuphiding", removeMenuitem, false, tabContextMenu);
addEventListener("command", onCommand, false, menuitem);

this.onDestroy = function(reason) {
    if (reason == "update" || reason == "delete") {
        Array.slice(gBrowser.tabs).forEach(function(tab) {
            delete tab.docs;
            setThrobberState(tab, true);
        });
    }
};

Отсутствует

 

№1301519-12-2018 12:35:18

Quartz1t
Участник
 
Группа: Members
Зарегистрирован: 25-11-2013
Сообщений: 111
UA: Firefox 60.0

Re: Custom Buttons

Помогите пожалуйста с кнопкой Google Переводчика.

скрытый текст
/*Initialization Code*/

var btn = this;

btn.lastClick = {
    X: 0,
    Y: 0
};
addEventListener("mouseup", function(e) {
    if (e && e.button == 0 && e.view.top == content) {
        var lc = btn.lastClick;
        lc.X = e.clientX;
        lc.Y = e.clientY;
    }
}, false);

var createWindow = function(text, status, title, id, pos, size){
    var win = document.commandDispatcher.focusedWindow.top == content ? document.commandDispatcher.focusedWindow : content;
    var doc = win.document, wId = 'ujs_window'+(id || ''), w = doc.getElementById(wId);
    var keyDown = function(e){if(!e.shiftKey && !e.ctrlKey && !e.altKey && e.keyCode == 27)doc.getElementById(wId).closeWin()};
    if(w)w.closeWin();
    w = doc.createElement('div');
    w.setAttribute('style', 'position:fixed;display:block;visibility:hidden;left:0;top:0;width:auto;height:auto;border:1px solid gray;padding:3px;margin:0;z-index:99999;overflow:hidden;cursor:move;'+(typeof w.style.borderRadius === 'string' ? 'background-color:#f3f5f7;padding-top:4px;border-radius:4px;box-shadow:0 0 12px rgba(0,0,0,.4);' : 'background:-o-skin("Window Skin");'));
    w.id = wId;
    w.closeWin = function(){
        doc.removeEventListener('keydown', keyDown, false);
        this.parentNode.removeChild(this);
    };
    w.addEle = function(str, style){
        var ele = doc.createElement('div');
        ele.setAttribute('style', style);
        if(str){
            ele.innerHTML = str;
            for(var el, all = ele.getElementsByTagName('*'), i = all.length; i--;){
                el = all[i];
                if(/^(script|frame|iframe|applet|embed|object)$/i.test(el.nodeName)){
                    el.parentNode.removeChild(el);
                }else{
                    for(var att = el.attributes, j = att.length; j--;){
                        if(/^on[a-z]+$/i.test(att[j].name))att[j].value = '';
                    }
                }
            }
        };
        return this.appendChild(ele);
    };
    var img = doc.createElement('div');
    img.setAttribute('style', 'display:block;float:right;width:18px;height:18px;padding:0;margin:0;border:none;cursor:pointer;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAQAAAD8x0bcAAAAZElEQVR42mNgGNyAGQixsVGU/AdCXjCbHczmxKaMFywlAlWiw6DAwIZNmQhYGqJEDWoqFiAGVmKKTwk73CRJ/Ep0GIyhbsPpO4hbIG4TwKaMk0EZ7hYBBk1cvmNDEmbDrmSwAADE8h10+qICXwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAASUVORK5CYII=");background:-o-skin("Caption Close Button Skin");');
    img.title = (win.navigator.language.indexOf('ru') == 0) ? '\u0417\u0430\u043A\u0440\u044B\u0442\u044C' : 'Close';
    img.addEventListener('click', function(){this.parentNode.closeWin()}, false);
    w.appendChild(img);
    w.addEle(title, 'display:table;color:#000;font:16px Times New Roman;width:auto;height:auto;padding:0;margin:0 2px;cursor:text;');
    var cnt = w.addEle(text, 'display:block;border:1px solid #aaa;margin:2px 0 1px 0;padding:4px;background-color:#fafcfe;color:#000;font:14px Times New Roman;width:240px;height:120px;overflow:auto;cursor:text;');
    w.addEle(status, 'display:table;color:#555;font:10px Times New Roman;width:auto;height:auto;padding:0;margin:0 2px;cursor:text;');
    w.addEventListener('mousedown', function(e){
        if(e.target == w){
            e.preventDefault();
            var grabX = e.clientX, grabY = e.clientY, origX = parseInt(w.style.left), origY = parseInt(w.style.top);
            var mouseMove = function(ev){
                w.style.left = origX+ev.clientX-grabX+'px';
                w.style.top = origY+ev.clientY-grabY+'px';
            };
            doc.addEventListener('mousemove', mouseMove, false);
            doc.addEventListener('mouseup', function(){doc.removeEventListener('mousemove', mouseMove, false)}, false);
        }
    }, false);
    doc.documentElement.appendChild(w);

    if(size){
        cnt.style.height = size.height;
        cnt.style.width = size.width;
    }else{
        for(var i = 3; i < 10; i++){
            if(cnt.scrollHeight > cnt.offsetHeight || cnt.scrollWidth > cnt.offsetWidth){
                cnt.style.height = 50*i+'px';
                cnt.style.width = 100*i+'px';
            }else break;
        }
    };
    var docEle = doc.compatMode == 'CSS1Compat' ? doc.documentElement : doc.body;
    var mX = docEle.clientWidth-w.offsetWidth, mY = docEle.clientHeight-w.offsetHeight;
    if(mX < 0){cnt.style.width = parseInt(cnt.style.width)+mX+'px'; mX = 0};
    if(mY < 0){cnt.style.height = parseInt(cnt.style.height)+mY+'px'; mY =0};
    var hW = parseInt(w.offsetWidth/2);
    w.style.left = (pos && pos.X < mX+hW ? (pos.X > hW ? pos.X-hW : 0) : mX)+'px';
    w.style.top = (pos && pos.Y+10 < mY ? pos.Y+10 : mY)+'px';
    w.style.visibility = 'visible';
    doc.addEventListener('keydown', keyDown, false);
};

var getSel = function (w) {
    var s, d = w.document;
    if (d.selection) {
        var r = d.selection.createRange();
        s = r ? r.text : ''
    } else {
        s = d.getSelection().toString();
        if (!s) {
            var e, t = d.getElementsByTagName('textarea'), u = d.getElementsByTagName('input'), i = t.length;
            while(e = (i > 0) ? t[--i] : u[-i--])try{
                if (e.offsetHeight > 0 && (s = e.value.substring(e.selectionStart, e.selectionEnd))) break
            }catch(x){}
        }
    };
    if (!s) for (var j = 0, f; f = w.frames[j]; j++) {
        try {
            if (s = getSel(f)) break
        } catch(x) {}
    };
    return s
};

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

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

    return sM(txt);
};

var ujs_google_translate = function (dir){
    var win = content, lng = win.navigator.language.slice(0, 2), txt = getSel(win), l = dir.split('|');
    if (txt) {
        var xhr = new XMLHttpRequest();
        var url = 'https://translate.google.com/translate_a/single?client=t&sl=' + l[0] + '&tl=' + l[1] + '&hl=' + lng + '&eotf=0&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t' + getHash(txt);

        xhr.open('POST', url, true);
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
        xhr.onreadystatechange = function() {
            try{
                if (xhr.readyState == 4 && xhr.status == 200) {
                    var result = '', status = '', tmp = JSON.parse(xhr.responseText.replace(/\[(?=,)/g, '[0').replace(/,(?=,|\])/g, ',0'));
                    for(var i = 0, n; n = tmp[0][i]; i++){
                        if(n[0])result += n[0].toString();
                    };
                    result = '<span style="background-color:inherit;color:inherit;font-size:inherit;font-family:Times,serif;">' + result + '</span>';
                    status = tmp[8][0][0].toUpperCase() + ' -\u203A ' + l[1].toUpperCase();

                    createWindow(result, status, '<a href="'+url.replace(/&/g,'&amp;')+'" target="_blank" style="display:inline;padding:0;margin:0;text-decoration:none;border:none;color:#009;font:16px Times New Roman;">Google Translate</a>', '_gt', btn.lastClick);
                }
            } catch (x){LOG(x)};
        };
        xhr.send('q=' + encodeURIComponent(txt));
    } else {
        win.open('http://translate.google.com/translate?u='+escape(win.location.href)+'&hl='+lng+'&langpair='+dir+'&tbb=1');
    };
};


btn.onclick = function(e){if(e.button == 0)ujs_google_translate('auto|ru')};

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

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

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

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

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

addEventListener('keydown', function (e){
if(e.shiftKey && !e.ctrlKey && e.altKey && e.keyCode == 84)ujs_google_translate('auto|ru');
}, false);


Возможно ли сделать так, чтобы при переводе выделенного текста, окно с переводом закрывалось не нажатием на крестик, а кликом в не этого окна?

Имею ввиду вот что...

2f71bc5c658e1bb662e9e6deeaafe28b.png

Отредактировано Quartz1t (20-12-2018 15:27:30)

Отсутствует

 

№1301621-12-2018 12:49:28

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

Re: Custom Buttons

Dumby Вы можете исправить свою старую кнопку Консоль браузера для 63? Я вносил изменения вплоть до 61 и все работало? В 63 способ добавления в сайдбар изменили. Вместо  .xul  сделали - .html и все стало не понятно.
И последний вопрос - еще вот есть код

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

Выделить код

Код:

// Сплывающая подсказка у кнопки ....
(function() {
    var title = self.label + ":\n\n";
    var data = {
        memory: "Memory Cache:  ",
        disk: "Disk Cache:  ",
        offline: "Offline Cache:  "
    };
    function getSize(size) {
        if (!size) return size === 0 ? "0" : "?";
        for(var count = -1; size >= 1024; size /= 1024, count++);
        return size.toFixed(2).replace(/0+$/, "").replace(/\.$/, "") + " " + ("KMGT"[count] || "") + "B";
    }
    function setInf(tot, max, type, i) {
        var inf = getSize(tot) + " / " + getSize(max);
        var key = "browser.cache." + type + ".enable";
        if (!Services.prefs.getBoolPref(key)) inf += " (disabled)";
        self.tooltipText = self.tooltipText.replace(zws(i), inf);
    }
   function zws(ind) {"\u200B\u200B\u200B".slice(0, ++ind)};

    var types = Object.keys(data);
    var ttt = title + types.map(function(key, i){ data[key] + zws(i)}).join("\n");

 
    
   var context = Cu.import("resource://gre/modules/Services.jsm", {}).Services.loadContextInfo.default;
 
    self.onmouseenter = function() {
        self.tooltipText = ttt;
        try {
            var entries = {};
            Services.cache.visitEntries({
                visitDevice: function(device, info) {entries[device] = info},
                visitEntry: function() {}
            });
            types.forEach(function(type, i) {
                var info = entries[type];
                setInf(info && info.totalSize, info && info.maximumSize, type, i)
            });
        } catch(ex) {
           Services.cache2 && types.forEach(function(type, i) {
               var func = function(aEntryCount, aConsumption, aCapacity, aDiskDirectory)
                         { setInf(aConsumption, aCapacity, type, i)};
               var storage = Services.cache2[(type == "offline" ? "app" : type) + "CacheStorage"](context, null);
               try { storage.asyncVisitStorage({onCacheStorageInfo: func}, false) } catch(ex) {};
            });
        }
    } ;
})();


В этой подсказке выводится только заголовок подсказки а  сами значения нет.

Если у Вас найдется время посмотрите пожайлуста.

Отредактировано Andrey_Krropotkin (23-12-2018 12:33:28)

Отсутствует

 

№1301722-12-2018 13:54:30

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

Re: Custom Buttons

Есть такой скрипт UserCSSLoader.uc.js  от 2018г. для управления стилями. Переделал его в кнопку. На 63 работает. Его возможности:
- загружает, включает и отключает стили без перезагрузки
- выводит список всех файлов-стилей
- создание файлов
- редактирование с помощью текстового редактора файлов-стилей по правой кнопке на файле-стиле
- открывает папку с файлами - стилями
- поиск на сайте userstyles.org исходя из названия открытого таба
- нет необходимости задействовать для простых стилей файл userChrome.css и userContent.css
Для его работы нужно создать в папке "chrome" папку "CSS" (в ней хранятся и создаются файлы с расширением ".css") или кнопка сама создаст эти папки, если их нет.
После создания файла - надо нажать на пункт "Обновить список файлов-стилей" для того чтобы он появился в меню кнопки
В самой кнопке подправить путь к редактору, у меня var editor = "C:\\Program Files\\AkelPad\\AkelPad.exe";

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

Выделить код

Код:

/*Initialization Code*/

// ==UserScript==
// @name           UserCSSLoader
// @description    CSS Codes - Styles laden und verwalten
// @namespace      http://d.hatena.ne.jp/Griever/
// @author         Griever
// @charset        UTF-8
// @version        0.0.4f
// ==/UserScript==

var idb=this.id;
var button = document.getElementById(idb);

(function(){

var editor = "C:\\Program Files\\AkelPad\\AkelPad.exe";

let { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
if (!window.Services)
    Cu.import("resource://gre/modules/Services.jsm");
let list = Services.wm.getEnumerator("navigator:browser");
while(list.hasMoreElements()){ if(list.getNext() != window) return; }

if (window.UCL) {
    window.UCL.destroy();
    delete window.UCL;
}

window.UCL = {
    USE_UC: "UC" in window,
    AGENT_SHEET: Ci.nsIStyleSheetService.AGENT_SHEET,
    USER_SHEET : Ci.nsIStyleSheetService.USER_SHEET,
    readCSS    : {},
    get disabled_list() {
        let obj = [];
        try {
            obj = this.prefs.getCharPref("disabled_list").split("|");
        } catch(e) {}
        delete this.disabled_list;
        return this.disabled_list = obj;
    },
    get prefs() {
        delete this.prefs;
        return this.prefs = Services.prefs.getBranch("UserCSSLoader.")
    },
    get styleSheetServices(){
        delete this.styleSheetServices;
        return this.styleSheetServices = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
    },
    get FOLDER() {
        let aFolder;
        try {
            let folderPath = this.prefs.getCharPref("FOLDER");
            aFolder = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile)
            aFolder.initWithPath(folderPath);
        } catch (e) {
            aFolder = Services.dirsvc.get("UChrm", Ci.nsIFile);
            aFolder.appendRelativePath("CSS");
        }
        if (!aFolder.exists() || !aFolder.isDirectory()) {
            aFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0664);
        }
        delete this.FOLDER;
        return this.FOLDER = aFolder;
    },
    getFocusedWindow: function() {
        let win = document.commandDispatcher.focusedWindow;
        if (!win || win == window) win = content;
        return win;
    },



    init: function() {
const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const  cbNS = "http://xsms.nm.ru/custombuttons/";
var menupopup = document.createElementNS(xulNS, "menupopup");
menupopup.onclick = function (event) {
  button.menuClick(event);
}
menupopup.addEventListener("popupshowing", function (event) {
  self.menuPopupShowing(event);
}, false);
button.appendChild(menupopup);
button.type = "menu";
button.orient = "horizontal";
button.menuClick = function (event) {
  event.preventDefault();
  event.stopPropagation();
  button.open = false;
}
button.menuPopupShowing = function (event) {
    var nodeList = event.target.childNodes;
  for (var i = nodeList.length - 1; i >= 0; i--)
    if (nodeList[i].hasAttributeNS(cbNS, "flag"))
      nodeList[i].parentNode.removeChild(nodeList[i]);

}
    
        let cssmenu = $C("menu", {
            id: "usercssloader-menu",
            label: "CSS",
        });
        menupopup.appendChild(cssmenu);
        
        let menupop = $C("menupopup", {
         id: "usercssloader-menupopup"
        });
        cssmenu.appendChild(menupop);

                let menu = $C("menu", {
                label: "Инструменты",
            });    
                menupopup.appendChild(menu);
                
        let mp = $C("menupopup", { id: "usercssloader-submenupopup" });
        menu.appendChild(mp);
        mp.appendChild($C("menuitem", {
            label: "Обновить список файлов-стилей",
            accesskey: "R",
            acceltext: "Alt + R",
            oncommand: "UCL.rebuild();"
        }));
        mp.appendChild($C("menuseparator"));
        mp.appendChild($C("menuitem", {
            label: "Создать файл CSS",
            accesskey: "D",
            oncommand: "UCL.create();"
        }));
        mp.appendChild($C("menuitem", {
            label: "Открыть папку CSS",
            accesskey: "O",
            oncommand: "UCL.openFolder();"
        }));
        mp.appendChild($C("menuitem", {
            label: "Редактировать userChrome.css",
            hidden: false,
            oncommand: "UCL.editUserCSS(\'userChrome.css\');"
        }));
        mp.appendChild($C("menuitem", {
            label: "Редактировать userContent.css",
            hidden: false,
            oncommand: "UCL.editUserCSS(\'userContent.css\');"
        }));
        mp.appendChild($C("menuseparator"));
        mp.appendChild($C("menuitem", {
            label: "Тест стиля (Chrome)",
            id: "usercssloader-test-chrome",
            hidden: true,
            accesskey: "C",
            oncommand: "UCL.styleTest(window);"
        }));
        mp.appendChild($C("menuitem", {
            label: "Тест стиля (Web)",
            id: "usercssloader-test-content",
            hidden: true,
            accesskey: "W",
            oncommand: "UCL.styleTest();"
        }));
        mp.appendChild($C("menuitem", {
            label: "Поиск стиля на userstyles.org",
            accesskey: "S",
            oncommand: "UCL.searchStyle();"
        }));

        menu = $C("menu", {
            label: ".uc.css",
            accesskey: "U",
            hidden: !UCL.USE_UC
        });
        
        
        mp = $C("menupopup", { id: "usercssloader-ucmenupopup" });
        menu.appendChild(mp);
        mp.appendChild($C("menuitem", {
            label: "Importieren(.uc.js)",
            oncommand: "UCL.UCrebuild();"
        }));
        mp.appendChild($C("menuseparator", { id: "usercssloader-ucsepalator" }));

        $("mainKeyset").appendChild($C("key", {
            id: "usercssloader-rebuild-key",
            oncommand: "UCL.rebuild();",
            key: "R",
            modifiers: "alt",
        }));


        this.rebuild();
        this.initialized = true;
        if (UCL.USE_UC) {
            setTimeout(function() {
                UCL.UCcreateMenuitem();
            }, 1000);
        }
        window.addEventListener("unload", this, false);
    },
    uninit: function() {
        const dis = [];
        for (let x of Object.keys(this.readCSS)) {
            if (!this.readCSS[x].enabled)
                dis.push(x);
        }
        this.prefs.setCharPref("disabled_list", dis.join("|"));
        window.removeEventListener("unload", this, false);
    },
    destroy: function() {
        var i = document.getElementById("usercssloader-menu");
        if (i) i.parentNode.removeChild(i);
        var i = document.getElementById("usercssloader-rebuild-key");
        if (i) i.parentNode.removeChild(i);
        this.uninit();
    },
    handleEvent: function(event) {
        switch(event.type){
            case "unload": this.uninit(); break;
        }
    },
    rebuild: function() {
        let ext = /\.css$/i;
        let not = /\.uc\.css/i;
        let files = this.FOLDER.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);

        while (files.hasMoreElements()) {
            let file = files.getNext().QueryInterface(Ci.nsIFile);
            if (!ext.test(file.leafName) || not.test(file.leafName)) continue;
            let CSS = this.loadCSS(file);
            CSS.flag = true;
        }
        for (let leafName of Object.keys(this.readCSS)) {
            const CSS = this.readCSS[leafName];
            if (!CSS.flag) {
                CSS.enabled = false;
                delete this.readCSS[leafName];
            }
            delete CSS.flag;
            this.rebuildMenu(leafName);
        }
        if (this.initialized) {
            if (typeof(StatusPanel) !== "undefined")
                StatusPanel._label = "Style importiert";
            else
                XULBrowserWindow.statusTextField.label = "Styles importieren";
        }
    },
    loadCSS: function(aFile) {
        var CSS = this.readCSS[aFile.leafName];
        if (!CSS) {
            CSS = this.readCSS[aFile.leafName] = new CSSEntry(aFile);
            if (this.disabled_list.indexOf(CSS.leafName) === -1) {
                CSS.enabled = true;
            }
        } else if (CSS.enabled) {
            CSS.enabled = true;
        }
        return CSS;
    },
    rebuildMenu: function(aLeafName) {
        var CSS = this.readCSS[aLeafName];
        var menuitem = document.getElementById("usercssloader-" + aLeafName);
        if (!CSS) {
            if (menuitem)
                menuitem.parentNode.removeChild(menuitem);
            return;
        }

        if (!menuitem) {
            menuitem = document.createElement("menuitem");
            menuitem.setAttribute("label", aLeafName);
             menuitem.setAttribute("id", "usercssloader-" + aLeafName);
            menuitem.setAttribute("class", "usercssloader-item " + (CSS.SHEET == this.AGENT_SHEET? "AGENT_SHEET" : "USER_SHEET"));
            menuitem.setAttribute("type", "checkbox");
            menuitem.setAttribute("autocheck", "false");
            menuitem.setAttribute("oncommand", "UCL.toggle('"+ aLeafName +"');");
            menuitem.setAttribute("onclick", "UCL.itemClick(event);");
            document.getElementById("usercssloader-menupopup").appendChild(menuitem);
        }
        menuitem.setAttribute("checked", CSS.enabled);
    },
    toggle: function(aLeafName) {
        var CSS = this.readCSS[aLeafName];
        if (!CSS) return;
        CSS.enabled = !CSS.enabled;
        this.rebuildMenu(aLeafName);
    },
    itemClick: function(event) {
        if (event.button == 0) return;

        event.preventDefault();
        event.stopPropagation();
        let label = event.currentTarget.getAttribute("label");

        if (event.button == 1) {
            this.toggle(label);
        }
        else if (event.button == 2) {
            closeMenus(event.target);
            this.edit(this.getFileFromLeafName(label));
        }
    },
    getFileFromLeafName: function(aLeafName) {
        let f = this.FOLDER.clone();
        f.QueryInterface(Ci.nsIFile); // use appendRelativePath
        f.appendRelativePath(aLeafName);
        return f;
    },
    styleTest: function(aWindow) {
        aWindow || (aWindow = this.getFocusedWindow());
        new CSSTester(aWindow, function(tester){
            if (tester.saved)
                UCL.rebuild();
        });
    },
    searchStyle: function() {
        let word;
        try {
            word = gBrowser.currentURI.host;
        } catch {
            word = gBrowser.currentURI.spec;
        }
        
        var ctabpos = gBrowser.selectedTab._tPos +1;
                gBrowser.moveTabTo(gBrowser.selectedTab = gBrowser.addWebTab("https://userstyles.org/styles/search/" + word), ctabpos);
    },
    openFolder: function() {
        this.FOLDER.launch();
    },
    editUserCSS: function(aLeafName) {
        let file = Services.dirsvc.get("UChrm", Ci.nsIFile);
        file.appendRelativePath(aLeafName);
        this.edit(file);
    },
    edit: function(aFile) {
        try {
            var UI = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
            UI.charset = window.navigator.platform.toLowerCase().indexOf("win") >= 0? "Shift_JIS": "UTF-8";
            var path = UI.ConvertFromUnicode(aFile.path);
            var app = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
            app.initWithPath(editor);
            var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
            process.init(app);
            process.run(false, [path], 1);
        } catch (e) {}
    },
    create: function(aLeafName) {
        if (!aLeafName) aLeafName = prompt("Имя файла", dateFormat(new Date(), "%Y_%m%d_%H%M%S"));
        if (aLeafName) aLeafName = aLeafName.replace(/\s+/g, " ").replace(/[\\/:*?\"<>|]/g, "");
        if (!aLeafName || !/\S/.test(aLeafName)) return;
        if (!/\.css$/.test(aLeafName)) aLeafName += ".css";
        let file = this.getFileFromLeafName(aLeafName);
        this.edit(file);
    },
    UCrebuild: function() {
        let re = /^file:.*\.uc\.css(?:\?\d+)?$/i;
        let query = "?" + new Date().getTime();
        Array.slice(document.styleSheets).forEach(function(css){
            if (!re.test(css.href)) return;
            if (css.ownerNode) {
                css.ownerNode.parentNode.removeChild(css.ownerNode);
            }
            let pi = document.createProcessingInstruction('xml-stylesheet','type="text/css" href="'+ css.href.replace(/\?.*/, '') + query +'"');
            document.insertBefore(pi, document.documentElement);
        });
        UCL.UCcreateMenuitem();
    },
    UCcreateMenuitem: function() {
        let sep = $("usercssloader-ucsepalator");
        let popup = sep.parentNode;
        if (sep.nextSibling) {
            let range = document.createRange();
            range.setStartAfter(sep);
            range.setEndAfter(popup.lastChild);
            range.deleteContents();
            range.detach();
        }

        let re = /^file:.*\.uc\.css(?:\?\d+)?$/i;
        Array.slice(document.styleSheets).forEach(function(css) {
            if (!re.test(css.href)) return;
            let fileURL = decodeURIComponent(css.href).split("?")[0];
            let aLeafName = fileURL.split("/").pop();
            let m = document.createElement("menuitem");
            m.setAttribute("label", aLeafName);
            m.setAttribute("tooltiptext", fileURL);
            m.setAttribute("id", "usercssloader-" + aLeafName);
            m.setAttribute("type", "checkbox");
            m.setAttribute("autocheck", "false");
            m.setAttribute("checked", "true");
            m.setAttribute("oncommand", "this.setAttribute('checked', !(this.css.disabled = !this.css.disabled));");
            m.setAttribute("onclick", "UCL.UCItemClick(event);");
            m.css = css;
            popup.appendChild(m);
        });
    },
    UCItemClick: function(event) {
        if (event.button == 0) return;
        event.preventDefault();
        event.stopPropagation();

        if (event.button == 1) {
            event.target.doCommand();
        }
        else if (event.button == 2) {
            closeMenus(event.target);
            let fileURL = event.currentTarget.getAttribute("tooltiptext");
            let file = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler).getFileFromURLSpec(fileURL);
            this.edit(file);
        }
    },
};

function CSSEntry(aFile) {
    this.path = aFile.path;
    this.leafName = aFile.leafName;
    this.lastModifiedTime = 1;
    this.SHEET = /^xul-|\.as\.css$/i.test(this.leafName) ? 
        Ci.nsIStyleSheetService.AGENT_SHEET: 
        Ci.nsIStyleSheetService.USER_SHEET;
}
CSSEntry.prototype = {
    sss: Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
    _enabled: false,
    get enabled() {
        return this._enabled;
    },
    set enabled(isEnable) {
        var aFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile)
        aFile.initWithPath(this.path);
    
        var isExists = aFile.exists(); // Wenn die Datei existiert true
        var lastModifiedTime = isExists ? aFile.lastModifiedTime : 0;
        var isForced = this.lastModifiedTime != lastModifiedTime; 

        var fileURL = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler).getURLSpecFromFile(aFile);
        var uri = Services.io.newURI(fileURL, null, null);

        if (this.sss.sheetRegistered(uri, this.SHEET)) {
            if (!isEnable || !isExists) {
                this.sss.unregisterSheet(uri, this.SHEET);
            }
            else if (isForced) {
                // Nach Stornierung erneut einlesen
                this.sss.unregisterSheet(uri, this.SHEET);
                this.sss.loadAndRegisterSheet(uri, this.SHEET);
            }
        } else {
            if (isEnable && isExists) {
                this.sss.loadAndRegisterSheet(uri, this.SHEET);
            }
        }
        if (this.lastModifiedTime !== 1 && isEnable && isForced) {
            log(this.leafName + " wurde aktualisiert");
        }
        this.lastModifiedTime = lastModifiedTime;
        return this._enabled = isEnable;
    },
};

function CSSTester(aWindow, aCallback) {
    this.win = aWindow || window;
    this.doc = this.win.document;
    this.callback = aCallback;
    this.init();
}
CSSTester.prototype = {
    sss: Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
    preview_code: "",
    saved: false,
    init: function() {
        this.dialog = openDialog(
            "data:text/html;charset=utf8,"+encodeURIComponent('<!DOCTYPE HTML><html lang="ja"><head><title>CSSTester</title></head><body></body></html>'),
            "",
            "width=550,height=400,dialog=no");
        this.dialog.addEventListener("load", this, false);
    },
    destroy: function() {
        this.preview_end();
        this.dialog.removeEventListener("unload", this, false);
        this.previewButton.removeEventListener("click", this, false);
        this.saveButton.removeEventListener("click", this, false);
        this.closeButton.removeEventListener("click", this, false);
    },
    handleEvent: function(event) {
        switch(event.type) {
            case "click":
                if (event.button != 0) return;
                if (this.previewButton == event.currentTarget) {
                    this.preview();
                }
                else if (this.saveButton == event.currentTarget) {
                    this.save();
                }
                else if (this.closeButton == event.currentTarget) {
                    this.dialog.close();
                }
                break;
            case "load":
                var doc = this.dialog.document;
                doc.body.innerHTML = '\
                    <style type="text/css">\
                        :not(input):not(select) { padding: 0px; margin: 0px; }\
                        table { border-spacing: 0px; }\
                        body, html, #main, #textarea { width: 100%; height: 100%; }\
                        #textarea { font-family: monospace; }\
                    </style>\
                    <table id="main">\
                        <tr height="100%">\
                            <td colspan="4"><textarea id="textarea"></textarea></td>\
                        </tr>\
                        <tr height="40">\
                            <td><input type="button" value="Предварительный просмотр" id="Vorschau"/></td>\
                            <td><input type="button" value="Speichern" id="Speichern"/></td>\
                            <td width="80%"><span class="log"></span></td>\
                            <td><input type="button" value="Schließen" id="Schliessen"/></td>\
                        </tr>\
                    </table>\
                ';
                this.textbox = doc.querySelector("textarea");
                this.previewButton = doc.querySelector('input[value="Предварительный просмотр"]');
                this.saveButton = doc.querySelector('input[value="Speichern"]');
                this.closeButton = doc.querySelector('input[value="Schließen"]');
                this.logField = doc.querySelector('.log');

                var code = "@namespace url(" + this.doc.documentElement.namespaceURI + ");\n";
                code += this.win.location.protocol.indexOf("http") === 0?
                    "@-moz-document domain(" + this.win.location.host + ") {\n\n\n\n}":
                    "@-moz-document url(" + this.win.location.href + ") {\n\n\n\n}";
                this.textbox.value = code;
                this.dialog.addEventListener("unload", this, false);
                this.previewButton.addEventListener("click", this, false);
                this.saveButton.addEventListener("click", this, false);
                this.closeButton.addEventListener("click", this, false);

                this.textbox.focus();
                let p = this.textbox.value.length - 3;
                this.textbox.setSelectionRange(p, p);

                break;
            case "unload":
                this.destroy();
                this.callback(this);
                break;
        }
    },
    preview: function() {
        var code = this.textbox.value;
        if (!code || !/\:/.test(code))
            return;
        code = "data:text/css;charset=utf-8," + encodeURIComponent(this.textbox.value);
        if (code == this.preview_code)
            return;
        this.preview_end();
        var uri = Services.io.newURI(code, null, null);
        this.sss.loadAndRegisterSheet(uri, Ci.nsIStyleSheetService.AGENT_SHEET);
        this.preview_code = code;
        this.log("Preview");
    },
    preview_end: function() {
        if (this.preview_code) {
            let uri = Services.io.newURI(this.preview_code, null, null);
            this.sss.unregisterSheet(uri, Ci.nsIStyleSheetService.AGENT_SHEET);
            this.preview_code = "";
        }
    },
    save: function() {
        var data = this.textbox.value;
        if (!data) return;

        var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
        fp.init(window, "", Ci.nsIFilePicker.modeSave);
        fp.appendFilter("CSS Files","*.css");
        fp.defaultExtension = "css";
        if (window.UCL)
            fp.displayDirectory = UCL.FOLDER;
        var res = fp.show();
        if (res != fp.returnOK && res != fp.returnReplace) return;

        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(fp.file, 0x02 | 0x08 | 0x20, 0664, 0);
        foStream.write(data, data.length);
        foStream.close();
        this.saved = true;
    },
    log: function() {
        this.logField.textContent = dateFormat(new Date(), "%H:%M:%S") + ": " + $A(arguments);
    }
};

UCL.init();

function $(id) { return document.getElementById(id); }
function $A(arr) { return Array.slice(arr); }
function $C(name, attr) {
    var el = document.createElement(name);
    if (attr) Object.keys(attr).forEach(function(n) { el.setAttribute(n, attr[n]) });
    return el;
}
function dateFormat(date, format) {
    format = format.replace("%Y", ("000" + date.getFullYear()).substr(-4));
    format = format.replace("%m", ("0" + (date.getMonth()+1)).substr(-2));
    format = format.replace("%d", ("0" + date.getDay()).substr(-2));
    format = format.replace("%H", ("0" + date.getHours()).substr(-2));
    format = format.replace("%M", ("0" + date.getMinutes()).substr(-2));
    format = format.replace("%S", ("0" + date.getSeconds()).substr(-2));
    return format;
}

function log() { Application.console.log(Array.slice(arguments)); }


})();

Отредактировано Andrey_Krropotkin (22-12-2018 20:10:33)

Отсутствует

 

№1301822-12-2018 19:20:49

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

Re: Custom Buttons

Andrey_Krropotkin
Этот код писали в конце 2012 судя по гитхабу, да и там много кодов но у всех срок больше 3 лет походу клал он на фф)) как раз начался переход на квант. Вот только вопрос тогда ведь можно было напрямую без всяких скриптов редактить в stylish? зачем он его писал, но да сейчас незаменимая штука если пашет (еще не проверял).
Кстати сперва думал ты с какойто сборки стянул типа runningcheese, у него там тоже полно всяких скриптов, Initialization code он как бы и выполняется как скрипт? можно еще типа TamperM,Violentmonkey. В общем затестим спс, а кто переводил ты?

Что делать если у меня путь не .\chrome, а такой .\user_chrome_files.
Он я как понял берет с дефолта? для меня это сложно(

Выделить код

Код:

Services.dirsvc.get("UChrm",Ci.nsIFile);

Вот кнопка посвежее вроде Dumby писал.

Выделить код

Код:

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%3EReload%20user%7BChrome%2C%20Content%7D.css%3C/name%3E%0A%20%20%3Cimage%3E%3C%21%5BCDATA%5Bdata%3Aimage/png%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAIpwAACKcBMsYCAwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAMwSURBVEiJ5dbNb5RVFMfxz3mmrYgYE0IN4IaKb4n4UqOwMCYu2JCoQVDiwoUrQ4j0xao7ExITQxRoodEFK1cmRkSE8AeYYKpEFF0YY4SiUSMRQW0sLe0818U8nekwHe3U7vhtnnNOzj3f89znPvderjVFK8npaSWrPSjpElahQzhvyrF4y++t1GqbF7DHOvQLj6Ozrt2EDutYRHAasMK0vXgWWZO0SX/7DlJf6Skp3UWcFeVRV4zG235tCZx6rDPtKLqqAN4XPhROm3DJEiG3LA6aKkZ14jUSKaOd1Gsco6Qz8vRiDDvTFJz63S13AjdVAg7JvBxDzs2RfrE2MP9ijolZijvJXo/h8pmmb5z6LZf7qICWJQNxwP5mM1OnzNdy03V1U0oi2x77y+/Wp16t3CDWgvDKvKGIQZepfO+iWBIpKG9s7HGW0k7dKgsJjsSQffOF1or4srAuS04U9jOp14amYGGgiF2Re6llaEWnMSbPNyl5DtNFQzvnBKdd2oRNhXt4ZvW1rCwfkbInY9jHMeiscBiEJ9Lz2mfSaovgovXC8sI7siAoYsgnMy8JkmPYhhtdbwOV6a9NdVhT69qphYIblPl0FuO2WrimVVVrcu7dZkFqd75q525uBCelqj0tXzRwvSYbwWZ1doOVi4Yad0vVDj81gjPfV+2y9YsGLnlgFrj6p9TA405irPAemwmn/raNqc/D/wO9uXj+bMhXDeDihDledLYt9VmTektb5flxebYgcOpx+yzw0aic3vXgSqY9hdUuOUx6T+WWcX/LUELYh3ZMyqq1G8FxwCl8ULjdVFd6d6tgPQbMfLIwHIPONgVXWs1OFm3Mjt6Rdlg2X2bq0yfsLtzP/OHVq3PqzuPUm/Vj9xz9ZDrcg5F/Bb6gS8mbkq1F6EdlW+IdE03Baae1pEeJb1SuO0vrMvPsPvKRArDaChf8qWRal/BQccBsxnXFiBFTtjS7czW93qYdVurQJZW6SLeK+DaGyofSLh0uGUNHk6F/SfZI3ojh2k41b3DThnrdS+1/nAnjcxzR5mDsdeG/6szrXl2nJX4w4RFJJ3LhF7lzMey3lmtdU/oHaoj4Y/PDRWgAAAAASUVORK5CYII%3D%5D%5D%3E%3C/image%3E%0A%20%20%3Cmode%3E0%3C/mode%3E%0A%20%20%3Cinitcode%3E%3C%21%5BCDATA%5B//%u0420%u0430%u0431%u043E%u0442%u0430%u0435%u0442%20%u0442%u043E%u043B%u044C%u043A%u043E%20%u0432%20%22profile/Chrome%22%20%u043F%u0430%u043F%u043A%u0435%21%0A%28obj%20%3D%3E%20%7B%0A%09this.onclick%20%3D%20obj.click.bind%28obj%29%3B%0A%09this.oncontextmenu%20%3D%20obj.contextmenu.bind%28obj%29%3B%0A%09this.tooltipText%20%3D%20%22L%3A%20Reload%20userChrome.css%5CnM%3A%20CB%20Menu%5CnR%3A%20Reload%20userContent.css%22%3B%0A%7D%29%28%7B%0A%09async%20click%28e%29%20%7B%0A%09%09if%20%28e.button%20%3D%3D%201%29%20return%20gShowPopup%28self%29%3B%0A%09%09if%20%28e.button%20%7C%7C%20%21this.chromeSheet%29%20return%3B%0A%09%09await%20this.reload%28this.chromeSheet%29%3B%0A%09%09this.restyle%280%29%3B%0A%09%7D%2C%0A%09async%20contextmenu%28e%29%20%7B%0A%09%09if%20%28e.ctrlKey%20%7C%7C%20e.shiftKey%20%7C%7C%20e.detail%20%21%3D%201%20%7C%7C%20%21this.contentSheetURL%29%20return%3B%0A%09%09e.preventDefault%28%29%3B%0A%0A%09%09var%20count%20%3D%20Services.ppmm.childCount%2C%20one%20%3D%20count%20%3D%3D%201%3B%0A%09%09var%20data%20%3D%20await%20this.reloadTab%28%22chrome%3A//extensions/content/dummy.xul%22%2C%20one%20%3F%20false%20%3A%20%7B%7D%29%3B%0A%09%09if%20%28one%29%20this.reloadTab%28%29%3B%0A%09%09else%20if%20%28data%29%20%7B%0A%09%09%09var%20url%20%3D%20%22data%3A%2C%22%20+%20encodeURIComponent%28%0A%09%09%09%09self.Help%20+%20this.contentSheetURL%20+%20%27%22%2C%20%27%20+%20JSON.stringify%28data%29%20+%20%22%29%3B%22%0A%09%09%09%29%3B%0A%09%09%09var%20types%20%3D%20%5B%22web%22%2C%20%22file%22%2C%20%22extension%22%5D%3B%0A%09%09%09for%28var%20ind%20%3D%200%3B%20ind%20%3C%20count%3B%20ind++%29%20%7B%0A%09%09%09%09var%20child%20%3D%20Services.ppmm.getChildAt%28ind%29%3B%0A%09%09%09%09types.includes%28child.remoteType%29%20%26%26%20child.loadProcessScript%28url%2C%20false%29%3B%0A%09%09%09%7D%0A%09%09%7D%0A%09%09this.restyle%28250%29%3B%0A%09%7D%2C%0A%09async%20reload%28sheet%2C%20obj%29%20%7B%0A%09%09try%20%7Bvar%20style%20%3D%20await%20%28await%20fetch%28sheet.href%29%29.text%28%29%3B%7D%0A%09%09catch%20%28ex%29%20%7Breturn%20obj%3B%7D%0A%09%09InspectorUtils.parseStyleSheet%28sheet%2C%20style%29%3B%0A%09%09if%20%28obj%29%20obj%5Bsheet.href%5D%20%3D%20style%3B%0A%09%09for%28var%20ind%20%3D%200%2C%20len%20%3D%20sheet.cssRules.length%3B%20ind%20%3C%20len%3B%20ind++%29%20%7B%0A%09%09%09var%20rule%20%3D%20sheet.cssRules.item%28ind%29%3B%0A%0A%09%09%09rule.type%20%3D%3D%20rule.IMPORT_RULE%0A%09%09%09%26%26%20rule.styleSheet.href.startsWith%28%22file%3A///%22%29%0A%09%09%09%26%26%20await%20this.reload%28rule.styleSheet%2C%20obj%29%3B%0A%09%09%7D%0A%09%09return%20obj%3B%0A%09%7D%2C%0A%09reloadTab%28url%2C%20obj%29%20%7B%0A%09%09var%20tab%20%3D%20gBrowser.addTab%28url%2C%20%7BskipAnimation%3A%20true%7D%29%3B%0A%09%09tab.style.setProperty%28%22display%22%2C%20%22none%22%2C%20%22important%22%29%3B%0A%09%09return%20new%20Promise%28resolve%20%3D%3E%20%7B%0A%09%09%09var%20result%2C%20stop%2C%20destroy%20%3D%20%28%29%20%3D%3E%20%7B%0A%09%09%09%09if%20%28%21stop%29%20resolve%28result%29%2C%20gBrowser.removeTab%28tab%29%2C%20stop%20%3D%20true%3B%0A%09%09%09%7D%0A%09%09%09setTimeout%28destroy%2C%20500%29%3B%0A%09%09%09try%20%7B%0A%09%09%09%09tab.linkedBrowser.addEventListener%28%22DOMContentLoaded%22%2C%20async%20e%20%3D%3E%20%7B%0A%09%09%09%09%09var%20sheet%20%3D%20this.getSheet%28e.target%2C%20this.contentSheetURL%29%3B%0A%09%09%09%09%09if%20%28sheet%29%20result%20%3D%20await%20this.reload%28sheet%2C%20obj%29%3B%0A%09%09%09%09%09destroy%28%29%3B%0A%09%09%09%09%7D%2C%20%7Bonce%3A%20true%7D%29%3B%0A%09%09%09%7D%20catch%28ex%29%20%7B%0A%09%09%09%09destroy%28%29%3B%0A%09%09%09%7D%0A%09%09%7D%29%3B%0A%09%7D%2C%0A%09getSheet%28doc%2C%20href%29%20%7B%0A%09%09var%20sheets%20%3D%20InspectorUtils.getAllStyleSheets%28doc%29%3B%0A%09%09return%20sheets.find%28sheet%20%3D%3E%20sheet.href%20%3D%3D%20href%29%3B%0A%09%7D%2C%0A%09get%20contentSheetURL%28%29%20%7B%0A%09%09var%20file%20%3D%20Services.dirsvc.get%28%22UChrm%22%2C%20Ci.nsIFile%29%3B%0A%09%09file.append%28%22userContent.css%22%29%3B%0A%09%09if%20%28%21file.exists%28%29%29%20return%20null%3B%0A%09%09delete%20this.contentSheetURL%3B%0A%09%09return%20this.contentSheetURL%20%3D%20Services.io.newFileURI%28file%29.spec%3B%0A%09%7D%2C%0A%09get%20restyle%28%29%20%7B%0A%09%09var%20sss%20%3D%20Cc%5B%22@mozilla.org/content/style-sheet-service%3B1%22%5D.getService%28Ci.nsIStyleSheetService%29%3B%0A%09%09var%20uri%20%3D%20Services.io.newURI%28%22data%3Atext/css%2C%3Aroot%7B%7D%22%29%2C%20type%20%3D%20sss.USER_SHEET%3B%0A%09%09delete%20this.restyle%3B%20return%20this.restyle%20%3D%20delay%20%3D%3E%20setTimeout%28%28%29%20%3D%3E%20%7B%0A%09%09%09sss.loadAndRegisterSheet%28uri%2C%20type%29%3B%0A%09%09%09sss.unregisterSheet%28uri%2C%20type%29%3B%0A%09%09%7D%2C%20delay%29%3B%0A%09%7D%2C%0A%09get%20chromeSheet%28%29%20%7B%0A%09%09var%20file%20%3D%20Services.dirsvc.get%28%22UChrm%22%2C%20Ci.nsIFile%29%3B%0A%09%09file.append%28%22userChrome.css%22%29%3B%0A%09%09if%20%28%21file.exists%28%29%29%20return%20null%3B%0A%0A%09%09var%20href%20%3D%20Services.io.newFileURI%28file%29.spec%3B%0A%09%09var%20sheet%20%3D%20this.getSheet%28document%2C%20href%29%3B%0A%09%09if%20%28%21sheet%29%20return%20null%3B%0A%0A%09%09delete%20this.chromeSheet%3B%20return%20this.chromeSheet%20%3D%20sheet%3B%0A%09%7D%0A%7D%29%3B%0A%5D%5D%3E%3C/initcode%3E%0A%20%20%3Ccode%3E%3C%21%5BCDATA%5B/*CODE*/%5D%5D%3E%3C/code%3E%0A%20%20%3Caccelkey%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/accelkey%3E%0A%20%20%3Chelp%3E%3C%21%5BCDATA%5B%28%28href%2C%20data%29%20%3D%3E%20%7B%0A%09var%20en%20%3D%20Services.ww.getWindowEnumerator%28null%29%3B%0A%09if%20%28%21en.hasMoreElements%28%29%29%20return%3B%0A%09var%20doc%20%3D%20en.getNext%28%29.document%3B%0A%09Cu.importGlobalProperties%28%5B%22InspectorUtils%22%5D%29%3B%0A%0A%09var%20reload%20%3D%20sheet%20%3D%3E%20%7B%0A%09%09var%20style%20%3D%20data%5Bsheet.href%5D%3B%20if%20%28%21style%29%20return%3B%0A%0A%09%09InspectorUtils.parseStyleSheet%28sheet%2C%20style%29%3B%0A%09%09for%28var%20ind%20%3D%200%2C%20len%20%3D%20sheet.cssRules.length%3B%20ind%20%3C%20len%3B%20ind++%29%20%7B%0A%09%09%09var%20rule%20%3D%20sheet.cssRules.item%28ind%29%3B%0A%0A%09%09%09rule.type%20%3D%3D%20rule.IMPORT_RULE%0A%09%09%09%26%26%20rule.styleSheet.href.startsWith%28%22file%3A///%22%29%0A%09%09%09%26%26%20reload%28rule.styleSheet%29%3B%0A%09%09%7D%0A%09%7D%0A%09var%20sheet%20%3D%20InspectorUtils.getAllStyleSheets%28doc%29.find%28sheet%20%3D%3E%20sheet.href%20%3D%3D%20href%29%3B%0A%09if%20%28sheet%29%20reload%28sheet%29%3B%0A%7D%29%28%22%5D%5D%3E%3C/help%3E%0A%20%20%3Cattributes/%3E%0A%3C/custombutton%3E

Отредактировано func4ptch4 (22-12-2018 19:41:27)

Отсутствует

 

№1301922-12-2018 19:41:57

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

Re: Custom Buttons

func4ptch4
Я брал с www.camp-firefox.de/forum, уже адаптированный под 61 , просто в заголовке оставил автора, т.к. это не моя идея, и подправил под 63 и перевел сам
Кнопка от  Dumby это перезапуск стилей, у меня совсем другое.
Папка chrome - это общепринятая папка. Эта кнопка (функция get FOLDER, которая завязана на все остальные) сама создает папку chrome и CSS если у Вас их нет.
И если вставить скрипт в инициализацию, это не означает что будет кнопка, а будет меню - в панели меню, что для меня неудобно, а у меня кнопка, со своим меню.

Отредактировано Andrey_Krropotkin (22-12-2018 20:18:16)

Отсутствует

 

№1302022-12-2018 20:34:10

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

Re: Custom Buttons

Andrey_Krropotkin user_chrome_files от Vitaliy V. запуск идет через config.js походу он просто перехватывает.
А там тулбары, биндинги, батники... походу надо путь писать, не через системное (но тогда проблема в портабельности?)...
может типа такого Services.dirsvc.get("ProfD"\\user_chrome_files,Ci.nsIFile); хотя не, может так ("%profile%/user_chrome_files",Ci.nsIFile)... лад проверю завтра, или как правильнее?

Да не спорю у тебя круче, я просто кинул эту кнопку так как думал она посвежее и более совместимая но как оказалось я ошибался.

Отредактировано func4ptch4 (22-12-2018 20:37:07)

Отсутствует

 

№1302122-12-2018 21:25:03

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

Re: Custom Buttons

func4ptch4 Конечно можно заменить 1. в функции get FOLDER 
aFolder = Services.dirsvc.get("UChrm", Ci.ns
aFolder.appendRelativePath("CSS");
       заменить на
aFolder = Services.dirsvc.get("ProfD", Ci.nsIFile);
aFolder.appendRelativePath("user_chrome_files");
2.  в функции editUserCSS: function(aLeafName)
let file = Services.dirsvc.get("UChrm", Ci.nsIFile);
на
et file = Services.dirsvc.get("ProfD", Ci.nsIFile);

Но эта кнопка Вам ничего не даст, так как у Vitaliy V сделано по принципу адона со своими конфигами и настройками в about:config.
У меня по принципу как в stylish

Отсутствует

 

№1302223-12-2018 11:59:59

drage2
Забанен
 
Группа: Members
Откуда: Донецк
Зарегистрирован: 23-11-2017
Сообщений: 392
UA: Firefox 64.0

Re: Custom Buttons

В 65 СВ - сдохло? Или новая версия есть? Похоже XUL прибили окончательно...

Отсутствует

 

№1302323-12-2018 12:39:12

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

Re: Custom Buttons

drage2    Пост Dumby

Отсутствует

 

№1302423-12-2018 12:57:13

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

Re: Custom Buttons

func4ptch4
я возможно добавлю свою кнопку для перезапуска .css файлов в user_chrome_files
потому что моё старое расширение для стилей нельзя переделать в webextensions experiments
вернее можно, но из-за позднего старта webextensions не годится
тоже самое и с кнопкой CB стили нужно регистрировать методом loadAndRegisterSheet прежде чем появится окно браузера
иначе туда нежелательно добавлять стили с биндингами, вообще для всего что видно при старте, для скроллбара и т.д.

Отсутствует

 

№1302523-12-2018 14:57:05

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

Re: Custom Buttons

Andrey_Krropotkin пишет

Dumby Вы можете исправить свою старую кнопку Консоль браузера для 63?

OK, попробую

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

Выделить код

Код:

({
    title: "Консоль браузера",
    url: "chrome://devtools/content/webconsole/index.html",
    icon: "chrome://devtools/skin/images/tool-webconsole.svg",
    init() {
        var trg = document.getElementById("browser");
        trg && addEventListener("DOMContentLoaded", this, false, trg);
        var id = "viewBrowserConsoleSidebar";

        var menuitem = this.element("menuitem", {
            label: this.title,
            id: "menu_browserConsoleSidebar",
            oncommand: `SidebarUI.toggle("${id}");`
        }, document.getElementById("viewSidebarMenu"));

        var btn = this.element("toolbarbutton", {
            type: "checkbox",
            label: this.title,
            id: "sidebar-switcher-browserConsole",
            oncommand: `SidebarUI.show("${id}");`,
            class: "subviewbutton subviewbutton-iconic"
        });
        document.querySelector(
            'toolbarbutton[id^="sidebar-switcher-"] + toolbarseparator'
        ).before(btn);

        SidebarUI.sidebars.set(id, {
            url: this.url,
            buttonId: btn.id,
            title: this.title,
            menuId: menuitem.id
        });
        SidebarUI.isOpen && SidebarUI.currentID == id && btn.setAttribute("checked", true);

        var popupset = this.popupset = this.element("popupset", {
            id: `CB${_id.slice(20)}-bpowserConsole-popupset`
        }, document.documentElement);

        var css = `\
            #${btn.id} > .toolbarbutton-icon,
            #sidebar-box[sidebarcommand="${id}"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon {
                list-style-image: url(${this.icon});
            }`;
        var str = "data:text/css," + encodeURIComponent(css), type = windowUtils.USER_SHEET;
        windowUtils.loadSheetUsingURIString(str, type);

        addDestructor(() => {
            SidebarUI.sidebars.delete(id);
            btn.remove(); menuitem.remove(); popupset.remove();
            windowUtils.removeSheetUsingURIString(str, type);
        });
        self.onclick = e => {
            if (e.button == 2) return;
            if (!e.button) return SidebarUI.toggle(id);
            var st = gBrowser.selectedTab, tab;
            if (!e.ctrlKey) tab = gBrowser.visibleTabs.find(tab => {
                var br = gBrowser.getBrowserForTab(tab);
                return br.currentURI.spec == this.url || (
                    "_cachedCurrentURI" in br
                    && br._cachedCurrentURI.spec == this.url
                )
            });
            if (tab == st) return;
            if (!tab) tab = gBrowser.addTrustedTab(this.url);
            gBrowser.moveTabTo(tab, st._tPos + 1);
            gBrowser.selectedTab = tab;
        }
        for(var br of gBrowser.browsers) {
            if (br.currentURI.spec != this.url) continue;
            var doc = br.contentDocument;
            if (!doc || doc.readyState != "complete") continue;
            doc.querySelector("main#app-wrapper,div#output-container").childElementCount
                ? this.definePopupset(doc) : this.handleEvent({target: doc});
        }
        if (!btn.hasAttribute("checked")) return;
        var doc = SidebarUI.browser.contentDocument;
        if (doc.documentURI != this.url) btn.doCommand();
        else if (doc.readyState == "complete") this.definePopupset(doc);
    },
    definePopupset(doc) {
        (doc.querySelector("popupset") ||
            doc.documentElement.appendChild(doc.createXULElement("popupset"))
        ).appendChild = this.popupset.appendChild.bind(this.popupset);
    },
    async handleEvent({target: doc}) {
        if (!doc || Cu.isCrossProcessWrapper(doc) || doc.documentURI != this.url) return;

        var win = doc.defaultView;
        if (win.docShell.name == "toolbox-panel-iframe-webconsole") return;

        "custombuttonsConsole" in win || Services.scriptloader.loadSubScript(
            "chrome://custombuttons/content/consoleOverlay.js", win
        );
        this.loader.Services.ww.wins.push(win);
        var bc = await new this.loader.HUDService().toggleBrowserConsole();
        this.definePopupset(doc);
        if (String(win).includes("ChromeWindow")) return;

        win.onbeforeunload = () => {bc.chromeWindow = {close() {}};}
        var link = doc.createElement("link");
        link.setAttribute("rel", "shortcut icon");
        link.setAttribute("href", this.icon);
        doc.head.prepend(link);
    },
    get loader() {
        delete this.loader;
        var id = _id + "-browser-console";
        var url = "resource://devtools/shared/Loader.jsm?" + id;
        var loader = {exports: {}}, nsvo = Cu.import(url, loader);
        addDestructor(reason => reason[5] == "e" && Cu.unload(url));

        if (id in nsvo) return this.loader = nsvo[id];

        Services.scriptloader.loadSubScript("resource://devtools/client/webconsole/hudservice.js", loader);
        var e = new CustomEvent("DOMContentLoaded", {bubbles: false}), ww = loader.Services.ww;
        loader.Services.ww = Cu.getGlobalForObject(nsvo).Object.create(ww, {
            wins: {value: []},
            openWindow: {value: function() {
                var win = this.wins.shift();
                win.setTimeout(() => win.dispatchEvent(e), 0);
                return win;
            }}
        });
        return this.loader = nsvo[id] = loader;
    },
    element(name, attrs, parent) {
        var node = document.createElement(name);
        for(var attr in attrs) node.setAttribute(attr, attrs[attr]);
        if (parent) parent.appendChild(node);
        return node;
    }
}).init();

Andrey_Krropotkin пишет

Как сделать чтобы в первой обновлялась индикация копки?

Не знаю, кнопка слишком сложноразвесистая для меня.
Вообще, для индикации, есть события "FullZoomChange" и "TextZoomChange".
Ну или может так попробуй

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

Выделить код

Код:

var hidden = Object.getOwnPropertyDescriptor(XULElement.prototype, "hidden");
    Object.defineProperty(but, "hidden", {
        configurable: true, enumerable: true, get: hidden.get.bind(but),
        set: val => {
            Components.stack.formattedStack.includes("LocationChange")
                || setTimeout(updateZoomButton, 50);
            return hidden.set.call(but, val);
        }
    });
    addDestructor(() => delete but.hidden);

Andrey_Krropotkin пишет

В этой подсказке выводится только заголовок подсказки а  сами значения нет.

Это потому, что у тебя две функции ничего
не возвращают, так как отсутствует инструкция return.
Или можно arrow-функциями

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

Выделить код

Код:

/*
   function zws(ind) {"\u200B\u200B\u200B".slice(0, ++ind)};

    var types = Object.keys(data);
    var ttt = title + types.map(function(key, i){ data[key] + zws(i)}).join("\n");
*/
    var zws = ind => "\u200B".repeat(++ind);

    var types = Object.keys(data);
    var ttt = title + types.map((key, i) => data[key] + zws(i)).join("\n");

Отсутствует

 

Board footer

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