Toggle Restartless Add-ons 0.1.2.2 (2016-04-10)
Совместимость: [firefox] Firefox 4.0+, [seamonkey] SeaMonkey 2.1+, [thunderbird] Thunderbird 5.0+
Автор: Infocatcher
Описание:
Кнопка-меню для переключения дополнений, не требующих перезапуска

Управление:
ЛКМ – открыть меню
СКМ или ЛКМ с любым модификатором – открыть управление дополнениями
В меню:
ЛКМ – включить/выключить дополнение
Shift+ЛКМ – включить/выключить дополнение без закрытия меню
СКМ или ЛКМ с любым модификатором (кроме Shift) – открыть страницу дополнения в управлении дополнениями
ПКМ – открыть настройки дополнения (если есть)

Скриншот:
toggleRestartlessAddons-ru.png

Установить:

Выделить код

Код:

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%3EToggle%20Restartless%20Add-ons%3C/name%3E%0A%20%20%3Cimage%3E%3C%21%5BCDATA%5Bchrome%3A//mozapps/skin/extensions/extensionGeneric-16.png%5D%5D%3E%3C/image%3E%0A%20%20%3Cmode%3E0%3C/mode%3E%0A%20%20%3Cinitcode%3E%3C%21%5BCDATA%5B//%20http%3A//infocatcher.ucoz.net/js/cb/toggleRestartlessAddons.js%0A//%20https%3A//forum.mozilla-russia.org/viewtopic.php%3Fid%3D57948%0A//%20https%3A//github.com/Infocatcher/Custom_Buttons/tree/master/Toggle_Restartless_Add-ons%0A%0A//%20Toggle%20Restartless%20Add-ons%20button%20for%20Custom%20Buttons%0A//%20%28code%20for%20%22initialization%22%20section%29%0A//%20Also%20the%20code%20can%20be%20used%20from%20main%20window%20context%20%28as%20Mouse%20Gestures%20code%2C%20for%20example%29%0A%0A//%20Also%20you%20can%20check%20for%20add-ons%20updates%20using%20right-click%3A%0A//%20copy%20all%20code%20from%0A//%20https%3A//github.com/Infocatcher/Custom_Buttons/blob/master/Check_for_Addons_Updates/checkForAddonsUpdates.js%0A//%20after%20%22//%3D%3D%20Check%20for%20Addons%20Updates%20begin%22%0A%0A//%20%28c%29%20Infocatcher%202013-2016%0A//%20version%200.1.2.2%20-%202016-04-10%0A%0Avar%20options%20%3D%20%7B%0A%09addonTypes%3A%20%5B%22extension%22%2C%20%22plugin%22%5D%2C%0A%09//%20Possible%20values%3A%20%22extension%22%2C%20%22plugin%22%0A%09//%20From%20extensions%3A%20%22userstyle%22%20%28Stylish%29%2C%20%22greasemonkey-user-script%22%20%28Greasemonkey%29%2C%20%22userscript%22%20%28Scriptish%29%0A%09//%20%28swap%20to%20reorder%20in%20the%20menu%29%0A%09showVersions%3A%200%2C%0A%09//%200%20-%20don%27t%20show%20versions%0A%09//%201%20-%20show%20after%20name%3A%20%22Addon%20Name%201.2%22%0A%09//%202%20-%20show%20as%20%22acceltext%22%20%28in%20place%20for%20hotkey%20text%29%0A%09sort%3A%20%7B%0A%09%09enabled%3A%20%20%20%20%200%2C%0A%09%09clickToPlay%3A%200%2C%0A%09%09disabled%3A%20%20%20%200%0A%09%09//%20Sort%20order%3A%0A%09%09//%200%2C%200%2C%200%20-%20sort%20add-ons%20of%20each%20type%20alphabetically%0A%09%09//%200%2C%200%2C%201%20-%20show%20enabled%20add-ons%20%28of%20each%20type%29%20first%0A%09%09//%200%2C%201%2C%202%20-%20enabled%20add-ons%2C%20then%20click-to-play%20and%20then%20disabled%0A%09%7D%2C%0A%09closeMenu%3A%20true%2C%0A%09//%20Close%20menu%20after%20left-click%20%28use%20Shift+click%20to%20invert%20this%20behavior%29%0A%09closeMenuClickToPlay%3A%20-1%0A%09//%20Special%20handling%20for%20click%20to%20play%20plugins%3A%0A%09//%20-1%20-%20invert%20Shift+click%20behavior%0A%09//%200%20%20-%20do%20nothing%20special%20%28and%20use%20%22closeMenu%22%20option%29%0A%09//%201%20%20-%20always%20don%27t%20close%20menu%0A%7D%3B%0A%0Avar%20mp%20%3D%20document.createElement%28%22menupopup%22%29%3B%0Amp.setAttribute%28%22onpopupshowing%22%2C%20%22this.updateMenu%28%29%3B%22%29%3B%0Amp.setAttribute%28%22oncommand%22%2C%20%22this.handleEvent%28event%29%3B%22%29%3B%0Amp.setAttribute%28%22onmousedown%22%2C%20%22if%28event.button%20%3D%3D%200%29%20this.handleEvent%28event%29%3B%22%29%3B%0Amp.setAttribute%28%22onclick%22%2C%20%22if%28event.button%20%3E%200%29%20this.handleEvent%28event%29%3B%22%29%3B%0Amp.setAttribute%28%22oncontextmenu%22%2C%20%22return%20false%3B%22%29%3B%0Amp.setAttribute%28%22onpopuphidden%22%2C%20%22this.destroyMenu%28%29%3B%22%29%3B%0A%0Avar%20tb%20%3D%20this.parentNode%3B%0Aif%28tb%20%26%26%20tb.getAttribute%28%22orient%22%29%20%3D%3D%20%22vertical%22%29%20%7B%0A%09//%20https%3A//addons.mozilla.org/firefox/addon/vertical-toolbar/%0A%09var%20isRight%20%3D%20tb.parentNode.getAttribute%28%22placement%22%29%20%3D%3D%20%22right%22%3B%0A%09mp.setAttribute%28%22position%22%2C%20isRight%20%3F%20%22start_before%22%20%3A%20%22end_before%22%29%3B%0A%7D%0A%0Avar%20cleanupTimer%20%3D%200%3B%0Amp.updateMenu%20%3D%20function%28%29%20%7B%0A%09clearTimeout%28cleanupTimer%29%3B%0A%09addStyle%28%29%3B%0A%09getRestartlessAddons%28options.addonTypes%2C%20function%28addons%29%20%7B%0A%09%09var%20df%20%3D%20document.createDocumentFragment%28%29%3B%0A%09%09var%20prevType%3B%0A%09%09function%20sortPosition%28addon%29%20%7B%0A%09%09%09if%28%22STATE_ASK_TO_ACTIVATE%22%20in%20AddonManager%20%26%26%20addon.userDisabled%20%3D%3D%20AddonManager.STATE_ASK_TO_ACTIVATE%29%0A%09%09%09%09return%20options.sort.clickToPlay%3B%0A%09%09%09if%28addon.isActive%29%0A%09%09%09%09return%20options.sort.enabled%3B%0A%09%09%09return%20options.sort.disabled%3B%0A%09%09%7D%0A%09%09function%20key%28addon%29%20%7B%0A%09%09%09return%20options.addonTypes.indexOf%28addon.type%29%0A%09%09%09%09+%20%22%5Cn%22%20+%20sortPosition%28addon%29%0A%09%09%09%09+%20%22%5Cn%22%20+%20addon.name.toLowerCase%28%29%3B%0A%09%09%7D%0A%09%09addons.sort%28function%28a%2C%20b%29%20%7B%0A%09%09%09var%20ka%20%3D%20key%28a%29%3B%0A%09%09%09var%20kb%20%3D%20key%28b%29%3B%0A%09%09%09return%20ka%20%3D%3D%20kb%20%3F%200%20%3A%20ka%20%3C%20kb%20%3F%20-1%20%3A%201%3B%0A%09%09%7D%29.forEach%28function%28addon%29%20%7B%0A%09%09%09var%20type%20%3D%20addon.type%3B%0A%09%09%09if%28prevType%20%26%26%20type%20%21%3D%20prevType%29%0A%09%09%09%09df.appendChild%28document.createElement%28%22menuseparator%22%29%29%3B%0A%09%09%09prevType%20%3D%20type%3B%0A%09%09%09var%20icon%20%3D%20addon.iconURL%20%7C%7C%20addon.icon64URL%0A%09%09%09%09%7C%7C%20type%20%3D%3D%20%22plugin%22%20%20%20%20%26%26%20%22chrome%3A//mozapps/skin/plugins/pluginGeneric-16.png%22%0A%09%09%09%09%7C%7C%20type%20%3D%3D%20%22extension%22%20%26%26%20%22chrome%3A//mozapps/skin/extensions/extensionGeneric-16.png%22%0A%09%09%09%09%7C%7C%20%22%22%3B%0A%09%09%09var%20mi%20%3D%20document.createElement%28%22menuitem%22%29%3B%0A%09%09%09mi.className%20%3D%20%22menuitem-iconic%22%3B%0A%09%09%09var%20label%20%3D%20addon.name%3B%0A%09%09%09if%28options.showVersions%20%3D%3D%201%29%0A%09%09%09%09label%20+%3D%20%22%20%22%20+%20addon.version%3B%0A%09%09%09else%20if%28options.showVersions%20%3D%3D%202%29%0A%09%09%09%09mi.setAttribute%28%22acceltext%22%2C%20addon.version%29%3B%0A%09%09%09mi.setAttribute%28%22label%22%2C%20label%29%3B%0A%09%09%09mi.setAttribute%28%22image%22%2C%20icon%29%3B%0A%09%09%09var%20desc%20%3D%20addon.description%3B%0A%09%09%09desc%20%26%26%20mi.setAttribute%28%22tooltiptext%22%2C%20desc%29%3B%0A%09%09%09setDisabled%28mi%2C%20addon.userDisabled%29%3B%0A%09%09%09mi._cbAddon%20%3D%20addon%3B%0A%09%09%09df.appendChild%28mi%29%3B%0A%09%09%7D%29%3B%0A%09%09mp.textContent%20%3D%20%22%22%3B%0A%09%09mp.appendChild%28df%29%3B%0A%09%7D%29%3B%0A%7D%3B%0Amp.handleEvent%20%3D%20function%28e%29%20%7B%0A%09var%20mi%20%3D%20e.target%3B%0A%09if%28%21%28%22_cbAddon%22%20in%20mi%29%29%0A%09%09return%3B%0A%09var%20addon%20%3D%20mi._cbAddon%3B%0A%09if%28e.type%20%3D%3D%20%22mousedown%22%29%20%7B%0A%09%09var%20stayOpen%20%3D%20options.closeMenu%20%3F%20e.shiftKey%20%3A%20%21e.shiftKey%3B%0A%09%09if%28options.closeMenuClickToPlay%20%26%26%20isAskToActivateAddon%28addon%29%29%0A%09%09%09stayOpen%20%3D%20options.closeMenuClickToPlay%20%3D%3D%20-1%20%3F%20%21stayOpen%20%3A%20true%3B%0A%09%09mi.setAttribute%28%22closemenu%22%2C%20stayOpen%20%3F%20%22none%22%20%3A%20%22auto%22%29%3B%0A%09%09return%3B%0A%09%7D%0A%09var%20hasMdf%20%3D%20hasModifier%28e%29%3B%0A%09if%28e.type%20%3D%3D%20%22command%22%20%26%26%20%28%21hasMdf%20%7C%7C%20e.shiftKey%29%29%20%7B%0A%09%09let%20newDis%20%3D%20setNewDisabled%28addon%29%3B%0A%09%09setDisabled%28mi%2C%20newDis%29%3B%0A%09%7D%0A%09else%20if%28e.type%20%3D%3D%20%22command%22%20%26%26%20hasMdf%20%7C%7C%20e.type%20%3D%3D%20%22click%22%20%26%26%20e.button%20%3D%3D%201%29%20%7B%0A%09%09openAddonPage%28addon%29%3B%0A%09%09closeMenus%28mi%29%3B%0A%09%7D%0A%09else%20if%28e.type%20%3D%3D%20%22click%22%20%26%26%20e.button%20%3D%3D%202%29%20%7B%0A%09%09if%28openAddonOptions%28addon%29%29%0A%09%09%09closeMenus%28mi%29%3B%0A%09%7D%0A%7D%3B%0Amp.destroyMenu%20%3D%20function%28%29%20%7B%0A%09removeStyle%28%29%3B%0A%09clearTimeout%28cleanupTimer%29%3B%0A%09cleanupTimer%20%3D%20setTimeout%28function%28%29%20%7B%0A%09%09mp.textContent%20%3D%20%22%22%3B%0A%09%7D%2C%205000%29%3B%0A%7D%3B%0Afunction%20isAskToActivateAddon%28addon%29%20%7B%0A%09return%20addon.type%20%3D%3D%20%22plugin%22%0A%09%09%26%26%20%22STATE_ASK_TO_ACTIVATE%22%20in%20AddonManager%0A%09%09%26%26%20Services.prefs.getBoolPref%28%22plugins.click_to_play%22%29%3B%0A%7D%0Afunction%20setNewDisabled%28addon%29%20%7B%0A%09var%20newDis%20%3D%20getNewDisabled%28addon%29%3B%0A%09var%20oldDis%20%3D%20addon.userDisabled%3B%0A%09addon.userDisabled%20%3D%20newDis%3B%0A%09var%20realDis%20%3D%20addon.userDisabled%3B%0A%09if%28realDis%20%21%3D%20newDis%29%20%7B%20//%20We%20can%27t%20enable%20vulnerable%20plugins%0A%09%09var%20err%20%3D%20%22Can%27t%20set%20addon.userDisabled%20to%20%22%20+%20newDis%20+%20%22%2C%20real%20value%3A%20%22%20+%20realDis%3B%0A%09%09if%28newDis%29%20%7B%0A%09%09%09LOG%28err%20+%20%22%5CnSTATE_ASK_TO_ACTIVATE%20not%20supported%3F%22%29%3B%0A%09%09%09newDis%20%3D%20false%3B%0A%09%09%7D%0A%09%09else%20%7B%0A%09%09%09LOG%28err%20+%20%22%5CnVulnerable%20plugin%3F%22%29%3B%0A%09%09%09if%28oldDis%20%3D%3D%20AddonManager.STATE_ASK_TO_ACTIVATE%29%0A%09%09%09%09newDis%20%3D%20true%3B%0A%09%09%09else%0A%09%09%09%09newDis%20%3D%20AddonManager.STATE_ASK_TO_ACTIVATE%3B%0A%09%09%7D%0A%09%09addon.userDisabled%20%3D%20newDis%3B%0A%09%7D%0A%09return%20addon.userDisabled%3B%0A%7D%0Afunction%20getNewDisabled%28addon%29%20%7B%0A%09//%20disabled%20-%3E%20STATE_ASK_TO_ACTIVATE%20-%3E%20enabled%20-%3E%20...%0A%09var%20curDis%20%3D%20addon.userDisabled%3B%0A%09var%20newDis%3B%0A%09if%28%22STATE_ASK_TO_ACTIVATE%22%20in%20AddonManager%20%26%26%20curDis%20%3D%3D%20AddonManager.STATE_ASK_TO_ACTIVATE%29%0A%09%09newDis%20%3D%20false%3B%0A%09else%20if%28%21curDis%29%0A%09%09newDis%20%3D%20true%3B%0A%09else%20%7B%0A%09%09if%28isAskToActivateAddon%28addon%29%29%0A%09%09%09newDis%20%3D%20AddonManager.STATE_ASK_TO_ACTIVATE%3B%0A%09%09else%0A%09%09%09newDis%20%3D%20false%3B%0A%09%7D%0A%09return%20newDis%3B%0A%7D%0Afunction%20setDisabled%28mi%2C%20disabled%29%20%7B%0A%09var%20askToActivate%20%3D%20%22STATE_ASK_TO_ACTIVATE%22%20in%20AddonManager%20%26%26%20disabled%20%3D%3D%20AddonManager.STATE_ASK_TO_ACTIVATE%3B%0A%09var%20cl%20%3D%20mi.classList%3B%0A%09cl.toggle%28%22toggleRestartlessAddons-askToActivate%22%2C%20askToActivate%29%3B%0A%09cl.toggle%28%22toggleRestartlessAddons-disabled%22%2C%20disabled%20%26%26%20%21askToActivate%29%3B%0A%7D%0A%0Aif%28%0A%09this%20instanceof%20XULElement%20//%20Custom%20Buttons%0A%09%26%26%20typeof%20event%20%3D%3D%20%22object%22%0A%09%26%26%20%21%28%22type%22%20in%20event%29%20%26%26%20typeof%20_phase%20%3D%3D%20%22string%22%20%26%26%20_phase%20%3D%3D%20%22init%22%20//%20Initialization%0A%29%20%7B%0A%09this.type%20%3D%20%22menu%22%3B%0A%09this.orient%20%3D%20%22horizontal%22%3B%0A%09this.appendChild%28mp%29%3B%0A%0A%09this.onmouseover%20%3D%20function%28e%29%20%7B%0A%09%09if%28e.target%20%21%3D%20this%29%0A%09%09%09return%3B%0A%09%09Array.some%28%0A%09%09%09this.parentNode.getElementsByTagName%28%22*%22%29%2C%0A%09%09%09function%28node%29%20%7B%0A%09%09%09%09if%28%0A%09%09%09%09%09node%20%21%3D%20this%0A%09%09%09%09%09%26%26%20node.namespaceURI%20%3D%3D%20xulns%0A%09%09%09%09%09%26%26%20node.boxObject%0A%09%09%09%09%09//%20See%20https%3A//github.com/Infocatcher/Custom_Buttons/issues/28%0A%09%09%09%09%09//%26%26%20node.boxObject%20instanceof%20Components.interfaces.nsIMenuBoxObject%0A%09%09%09%09%09%26%26%20%22open%22%20in%20node%0A%09%09%09%09%09%26%26%20node.open%0A%09%09%09%09%09%26%26%20node.getElementsByTagName%28%22menupopup%22%29.length%0A%09%09%09%09%29%20%7B%0A%09%09%09%09%09node.open%20%3D%20false%3B%0A%09%09%09%09%09this.open%20%3D%20true%3B%0A%09%09%09%09%09return%20true%3B%0A%09%09%09%09%7D%0A%09%09%09%09return%20false%3B%0A%09%09%09%7D%2C%0A%09%09%09this%0A%09%09%29%3B%0A%09%7D%3B%0A%09this.onmousedown%20%3D%20function%28e%29%20%7B%0A%09%09if%28e.target%20%3D%3D%20this%20%26%26%20e.button%20%3D%3D%200%20%26%26%20hasModifier%28e%29%29%0A%09%09%09e.preventDefault%28%29%3B%0A%09%7D%3B%0A%09this.oncontextmenu%20%3D%20function%28e%29%20%7B%0A%09%09if%28e.target%20%3D%3D%20this%20%26%26%20%21hasModifier%28e%29%20%26%26%20hasUpdater%28%29%29%0A%09%09%09e.preventDefault%28%29%3B%0A%09%7D%3B%0A%09this.onclick%20%3D%20function%28e%29%20%7B%0A%09%09if%28e.target%20%21%3D%20this%29%0A%09%09%09return%3B%0A%09%09if%28e.button%20%3D%3D%200%20%26%26%20hasModifier%28e%29%20%7C%7C%20e.button%20%3D%3D%201%29%0A%09%09%09openAddonsManager%28%29%3B%0A%09%09else%20if%28e.button%20%3D%3D%202%20%26%26%20%21hasModifier%28e%29%20%26%26%20hasUpdater%28%29%29%0A%09%09%09checkForAddonsUpdates.call%28this%29%3B%0A%09%7D%3B%0A%7D%0Aelse%20%7B%20//%20Mouse%20gestures%20or%20something%20other...%0A%09let%20e%3B%0A%09if%28typeof%20event%20%3D%3D%20%22object%22%20%26%26%20event%20instanceof%20Event%20%26%26%20%22screenX%22%20in%20event%29%20//%20FireGestures%0A%09%09e%20%3D%20event%3B%0A%09else%20if%28this%20%3D%3D%20window%20%26%26%20%22mgGestureState%22%20in%20window%20%26%26%20%22endEvent%22%20in%20mgGestureState%29%20//%20Mouse%20Gestures%20Redox%0A%09%09e%20%3D%20mgGestureState.endEvent%3B%0A%09else%20%7B%0A%09%09let%20anchor%20%3D%20this%20instanceof%20XULElement%20%26%26%20this%0A%09%09%09%7C%7C%20window.gBrowser%20%26%26%20gBrowser.selectedBrowser%0A%09%09%09%7C%7C%20document.documentElement%3B%0A%09%09if%28%22boxObject%22%20in%20anchor%29%20%7B%0A%09%09%09let%20bo%20%3D%20anchor.boxObject%3B%0A%09%09%09e%20%3D%20%7B%0A%09%09%09%09screenX%3A%20bo.screenX%2C%0A%09%09%09%09screenY%3A%20bo.screenY%0A%09%09%09%7D%3B%0A%09%09%09if%28this%20instanceof%20XULElement%29%0A%09%09%09%09e.screenY%20+%3D%20bo.height%3B%0A%09%09%7D%0A%09%7D%0A%09if%28%21e%20%7C%7C%20%21%28%22screenX%22%20in%20e%29%29%0A%09%09throw%20new%20Error%28%22%5BToggle%20Restartless%20Add-ons%5D%3A%20Can%27t%20get%20event%20object%22%29%3B%0A%09document.documentElement.appendChild%28mp%29%3B%0A%09mp.addEventListener%28%22popuphidden%22%2C%20function%20destroy%28e%29%20%7B%0A%09%09mp.removeEventListener%28e.type%2C%20destroy%2C%20false%29%3B%0A%09%09setTimeout%28function%28%29%20%7B%0A%09%09%09mp.destroyMenu%28%29%3B%0A%09%09%09mp.parentNode.removeChild%28mp%29%3B%0A%09%09%7D%2C%200%29%3B%0A%09%7D%2C%20false%29%3B%0A%09mp.openPopupAtScreen%28e.screenX%2C%20e.screenY%29%3B%0A%7D%0A%0Afunction%20getRestartlessAddons%28addonTypes%2C%20callback%2C%20context%29%20%7B%0A%09if%28%21%28%22AddonManager%22%20in%20window%29%29%0A%09%09Components.utils.import%28%22resource%3A//gre/modules/AddonManager.jsm%22%29%3B%0A%09AddonManager.getAddonsByTypes%28addonTypes%2C%20function%28addons%29%20%7B%0A%09%09var%20restartless%20%3D%20addons.filter%28function%28addon%29%20%7B%0A%09%09%09var%20ops%20%3D%20addon.operationsRequiringRestart%3B%0A%09%09%09return%20%21addon.appDisabled%0A%09%09%09%09%26%26%20%21%28ops%20%26%20AddonManager.OP_NEEDS_RESTART_ENABLE%20%7C%7C%20ops%20%26%20AddonManager.OP_NEEDS_RESTART_DISABLE%29%3B%0A%09%09%7D%29%3B%0A%09%09callback.call%28context%2C%20restartless%29%3B%0A%09%7D%29%3B%0A%7D%0Afunction%20openAddonOptions%28addon%29%20%7B%0A%09//%20Based%20on%20code%20from%20chrome%3A//mozapps/content/extensions/extensions.js%0A%09//%20Firefox%2021.0a1%20%282013-01-27%29%0A%09Components.utils.import%28%22resource%3A//gre/modules/Services.jsm%22%29%3B%0A%09var%20optionsURL%20%3D%20addon.optionsURL%3B%0A%09if%28%21addon.isActive%20%7C%7C%20%21optionsURL%29%0A%09%09return%20false%3B%0A%09if%28addon.type%20%3D%3D%20%22plugin%22%29%20//%20No%20options%20for%20now%21%0A%09%09return%20false%3B%0A%09if%28addon.optionsType%20%3D%3D%20AddonManager.OPTIONS_TYPE_INLINE%29%0A%09%09openAddonPage%28addon%2C%20true%29%3B%0A%09else%20if%28addon.optionsType%20%3D%3D%20AddonManager.OPTIONS_TYPE_TAB%20%26%26%20%22switchToTabHavingURI%22%20in%20window%29%0A%09%09switchToTabHavingURI%28optionsURL%2C%20true%29%3B%0A%09else%20%7B%0A%09%09let%20windows%20%3D%20Services.wm.getEnumerator%28null%29%3B%0A%09%09while%28windows.hasMoreElements%28%29%29%20%7B%0A%09%09%09let%20win%20%3D%20windows.getNext%28%29%3B%0A%09%09%09if%28win.document.documentURI%20%3D%3D%20optionsURL%29%20%7B%0A%09%09%09%09win.focus%28%29%3B%0A%09%09%09%09return%20true%3B%0A%09%09%09%7D%0A%09%09%7D%0A%09%09//%20Note%3A%20original%20code%20checks%20browser.preferences.instantApply%20and%20may%20open%20modal%20windows%0A%09%09window.openDialog%28optionsURL%2C%20%22%22%2C%20%22chrome%2Ctitlebar%2Ctoolbar%2Ccenterscreen%2Cdialog%3Dno%22%29%3B%0A%09%7D%0A%09return%20true%3B%0A%7D%0Afunction%20openAddonsManager%28view%29%20%7B%0A%09var%20openAddonsMgr%20%3D%20window.BrowserOpenAddonsMgr%20//%20Firefox%0A%09%09%7C%7C%20window.openAddonsMgr%20//%20Thunderbird%0A%09%09%7C%7C%20window.toEM%3B%20//%20SeaMonkey%0A%09openAddonsMgr%28view%29%3B%0A%7D%0Afunction%20openAddonPage%28addon%2C%20scrollToPreferences%29%20%7B%0A%09scrollToPreferences%20%3D%20scrollToPreferences%20%26%26%20parseFloat%28Services.appinfo.platformVersion%29%20%3E%3D%2012%0A%09%09%3F%20%22/preferences%22%0A%09%09%3A%20%22%22%3B%0A%09openAddonsManager%28%22addons%3A//detail/%22%20+%20encodeURIComponent%28addon.id%29%20+%20scrollToPreferences%29%3B%0A%7D%0A%0Afunction%20hasModifier%28e%29%20%7B%0A%09return%20e.ctrlKey%20%7C%7C%20e.shiftKey%20%7C%7C%20e.altKey%20%7C%7C%20e.metaKey%3B%0A%7D%0A%0Afunction%20addStyle%28%29%20%7B%0A%09if%28addStyle.hasOwnProperty%28%22_style%22%29%29%0A%09%09return%3B%0A%09var%20style%20%3D%20%27%5C%0A%09%09.toggleRestartlessAddons-disabled%20%3E%20.menu-iconic-left%20%7B%5Cn%5C%0A%09%09%09opacity%3A%200.4%3B%5Cn%5C%0A%09%09%7D%5Cn%5C%0A%09%09.toggleRestartlessAddons-disabled%20%3E%20.menu-iconic-text%2C%5Cn%5C%0A%09%09.toggleRestartlessAddons-disabled%20%3E%20.menu-accel-container%20%7B%5Cn%5C%0A%09%09%09opacity%3A%200.5%3B%5Cn%5C%0A%09%09%7D%5Cn%5C%0A%09%09.toggleRestartlessAddons-askToActivate%20%7B%5Cn%5C%0A%09%09%09color%3A%20-moz-nativehyperlinktext%3B%5Cn%5C%0A%09%09%7D%27%3B%0A%09addStyle._style%20%3D%20document.insertBefore%28%0A%09%09document.createProcessingInstruction%28%0A%09%09%09%22xml-stylesheet%22%2C%0A%09%09%09%27href%3D%22%27%20+%20%22data%3Atext/css%2C%22%0A%09%09%09%09+%20encodeURIComponent%28style%29%20+%20%27%22%20type%3D%22text/css%22%27%0A%09%09%29%2C%0A%09%09document.documentElement%0A%09%29%3B%0A%7D%0Afunction%20removeStyle%28%29%20%7B%0A%09if%28%21addStyle.hasOwnProperty%28%22_style%22%29%29%0A%09%09return%3B%0A%09var%20s%20%3D%20addStyle._style%3B%0A%09s.parentNode.removeChild%28s%29%3B%0A%09delete%20addStyle._style%3B%0A%7D%0Afunction%20closeMenus%28node%29%20%7B%0A%09//%20Based%20on%20function%20closeMenus%20from%20chrome%3A//browser/content/utilityOverlay.js%0A%09for%28%3B%20node%20%26%26%20%22tagName%22%20in%20node%3B%20node%20%3D%20node.parentNode%29%20%7B%0A%09%09if%28%0A%09%09%09node.namespaceURI%20%3D%3D%20%22http%3A//www.mozilla.org/keymaster/gatekeeper/there.is.only.xul%22%0A%09%09%09%26%26%20%28node.localName%20%3D%3D%20%22menupopup%22%20%7C%7C%20node.localName%20%3D%3D%20%22popup%22%29%0A%09%09%29%0A%09%09%09node.hidePopup%28%29%3B%0A%09%7D%0A%7D%0A%0Afunction%20hasUpdater%28%29%20%7B%0A%09var%20has%20%3D%20checkForAddonsUpdates.toString%28%29.indexOf%28%22Services.jsm%22%29%20%21%3D%20-1%3B%0A%09hasUpdater%20%3D%20function%28%29%20%7B%0A%09%09return%20has%3B%0A%09%7D%3B%0A%09return%20has%3B%0A%7D%0Afunction%20checkForAddonsUpdates%28%29%20%7B%0A//%3D%3D%20Check%20for%20Addons%20Updates%20begin%0A%0A//%3D%3D%20Check%20for%20Addons%20Updates%20end%0A%7D%5D%5D%3E%3C/initcode%3E%0A%20%20%3Ccode%3E%3C%21%5BCDATA%5Bif%28%21event.target%29%20//%20Button%27s%20hotkey%20pressed%0A%09this.open%20%3D%20true%3B%5D%5D%3E%3C/code%3E%0A%20%20%3Caccelkey%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/accelkey%3E%0A%20%20%3Chelp%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/help%3E%0A%20%20%3Cattributes/%3E%0A%3C/custombutton%3E


Исходный код, инициализация: toggleRestartlessAddons.js

Также код можно использовать из других расширений, позволяющих выполнять произвольный код в контексте главного окна приложения, например, из Mouse Gestures.
Дополнительно можно сделать проверку обновлений кликом правой кнопкой мыши по кнопке: надо скопировать код кнопки Check for Addons Updates после «//== Check for Addons Updates begin».

Тестовая версия, будьте осторожны!

Разрабатываемая версия

feature requests:
1. пусть MMB по самой кнопке открывает about:addons.
2. пусть RMB по самой кнопке срабатывает как Check for Addons Updates.

iDev.Pi пишет

1. пусть MMB по самой кнопке открывает about:addons.

Это можно.

iDev.Pi пишет

2. пусть RMB по самой кнопке срабатывает как Check for Addons Updates.

Мне как-то не очень нравится заменять контекстное меню действием.
И, если честно, не особо хочется пихать все в одну кнопку. Вдобавок код можно запускать жестами мышью, например, там это вообще окажется кучей невостребованного кода. :D

Infocatcher пишет

И, если честно, не особо хочется пихать все в одну кнопку. Вдобавок код можно запускать жестами мышью, например, там это вообще окажется кучей невостребованного кода.

А я вот наоборот, хочу поменьше кнопок на панели иметь :)

Infocatcher пишет

Мне как-то не очень нравится заменять контекстное меню действием

Это можно обойти так:
пусть MMB по самой кнопке срабатывает как Check for Addons Updates, а открытие about:addons убрать в меню, открывающееся по LMB.

04-02-2013 01:16:36
И да, а тебе не кажется ли, что лучше было бы отделить включённые дополнения (и плагины) от отключённых? правда так 4 списка получится - это да. Но можно между включёнными и выключенными не ставить разделитель или ставить, а между дополнениями и плагинами - сделать его потолще.

Infocatcher пишет

Мне как-то не очень нравится заменять контекстное меню действием.

И синхронизировать изменения тоже не очень-то удобно. И забыть можно.
Пока вот так: Allow use checkForAddonsUpdates.js – если скопировать код из checkForAddonsUpdates.js вовнутрь функции checkForAddonsUpdates(), он будет вызываться по клику правой кнопкой мыши.


iDev.Pi пишет

а открытие about:addons убрать в меню, открывающееся по LMB.

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

iDev.Pi пишет

отделить включённые дополнения (и плагины) от отключённых?

Я про это думал. По-моему, так искать проще, когда по алфавиту.
Приделал настройку: Add "separateDisabledAddons" option

Toggle Restartless Add-ons 0.1.1 (2013-02-04)
[+] Клик СКМ или ЛКМ с любым модификатором на самой кнопке – открыть управление дополнениями.
[+] Добавлена возможность использования кода кнопки Check for Addons Updates для проверки обновлений по клику правой кнопкой мыши на самой кнопке – см. описание в коде.
[+] Добавлена настройка «separateDisabledAddons» для возможности вывода сначала включенных дополнений в каждой из категорий.

Toggle Restartless Add-ons 0.1.2 (2013-10-02)
[+] Добавлена поддержка click-to-play плагинов (plugins.click_to_play = true) (#15).
[+] Добавлены настройки закрытия меню после клика левой кнопкой мыши (closeMenu и closeMenuClickToPlay).
[+] Добавлена расширенная настройка сортировки (см. примеры для настройки sort).

Toggle Restartless Add-ons 0.1.2.1 (2014-02-21)
[x] Исправлена обработка уязвимых плагинов (их невозможно включить).

1. Есть ли возможность вызова настроек для аддонов, у которых есть настройки?
2. Есть ли возможность "задавить" некоторые аддоны, которые не нуждаются в тогглинге (чтобы уменьшить само меню).
3. Пункт 1 был бы актуален не только для рестартлесс аддонов.

difabor пишет

1. Есть ли возможность вызова настроек для аддонов, у которых есть настройки?

Из описания:

В меню:
ЛКМ – включить/выключить дополнение
Shift+ЛКМ – включить/выключить дополнение без закрытия меню
СКМ или ЛКМ с любым модификатором (кроме Shift) – открыть страницу дополнения в управлении дополнениями
ПКМ – открыть настройки дополнения (если есть)

difabor пишет

2. Есть ли возможность "задавить" некоторые аддоны, которые не нуждаются в тогглинге (чтобы уменьшить само меню).

На данный момент – только правкой исходного кода.

Например, так (надо заменить соответствующую функцию в коде):

Выделить код

Код:

function getRestartlessAddons(addonTypes, callback, context) {
    if(!("AddonManager" in window))
        Components.utils.import("resource://gre/modules/AddonManager.jsm");
    var excludeIds = [
        "{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}", // Adblock Plus
        "elemhidehelper@adblockplus.org"
    ];
    var excludeNames = [
        "Shockwave Flash"
    ];
    AddonManager.getAddonsByTypes(addonTypes, function(addons) {
        var restartless = addons.filter(function(addon) {
            var ops = addon.operationsRequiringRestart;
            return !addon.appDisabled
                && excludeIds.indexOf(addon.id) == -1
                && excludeNames.indexOf(addon.name) == -1
                && !(ops & AddonManager.OP_NEEDS_RESTART_ENABLE || ops & AddonManager.OP_NEEDS_RESTART_DISABLE);
        });
        callback.call(context, restartless);
    });
}

difabor пишет

3. Пункт 1 был бы актуален не только для рестартлесс аддонов.

Extension Options Menu?
Поддержка обычных дополнений изначально не планировалась, нужен был только переключатель.
Но, в принципе, в той же функции getRestartlessAddons() можно убрать проверку на необходимость перезапуска – все должно работать, только, конечно, никакой специальной обработки типа предложения сделать перезапуск не будет. И индикация будет показывать не текущую включенность, а ту, что будет после перезапуска.

1. Спасибо за разъяснение и извините, что сам не разобрался с описанием.
2. Насчёт выборочного задавливания -  в моём понимании - это 100% решение, задавливание делается один раз и можно спокойно - жёстко в коде.
Ещё раз спасибо - в целом :)

del

Xant1k
Эээ... выводятся только дополнения, не требующие перезапуска. Такие вообще есть?

Если очень хочется, можно закомментировать в коде проверку:

Выделить код

Код:

function getRestartlessAddons(addonTypes, callback, context) {
    if(!("AddonManager" in window))
        Components.utils.import("resource://gre/modules/AddonManager.jsm");
    AddonManager.getAddonsByTypes(addonTypes, function(addons) {
        var restartless = addons.filter(function(addon) {
            var ops = addon.operationsRequiringRestart;
            return !addon.appDisabled
                //&& !(ops & AddonManager.OP_NEEDS_RESTART_ENABLE || ops & AddonManager.OP_NEEDS_RESTART_DISABLE);
        });
        callback.call(context, restartless);
    });
}

Можно исключить из меню все плагины? Их названия вытягивают меню на 2\3 экрана...да и не особо нужно.

oleg.sgh
Можно, в самом начале подправить вот так:

Выделить код

Код:

var options = {
    addonTypes: ["extension"],

Infocatcher
На самом видном месте не увидел и не сообразил....
Благодарю.

Уважаемый Infocatcher,
у меня есть несколько вопросов касательно Вашего Менеджера-меню.
Только заранее хочу пояснить - это ни в коей мере не пожелания что-то туда добавить или изменить.
Просто я хотел бы сам попытаться что-то модифицировать, но вряд ли самостоятельно мне это удастся...
1. Недавно bunda1 показал мне как организовывать меню в две колонки (по-видимому, так же можно организовать меню и в любое К колонок):

Выделить код

Код:

// Создать двухсекционное меню ...................... 
var popup = addElement("menupopup", {
   position: "after_start",
   oncontextmenu: "return false",
   style: "-moz-appearance: none; border: 1px solid"
}, self);

var mainBox = addElement("hbox", {}, popup);
var leftBox = addElement("vbox", {style: "background-color: rgb(255,255,0);"},  mainBox);     // Левое меню
var rightBox = addElement("vbox", {                 // Правое меню
   style: "background-color: rgb(255,0,0); box-shadow: 1px 0px 2px rgb(204, 214, 234) inset;" // стиль правого меню 241, 245, 251
}, mainBox);

Можно задать счётчик менюитемов и каждый менюитем с №М%К равным 0 помещать в первую колонку, №М%К равным 1 помещать во вторую колонку, и т.д.
В принципе, можно сделать, чтобы сначала менюитемы заполняли бы первую колонку, с некоторого их номера - вторую и т.д.
Но вот где у Вас в коде можно организовать счётчик менюитемов и как указывать в какую колонку его помещать, я не знаю.
Кроме того, потребуется ограничить макс. ширину колонок. Это, наверное, в стиле колонок.
При большом кол-ве расширений и желании видеть не только безрестартные - это было бы хорошим подспорьем.
2. Вы объяснили как выборочно исключать расширения:

Выделить код

Код:

function getRestartlessAddons(addonTypes, callback, context) {
    if(!("AddonManager" in window))
        Components.utils.import("resource://gre/modules/AddonManager.jsm");
    var excludeIds = [
        "{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}", // Adblock Plus
        "elemhidehelper@adblockplus.org"
    ];
    var excludeNames = [
        "Shockwave Flash"
    ];
    AddonManager.getAddonsByTypes(addonTypes, function(addons) {
        var restartless = addons.filter(function(addon) {
            var ops = addon.operationsRequiringRestart;
            return !addon.appDisabled
                && excludeIds.indexOf(addon.id) == -1
                && excludeNames.indexOf(addon.name) == -1
                && !(ops & AddonManager.OP_NEEDS_RESTART_ENABLE || ops & AddonManager.OP_NEEDS_RESTART_DISABLE);
        });
        callback.call(context, restartless);
    });
}

В принципе, если в about:config хранить список таких исключений, то их можно исключать по такому списку.
Надо получить этот список из about:config один раз при старте браузера и это должно работать.
3. Было бы удобно иметь возможность добавлять исключения в такой список из самого меню, например по отпусканию СКМ (или ЛКМ), когда нажатие было левее.
Кстати, использование жестов "влево"/"вправо" на менюитемах может быть удобнее модификаторов
4. Исключённые расширения - это расширения, которые юзер не хочет видеть в меню высшего уровня (чтобы оно выглядело не таким большим)
Но это не значит, что он вообще не хочет иметь к ним доступ.
Поэтому желательно чтобы имелось подменю "Спрятанные" и чтобы оно открывало список спрятанных расширений/плагинов
Возвращение расширения из этого списка в главное меню может быть по отпусканию СКМ/ЛКМ когда нажатие было правее
5. Число спрятанных расширений может быть большим и возникнет необходимость в нескольких списках спрятанных расширений.
Для этого нужен механизм создания списка где по промпту можно задать его название.
В принципе если есть хотя бы одно подменю, кликами на него самого можно и формировать подобный промпт для создания/добавления другого списка.
Другим кликом можно удалять подменю. Если оно не пустое, все расширения из такого списка перейдут в главное меню.
6. В принципе пп. 2 и 3 я бы мог (надеюсь) реализовать самостоятельно. А с остальными - напряжёнка...

del

difabor пишет

1. ... организовать меню и в любое К колонок

Можно, что-то такое будет:

Выделить код

Код:

<hbox>
    <vbox>
        <menuitem label="1" />
        <menuitem label="2" />
    </vbox>
    <vbox>
        <menuitem label="3" />
        <menuitem label="4" />
    </vbox>
    <vbox>...</vbox>
    ...
</hbox>

Только, скорее всего, не будет работать навигация по меню с клавиатуры.

difabor пишет

Но вот где у Вас в коде можно организовать счётчик менюитемов и как указывать в какую колонку его помещать, я не знаю.

Это просто, надо искать в коде создание пунктов меню, по "menuitem" находится одно такое место.

Выделить код

Код:

mp.updateMenu = function() {
    ...
    getRestartlessAddons(options.addonTypes, function(addons) { // Получение списка дополнений
        // Создание "буфера" для небольшого увеличения производительности
        // https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment
        var df = document.createDocumentFragment();
        ...
        // Тут можно объявить какие-нибудь счетчики
        addons.sort(function(a, b) { // Сортировка списка дополнений
            var ka = key(a);
            var kb = key(b);
            return ka == kb ? 0 : ka < kb ? -1 : 1;
        }).forEach(function(addon) { // Перебор всех элементов списка
            ...
            var mi = document.createElement("menuitem"); // Создается новый пункт меню
            ...
            df.appendChild(mi); // Созданный пункт меню добавляется в "буфер"
        });
        mp.textContent = ""; // Очистка меню
        mp.appendChild(df); // Меню заполняется содержимым "буфера"
difabor пишет

В принципе, если в about:config хранить список таких исключений, то их можно исключать по такому списку.

Можно, что-то такое:

Выделить код

Код:

var excludeIds = getRestartlessAddons._excludeIds || (
        getRestartlessAddons._excludeIds = Services.prefs.getCharPref("extensions.custombuttons.button.toggleRestartlessAddons.excludeIds")
            .split("|")
    );
    var excludeNames = getRestartlessAddons._excludeNames || (
        getRestartlessAddons._excludeNames = Services.prefs.getCharPref("extensions.custombuttons.button.toggleRestartlessAddons.excludeNames")
            .split("|")
    );

Только Services.prefs.getCharPref() не понимает юникод и выпадет с ошибкой, если настройка не существует.

(на остальное попозже отвечу)

difabor пишет

3. Было бы удобно иметь возможность добавлять исключения в такой список из самого меню, например по отпусканию СКМ (или ЛКМ), когда нажатие было левее.

Это все реализуемо, просто тогда уж интуитивнее сделать контекстное меню.

difabor пишет

Кстати, использование жестов "влево"/"вправо" на менюитемах может быть удобнее модификаторов

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

difabor пишет

4. Исключённые расширения - это расширения, которые юзер не хочет видеть в меню высшего уровня (чтобы оно выглядело не таким большим)
Но это не значит, что он вообще не хочет иметь к ним доступ.
Поэтому желательно чтобы имелось подменю "Спрятанные" и чтобы оно открывало список спрятанных расширений/плагинов
Возвращение расширения из этого списка в главное меню может быть по отпусканию СКМ/ЛКМ когда нажатие было правее

Тут на самом деле сложнее всего сделать интерфейс настроек.

Вот упрощенный пример с вложенным меню. Только там если скрыть все дополнения одного типа, неправильно выведет разделитель.

Выделить код

Код:

--- toggleRestartlessAddons.js
+++ toggleRestartlessAddons_submenu.js
@@ -42,7 +42,7 @@
 };
 
 var mp = document.createElement("menupopup");
-mp.setAttribute("onpopupshowing", "this.updateMenu();");
+mp.setAttribute("onpopupshowing", "if(event.target == this) this.updateMenu();");
 mp.setAttribute("oncommand", "this.handleEvent(event);");
 mp.setAttribute("onmousedown", "if(event.button == 0) this.handleEvent(event);");
 mp.setAttribute("onclick", "if(event.button > 0) this.handleEvent(event);");
@@ -75,6 +75,20 @@
                 + "\n" + sortPosition(addon)
                 + "\n" + addon.name.toLowerCase();
         }
+        var collapseNames = [
+            "Adblock Plus"
+        ];
+        var menu;
+        function more(mi) {
+            menu = document.createElement("menu");
+            menu.setAttribute("label", "More…");
+            var mp = document.createElement("menupopup");
+            menu.appendChild(mp);
+            more = function(mi) {
+                mp.appendChild(mi);
+            };
+            more(mi);
+        }
         addons.sort(function(a, b) {
             var ka = key(a);
             var kb = key(b);
@@ -101,8 +115,13 @@
             desc && mi.setAttribute("tooltiptext", desc);
             setDisabled(mi, addon.userDisabled);
             mi._cbAddon = addon;
-            df.appendChild(mi);
+            if(collapseNames.indexOf(addon.name) != -1)
+                more(mi);
+            else
+                df.appendChild(mi);
         });
+        if(menu)
+            df.appendChild(menu);
         mp.textContent = "";
         mp.appendChild(df);
     });
difabor пишет

5. Число спрятанных расширений может быть большим и возникнет необходимость в нескольких списках спрятанных расширений.

Я не вполне уверен, что получится найти такое количество полезных расширений, чтобы эти все доработки оказались оправданы. :)

Infocatcher пишет

Вот упрощенный пример с вложенным меню. Только там если скрыть все дополнения одного типа, неправильно выведет разделитель.

Выделить код

Код:

--- toggleRestartlessAddons.js
+++ toggleRestartlessAddons_submenu.js
@@ -42,7 +42,7 @@
 };
 
 var mp = document.createElement("menupopup");
-mp.setAttribute("onpopupshowing", "this.updateMenu();");
+mp.setAttribute("onpopupshowing", "if(event.target == this) this.updateMenu();");
 mp.setAttribute("oncommand", "this.handleEvent(event);");
 mp.setAttribute("onmousedown", "if(event.button == 0) this.handleEvent(event);");
 mp.setAttribute("onclick", "if(event.button > 0) this.handleEvent(event);");
@@ -75,6 +75,20 @@
                 + "\n" + sortPosition(addon)
                 + "\n" + addon.name.toLowerCase();
         }
+        var collapseNames = [
+            "Adblock Plus"
+        ];
+        var menu;
+        function more(mi) {
+            menu = document.createElement("menu");
+            menu.setAttribute("label", "More…");
+            var mp = document.createElement("menupopup");
+            menu.appendChild(mp);
+            more = function(mi) {
+                mp.appendChild(mi);
+            };
+            more(mi);
+        }
         addons.sort(function(a, b) {
             var ka = key(a);
             var kb = key(b);
@@ -101,8 +115,13 @@
             desc && mi.setAttribute("tooltiptext", desc);
             setDisabled(mi, addon.userDisabled);
             mi._cbAddon = addon;
-            df.appendChild(mi);
+            if(collapseNames.indexOf(addon.name) != -1)
+                more(mi);
+            else
+                df.appendChild(mi);
         });
+        if(menu)
+            df.appendChild(menu);
         mp.textContent = "";
         mp.appendChild(df);
     });

Спасибо большое! Буду "переваривать".
По ходу у меня возникло пару имхо простых вопросов:
1.Приведённый ниже кусочек - это результат diff'a двух файлов, или этим можно как-то пользоваться в самой кнопке?

Выделить код

Код:

--- toggleRestartlessAddons.js
+++ toggleRestartlessAddons_submenu.js
@@ -42,7 +42,7 @@
... и т.д.

2.Я совсем не понял нотацию в приведённом Вами коде:

Infocatcher пишет
difabor пишет

... организовать меню и в любое К колонок

Можно, что-то такое будет:

Выделить код

Код:

<hbox>
    <vbox>
        <menuitem label="1" />
        <menuitem label="2" />
    </vbox>
    <vbox>
        <menuitem label="3" />
        <menuitem label="4" />
    </vbox>
    <vbox>...</vbox>
    ...
</hbox>

Только, скорее всего, не будет работать навигация по меню с клавиатуры.

Где этот код писать?
Что такое "1", "2" и т.д.?
Что должно быть вместо "..." в <vbox>...</vbox>
Заранее извините, если вопросы выглядят идиотскими :(

difabor пишет

1.Приведённый ниже кусочек - это результат diff'a двух файлов, или этим можно как-то пользоваться в самой кнопке?

Это diff, да.

difabor пишет

Где этот код писать?
Что такое "1", "2" и т.д.?
Что должно быть вместо "..." в <vbox>...</vbox>

Это не совсем код, это результат (можно наглядно увидеть в DOM Inspector'е).
Но можно и превратить строку с подобной разметкой в DOM-дерево примерно так:
https://github.com/Infocatcher/Custom_B … ks.js#L552
https://github.com/Infocatcher/Custom_B … 2318-L2321

label="1" и прочее – просто для примера, это название пункта меню.
<vbox>...</vbox> добавляет очередную вертикальную колонку, в которую можно добавлять menuitem'ы.

Спасибо! Понял :) Извините за тупость!
Есть ещё два вопроса..
1. Как сортировать аддоны не по имени, а по времени последнего обновления?
2. Как (болдом) выделять аддоны, имеющие настройки от не имеющих и (курсивом)  не Restartless от Restartless?
Как я понимаю, что-то надо добавить в

Выделить код

Код:

function addStyle() {
    if(addStyle.hasOwnProperty("_style"))
        return;
    var style = '\
        .toggleRestartlessAddons-disabled > .menu-iconic-left {\n\
            opacity: 0.4;\n\
        }\n\
        .toggleRestartlessAddons-disabled > .menu-iconic-text,\n\
        .toggleRestartlessAddons-disabled > .menu-accel-container {\n\
            opacity: 0.5;\n\
        }\n\
        .toggleRestartlessAddons-askToActivate {\n\
            color: -moz-nativehyperlinktext;\n\
        }';
    addStyle._style = document.insertBefore(
        document.createProcessingInstruction(
            "xml-stylesheet",
            'href="' + "data:text/css,"
                + encodeURIComponent(style) + '" type="text/css"'
        ),
        document.documentElement
    );
}
difabor пишет

1. Как сортировать аддоны не по имени, а по времени последнего обновления?

Надо внести правки в

Выделить код

Код:

function sortPosition(addon) {
            if("STATE_ASK_TO_ACTIVATE" in AddonManager && addon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE)
                return options.sort.clickToPlay;
            if(addon.isActive)
                return options.sort.enabled;
            return options.sort.disabled;
        }
        function key(addon) {
            return options.addonTypes.indexOf(addon.type)
                + "\n" + sortPosition(addon)
                + "\n" + addon.name.toLowerCase();
        }
        addons.sort(function(a, b) { // Вот тут собственно сортировка, остальное – вспомогательные функции
            var ka = key(a);
            var kb = key(b);
            return ka == kb ? 0 : ka < kb ? -1 : 1;
        })

Только там специальные штуки, чтобы работал настроечный объект и группировка по типам.
Можно заменить

Выделить код

Код:

function sortPosition(addon) {
            if("STATE_ASK_TO_ACTIVATE" in AddonManager && addon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE)
                return options.sort.clickToPlay;
            if(addon.isActive)
                return options.sort.enabled;
            return options.sort.disabled;
        }

на что-нибудь вроде

Выделить код

Код:

function sortPosition(addon) {
            var time = new Date(addon.updateDate).getTime() || 0;
            return "0".repeat(13 - String(time).length) + time;
        }
difabor пишет

2. Как (болдом) выделять аддоны, имеющие настройки от не имеющих и (курсивом)  не Restartless от Restartless?
Как я понимаю, что-то надо добавить в

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

В простейшем случае надо к уже имеющемуся дописать

Выделить код

Код:

mi.setAttribute("label", label);
            mi.setAttribute("image", icon);
            // Для дополнительной подсветки
            if(addon.optionsURL)
                mi.style.fontWeight = "bold";
            var ops = addon.operationsRequiringRestart;
            if(!(ops & AddonManager.OP_NEEDS_RESTART_ENABLE || ops & AddonManager.OP_NEEDS_RESTART_DISABLE))
                mi.style.fontStyle = "italic";

Спасибо большое!
Как я понял, дополнительную подсветку болдом и курсивом осуществить даже проще, чем включён/выключен, поскольку включён/выключен - вещь динамическая, а наличие опций и безрестартность - статическая.

difabor пишет

Как я понял, дополнительную подсветку болдом и курсивом осуществить даже проще, чем включён/выключен, поскольку включён/выключен - вещь динамическая, а наличие опций и безрестартность - статическая.

Там все проще сделано: список обновляется при каждом открытии (пересоздается заново).

Выделить код

Код:

mp.setAttribute("onpopupshowing", "this.updateMenu();");
...
mp.updateMenu = function() { ... };

Все равно отслеживать что-то пока меню закрыто нет смысла (да и вредно для производительности.

Infocatcher пишет
difabor пишет

Как я понял, дополнительную подсветку болдом и курсивом осуществить даже проще, чем включён/выключен, поскольку включён/выключен - вещь динамическая, а наличие опций и безрестартность - статическая.

Там все проще сделано: список обновляется при каждом открытии (пересоздается заново).

Выделить код

Код:

mp.setAttribute("onpopupshowing", "this.updateMenu();");
...
mp.updateMenu = function() { ... };

Все равно отслеживать что-то пока меню закрыто нет смысла (да и вредно для производительности.

Спасибо!
Но я обратил внимание на следующее (после того, как "раскрасил" меню болдом и курсивом):
Отключение Restartless аддона с опциями (т.е. который болдом) без закрытия меню меняет его прозрачность (он становится бледнее), но остаётся болдом.
И только, когда снова открываешь меню - он уже без болда.
Из этого я и сделал такой вывод. :)

difabor
Странно, что информация насчет наличия настроек пропадает...
А так – да, я забыл, там после включения/выключения специально вызывается

Выделить код

Код:

function setDisabled(mi, disabled) { ... }

, как и при построении меню.
В принципе, можно в эту же функцию и перенести дополнительный код для раскрашивания (только надо будет еще и ссылку на addon в нее передавать).

Infocatcher пишет

difabor
Странно, что информация насчет наличия настроек пропадает...

Информация насчёт наличия настроек пропадает и в about:addons и это имхо правильно - нельзя вызывать настройки отключённого аддона и не надо даже провоцировать на это.

Infocatcher пишет

А так – да, я забыл, там после включения/выключения специально вызывается

Выделить код

Код:

function setDisabled(mi, disabled) { ... }

, как и при построении меню.
В принципе, можно в эту же функцию и перенести дополнительный код для раскрашивания (только надо будет еще и ссылку на addon в нее передавать).

В данном конкретном случае имхо нет такой необходимости, но знать как в эту же функцию перенести дополнительный код для раскрашивания и передать  в нее ссылку на addon было бы очень желательно.

difabor пишет

В данном конкретном случае имхо нет такой необходимости, но знать как в эту же функцию перенести дополнительный код для раскрашивания и передать  в нее ссылку на addon было бы очень желательно.

Примерно так (там в двух местах вызывается setDisabled() + лучше переименовать для соответствия):

Выделить код

Код:

setDisabled(mi, newDis);

->

Выделить код

Код:

highlightFeatures(mi, addon, newDis);
Выделить код

Код:

setDisabled(mi, addon.userDisabled);

->

Выделить код

Код:

highlightFeatures(mi, addon, addon.userDisabled);

И саму функцию:

Выделить код

Код:

function setDisabled(mi, disabled) {

->

Выделить код

Код:

function highlightFeatures(mi, addon, disabled) {
    // Для дополнительной подсветки
    if(addon.optionsURL)
        mi.style.fontWeight = "bold";
    var ops = addon.operationsRequiringRestart;
    if(!(ops & AddonManager.OP_NEEDS_RESTART_ENABLE || ops & AddonManager.OP_NEEDS_RESTART_DISABLE))
        mi.style.fontStyle = "italic";
    ...

Столько интересного понаписали, а готовую кнопку выкладывать будете?

Mishania пишет

Столько интересного понаписали, а готовую кнопку выкладывать будете?

Так ведь эта кнопка Infocatcherа выложена и прекрасно работает.

01-02-2016 02:38:26

Infocatcher пишет

Примерно так (там в двух местах вызывается setDisabled() + лучше переименовать для соответствия)

Огромнейшее спасибо!

Уважаемый Infocatcher,
какая функция делает  в Вашей кнопке быстрый поиск по меню?

difabor пишет

какая функция делает  в Вашей кнопке быстрый поиск по меню?

Эээ... о каком быстром поиске речь? Там ничего такого не реализовано.
Если речь о выделении/открытии по первой букве названия (если не задано особо, а тут не задано), то это так себя все меню ведут.

Впрочем, я еще вот такую штуку делал для фильтрации:
https://github.com/Infocatcher/Bookmarks_Menu_Filter

Infocatcher пишет
difabor пишет

какая функция делает  в Вашей кнопке быстрый поиск по меню?

Эээ... о каком быстром поиске речь? Там ничего такого не реализовано.
Если речь о выделении/открытии по первой букве названия (если не задано особо, а тут не задано), то это так себя все меню ведут.

Впрочем, я еще вот такую штуку делал для фильтрации:
https://github.com/Infocatcher/Bookmarks_Menu_Filter

Спасибо!
Извините, что докучаю :)
Я не знал об этом свойстве меню и искал функцию поиска, чтобы подправить - указывать не первый, а последний менюитем с этой начальной буквой (или 20-й - что раньше)

А как можно менять фон самого меню (не менюитема, а меню в целом)? Я имею в виду цвет фона?
Куда надо вписать что-то типа:

Выделить код

Код:

style: "-moz-appearance: none; background-color: rgba(0,255,0,0.8);"
difabor пишет

Куда надо вписать что-то типа

Тут два варианта: или в userChrome.css, или в код кнопки.
В userChrome.css можно что-то такое воткнуть:

Выделить код

Код:

toolbarbutton[id^="custombuttons-button"][label="Search"] > menupopup {
    -moz-appearance: none;
    background-color: rgba(0,255,0,0.8);
}

Это для menupopup внутри CB-кнопки с названием «Search».
Или можно по идентификатору кнопки:

Выделить код

Код:

#custombuttons-button99 > menupopup { ... }

Но здесь надо вручную номер вписывать: button99.

А если в коде, то надо найти место, где создается menupopup, в данном случае это

Выделить код

Код:

var mp = document.createElement("menupopup");
// Добавить для раскраски:
mp.style.cssText = "-moz-appearance: none; background-color: rgba(0,255,0,0.8);";
Infocatcher пишет

Тут два варианта: или в userChrome.css, или в код кнопки.

Огромное спасибо!

Уважаемый Infocatcher,
когда я устанавливаю showVersions: 2, (//show as "acceltext" (in place for hotkey text)),
то все версии у меня показываются в "бледном" виде независимо от того, включён аддон или нет.
Это так задумано?
P.S. Bold и italic сохраняются как и для названия.

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

Это из-за chrome://browser/skin/browser.css

Выделить код

Код:

.menu-accel,
  .menu-iconic-accel {
    color: graytext;
  }

Обесцвечивается вот так (в userChrome.css):

Выделить код

Код:

.menu-accel,
.menu-iconic-accel {
    color: inherit !important;
}

Спасибо большое!
Действиельно, я поменял цвет в Stylish и всё изменилось. :)
Но у меня вопрос не конкретно по этому меню, а в целом по меню:
Есть ли возможность задавать стили/цвета и пр. для accel текста "персонально" для менюитема/подменю и т.п.?
Иными словами есть ли какой-то путь одну часть менюитема выдавать одним стилем, а другую - другим и управлять этим?

difabor
Во-первых, можно применить стили только к конкретным пунктам, например, так:

Выделить код

Код:

#tools-menu .menu-accel,
#tools-menu .menu-iconic-accel {
    color: red !important;
}

Вместо #tools-menu (меню Инструменты) можно задавать штуки типа menu[label="Инструменты"] для определения по названию.

А во-вторых, можно получить ссылку на сам этот узел, в котором находится текст сочетания клавиш, и перекрасить только его:

Выделить код

Код:

var mi = document.getElementById("menu_openDownloads"); // Для примера пункт Инструменты – Загрузки
var accel = document.getAnonymousElementByAttribute(mi, "class", "menu-accel"); // У пунктов с иконками тут будет "menu-iconic-accel"
accel.style.color = "green";

Большое спасибо!

Infocatcher
А как сделать чтобы меню не закрывалось после каждого клика.

voqabuhe пишет

А как сделать чтобы меню не закрывалось после каждого клика.

Или Shift+клик, или поменять там в самом начале:

Выделить код

Код:

var options = {
    ...
    closeMenu: true,
    // Close menu after left-click (use Shift+click to invert this behavior)

Infocatcher
Установил closeMenuClickToPlay: 1
    // 1  - always don't close menu  всё равно закрывается.
А если closeMenu: false, то не закрывается при переключение дополнений и закрывается, если переключать плагины. А сами плагины не переключаются при любых настройках, это я понял из-за [nightly].

voqabuhe
А что получить требуется? Изначально меню закрывалось, а для «включать по запросу» у плагинов стало неинтуитивно, в какой режим перешло, поэтому там появилась особая настройка.
closeMenu – общая настройка, closeMenuClickToPlay – особое поведение для плагинов (и только если plugins.click_to_play = true).
Можно задать
closeMenu: false, // не закрывать меню
closeMenuClickToPlay: 0 // обрабатывать плагины как дополнения, то есть тоже не закрывать

Infocatcher
Теперь меню не закрывается, как и хотел. Но плагины не переключаются.

voqabuhe
У меня на 48.0a1 (2016-03-27) переключаются. А вообще все? Из управления дополнениями можно переключить? А то ведь нынче устаревшие и заблокированные может не дать включить вообще.

Infocatcher
Через управление дополнений включается и выключается. А через кнопку как оказалось только выключается.

31-03-2016 01:25:29

Infocatcher пишет

У меня на 48.0a1 (2016-03-27) переключаются

У меня 48.0a1 (2016-03-30)

Хм, наверное, дело в этом исправлении, которое пока попало только в разрабатываемую версию.

Infocatcher пишет

Хм, наверное, дело в этом исправлении, которое пока попало только в разрабатываемую версию.

У меня версия version 0.1.2.1 - 2014-02-21

Там заголовок старый, это видно по логам.

Infocatcher
Попробовал кнопку с первого поста, тоже не переключает плагины.

voqabuhe
Нужна именно разрабатываемая версия: Custom_Buttons/raw/master/Toggle_Restartless_Add-ons/toggleRestartlessAddons.js

Infocatcher
Теперь дошло :dumb:. Спасибо. Всё сделал.

Блин, не показывает устаревшие расширения(

momo2000 пишет

Блин, не показывает устаревшие расширения(

Эмм, показывает:
u3M9BSy.png

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

Выделить код

Код:

function getRestartlessAddons(addonTypes, callback, context) {
    …
    AddonManager.getAddonsByTypes(addonTypes, function(addons) {
        var restartless = addons.filter(function(addon) {
            var ops = addon.operationsRequiringRestart;
            return !addon.appDisabled
                // закомментировать проверку && !(ops & AddonManager.OP_NEEDS_RESTART_ENABLE || ops & AddonManager.OP_NEEDS_RESTART_DISABLE)
                …

Infocatcher
точно, у меня устаревшие как раз все с перезагрузкой, поэтому и не понял разницу

Дык надо пункт перезагрузки в конец вставить и тогда будет практически полный аналог Extension Options Menu, его даже с AMO удалили, видать как супер пупер устаревшее)
http://forums.mozillazine.org/viewtopic … &t=2141579

Infocatcher или другой мастер
Если не трудно, подскажите куда добавить и сам код с кнопокй перезапуска браузера в самый конец.

Services.startup.quit(Services.startup.eAttemptQuit | Services.startup.eRestart);

иконка

Выделить код

Код:

data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAD///8A/Pz8A/v7+gX7+/oF+fn4B////wB7d3JQDgYA8A4GAPB7d3JQ////APv7+gX8/PsD//7/AP///wD///8A////AP///wD///8A/v7+Af///wDx8fAFIRoU2BEJAP8RCQD/IRoU2PLx8AX///8A/Pz8Af7+/gL///8A////AP///wCalpFfgHx1jYiEfoCUkYt26unnDh4YFdgLAwD/DAQA/xoUEN38/PwAfXl0Wnp2cF////8A/v7+A////wD///8Aw8G9LwwJBuoAAAD/Ew8P7/f4+AeIhIBHHBUK4hsUCOKOi4dH1NTSCQUBAOkAAAD/iYV/U////wD8/PwD////AMrKxxUaEwfhDwcA/yMcFOvy8fAQ////APDv7gjw7+4H////APf39wBlYFx/CQIA/w0FAOjBv70Z////AP///wBbV1V/AAAA/zIsI8E6NTC+5+foGf///wD+/v4C////Afz8/AP///8B8fHxADYxKq0AAAD/aGRidv///wD19fUANC0lxAAAAP+ppqJE5eTjD+3t7A////8A/v7+Af7+/gH///8A+/v6BP///wCjoZxGAgAA/ykkHMDv7+8A7u3uDSghGOcFAAD8wsG+Hv///wD8/PwB////AP///wD///8A////APz8/AH///8Aw8G+GwQAAPwqIhji7+7uCu7t7gwoIRjlBQAA+sPBvhn///8A/Pz8Av///wD///8A////AP///wD8/PwB////AMPBvhkFAAD6JyAY5u7t7gz19fUANC0lxAAAAP+koZxF////APr6+gT///8A////AP///wD///8A+vr6BP///wCkoZxFAAAA/zMtJcP19fUA////AF1YVn0AAAD/NjEprfHx8QD///8E+vr6BPz8/AH8/PwB+vr6BP///wTx8fEANjEprQAAAP9dWFZ8////AP///wDBv70bCwQA6wkBAP9lYFx69vb1AP///wH+/v4A/v7+AP///wH29vUAZWBcegkBAP8LBADrwb+9Gv///wD8/PwD////AHl1cFgAAAD/CQIA/zUuJq6ppqE/x8XCF8fFwheppqE/NS4mrgkCAP8AAAD/eHVwV////wD8/PwD////AP7+/gP///8Ae3dwVgoDAO8BAAD/AgAA/wQAAPoEAAD6AgAA/wEAAP8KAwDvendwVv///wD+/v4D////AP///wD///8A/fz8A////wDDwL8aYFpTfjQtIsYoIRbmKCEW5jQtIsZgWlN+w8C/Gv///wD9/PwD////AP///wD///8A////AP7+/wD8/PwD////Af///wDz8vIB7u3sC+7t7Avz8vIB////AP///wH8/PwD/v7/AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==

И можно ли у плагинов сделать режим "Всегда включать" и "Никогда не включать", а не "Всегда включать" и "Включать по запросу"?

Infocatcher
Переключение скрытых аддонов опять сломали.
Вот, так, вроде, работает

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

Выделить код

Код:

if(addon.hidden) {
            _log("Let's try set addon.userDisabled using raw hack");
            let g = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm", {});

            if("XPIDatabase" in g && "updateAddonDisabledState" in g.XPIDatabase) { // Firefox 61+
                let rawAddon = g.XPIDatabase.syncGetAddon(function(rawAddon) {
                    return rawAddon.id == addon.id
                });
                g.XPIDatabase.updateAddonDisabledState(rawAddon, newDis);
            }
            else {
                // See "set userDisabled(val)"
                if("eval" in g) {

Dumby пишет

Переключение скрытых аддонов опять сломали.
Вот, так, вроде, работает

Совсем заработался, сообщение видел, даже запомнил, что было второе исправление... вспомнил только когда попытался применить кнопку.
Спасибо!
https://github.com/Infocatcher/Custom_B … 2a1031b9f8

Infocatcher
Опять сломали. Может так

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

Выделить код

Код:

function setNewDisabled(addon) {
    var newDis = getNewDisabled(addon);
    var oldDis = addon.userDisabled;
    try {
        if(addon.hidden && !addon.__lookupSetter__("userDisabled")) // Firefox 62+
            throw 0;
        addon.userDisabled = newDis;
    }
    catch(e) { // Error: Cannot disable hidden add-on firefox@getpocket.com

Dumby пишет

Опять сломали. Может так

О! А я уже успел вот так поразвлекаться:
https://github.com/Infocatcher/Custom_B … 3a2653135b
https://github.com/Infocatcher/Custom_B … 38f88466fa
Проверка на addon.type, наверное, лишняя, но пока, вроде, работает, а дальше, глядишь, еще чего поломают. :sick:

А вот и источник проблемы:
https://bugzilla.mozilla.org/show_bug.cgi?id=1461146
Make enable/disable/uninstall operations on AddonWrappers asynchronous

Infocatcher
Спасибо, забрал.

Надо будет в addons4.js в CustombuttonsButton.prototype
добавить методы enable и disable.
Надеюсь просто пустых функций (без возвращения promise)
будет достаточно.

Наблюдение: если кнопка расположена на панели вкладок,
то, svg'шки в меню не слишком хорошо видны.
Win7, Nightly, чистый профиль, дефолтная тема, скриншот.

Dumby пишет

Наблюдение: если кнопка расположена на панели вкладок,
то, svg'шки в меню не слишком хорошо видны.
Win7, Nightly, чистый профиль, дефолтная тема, скриншот.

Не придумалось, как сбросить цвет... перекрасил:

Выделить код

Код:

mi.style.fill = "#15c";

https://github.com/Infocatcher/Custom_B … 5ab04fdd31
+ https://github.com/Infocatcher/Custom_B … 5c85a25c2f

Infocatcher
И снова! Может так

Выделить код

Код:

//let rawAddon = g.XPIDatabase.syncGetAddon(function(rawAddon) {
        let rawAddon = Array.from(g.XPIDatabase.addonDB.values()).find(function(rawAddon) {

Dumby
Спасибо!
Покопался... нашел, что сами они применяют вот такое:
resource://gre/modules/addons/XPIProvider.jsm

Выделить код

Код:

getDependentAddons(aAddon) {
    return Array.from(XPIDatabase.getAddons())
                .filter(addon => addon.dependencies.includes(aAddon.id));
  },

resource://gre/modules/addons/XPIDatabase.jsm

Выделить код

Код:

/**
   * Synchronously gets all add-ons in the database.
   * This is only called from the preference observer for the default
   * compatibility version preference, so we can return an empty list if
   * we haven't loaded the database yet.
   *
   * @returns {Array<AddonInternal>}
   */
  getAddons() {
    if (!this.addonDB) {
      return [];
    }
    return _filterDB(this.addonDB, aAddon => true);
  },
Выделить код

Код:

var g = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
Array.isArray(g.XPIDatabase.getAddons()); // true

И к чему тогда Array.from()? о_О Шаловливые клоуны… ©
Подправил: https://github.com/Infocatcher/Custom_B … 8533bb0ebd

Всё работает, но с 68 показывает ещё и поисковые плагины, даже при addonTypes: ["extension"]

momo2000 пишет

Всё работает, но с 68 показывает ещё и поисковые плагины, даже при addonTypes: ["extension"]

Это к разработчикам Firefox, к сожалению: у встроенных поисковых плагинов теперь type = "extension":
https://bugzilla.mozilla.org/show_bug.cgi?id=1486820 [meta] Convert builtin opensearch files to webextensions
Можно спрятать вместе со всеми расширениями-невидимками:

Выделить код

Код:

var options = {
    …
    showHidden: 0,

Распорка для скрытия поисковых плагинов: https://github.com/Infocatcher/Custom_B … 941d074ed6
Но не уверен, начиная с какой версии заработает.

Infocatcher
Сделайте пожалуйста, что бы работала в [firefox] 69 без отключения многопроцессорного режима?

kokoss а в чем проблема? Он и так работает в 69 без отключения многопроцессорного режима.

Andrey_Krropotkin
У меня в [firefox] 69 не работает(не активна), кнопку взял от сюда: https://forum.mozilla-russia.org/viewto … 78#p600078 ?

kokoss брал у Infocatcher здесь
У меня так:
секция /*Initialization Code*/

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

Выделить код

Код:

// http://infocatcher.ucoz.net/js/cb/toggleRestartlessAddons.js
    // https://forum.mozilla-russia.org/viewtopic.php?id=57948
    // https://github.com/Infocatcher/Custom_Buttons/tree/master/Toggle_Restartless_Add-ons
    
    // Toggle Restartless Add-ons button for Custom Buttons
    // (code for "initialization" section)
    // Also the code can be used from main window context (as Mouse Gestures code, for example)
    
    // Also you can check for add-ons updates using right-click:
    // copy all code from
    // https://github.com/Infocatcher/Custom_Buttons/blob/master/Check_for_Addons_Updates/checkForAddonsUpdates.js
    // after "//== Check for Addons Updates begin"
    
    // See "var style = " to modify styles for specific add-ons
    
    // (c) Infocatcher 2013-2017
    // version 0.1.3pre3 - 2017-10-23
      
    var options = {
        addonTypes: ["extension"],
        // Possible values: "extension", "plugin"
        // From extensions: "userstyle" (Stylish), "greasemonkey-user-script" (Greasemonkey), "userscript" (Scriptish)
        // (swap to reorder in the menu)
        showVersions: 1,
        // 0 - don't show versions
        // 1 - show after name: "Addon Name 1.2"
        // 2 - show as "acceltext" (in place for hotkey text)
        showHidden: 0,
        // 0  - don't show hidden add-ons
        // -1 - show only enabled hidden add-ons (e.g. to track new items)
        // 1  - show all hidden add-ons
        sort: {
            enabled:     0,
            clickToPlay: 0,
            disabled:    0
            // Sort order:
            // 0, 0, 0 - sort add-ons of each type alphabetically
            // 0, 0, 1 - show enabled add-ons (of each type) first
            // 0, 1, 2 - enabled add-ons, then click-to-play and then disabled
        },
        closeMenu: false, // Close menu after left-click
        closeMenuClickToPlay: false // Close menu after left-click, for click to play plugins
        // Use Shift+click to invert closeMenu* behavior
    };
    
    var mp = document.createXULElement("menupopup");
    mp.setAttribute("onpopupshowing", "this.updateMenu();");
    mp.setAttribute("oncommand", "this.handleEvent(event);");
    mp.setAttribute("onmousedown", "if(event.button == 0) this.handleEvent(event);");
    mp.setAttribute("onclick", "if(event.button > 0) this.handleEvent(event);");
    mp.setAttribute("oncontextmenu", "return false;");
    mp.setAttribute("onpopuphidden", "this.destroyMenu();");
    
    var tb = this.parentNode;
    if(tb && tb.getAttribute("orient") == "vertical") {
        // https://addons.mozilla.org/firefox/addon/vertical-toolbar/
        var isRight = tb.parentNode.getAttribute("placement") == "right";
        mp.setAttribute("position", isRight ? "start_before" : "end_before");
    }
    
    var cleanupTimer = 0;
    mp.updateMenu = function() {
        clearTimeout(cleanupTimer);
        addStyle();
        getRestartlessAddons(options.addonTypes, function(addons) {
            var df = document.createDocumentFragment();
            var prevType;
            function sortPosition(addon) {
                if("STATE_ASK_TO_ACTIVATE" in AddonManager && addon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE)
                    return options.sort.clickToPlay;
                if(addon.isActive)
                    return options.sort.enabled;
                return options.sort.disabled;
            }
            function key(addon) {
                return options.addonTypes.indexOf(addon.type)
                    + "\n" + sortPosition(addon)
                    + "\n" + addon.name.toLowerCase();
            }
            addons.sort(function(a, b) {
                var ka = key(a);
                var kb = key(b);
                return ka == kb ? 0 : ka < kb ? -1 : 1;
            }).forEach(function(addon) {
                var type = addon.type;
                if(prevType && type != prevType)
                    df.appendChild(document.createXULElement("menuseparator"));
                prevType = type;
                var icon = addon.iconURL || addon.icon64URL;
                var mi = document.createXULElement("menuitem");
                mi.className = "menuitem-iconic";
                var label = addon.name;
                if(options.showVersions == 1)
                    label += " " + addon.version;
                else if(options.showVersions == 2)
                    mi.setAttribute("acceltext", addon.version);
                mi.setAttribute("label", label);
                mi.setAttribute("image", icon || mp.icons[type] || "");
                if(!icon && mp.icons.useSVG)
                    mi.style.fill = "#15c";
                var tip = addon.description || "";
                var delay = "delayedStartupAddons" in Services
                    && Services.delayedStartupAddons[addon.id] || null;
                var isDelayed = delay !== null;
                mi.classList.toggle("toggleRestartlessAddons-isDelayed", isDelayed);
                if(isDelayed)
                    tip = "[Delayed Startup: " + delay.toLocaleString() + "]" + (tip ? "\n" + tip : "");
                tip && mi.setAttribute("tooltiptext", tip);
                mi.classList.toggle("toggleRestartlessAddons-isHidden", addon.hidden || false);
                setDisabled(mi, addon.userDisabled);
                mi._cbAddon = addon;
                df.appendChild(mi);
            });
            mp.textContent = "";
            mp.appendChild(df);
        });
    };
    mp.handleEvent = function(e) {
        var mi = e.target;
        if(!("_cbAddon" in mi))
            return;
        var addon = mi._cbAddon;
        if(e.type == "mousedown") {
            var closeMenu = isAskToActivateAddon(addon)
                ? options.closeMenuClickToPlay
                : options.closeMenu;
            if(e.shiftKey)
                closeMenu = !closeMenu;
            mi.setAttribute("closemenu", closeMenu ? "auto" : "none");
            return;
        }
        var hasMdf = hasModifier(e);
        if(e.type == "command" && (!hasMdf || e.shiftKey)) {
            let newDis = setNewDisabled(addon);
            setDisabled(mi, newDis);
        }
        else if(e.type == "command" && hasMdf || e.type == "click" && e.button == 1) {
            openAddonPage(addon);
            closeMenus(mi);
        }
        else if(e.type == "click" && e.button == 2) {
            if(openAddonOptions(addon))
                closeMenus(mi);
        }
    };
    mp.destroyMenu = function() {
        removeStyle();
        clearTimeout(cleanupTimer);
        cleanupTimer = setTimeout(function() {
            mp.textContent = "";
        }, 5000);
    };
    mp.icons = {
        get useSVG() {
            delete this.useSVG;
            return this.useSVG = Services.appinfo.name == "Firefox"
                && parseFloat(Services.appinfo.version) >= 57;
        },
        get plugin() {
            delete this.plugin;
            return this.plugin = this.useSVG
                ? "chrome://mozapps/skin/plugins/pluginGeneric.svg"
                : "chrome://mozapps/skin/plugins/pluginGeneric-16.png";
        },
        get extension() {
            delete this.extension;
            return this.extension = this.useSVG
                ? "chrome://mozapps/skin/extensions/extensionGeneric-16.svg"
                : "chrome://mozapps/skin/extensions/extensionGeneric-16.png";
        }
    };
    function isAskToActivateAddon(addon) {
        return addon.type == "plugin"
            && "STATE_ASK_TO_ACTIVATE" in AddonManager
            && Services.prefs.getBoolPref("plugins.click_to_play");
    }
    function setNewDisabled(addon) {
        var newDis = getNewDisabled(addon);
        var oldDis = addon.userDisabled;
        try {
            addon.userDisabled = newDis;
        }
        catch(e) { // Error: Cannot disable hidden add-on firefox@getpocket.com
            _log("Can't set addon.userDisabled to " + newDis + ", error:\n" + e);
            if(addon.hidden)
                setNewDisabledRaw(addon, newDis);
        }
        var realDis = addon.userDisabled;
        if(realDis != newDis && addon.type == "extension") { // Firefox 62+? Weird things happens
            setNewDisabledRaw(addon, newDis);
            realDis = addon.userDisabled;
        }
        if(realDis != newDis) { // We can't enable vulnerable plugins
            let err = "Can't set addon.userDisabled to " + newDis + ", real value: " + realDis;
            if(newDis) {
                _log(err + "\nSTATE_ASK_TO_ACTIVATE not supported?");
                newDis = false;
            }
            else {
                _log(err + "\nVulnerable plugin?");
                if(oldDis == AddonManager.STATE_ASK_TO_ACTIVATE)
                    newDis = true;
                else
                    newDis = AddonManager.STATE_ASK_TO_ACTIVATE;
            }
            addon.userDisabled = newDis;
        }
        return addon.userDisabled;
    }
    function getNewDisabled(addon) {
        // disabled -> STATE_ASK_TO_ACTIVATE -> enabled -> ...
        var curDis = addon.userDisabled;
        var newDis;
        if("STATE_ASK_TO_ACTIVATE" in AddonManager && curDis == AddonManager.STATE_ASK_TO_ACTIVATE)
            newDis = false;
        else if(!curDis)
            newDis = true;
        else {
            if(isAskToActivateAddon(addon))
                newDis = AddonManager.STATE_ASK_TO_ACTIVATE;
            else
                newDis = false;
        }
        return newDis;
    }
    function setNewDisabledRaw(addon, newDis) {
        _log("Let's try set addon.userDisabled using raw hack");
        let g = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
        if("XPIDatabase" in g && "updateAddonDisabledState" in g.XPIDatabase) { // Firefox 61+
            let rawAddon = g.XPIDatabase.getAddons().find(function(rawAddon) {
                return rawAddon.id == addon.id;
            });
            g.XPIDatabase.updateAddonDisabledState(rawAddon, newDis);
        }
        else if("eval" in g) { // See "set userDisabled(val)"
            let addonFor = g.eval("addonFor");
            let rawAddon = addonFor(addon);
            //rawAddon.userDisabled = newDis;
            g.XPIProvider.updateAddonDisabledState(rawAddon, newDis);
        }
        else { // Firefox 57+? See https://forum.mozilla-russia.org/viewtopic.php?pid=745272#p745272
            updateAddonDisabledState(addon, newDis);
        }
    }
    function updateAddonDisabledState(addon, newDis) {
        var nsvo = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
        var key = "_cbToggleRestartlessAddonsData";
        var url = URL.createObjectURL(new Blob([
            "XPIProvider.updateAddonDisabledState(addonFor(this." + key + "[0]), this." + key + "[1]); delete this." + key + ";"
        ]));
        addDestructor(function() {
            URL.revokeObjectURL(url);
        });
        (updateAddonDisabledState = function(addon, newDis) {
            nsvo[key] = [addon, newDis];
            Services.scriptloader.loadSubScript(url, nsvo);
        })(addon, newDis);
    }
    function setDisabled(mi, disabled) {
        var askToActivate = "STATE_ASK_TO_ACTIVATE" in AddonManager && disabled == AddonManager.STATE_ASK_TO_ACTIVATE;
        var cl = mi.classList;
        cl.toggle("toggleRestartlessAddons-askToActivate", askToActivate);
        cl.toggle("toggleRestartlessAddons-disabled", disabled && !askToActivate);
    }
    
    if(
        this instanceof XULElement // Custom Buttons
        && typeof event == "object"
        && !("type" in event) && typeof _phase == "string" && _phase == "init" // Initialization
    ) {
        this.type = "menu";
        this.orient = "horizontal";
        this.appendChild(mp);
    
        this.onmouseover = function(e) {
            if(e.target != this)
                return;
            Array.prototype.some.call(
                this.parentNode.getElementsByTagName("*"),
                function(node) {
                    if(
                        node != this
                        && node.namespaceURI == xulns
                        && node.boxObject
                        // See https://github.com/Infocatcher/Custom_Buttons/issues/28
                        //&& node.boxObject instanceof Components.interfaces.nsIMenuBoxObject
                        && "open" in node
                        && node.open
                        && node.getElementsByTagName("menupopup").length
                    ) {
                        node.open = false;
                        this.open = true;
                        return true;
                    }
                    return false;
                },
                this
            );
        };
        this.onmousedown = function(e) {
            if(e.target == this && e.button == 0 && hasModifier(e))
                e.preventDefault();
        };
        this.oncontextmenu = function(e) {
            if(e.target == this && !hasModifier(e) && hasUpdater())
                e.preventDefault();
        };
        this.onclick = function(e) {
            if(e.target != this)
                return;
            if(e.button == 0 && hasModifier(e) || e.button == 1)
                openAddonsManager();
            else if(e.button == 2 && !hasModifier(e) && hasUpdater())
                checkForAddonsUpdates.call(this);
        };
    }
    else { // Mouse gestures or something other...
        let e;
        if(typeof event == "object" && event instanceof Event && "screenX" in event) // FireGestures
            e = event;
        else if(
            this instanceof Components.interfaces.nsIDOMChromeWindow
            && "mgGestureState" in window && "endEvent" in mgGestureState // Mouse Gestures Redox
        )
            e = mgGestureState.endEvent;
        else {
            let anchor = this instanceof XULElement && this
                || window.gBrowser && gBrowser.selectedBrowser
                || document.documentElement;
            if("boxObject" in anchor) {
                let bo = anchor.boxObject;
                e = {
                    screenX: bo.screenX,
                    screenY: bo.screenY
                };
                if(this instanceof XULElement)
                    e.screenY += bo.height;
            }
        }
        if(!e || !("screenX" in e))
            throw new Error("[Toggle Restartless Add-ons]: Can't get event object");
        document.documentElement.appendChild(mp);
        mp.addEventListener("popuphidden", function destroy(e) {
            mp.removeEventListener(e.type, destroy, false);
            setTimeout(function() {
                mp.destroyMenu();
                mp.parentNode.removeChild(mp);
            }, 0);
        }, false);
        mp.openPopupAtScreen(e.screenX, e.screenY);
    }
    
    function getRestartlessAddons(addonTypes, callback, context) {
        if(!("AddonManager" in window))
            Components.utils.import("resource://gre/modules/AddonManager.jsm");
        if(!("Services" in window))
            Components.utils.import("resource://gre/modules/Services.jsm");
        var then, promise = AddonManager.getAddonsByTypes(addonTypes, then = function(addons) {
            var restartless = addons.filter(function(addon) {
                var ops = addon.operationsRequiringRestart;
                return !addon.appDisabled
                    && !(ops & AddonManager.OP_NEEDS_RESTART_ENABLE || ops & AddonManager.OP_NEEDS_RESTART_DISABLE)
                    && (
                        !addon.hidden
                        || options.showHidden > 0
                        || options.showHidden == -1 && !addon.userDisabled
                    );
            });
            callback.call(context, restartless);
        });
        promise && typeof promise.then == "function" && promise.then(then, Components.utils.reportError); // Firefox 61+
    }
    function openAddonOptions(addon) {
        // Based on code from chrome://mozapps/content/extensions/extensions.js
        // Firefox 21.0a1 (2013-01-27)
        var optionsURL = addon.optionsURL;
        if(!addon.isActive || !optionsURL)
            return false;
        if(addon.type == "plugin") // No options for now!
            return false;
        if(
            addon.optionsType == AddonManager.OPTIONS_TYPE_INLINE
            || addon.optionsType == (AddonManager.OPTIONS_TYPE_INLINE_INFO || NaN)
            || addon.optionsType == (AddonManager.OPTIONS_TYPE_INLINE_BROWSER || NaN)
        )
            openAddonPage(addon, true);
        else if(addon.optionsType == AddonManager.OPTIONS_TYPE_TAB && "switchToTabHavingURI" in window)
            switchToTabHavingURI(optionsURL, true);
        else {
            let windows = Services.wm.getEnumerator(null);
            while(windows.hasMoreElements()) {
                let win = windows.getNext();
                if(win.document.documentURI == optionsURL) {
                    win.focus();
                    return true;
                }
            }
            // Note: original code checks browser.preferences.instantApply and may open modal windows
            window.openDialog(optionsURL, "", "chrome,titlebar,toolbar,centerscreen,dialog=no");
        }
        return true;
    }
    function openAddonsManager(view) {
        var openAddonsMgr = window.BrowserOpenAddonsMgr // Firefox
            || window.openAddonsMgr // Thunderbird
            || window.toEM; // SeaMonkey
        openAddonsMgr(view);
    }
    function openAddonPage(addon, scrollToPreferences) {
        var platformVersion = parseFloat(
            Services.appinfo.name == "Pale Moon"
                ? Services.appinfo.version
                : Services.appinfo.platformVersion
        );
        scrollToPreferences = scrollToPreferences && platformVersion >= 12
            ? "/preferences"
            : "";
        openAddonsManager("addons://detail/" + encodeURIComponent(addon.id) + scrollToPreferences);
    }
    
    function hasModifier(e) {
        return e.ctrlKey || e.shiftKey || e.altKey || e.metaKey;
    }
    
    function addStyle() {
        if(addStyle.hasOwnProperty("_style"))
            return;
        var style = '\
            .toggleRestartlessAddons-isDelayed > .menu-iconic-text {\n\
                opacity: 0.75;\n\
                color: #070;\n\
            }\n\
            .toggleRestartlessAddons-isHidden > .menu-iconic-text {\n\
                color: #609;\n\
            }\n\
            .toggleRestartlessAddons-disabled > .menu-iconic-left {\n\
                opacity: 0.4;\n\
            }\n\
            .toggleRestartlessAddons-disabled > .menu-iconic-text,\n\
            .toggleRestartlessAddons-disabled > .menu-accel-container {\n\
                opacity: 0.5;\n\
            }\n\
            .toggleRestartlessAddons-askToActivate {\n\
                color: -moz-nativehyperlinktext;\n\
            }';
        addStyle._style = document.insertBefore(
            document.createProcessingInstruction(
                "xml-stylesheet",
                'href="' + "data:text/css,"
                    + encodeURIComponent(style) + '" type="text/css"'
            ),
            document.documentElement
        );
    }
    function removeStyle() {
        if(!addStyle.hasOwnProperty("_style"))
            return;
        var s = addStyle._style;
        s.parentNode.removeChild(s);
        delete addStyle._style;
    }
    function closeMenus(node) {
        // Based on function closeMenus from chrome://browser/content/utilityOverlay.js
        for(; node && "tagName" in node; node = node.parentNode) {
            if(
                node.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
                && (node.localName == "menupopup" || node.localName == "popup")
            )
                node.hidePopup();
        }
    }
    function _log(s) {
        if(typeof LOG == "function") // Custom Buttons
            LOG(s);
        else // Or something else
            Services.console.logStringMessage("Toggle Restartless Add-ons: " + s);
    }
    
    function hasUpdater() {
        var has = checkForAddonsUpdates.toString().indexOf("about:addons") != -1;
        hasUpdater = function() {
            return has;
        };
        return has;
    }
    
    
    
    
    
    
    
    
    
    function checkForAddonsUpdates() {
// http://infocatcher.ucoz.net/js/cb/checkForAddonsUpdates.js
// https://forum.mozilla-russia.org/viewtopic.php?id=57958
// https://github.com/Infocatcher/Custom_Buttons/tree/master/Check_for_Addons_Updates

// Check for Addons Updates button for Custom Buttons
// (code for "code" section)

// (c) Infocatcher 2012-2014
// version 0.1.5 - 2014-10-13

// Button just open hidden tab with about:addons and trigger built-in "Check for Updates" function.
// And show tab, if found updates.

(function() {
var btn = this instanceof XULElement
    ? this
    : { // Launched not from custom button
        image: "", // Base64-encoded icon (if empty, will be used "imgLoading")
        label: "Check for Addons Updates",
        tooltipText: ""
    };
if("_cb_disabled" in btn)
    return;
btn._cb_disabled = true;

if(!("Services" in window))
    Components.utils.import("resource://gre/modules/Services.jsm");
var app = Services.appinfo.name;

var ADDONS_URL = "about:addons";

var progressIcon = new ProgressIcon(btn);
var image = btn.image || progressIcon.imgLoading;
var tip = btn.tooltipText;
btn.tooltipText = "Open " + ADDONS_URL + "…";

var tab, browser, gBrowser;
var tbTabInfo, tbTab;

var trgWindow = Services.wm.getMostRecentWindow("navigator:browser")
    || app == "Thunderbird" && Services.wm.getMostRecentWindow("mail:3pane")
    || window;
var trgDocument = trgWindow.document;
var tabmail = trgDocument.getElementById("tabmail");

if(tabmail && app == "Thunderbird") { // Note: SeaMonkey doesn't support content tabs in mail window
    let addonsWin;
    let receivePong = function(subject, topic, data) {
        addonsWin = subject;
    };
    Services.obs.addObserver(receivePong, "EM-pong", false);
    Services.obs.notifyObservers(null, "EM-ping", "");
    Services.obs.removeObserver(receivePong, "EM-pong");
    if(addonsWin) {
        let rootWindow = addonsWin
            .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
            .getInterface(Components.interfaces.nsIWebNavigation)
            .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
            .rootTreeItem
            .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
            .getInterface(Components.interfaces.nsIDOMWindow);
        tabmail = rootWindow.document.getElementById("tabmail");
        tbTabInfo = tabmail.getBrowserForDocument(addonsWin);
        tbTab = tab = tbTabInfo.tabNode;
        processAddonsTab(addonsWin);
    }
    else {
        Services.obs.addObserver(function observer(subject, topic, data) {
            Services.obs.removeObserver(observer, topic);
            if(subject.document.readyState == "complete")
                processAddonsTab(subject);
            else {
                subject.addEventListener("load", function onLoad(e) {
                    subject.removeEventListener(e.type, onLoad, false);
                    processAddonsTab(subject);
                }, false);
            }
        }, "EM-loaded", false);
        // See openAddonsMgr() -> openContentTab()
        tbTabInfo = tabmail.openTab("contentTab", {
            contentPage: ADDONS_URL,
            clickHandler: "specialTabs.siteClickHandler(event, /addons\.mozilla\.org/);",
            background: true
        });
        tbTab = tab = tbTabInfo.tabNode;
        tbTab.collapsed = true;
        // Note: dontSelectHiddenTab() not implemented
    }
}
else if("gBrowser" in trgWindow && trgWindow.gBrowser.tabs) {
    let isPending = false;
    let ws = Services.wm.getEnumerator("navigator:browser");
    windowsLoop:
    while(ws.hasMoreElements()) {
        let w = ws.getNext();
        let tabs = w.gBrowser.tabs;
        for(let i = 0, l = tabs.length; i < l; ++i) {
            let t = tabs[i];
            if(
                !t.closing
                && t.linkedBrowser
                && t.linkedBrowser.currentURI.spec == ADDONS_URL
            ) {
                tab = t;
                break windowsLoop;
            }
        }
    }

    gBrowser = trgWindow.gBrowser;
    if(!tab) {
        tab = gBrowser.addTab(ADDONS_URL, {
            triggeringPrincipal: "Services" in window // Firefox 63+
                && Services.scriptSecurityManager
                && Services.scriptSecurityManager.getSystemPrincipal()
        });
        tab.collapsed = true;
        tab.closing = true; // See "visibleTabs" getter in chrome://browser/content/tabbrowser.xml
        trgWindow.addEventListener("TabSelect", dontSelectHiddenTab, false);
    }
    else if(
        tab.getAttribute("pending") == "true" // Gecko >= 9.0
        || tab.linkedBrowser.contentDocument.readyState == "uninitialized"
        // || tab.linkedBrowser.__SS_restoreState == 1
    )
        isPending = true;

    browser = tab.linkedBrowser;
    if(isPending || browser.webProgress.isLoadingDocument) {
        browser.addEventListener("load", processAddonsTab, true);
        if(isPending) {
            if(parseFloat(Services.appinfo.platformVersion) >= 41) {
                // Workaround to correctly restore pending tab
                // See https://github.com/Infocatcher/Custom_Buttons/issues/39
                let selTab = gBrowser.selectedTab;
                gBrowser.selectedTab = tab;
                gBrowser.selectedTab = selTab;
            }
            else {
                browser.reload();
            }
        }
    }
    else {
        processAddonsTab();
    }
}
else {
    progressIcon.restore();
    btn.tooltipText = tip;
    delete btn._cb_disabled;
    Services.prompt.alert(window, btn.label, "Error: Can't find supported window!");
    return;
}

function processAddonsTab(e) {
    var doc;
    if(e && e instanceof Components.interfaces.nsIDOMWindow) {
        doc = e.document;
    }
    else if(e) {
        doc = e.target;
        if(doc.location != ADDONS_URL)
            return;
        browser.removeEventListener(e.type, processAddonsTab, true);
    }
    else {
        doc = browser.contentDocument;
    }

    progressIcon.loading();
    var inProgress = $("updates-progress");
    btn.tooltipText = inProgress.getAttribute("value");

    var origIcon = tab.image;
    tab.image = image;

    var updEnabledPref = "extensions.update.enabled";
    var updEnabled = Services.prefs.getBoolPref(updEnabledPref);
    if(!updEnabled)
        Services.prefs.setBoolPref(updEnabledPref, true);

    var notFound = $("updates-noneFound");
    var updated = $("updates-installed");
    // Avoid getting false results from the past update check (may not be required for "noneFound")
    notFound.hidden = updated.hidden = true;

    $("cmd_findAllUpdates").doCommand();

    var waitTimer = setInterval(function() {
        if(!doc.defaultView || doc.defaultView.closed) {
            stopWait();
            notify("Tab with add-ons manager was closed!");
            return;
        }
        if(!inProgress.hidden)
             return;
        var autoUpdate = $("utils-autoUpdateDefault");
        var autoUpdateChecked = autoUpdate.getAttribute("checked") == "true";

        var found = $("updates-manualUpdatesFound-btn");
        if(
            autoUpdateChecked
                ? notFound.hidden && updated.hidden
                : notFound.hidden && found.hidden
        ) // Too early?
            return;

        stopWait();
        if(!tbTab)
            tab.closing = false;
        function removeTab() {
            if(!tab.collapsed)
                return;
            if(tbTab)
                tabmail.closeTab(tbTabInfo, true /*aNoUndo*/);
            else {
                gBrowser.removeTab(tab);
                (function forgetClosedTab(isSecondTry) {
                    var ss = "nsISessionStore" in Components.interfaces
                        ? (
                            Components.classes["@mozilla.org/browser/sessionstore;1"]
                            || Components.classes["@mozilla.org/suite/sessionstore;1"]
                        ).getService(Components.interfaces.nsISessionStore)
                        : SessionStore; // Firefox 61+ https://bugzilla.mozilla.org/show_bug.cgi?id=1450559
                    if(!("forgetClosedTab" in ss))
                        return;
                    var closedTabs = JSON.parse(ss.getClosedTabData(window));
                    for(let i = 0, l = closedTabs.length; i < l; ++i) {
                        let closedTab = closedTabs[i];
                        let state = closedTab.state;
                        if(state.entries[state.index - 1].url == ADDONS_URL) {
                            ss.forgetClosedTab(window, i);
                            return;
                        }
                    }
                    if(!isSecondTry) // May be needed in SeaMonkey
                        setTimeout(forgetClosedTab, 0, true);
                })();
            }
        }

        if(!updEnabled)
            Services.prefs.setBoolPref(updEnabledPref, false);

        if(!notFound.hidden) {
            removeTab();
            notify(notFound.getAttribute("value"));
            return;
        }
        if(autoUpdateChecked) {
            removeTab();
            notify(updated.getAttribute("value"));
            return;
        }

        tab.collapsed = false;
        $("categories").selectedItem = $("category-availableUpdates");
        var tabWin = tab.ownerDocument.defaultView;
        if(tbTab)
            tabmail.switchToTab(tbTabInfo);
        else
            tabWin.gBrowser.selectedTab = tab;
        setTimeout(function() {
            tabWin.focus();
            doc.defaultView.focus();
            $("addon-list").focus();
        }, 0);
    }, 50);
    function $(id) {
        return doc.getElementById(id);
    }
    function stopWait() {
        clearInterval(waitTimer);
        progressIcon.restore();
        btn.tooltipText = tip;
        if(tab.image == image)
            tab.image = origIcon;
        trgWindow.removeEventListener("TabSelect", dontSelectHiddenTab, false);
        setTimeout(function() {
            delete btn._cb_disabled;
        }, 500);
    }
    function notify(msg) {
        Components.classes["@mozilla.org/alerts-service;1"]
            .getService(Components.interfaces.nsIAlertsService)
            .showAlertNotification(
                Services.appinfo.name == "Firefox" && parseFloat(Services.appinfo.version) >= 57
                    ? "chrome://mozapps/skin/extensions/extensionGeneric.svg"
                    : "chrome://mozapps/skin/extensions/extensionGeneric.png",
                btn.label,
                msg, false, "", null
            );
    }
}
function dontSelectHiddenTab(e) {
    // <tab /><tab collapsed="true" />
    // Close first tab: collapsed tab becomes selected
    var trgTab = e.originalTarget || e.target;
    if(trgTab != tab)
        return;

    if(/\n(?:BrowserOpenAddonsMgr|toEM)@chrome:\/\//.test(new Error().stack)) {
        // User open Add-ons Manager, show tab
        trgWindow.removeEventListener("TabSelect", dontSelectHiddenTab, false);
        setTimeout(function() { // Hidden tab can't be selected, so select it manually...
            tab.collapsed = tab.closing = false;
            gBrowser.selectedTab = tab;
        }, 0);
    }

    function done(t) {
        if(!t.hidden && !t.closing) {
            e.preventDefault();
            e.stopPropagation();
            return gBrowser.selectedTab = t;
        }
        return false;
    }
    for(var t = tab.nextSibling; t; t = t.nextSibling)
        if(done(t))
            return;
    for(var t = tab.previousSibling; t; t = t.previousSibling)
        if(done(t))
            return;
}
function ProgressIcon(btn) {
    if(!(btn instanceof XULElement)) {
        this.loading = this.restore = function() {};
        return;
    }
    var app = Services.appinfo.name;
    var pv = parseFloat(Services.appinfo.platformVersion);
    if(app == "SeaMonkey")
        this.imgConnecting = this.imgLoading = "chrome://communicator/skin/icons/loading.gif";
    else if(app == "Thunderbird") {
        this.imgConnecting = "chrome://messenger/skin/icons/connecting.png";
        this.imgLoading = "chrome://messenger/skin/icons/loading.png";
    }
    else {
        this.imgConnecting = "chrome://browser/skin/tabbrowser/connecting.png";
        this.imgLoading = app == "Firefox" && pv >= 48
            ? "chrome://global/skin/icons/loading.png"
            : "chrome://browser/skin/tabbrowser/loading.png";
    }
    var useAnimation = app == "Firefox" && pv >= 32;
    var btnIcon = btn.ownerDocument.getAnonymousElementByAttribute(btn, "class", "toolbarbutton-icon")
                    || btn.getElementsByClassName("toolbarbutton-icon")[0];
    var origIcon = btnIcon.src;
    btnIcon.src = this.imgConnecting;
    if(useAnimation) {
        let cs = btnIcon.ownerDocument.defaultView.getComputedStyle(btnIcon, null);
        let s = btnIcon.style;
        s.margin = [cs.marginTop, cs.marginRight, cs.marginBottom, cs.marginLeft].join(" ");
        s.padding = [cs.paddingTop, cs.paddingRight, cs.paddingBottom, cs.paddingLeft].join(" ");
        s.width = cs.width;
        s.height = cs.height;
        s.boxShadow = "none";
        s.borderColor = s.background = "transparent";
        btnIcon.setAttribute("fadein", "true");
        btnIcon.setAttribute("busy", "true");
        btnIcon.classList.add("tab-throbber");
        btnIcon._restore = function() {
            delete btnIcon._restore;
            btnIcon.removeAttribute("busy");
            btnIcon.removeAttribute("progress");
            setTimeout(function() {
                btnIcon.classList.remove("tab-throbber");
                btnIcon.removeAttribute("style");
                btnIcon.removeAttribute("fadein");
            }, 0);
        };
    }
    this.loading = function() {
        btnIcon.src = this.imgLoading;
        if(useAnimation)
            btnIcon.setAttribute("progress", "true");
    };
    this.restore = function() {
        btnIcon.src = origIcon;
        if(useAnimation)
            btnIcon._restore();
    };
}
}).call(this);
//== Check for Addons Updates end
}


this.tooltipText = "Переключатель джетпаков" 
                   + "\n\nУправление:\nЛКМ – открыть меню" 
                   + "\nПКМ – проверить обновления"
                   + "\nСКМ – открыть страницу дополнений"
                   + "\nShift+ПКМ – меню кнопки"
                   + "\n\nВ меню: \nЛКМ – включить/выключить дополнение"
                   + "\nShift+ЛКМ – включить/выключить дополнение без закрытия меню"   
                   + "\nСКМ – открыть страницу дополнения в управлении дополнениями"                    
                   + "\nПКМ – открыть настройки дополнения (если есть)";


секция /*CODE*/
скрытый текст

Выделить код

Код:

if(!event.target) // Button's hotkey pressed
    this.open = true;

Andrey_Krropotkin
Этот код работает! Благодарю! А можно сделать что бы отключенные дополнения отражались в конце списка?

kokoss это не ко мне, это не мой код, я в него не вникал.

kokoss пишет

А можно сделать что бы отключенные дополнения отражались в конце списка?

В начале кода есть настройки, sort: { … disabled: 1 } переместит отключенные в конец списка:

Выделить код

Код:

var options = {
    …
    sort: {
        enabled:     0,
        clickToPlay: 0,
        disabled:    0
        // Sort order:
        // 0, 0, 0 - sort add-ons of each type alphabetically
        // 0, 0, 1 - show enabled add-ons (of each type) first
        // 0, 1, 2 - enabled add-ons, then click-to-play and then disabled
    },

Infocatcher
Andrey_Krropotkin
Большое спасибо за помощь :beer:

Infocatcher
А эту кнопку планируете обновить и когда, если планируете?

Есть тестовая:
Toggle Restartless Add-ons 0.1.3pre4 (2020-01-01)

Но у тестовых обновлены только непосредственно исходник (toggleRestartlessAddons.js) и установочная страница (toggleRestartlessAddons.html, которую можно скачать отдельно и открыть или скопировать custombutton:// ссылку).

Infocatcher
Понял, работает. Спасибо

Infocatcher

В Firefox 74 для метода XPIDatabase.updateAddonDisabledState()
изменили аргументы. Пока записал просто так:

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

Выделить код

Код:

//g.XPIDatabase.updateAddonDisabledState(rawAddon, newDis);
        g.XPIDatabase.updateAddonDisabledState(
            rawAddon,
            g.XPIDatabase.updateAddonDisabledState.length == 1 // Firefox 74+
                ? {userDisabled: newDis}
                : newDis
        );

Dumby пишет

В Firefox 74 для метода XPIDatabase.updateAddonDisabledState()

Вот ведь…
Спасибо, обновил: https://github.com/Infocatcher/Custom_B … 09bdbc351b

Заодно обнаружил, что в Firefox 74.0b7 подозрительно себя ведет Firefox Screenshots: как бы выключается, но восстанавливается после перезапуска. А в консоли

Кондуит и Швамбрания…
sendRemoveListener on closed conduit screenshots@mozilla.org.33 ConduitsChild.jsm:108
    _send resource://gre/modules/ConduitsChild.jsm:108
    _send self-hosted:977
    removeListener resource://gre/modules/ExtensionChild.jsm:1138
    removeListener resource://gre/modules/ExtensionChild.jsm:1361
    onClicked chrome://browser/content/child/ext-menus.js:282
    removeListener resource://gre/modules/ExtensionCommon.jsm:2544
    revoke resource://gre/modules/ExtensionCommon.jsm:2566
    close resource://gre/modules/ExtensionCommon.jsm:2571
    unload resource://gre/modules/ExtensionCommon.jsm:910
    unload resource://gre/modules/ExtensionPageChild.jsm:261
    unload resource://gre/modules/ExtensionPageChild.jsm:310
    destroyExtensionContext resource://gre/modules/ExtensionPageChild.jsm:494
    observe resource://gre/modules/ExtensionPageChild.jsm:407

Infocatcher пишет

подозрительно себя ведет Firefox Screenshots

Пришлось еще и extensions.screenshots.disabled переключать.

Infocatcher пишет

Пришлось еще и extensions.screenshots.disabled переключать.

Нефига опять не пойму откуда её ставить то?

voqabuhe пишет

Нефига опять не пойму откуда её ставить то?

В общем случае – по инструкции.
В данном случае быстрее так (нужен toggleRestartlessAddons.js с внесенными изменениями):

скрытый текст
JWbSkIZ.png

Откроется измененный файл: https://github.com/Infocatcher/Custom_B … sAddons.js

z4EJgpR.png

И вот постоянная ссылка на версию с исправлением: https://raw.githubusercontent.com/Infoc … sAddons.js

Infocatcher
Дык там же версия от 2020-01-01, а я пытался найти от 26-02-26/27, или вы просто дату не поменяли?

voqabuhe
да, дата старая и версия, надо смотреть, когда сделаны изменения, справа от toggleRestartlessAddons.js     Force disable Firefox Screenshots:  yesterday

Infocatcher
В Firefox 76 удалили extensionGeneric-16.svg
̣
Сначала замена была однозначной:
chrome://mozapps/skin/extensions/extensionGeneric.svg
поскольку
chrome://mozapps/skin/extensions/extension.svg
выглядела плохо.
̣
Затем похлопотали, и стала выглядеть хорошо, осталось выбрать.

Dumby пишет

В Firefox 76 удалили extensionGeneric-16.svg …

Вот ведь иконисты…
Спасибо, обновил: https://github.com/Infocatcher/Custom_B … aed9ec6235

egorsemenov06 пишет

Сделайте пожалуйста Вашу кнопку для user_chrome_files

https://github.com/VitaliyVstyle/Vitali … _files.zip ?

Судя по описанию, надо в user_chrome_files/custom_scripts/custom_script.js вписать вот такое:

Выделить код

Код:

(function () { // Toggle Restartless Add-ons button
// Custom Buttons-like environment
var event = {};
var _phase = "init";

var id = "__cb_toggleRestartlessAddons";

CustomizableUI.createWidget({
	id: id,
	type: "custom",
	defaultArea: CustomizableUI.AREA_NAVBAR,
	onBuild: function(doc) {
		var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
		var btn = doc.createElementNS(XUL_NS, "toolbarbutton");
		var attrs = {
			id: id,
			class: "toolbarbutton-1 chromeclass-toolbar-additional",
			label: "Toggle Restartless Add-ons",
			tooltiptext: "Toggle Restartless Add-ons",
			style: 'list-style-image: url("chrome://branding/content/icon16.png");', // Set icon here
			__proto__: null
		};
		for(var p in attrs)
			btn.setAttribute(p, attrs[p]);
		doc.defaultView.setTimeout(function() {
			toggleRestartlessAddons.call(btn);
		}, 0);
		return btn;
	}
});

function toggleRestartlessAddons() {
	// Code from https://github.com/Infocatcher/Custom_Buttons/blob/master/Toggle_Restartless_Add-ons/toggleRestartlessAddons.js

}

})();

Вместо chrome://branding/content/icon16.png надо вписать длинный data:image… иконки.
И после «function toggleRestartlessAddons() {» вставить код инициализации кнопки.

Из консоли ошибок работает. Наверное, и из user_chrome_files запустится.

egorsemenov06
Extension Options Menu. Плохо  только что плагинов нет в списке.

egorsemenov06
В папке  chrome создать файл Extension Options Menu.uc.js. и в него вписать. На 75 [firefox] работает.

23-04-2020 00:04:37
Если что непонятно, по ссылке которую я вам дал, вверху есть  • к этому сообщению •, там найдёте инструкцию.

egorsemenov06
Я дополнил предыдущее сообщение.

Секция на замену:

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

Выделить код

Код:

style: `
      @namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
      .restartless label:after { content:"☑"; }
      .enabling label:after { content:"☑" !important; }
      .disabling label:after { content:"☐" !important; }
      .uninstalling label:after { content: '!' !important; }
      .noOptions label { font-style: italic; color: silver; }
      .disabled label { color: gray; font-style: italic; }
	  .disabled label:after { content:"☐" !important; }
    `,

Или так:
скрытый текст

Выделить код

Код:

style: `
      @namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
      .restartless label:after { content:"☑"; }
      .enabling label:after { content:"☑" !important; }
      .disabling label:after { content:"☐" !important; }
      .uninstalling label:after { content: '!' !important; }
      .noOptions label { font-style: italic; color: gray }
      .disabled label { color: orange; font-style: italic; }
	  .disabled label:after { content:"☐" !important; }
    `,

Или так. Так себе оставил:
скрытый текст

Выделить код

Код:

style: `
      @namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
      .restartless label:after { font-size: 18px; content:"☑"; }
      .enabling label:after { content:"☑" !important; }
      .disabling label:after { content:"☐" !important; }
      .uninstalling label:after { content: '!' !important; }
      .noOptions label { color: gray; }
      .disabled label { color: orange; font-style: italic; }
	  .disabled label:after { content:"☐" !important; }
    `,

В общем, принцип должен быть понятен.
   
Ну и это можно:

Выделить код

Код:

mi.setAttribute('tooltiptext', addon.description + '\nID : ' + addon.id + '\n\nЛКМ            :  Настройки\nПКМ            :  Откл. / Включить\nСКМ            :  Домашняя страница\nCtrl + ЛКМ :  Открыть архив\nCtrl + ПКМ :  Деинсталлировать\nCtrl + СКМ :  Копировать ID');

Размер удален, так как все равно не работает. В общей теме есть замена, но она не реальный, а распакованный размер показывает.

egorsemenov06 пишет

Увы но не запустилась

Поставил. Вот так, вроде, работает (по-прежнему надо дописать код инициализации и задать иконку):

Выделить код

Код:

(function () { // Toggle Restartless Add-ons button
// Custom Buttons-like environment
var event = {};
var _phase = "init";
var window, document, XULElement, setTimeout, clearTimeout;
var AddonManager;

var id = "__cb_toggleRestartlessAddons";

CustomizableUI.createWidget({
	id: id,
	type: "custom",
	defaultArea: CustomizableUI.AREA_NAVBAR,
	onBuild: function(doc) {
		var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
		var btn = doc.createElementNS(XUL_NS, "toolbarbutton");
		var attrs = {
			id: id,
			class: "toolbarbutton-1 chromeclass-toolbar-additional",
			label: "Toggle Restartless Add-ons",
			tooltiptext: "Toggle Restartless Add-ons",
			style: 'list-style-image: url("chrome://branding/content/icon16.png");', // Set icon here
			__proto__: null
		};
		for(var p in attrs)
			btn.setAttribute(p, attrs[p]);
		var win = doc.defaultView;
		win.setTimeout(function() {
			window = win;
			document = win.document;
			XULElement = win.XULElement;
			setTimeout = win.setTimeout;
			clearTimeout = win.clearTimeout;
			AddonManager = win.AddonManager;

			toggleRestartlessAddons.call(btn);
		}, 0);
		return btn;
	}
});

function toggleRestartlessAddons() {
	// Code from https://github.com/Infocatcher/Custom_Buttons/blob/master/Toggle_Restartless_Add-ons/toggleRestartlessAddons.js

}

})();

24-04-2020 23:21:03
Но есть ограничение: если открыть больше одного окна, то будет пытаться работать с последним открытым.

24-04-2020 23:35:04
А вот так должно уже работать и в нескольких окнах, не вполне оптимально, но Custom Buttons работает аналогично:

Выделить код

Код:

(function () { // Toggle Restartless Add-ons button
var id = "__cb_toggleRestartlessAddons";

CustomizableUI.createWidget({
	id: id,
	type: "custom",
	defaultArea: CustomizableUI.AREA_NAVBAR,
	onBuild: function(doc) {
		var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
		var btn = doc.createElementNS(XUL_NS, "toolbarbutton");
		var attrs = {
			id: id,
			class: "toolbarbutton-1 chromeclass-toolbar-additional",
			label: "Toggle Restartless Add-ons",
			tooltiptext: "Toggle Restartless Add-ons",
			style: 'list-style-image: url("chrome://branding/content/icon16.png");', // Set icon here
			__proto__: null
		};
		for(var p in attrs)
			btn.setAttribute(p, attrs[p]);
		var win = doc.defaultView;
		win.setTimeout(function() {
			new win.Function(
				"("
				+ toggleRestartlessAddons.toString()
					.replace("{", '{\n\tvar event = {}, _phase = "init";')
				+ ").call(document.getElementById('" + id + "'));"
			)();
		}, 0);
		return btn;
	}
});

function toggleRestartlessAddons() {
	// Code from https://github.com/Infocatcher/Custom_Buttons/blob/master/Toggle_Restartless_Add-ons/toggleRestartlessAddons.js

}

})();

Уважаемые, так где собственно взять готовый окончательный на сегодня вариант, работающий на FF-78? Ну чтоб без «к тому добавить», «там убрать». Читаю посты и уже запутался.
UPD
Вопрос снят. №98  Вроде работает :)

JKT
В FF 78 работает!


Add, или такой вариант для -> user_chrome_files/custom_script.js: https://forum.mozilla-russia.org/viewto … 12#p780412

У меня в 79 перестало работать обновление расширений по правому клику, просто крутится кольцо...

Garalf
Вы однако темы попутали, вам похоже нужно в  [CB]Check for Addons Updates.
Но Check for Addons Updates в [firefox] 79 у меня работает, если чё.

voqabuhe
А вы не в курсе, что по правому клику на кнопке производится проверка обновлений расширений?

Garalf
У меня не производится. Как я понял, это не основная версия кнопки, а фишка которую Infocatcher  добавил по заказу.

Разобрался. Все работает!

Mozilla Firefox 78.3.1esr 

Toggle Restartless Add-ons

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

Выделить код

Код:

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%u0410%u0432%u0442%u043E%u043C%u0430%u0442%u0438%u0447%u0435%u0441%u043A%u0438%20%u043F%u0435%u0440%u0435%u0437%u0430%u0433%u0440%u0443%u0436%u0430%u0442%u044C%20%u0432%u043A%u043B%u0430%u0434%u043A%u0443%3C/name%3E%0A%20%20%3Cimage%3E%3C%21%5BCDATA%5Bhttps%3A//raw.githubusercontent.com/Infocatcher/Custom_Buttons/master/Toggle_Restartless_Add-ons/icon.png%5D%5D%3E%3C/image%3E%0A%20%20%3Cmode%3E0%3C/mode%3E%0A%20%20%3Cinitcode%3E%3C%21%5BCDATA%5B//%20http%3A//infocatcher.ucoz.net/js/cb/toggleRestartlessAddons.js%0A//%20https%3A//forum.mozilla-russia.org/viewtopic.php%3Fid%3D57948%0A//%20https%3A//github.com/Infocatcher/Custom_Buttons/tree/master/Toggle_Restartless_Add-ons%0A%0A//%20Toggle%20Restartless%20Add-ons%20button%20for%20Custom%20Buttons%0A//%20%28code%20for%20%22initialization%22%20section%29%0A//%20Also%20the%20code%20can%20be%20used%20from%20main%20window%20context%20%28as%20Mouse%20Gestures%20code%2C%20for%20example%29%0A%0A//%20Also%20you%20can%20check%20for%20add-ons%20updates%20using%20right-click%3A%0A//%20copy%20all%20code%20from%0A//%20https%3A//github.com/Infocatcher/Custom_Buttons/blob/master/Check_for_Addons_Updates/checkForAddonsUpdates.js%0A//%20after%20%22//%3D%3D%20Check%20for%20Addons%20Updates%20begin%22%0A%0A//%20See%20%22var%20style%20%3D%20%22%20to%20modify%20styles%20for%20specific%20add-ons%0A%0A//%20%28c%29%20Infocatcher%202013-2019%0A//%20version%200.1.3pre4%20-%202020-01-01%0A%0Avar%20options%20%3D%20%7B%0A%09addonTypes%3A%20%5B%22extension%22%2C%20%22plugin%22%5D%2C%0A%09//%20Possible%20values%3A%20%22extension%22%2C%20%22plugin%22%0A%09//%20From%20extensions%3A%20%22userstyle%22%20%28Stylish%29%2C%20%22greasemonkey-user-script%22%20%28Greasemonkey%29%2C%20%22userscript%22%20%28Scriptish%29%0A%09//%20%28swap%20to%20reorder%20in%20the%20menu%29%0A%09showVersions%3A%200%2C%0A%09//%200%20-%20don%27t%20show%20versions%0A%09//%201%20-%20show%20after%20name%3A%20%22Addon%20Name%201.2%22%0A%09//%202%20-%20show%20as%20%22acceltext%22%20%28in%20place%20for%20hotkey%20text%29%0A%09showHidden%3A%201%2C%0A%09//%200%20%20-%20don%27t%20show%20hidden%20add-ons%0A%09//%20-1%20-%20show%20only%20enabled%20hidden%20add-ons%20%28e.g.%20to%20track%20new%20items%29%0A%09//%201%20%20-%20show%20all%20hidden%20add-ons%0A%09sort%3A%20%7B%0A%09%09enabled%3A%20%20%20%20%200%2C%0A%09%09clickToPlay%3A%200%2C%0A%09%09disabled%3A%20%20%20%200%0A%09%09//%20Sort%20order%3A%0A%09%09//%200%2C%200%2C%200%20-%20sort%20add-ons%20of%20each%20type%20alphabetically%0A%09%09//%200%2C%200%2C%201%20-%20show%20enabled%20add-ons%20%28of%20each%20type%29%20first%0A%09%09//%200%2C%201%2C%202%20-%20enabled%20add-ons%2C%20then%20click-to-play%20and%20then%20disabled%0A%09%7D%2C%0A%09closeMenu%3A%20false%2C%20//%20Close%20menu%20after%20left-click%0A%09closeMenuClickToPlay%3A%20false%20//%20Close%20menu%20after%20left-click%2C%20for%20click%20to%20play%20plugins%0A%09//%20Use%20Shift+click%20to%20invert%20closeMenu*%20behavior%0A%7D%3B%0A%0Avar%20xulns%20%3D%20%22http%3A//www.mozilla.org/keymaster/gatekeeper/there.is.only.xul%22%3B%0A%0Avar%20mp%20%3D%20document.createElementNS%28xulns%2C%20%22menupopup%22%29%3B%0Amp.setAttribute%28%22onpopupshowing%22%2C%20%22this.updateMenu%28%29%3B%22%29%3B%0Amp.setAttribute%28%22oncommand%22%2C%20%22this.handleEvent%28event%29%3B%22%29%3B%0Amp.setAttribute%28%22onmousedown%22%2C%20%22if%28event.button%20%3D%3D%200%29%20this.handleEvent%28event%29%3B%22%29%3B%0Amp.setAttribute%28%22onclick%22%2C%20%22if%28event.button%20%3E%200%29%20this.handleEvent%28event%29%3B%22%29%3B%0Amp.setAttribute%28%22oncontextmenu%22%2C%20%22return%20false%3B%22%29%3B%0Amp.setAttribute%28%22onpopuphidden%22%2C%20%22this.destroyMenu%28%29%3B%22%29%3B%0A%0Avar%20tb%20%3D%20this.parentNode%3B%0Aif%28tb%20%26%26%20tb.getAttribute%28%22orient%22%29%20%3D%3D%20%22vertical%22%29%20%7B%0A%09//%20https%3A//addons.mozilla.org/firefox/addon/vertical-toolbar/%0A%09var%20isRight%20%3D%20tb.parentNode.getAttribute%28%22placement%22%29%20%3D%3D%20%22right%22%3B%0A%09mp.setAttribute%28%22position%22%2C%20isRight%20%3F%20%22start_before%22%20%3A%20%22end_before%22%29%3B%0A%7D%0A%0Avar%20cleanupTimer%20%3D%200%3B%0Amp.updateMenu%20%3D%20function%28%29%20%7B%0A%09clearTimeout%28cleanupTimer%29%3B%0A%09addStyle%28%29%3B%0A%09getRestartlessAddons%28options.addonTypes%2C%20function%28addons%29%20%7B%0A%09%09var%20df%20%3D%20document.createDocumentFragment%28%29%3B%0A%09%09var%20prevType%3B%0A%09%09function%20sortPosition%28addon%29%20%7B%0A%09%09%09if%28%22STATE_ASK_TO_ACTIVATE%22%20in%20AddonManager%20%26%26%20addon.userDisabled%20%3D%3D%20AddonManager.STATE_ASK_TO_ACTIVATE%29%0A%09%09%09%09return%20options.sort.clickToPlay%3B%0A%09%09%09if%28addon.isActive%29%0A%09%09%09%09return%20options.sort.enabled%3B%0A%09%09%09return%20options.sort.disabled%3B%0A%09%09%7D%0A%09%09function%20key%28addon%29%20%7B%0A%09%09%09return%20options.addonTypes.indexOf%28addon.type%29%0A%09%09%09%09+%20%22%5Cn%22%20+%20sortPosition%28addon%29%0A%09%09%09%09+%20%22%5Cn%22%20+%20addon.name.toLowerCase%28%29%3B%0A%09%09%7D%0A%09%09addons.sort%28function%28a%2C%20b%29%20%7B%0A%09%09%09var%20ka%20%3D%20key%28a%29%3B%0A%09%09%09var%20kb%20%3D%20key%28b%29%3B%0A%09%09%09return%20ka%20%3D%3D%20kb%20%3F%200%20%3A%20ka%20%3C%20kb%20%3F%20-1%20%3A%201%3B%0A%09%09%7D%29.forEach%28function%28addon%29%20%7B%0A%09%09%09var%20type%20%3D%20addon.type%3B%0A%09%09%09if%28prevType%20%26%26%20type%20%21%3D%20prevType%29%0A%09%09%09%09df.appendChild%28document.createElementNS%28xulns%2C%20%22menuseparator%22%29%29%3B%0A%09%09%09prevType%20%3D%20type%3B%0A%09%09%09var%20icon%20%3D%20addon.iconURL%20%7C%7C%20addon.icon64URL%3B%0A%09%09%09var%20mi%20%3D%20document.createElementNS%28xulns%2C%20%22menuitem%22%29%3B%0A%09%09%09mi.className%20%3D%20%22menuitem-iconic%22%3B%0A%09%09%09var%20label%20%3D%20addon.name%3B%0A%09%09%09if%28options.showVersions%20%3D%3D%201%29%0A%09%09%09%09label%20+%3D%20%22%20%22%20+%20addon.version%3B%0A%09%09%09else%20if%28options.showVersions%20%3D%3D%202%29%0A%09%09%09%09mi.setAttribute%28%22acceltext%22%2C%20addon.version%29%3B%0A%09%09%09mi.setAttribute%28%22label%22%2C%20label%29%3B%0A%09%09%09mi.setAttribute%28%22image%22%2C%20icon%20%7C%7C%20mp.icons%5Btype%5D%20%7C%7C%20%22%22%29%3B%0A%09%09%09if%28%21icon%20%26%26%20mp.icons.useSVG%29%0A%09%09%09%09mi.style.fill%20%3D%20%22%2315c%22%3B%0A%09%09%09var%20tip%20%3D%20addon.description%20%7C%7C%20%22%22%3B%0A%09%09%09var%20delay%20%3D%20%22delayedStartupAddons%22%20in%20Services%0A%09%09%09%09%26%26%20Services.delayedStartupAddons%5Baddon.id%5D%20%7C%7C%20null%3B%0A%09%09%09var%20isDelayed%20%3D%20delay%20%21%3D%3D%20null%3B%0A%09%09%09mi.classList.toggle%28%22toggleRestartlessAddons-isDelayed%22%2C%20isDelayed%29%3B%0A%09%09%09if%28isDelayed%29%0A%09%09%09%09tip%20%3D%20%22%5BDelayed%20Startup%3A%20%22%20+%20delay.toLocaleString%28%29%20+%20%22%5D%22%20+%20%28tip%20%3F%20%22%5Cn%22%20+%20tip%20%3A%20%22%22%29%3B%0A%09%09%09tip%20%26%26%20mi.setAttribute%28%22tooltiptext%22%2C%20tip%29%3B%0A%09%09%09mi.classList.toggle%28%22toggleRestartlessAddons-isHidden%22%2C%20addon.hidden%20%7C%7C%20false%29%3B%0A%09%09%09setDisabled%28mi%2C%20addon.userDisabled%29%3B%0A%09%09%09mi._cbAddon%20%3D%20addon%3B%0A%09%09%09df.appendChild%28mi%29%3B%0A%09%09%7D%29%3B%0A%09%09mp.textContent%20%3D%20%22%22%3B%0A%09%09mp.appendChild%28df%29%3B%0A%09%7D%29%3B%0A%7D%3B%0Amp.handleEvent%20%3D%20function%28e%29%20%7B%0A%09var%20mi%20%3D%20e.target%3B%0A%09if%28%21%28%22_cbAddon%22%20in%20mi%29%29%0A%09%09return%3B%0A%09var%20addon%20%3D%20mi._cbAddon%3B%0A%09if%28e.type%20%3D%3D%20%22mousedown%22%29%20%7B%0A%09%09var%20closeMenu%20%3D%20isAskToActivateAddon%28addon%29%0A%09%09%09%3F%20options.closeMenuClickToPlay%0A%09%09%09%3A%20options.closeMenu%3B%0A%09%09if%28e.shiftKey%29%0A%09%09%09closeMenu%20%3D%20%21closeMenu%3B%0A%09%09mi.setAttribute%28%22closemenu%22%2C%20closeMenu%20%3F%20%22auto%22%20%3A%20%22none%22%29%3B%0A%09%09return%3B%0A%09%7D%0A%09var%20hasMdf%20%3D%20hasModifier%28e%29%3B%0A%09if%28e.type%20%3D%3D%20%22command%22%20%26%26%20%28%21hasMdf%20%7C%7C%20e.shiftKey%29%29%20%7B%0A%09%09let%20newDis%20%3D%20setNewDisabled%28addon%29%3B%0A%09%09setDisabled%28mi%2C%20newDis%29%3B%0A%09%7D%0A%09else%20if%28e.type%20%3D%3D%20%22command%22%20%26%26%20hasMdf%20%7C%7C%20e.type%20%3D%3D%20%22click%22%20%26%26%20e.button%20%3D%3D%201%29%20%7B%0A%09%09openAddonPage%28addon%29%3B%0A%09%09closeMenus%28mi%29%3B%0A%09%7D%0A%09else%20if%28e.type%20%3D%3D%20%22click%22%20%26%26%20e.button%20%3D%3D%202%29%20%7B%0A%09%09if%28openAddonOptions%28addon%29%29%0A%09%09%09closeMenus%28mi%29%3B%0A%09%7D%0A%7D%3B%0Amp.destroyMenu%20%3D%20function%28%29%20%7B%0A%09removeStyle%28%29%3B%0A%09clearTimeout%28cleanupTimer%29%3B%0A%09cleanupTimer%20%3D%20setTimeout%28function%28%29%20%7B%0A%09%09mp.textContent%20%3D%20%22%22%3B%0A%09%7D%2C%205000%29%3B%0A%7D%3B%0Amp.icons%20%3D%20%7B%0A%09get%20platformVersion%28%29%20%7B%0A%09%09delete%20this.platformVersion%3B%0A%09%09return%20this.platformVersion%20%3D%20parseFloat%28Services.appinfo.platformVersion%29%3B%0A%09%7D%2C%0A%09get%20useSVG%28%29%20%7B%0A%09%09delete%20this.useSVG%3B%0A%09%09return%20this.useSVG%20%3D%20Services.appinfo.name%20%3D%3D%20%22Firefox%22%20%26%26%20this.platformVersion%20%3E%3D%2057%3B%0A%09%7D%2C%0A%09get%20plugin%28%29%20%7B%0A%09%09delete%20this.plugin%3B%0A%09%09return%20this.plugin%20%3D%20this.useSVG%0A%09%09%09%3F%20this.platformVersion%20%3E%3D%2065%0A%09%09%09%09%3F%20%22chrome%3A//global/skin/plugins/pluginGeneric.svg%22%0A%09%09%09%09%3A%20%22chrome%3A//mozapps/skin/plugins/pluginGeneric.svg%22%0A%09%09%09%3A%20%22chrome%3A//mozapps/skin/plugins/pluginGeneric-16.png%22%3B%0A%09%7D%2C%0A%09get%20extension%28%29%20%7B%0A%09%09delete%20this.extension%3B%0A%09%09return%20this.extension%20%3D%20this.useSVG%0A%09%09%09%3F%20this.platformVersion%20%3E%3D%2076%0A%09%09%09%09%3F%20%22chrome%3A//mozapps/skin/extensions/extensionGeneric.svg%22%20//%20Or%20chrome%3A//mozapps/skin/extensions/extension.svg%0A%09%09%09%09%3A%20%22chrome%3A//mozapps/skin/extensions/extensionGeneric-16.svg%22%0A%09%09%09%3A%20%22chrome%3A//mozapps/skin/extensions/extensionGeneric-16.png%22%3B%0A%09%7D%0A%7D%3B%0Afunction%20isAskToActivateAddon%28addon%29%20%7B%0A%09return%20addon.type%20%3D%3D%20%22plugin%22%0A%09%09%26%26%20%22STATE_ASK_TO_ACTIVATE%22%20in%20AddonManager%0A%09%09%26%26%20Services.prefs.getBoolPref%28%22plugins.click_to_play%22%2C%20true%29%3B%0A%7D%0Afunction%20setNewDisabled%28addon%29%20%7B%0A%09var%20newDis%20%3D%20getNewDisabled%28addon%29%3B%0A%09var%20oldDis%20%3D%20addon.userDisabled%3B%0A%09try%20%7B%0A%09%09addon.userDisabled%20%3D%20newDis%3B%0A%09%7D%0A%09catch%28e%29%20%7B%20//%20Error%3A%20Cannot%20disable%20hidden%20add-on%20firefox@getpocket.com%0A%09%09_log%28%22Can%27t%20set%20addon.userDisabled%20to%20%22%20+%20newDis%20+%20%22%2C%20error%3A%5Cn%22%20+%20e%29%3B%0A%09%09if%28addon.hidden%29%0A%09%09%09setNewDisabledRaw%28addon%2C%20newDis%29%3B%0A%09%7D%0A%09var%20realDis%20%3D%20addon.userDisabled%3B%0A%09if%28realDis%20%21%3D%20newDis%20%26%26%20addon.type%20%3D%3D%20%22extension%22%29%20%7B%20//%20Firefox%2062+%3F%20Weird%20things%20happens%0A%09%09setNewDisabledRaw%28addon%2C%20newDis%29%3B%0A%09%09realDis%20%3D%20addon.userDisabled%3B%0A%09%7D%0A%09if%28realDis%20%21%3D%20newDis%29%20%7B%20//%20We%20can%27t%20enable%20vulnerable%20plugins%0A%09%09let%20err%20%3D%20%22Can%27t%20set%20addon.userDisabled%20to%20%22%20+%20newDis%20+%20%22%2C%20real%20value%3A%20%22%20+%20realDis%3B%0A%09%09if%28newDis%29%20%7B%0A%09%09%09_log%28err%20+%20%22%5CnSTATE_ASK_TO_ACTIVATE%20not%20supported%3F%22%29%3B%0A%09%09%09newDis%20%3D%20false%3B%0A%09%09%7D%0A%09%09else%20%7B%0A%09%09%09_log%28err%20+%20%22%5CnVulnerable%20plugin%3F%22%29%3B%0A%09%09%09if%28oldDis%20%3D%3D%20AddonManager.STATE_ASK_TO_ACTIVATE%29%0A%09%09%09%09newDis%20%3D%20true%3B%0A%09%09%09else%0A%09%09%09%09newDis%20%3D%20AddonManager.STATE_ASK_TO_ACTIVATE%3B%0A%09%09%7D%0A%09%09addon.userDisabled%20%3D%20newDis%3B%0A%09%7D%0A%09ensureSpecialDisabled%28addon%2C%20newDis%29%3B%0A%09return%20addon.userDisabled%3B%0A%7D%0Afunction%20getNewDisabled%28addon%29%20%7B%0A%09//%20disabled%20-%3E%20STATE_ASK_TO_ACTIVATE%20-%3E%20enabled%20-%3E%20...%0A%09var%20curDis%20%3D%20addon.userDisabled%3B%0A%09var%20newDis%3B%0A%09if%28%22STATE_ASK_TO_ACTIVATE%22%20in%20AddonManager%20%26%26%20curDis%20%3D%3D%20AddonManager.STATE_ASK_TO_ACTIVATE%29%0A%09%09newDis%20%3D%20false%3B%0A%09else%20if%28%21curDis%29%0A%09%09newDis%20%3D%20true%3B%0A%09else%20%7B%0A%09%09if%28isAskToActivateAddon%28addon%29%29%0A%09%09%09newDis%20%3D%20AddonManager.STATE_ASK_TO_ACTIVATE%3B%0A%09%09else%0A%09%09%09newDis%20%3D%20false%3B%0A%09%7D%0A%09return%20newDis%3B%0A%7D%0Afunction%20setNewDisabledRaw%28addon%2C%20newDis%29%20%7B%0A%09_log%28%22Let%27s%20try%20set%20addon.userDisabled%20using%20raw%20hack%22%29%3B%0A%09let%20g%20%3D%20Components.utils.import%28%22resource%3A//gre/modules/addons/XPIProvider.jsm%22%2C%20%7B%7D%29%3B%0A%09if%28%22XPIDatabase%22%20in%20g%20%26%26%20%22updateAddonDisabledState%22%20in%20g.XPIDatabase%29%20%7B%20//%20Firefox%2061+%0A%09%09let%20rawAddon%20%3D%20g.XPIDatabase.getAddons%28%29.find%28function%28rawAddon%29%20%7B%0A%09%09%09return%20rawAddon.id%20%3D%3D%20addon.id%3B%0A%09%09%7D%29%3B%0A%09%09g.XPIDatabase.updateAddonDisabledState%28%0A%09%09%09rawAddon%2C%0A%09%09%09g.XPIDatabase.updateAddonDisabledState.length%20%3D%3D%201%20//%20Firefox%2074+%0A%09%09%09%09%3F%20%7B%20userDisabled%3A%20newDis%20%7D%0A%09%09%09%09%3A%20newDis%0A%09%09%29%3B%0A%09%7D%0A%09else%20if%28%22eval%22%20in%20g%29%20%7B%20//%20See%20%22set%20userDisabled%28val%29%22%0A%09%09let%20addonFor%20%3D%20g.eval%28%22addonFor%22%29%3B%0A%09%09let%20rawAddon%20%3D%20addonFor%28addon%29%3B%0A%09%09//rawAddon.userDisabled%20%3D%20newDis%3B%0A%09%09g.XPIProvider.updateAddonDisabledState%28rawAddon%2C%20newDis%29%3B%0A%09%7D%0A%09else%20%7B%20//%20Firefox%2057+%3F%20See%20https%3A//forum.mozilla-russia.org/viewtopic.php%3Fpid%3D745272%23p745272%0A%09%09updateAddonDisabledState%28addon%2C%20newDis%29%3B%0A%09%7D%0A%7D%0Afunction%20updateAddonDisabledState%28addon%2C%20newDis%29%20%7B%0A%09var%20nsvo%20%3D%20Components.utils.import%28%22resource%3A//gre/modules/addons/XPIProvider.jsm%22%2C%20%7B%7D%29%3B%0A%09var%20key%20%3D%20%22_cbToggleRestartlessAddonsData%22%3B%0A%09var%20url%20%3D%20URL.createObjectURL%28new%20Blob%28%5B%0A%09%09%22XPIProvider.updateAddonDisabledState%28addonFor%28this.%22%20+%20key%20+%20%22%5B0%5D%29%2C%20this.%22%20+%20key%20+%20%22%5B1%5D%29%3B%20delete%20this.%22%20+%20key%20+%20%22%3B%22%0A%09%5D%29%29%3B%0A%09addDestructor%28function%28%29%20%7B%0A%09%09URL.revokeObjectURL%28url%29%3B%0A%09%7D%29%3B%0A%09%28updateAddonDisabledState%20%3D%20function%28addon%2C%20newDis%29%20%7B%0A%09%09nsvo%5Bkey%5D%20%3D%20%5Baddon%2C%20newDis%5D%3B%0A%09%09Services.scriptloader.loadSubScript%28url%2C%20nsvo%29%3B%0A%09%7D%29%28addon%2C%20newDis%29%3B%0A%7D%0Afunction%20setDisabled%28mi%2C%20disabled%29%20%7B%0A%09var%20askToActivate%20%3D%20%22STATE_ASK_TO_ACTIVATE%22%20in%20AddonManager%20%26%26%20disabled%20%3D%3D%20AddonManager.STATE_ASK_TO_ACTIVATE%3B%0A%09var%20cl%20%3D%20mi.classList%3B%0A%09cl.toggle%28%22toggleRestartlessAddons-askToActivate%22%2C%20askToActivate%29%3B%0A%09cl.toggle%28%22toggleRestartlessAddons-disabled%22%2C%20disabled%20%26%26%20%21askToActivate%29%3B%0A%7D%0Afunction%20ensureSpecialDisabled%28addon%2C%20newDis%29%20%7B%0A%09if%28addon.id%20%3D%3D%20%22screenshots@mozilla.org%22%29%0A%09%09Services.prefs.setBoolPref%28%22extensions.screenshots.disabled%22%2C%20newDis%29%3B%0A%7D%0A%0Aif%28%0A%09this%20instanceof%20XULElement%20//%20Custom%20Buttons%0A%09%26%26%20typeof%20event%20%3D%3D%20%22object%22%0A%09%26%26%20%21%28%22type%22%20in%20event%29%20%26%26%20typeof%20_phase%20%3D%3D%20%22string%22%20%26%26%20_phase%20%3D%3D%20%22init%22%20//%20Initialization%0A%29%20%7B%0A%09this.type%20%3D%20%22menu%22%3B%0A%09this.orient%20%3D%20%22horizontal%22%3B%0A%09this.appendChild%28mp%29%3B%0A%0A%09this.onmouseover%20%3D%20function%28e%29%20%7B%0A%09%09if%28e.target%20%21%3D%20this%29%0A%09%09%09return%3B%0A%09%09Array.prototype.some.call%28%0A%09%09%09this.parentNode.getElementsByTagName%28%22*%22%29%2C%0A%09%09%09function%28node%29%20%7B%0A%09%09%09%09if%28%0A%09%09%09%09%09node%20%21%3D%20this%0A%09%09%09%09%09%26%26%20node.namespaceURI%20%3D%3D%20xulns%0A%09%09%09%09%09//%20See%20https%3A//github.com/Infocatcher/Custom_Buttons/issues/28%0A%09%09%09%09%09//%26%26%20node.boxObject%0A%09%09%09%09%09//%26%26%20node.boxObject%20instanceof%20Components.interfaces.nsIMenuBoxObject%0A%09%09%09%09%09%26%26%20%22open%22%20in%20node%0A%09%09%09%09%09%26%26%20node.open%0A%09%09%09%09%09%26%26%20node.getElementsByTagName%28%22menupopup%22%29.length%0A%09%09%09%09%29%20%7B%0A%09%09%09%09%09node.open%20%3D%20false%3B%0A%09%09%09%09%09this.open%20%3D%20true%3B%0A%09%09%09%09%09return%20true%3B%0A%09%09%09%09%7D%0A%09%09%09%09return%20false%3B%0A%09%09%09%7D%2C%0A%09%09%09this%0A%09%09%29%3B%0A%09%7D%3B%0A%09this.onmousedown%20%3D%20function%28e%29%20%7B%0A%09%09if%28e.target%20%3D%3D%20this%20%26%26%20e.button%20%3D%3D%200%20%26%26%20hasModifier%28e%29%29%0A%09%09%09e.preventDefault%28%29%3B%0A%09%7D%3B%0A%09this.oncontextmenu%20%3D%20function%28e%29%20%7B%0A%09%09if%28e.target%20%3D%3D%20this%20%26%26%20%21hasModifier%28e%29%20%26%26%20hasUpdater%28%29%29%0A%09%09%09e.preventDefault%28%29%3B%0A%09%7D%3B%0A%09this.onclick%20%3D%20function%28e%29%20%7B%0A%09%09if%28e.target%20%21%3D%20this%29%0A%09%09%09return%3B%0A%09%09if%28e.button%20%3D%3D%200%20%26%26%20hasModifier%28e%29%20%7C%7C%20e.button%20%3D%3D%201%29%0A%09%09%09openAddonsManager%28%29%3B%0A%09%09else%20if%28e.button%20%3D%3D%202%20%26%26%20%21hasModifier%28e%29%20%26%26%20hasUpdater%28%29%29%0A%09%09%09checkForAddonsUpdates.call%28this%29%3B%0A%09%7D%3B%0A%7D%0Aelse%20%7B%20//%20Mouse%20gestures%20or%20something%20other...%0A%09let%20e%3B%0A%09if%28typeof%20event%20%3D%3D%20%22object%22%20%26%26%20event%20instanceof%20Event%20%26%26%20%22screenX%22%20in%20event%29%20//%20FireGestures%0A%09%09e%20%3D%20event%3B%0A%09else%20if%28%0A%09%09this%20instanceof%20Components.interfaces.nsIDOMChromeWindow%0A%09%09%26%26%20%22mgGestureState%22%20in%20window%20%26%26%20%22endEvent%22%20in%20mgGestureState%20//%20Mouse%20Gestures%20Redox%0A%09%29%0A%09%09e%20%3D%20mgGestureState.endEvent%3B%0A%09else%20%7B%0A%09%09let%20anchor%20%3D%20this%20instanceof%20XULElement%20%26%26%20this%0A%09%09%09%7C%7C%20window.gBrowser%20%26%26%20gBrowser.selectedBrowser%0A%09%09%09%7C%7C%20document.documentElement%3B%0A%09%09if%28%22boxObject%22%20in%20anchor%29%20%7B%0A%09%09%09let%20bo%20%3D%20anchor.boxObject%3B%0A%09%09%09e%20%3D%20%7B%0A%09%09%09%09screenX%3A%20bo.screenX%2C%0A%09%09%09%09screenY%3A%20bo.screenY%0A%09%09%09%7D%3B%0A%09%09%09if%28this%20instanceof%20XULElement%29%0A%09%09%09%09e.screenY%20+%3D%20bo.height%3B%0A%09%09%7D%0A%09%7D%0A%09if%28%21e%20%7C%7C%20%21%28%22screenX%22%20in%20e%29%29%0A%09%09throw%20new%20Error%28%22%5BToggle%20Restartless%20Add-ons%5D%3A%20Can%27t%20get%20event%20object%22%29%3B%0A%09document.documentElement.appendChild%28mp%29%3B%0A%09mp.addEventListener%28%22popuphidden%22%2C%20function%20destroy%28e%29%20%7B%0A%09%09mp.removeEventListener%28e.type%2C%20destroy%2C%20false%29%3B%0A%09%09setTimeout%28function%28%29%20%7B%0A%09%09%09mp.destroyMenu%28%29%3B%0A%09%09%09mp.parentNode.removeChild%28mp%29%3B%0A%09%09%7D%2C%200%29%3B%0A%09%7D%2C%20false%29%3B%0A%09mp.openPopupAtScreen%28e.screenX%2C%20e.screenY%29%3B%0A%7D%0A%0Afunction%20getRestartlessAddons%28addonTypes%2C%20callback%2C%20context%29%20%7B%0A%09if%28%21%28%22AddonManager%22%20in%20window%29%29%0A%09%09Components.utils.import%28%22resource%3A//gre/modules/AddonManager.jsm%22%29%3B%0A%09if%28%21%28%22Services%22%20in%20window%29%29%0A%09%09Components.utils.import%28%22resource%3A//gre/modules/Services.jsm%22%29%3B%0A%09var%20then%2C%20promise%20%3D%20AddonManager.getAddonsByTypes%28addonTypes%2C%20then%20%3D%20function%28addons%29%20%7B%0A%09%09callback.call%28context%2C%20addons.filter%28function%28addon%29%20%7B%0A%09%09%09var%20ops%20%3D%20addon.operationsRequiringRestart%3B%0A%09%09%09return%20%21addon.appDisabled%0A%09%09%09%09%26%26%20%21%28ops%20%26%20AddonManager.OP_NEEDS_RESTART_ENABLE%20%7C%7C%20ops%20%26%20AddonManager.OP_NEEDS_RESTART_DISABLE%29%0A%09%09%09%09%26%26%20%28%0A%09%09%09%09%09%21addon.hidden%0A%09%09%09%09%09%7C%7C%20options.showHidden%20%3E%200%0A%09%09%09%09%09%7C%7C%20options.showHidden%20%3D%3D%20-1%20%26%26%20%21addon.userDisabled%0A%09%09%09%09%29%0A%09%09%09%09%26%26%20%28addon.iconURL%20%7C%7C%20%22%22%29.substr%280%2C%2029%29%20%21%3D%20%22resource%3A//search-extensions/%22%3B%0A%09%09%7D%29%29%3B%0A%09%7D%29%3B%0A%09promise%20%26%26%20typeof%20promise.then%20%3D%3D%20%22function%22%20%26%26%20promise.then%28then%2C%20Components.utils.reportError%29%3B%20//%20Firefox%2061+%0A%7D%0Afunction%20openAddonOptions%28addon%29%20%7B%0A%09//%20Based%20on%20code%20from%20chrome%3A//mozapps/content/extensions/extensions.js%0A%09//%20Firefox%2021.0a1%20%282013-01-27%29%0A%09var%20optionsURL%20%3D%20addon.optionsURL%3B%0A%09if%28%21addon.isActive%20%7C%7C%20%21optionsURL%29%0A%09%09return%20false%3B%0A%09if%28addon.type%20%3D%3D%20%22plugin%22%29%20//%20No%20options%20for%20now%21%0A%09%09return%20false%3B%0A%09if%28%0A%09%09addon.optionsType%20%3D%3D%20%28AddonManager.OPTIONS_TYPE_INLINE%20%7C%7C%20NaN%29%0A%09%09%7C%7C%20addon.optionsType%20%3D%3D%20%28AddonManager.OPTIONS_TYPE_INLINE_INFO%20%7C%7C%20NaN%29%0A%09%09%7C%7C%20addon.optionsType%20%3D%3D%20%28AddonManager.OPTIONS_TYPE_INLINE_BROWSER%20%7C%7C%20NaN%29%0A%09%29%0A%09%09openAddonPage%28addon%2C%20true%29%3B%0A%09else%20if%28addon.optionsType%20%3D%3D%20AddonManager.OPTIONS_TYPE_TAB%20%26%26%20%22switchToTabHavingURI%22%20in%20window%29%0A%09%09switchToTabHavingURI%28optionsURL%2C%20true%29%3B%0A%09else%20%7B%0A%09%09let%20windows%20%3D%20Services.wm.getEnumerator%28null%29%3B%0A%09%09while%28windows.hasMoreElements%28%29%29%20%7B%0A%09%09%09let%20win%20%3D%20windows.getNext%28%29%3B%0A%09%09%09if%28win.document.documentURI%20%3D%3D%20optionsURL%29%20%7B%0A%09%09%09%09win.focus%28%29%3B%0A%09%09%09%09return%20true%3B%0A%09%09%09%7D%0A%09%09%7D%0A%09%09//%20Note%3A%20original%20code%20checks%20browser.preferences.instantApply%20and%20may%20open%20modal%20windows%0A%09%09window.openDialog%28optionsURL%2C%20%22%22%2C%20%22chrome%2Ctitlebar%2Ctoolbar%2Ccenterscreen%2Cdialog%3Dno%22%29%3B%0A%09%7D%0A%09return%20true%3B%0A%7D%0Afunction%20openAddonsManager%28view%29%20%7B%0A%09var%20openAddonsMgr%20%3D%20window.BrowserOpenAddonsMgr%20//%20Firefox%0A%09%09%7C%7C%20window.openAddonsMgr%20//%20Thunderbird%0A%09%09%7C%7C%20window.toEM%3B%20//%20SeaMonkey%0A%09openAddonsMgr%28view%29%3B%0A%7D%0Afunction%20openAddonPage%28addon%2C%20scrollToPreferences%29%20%7B%0A%09var%20platformVersion%20%3D%20parseFloat%28%0A%09%09Services.appinfo.name%20%3D%3D%20%22Pale%20Moon%22%0A%09%09%09%3F%20Services.appinfo.version%0A%09%09%09%3A%20Services.appinfo.platformVersion%0A%09%29%3B%0A%09scrollToPreferences%20%3D%20scrollToPreferences%20%26%26%20platformVersion%20%3E%3D%2012%0A%09%09%3F%20%22/preferences%22%0A%09%09%3A%20%22%22%3B%0A%09openAddonsManager%28%22addons%3A//detail/%22%20+%20encodeURIComponent%28addon.id%29%20+%20scrollToPreferences%29%3B%0A%7D%0A%0Afunction%20hasModifier%28e%29%20%7B%0A%09return%20e.ctrlKey%20%7C%7C%20e.shiftKey%20%7C%7C%20e.altKey%20%7C%7C%20e.metaKey%3B%0A%7D%0A%0Afunction%20addStyle%28%29%20%7B%0A%09if%28addStyle.hasOwnProperty%28%22_style%22%29%29%0A%09%09return%3B%0A%09var%20style%20%3D%20%27%5C%0A%09%09.toggleRestartlessAddons-isDelayed%20%3E%20.menu-iconic-text%20%7B%5Cn%5C%0A%09%09%09opacity%3A%200.75%3B%5Cn%5C%0A%09%09%09color%3A%20%23070%3B%5Cn%5C%0A%09%09%7D%5Cn%5C%0A%09%09.toggleRestartlessAddons-isHidden%20%3E%20.menu-iconic-text%20%7B%5Cn%5C%0A%09%09%09color%3A%20%23609%3B%5Cn%5C%0A%09%09%7D%5Cn%5C%0A%09%09.toggleRestartlessAddons-disabled%20%3E%20.menu-iconic-left%20%7B%5Cn%5C%0A%09%09%09opacity%3A%200.4%3B%5Cn%5C%0A%09%09%7D%5Cn%5C%0A%09%09.toggleRestartlessAddons-disabled%20%3E%20.menu-iconic-text%2C%5Cn%5C%0A%09%09.toggleRestartlessAddons-disabled%20%3E%20.menu-accel-container%20%7B%5Cn%5C%0A%09%09%09opacity%3A%200.5%3B%5Cn%5C%0A%09%09%7D%5Cn%5C%0A%09%09.toggleRestartlessAddons-askToActivate%20%7B%5Cn%5C%0A%09%09%09color%3A%20-moz-nativehyperlinktext%3B%5Cn%5C%0A%09%09%7D%27%3B%0A%09addStyle._style%20%3D%20document.insertBefore%28%0A%09%09document.createProcessingInstruction%28%0A%09%09%09%22xml-stylesheet%22%2C%0A%09%09%09%27href%3D%22%27%20+%20%22data%3Atext/css%2C%22%0A%09%09%09%09+%20encodeURIComponent%28style%29%20+%20%27%22%20type%3D%22text/css%22%27%0A%09%09%29%2C%0A%09%09document.documentElement%0A%09%29%3B%0A%7D%0Afunction%20removeStyle%28%29%20%7B%0A%09if%28%21addStyle.hasOwnProperty%28%22_style%22%29%29%0A%09%09return%3B%0A%09var%20s%20%3D%20addStyle._style%3B%0A%09s.parentNode.removeChild%28s%29%3B%0A%09delete%20addStyle._style%3B%0A%7D%0Afunction%20closeMenus%28node%29%20%7B%0A%09//%20Based%20on%20function%20closeMenus%20from%20chrome%3A//browser/content/utilityOverlay.js%0A%09for%28%3B%20node%20%26%26%20%22tagName%22%20in%20node%3B%20node%20%3D%20node.parentNode%29%20%7B%0A%09%09if%28%0A%09%09%09node.namespaceURI%20%3D%3D%20%22http%3A//www.mozilla.org/keymaster/gatekeeper/there.is.only.xul%22%0A%09%09%09%26%26%20%28node.localName%20%3D%3D%20%22menupopup%22%20%7C%7C%20node.localName%20%3D%3D%20%22popup%22%29%0A%09%09%29%0A%09%09%09node.hidePopup%28%29%3B%0A%09%7D%0A%7D%0Afunction%20_log%28s%29%20%7B%0A%09if%28typeof%20LOG%20%3D%3D%20%22function%22%29%20//%20Custom%20Buttons%0A%09%09LOG%28s%29%3B%0A%09else%20//%20Or%20something%20else%0A%09%09Services.console.logStringMessage%28%22Toggle%20Restartless%20Add-ons%3A%20%22%20+%20s%29%3B%0A%7D%0A%0Afunction%20hasUpdater%28%29%20%7B%0A%09var%20has%20%3D%20checkForAddonsUpdates.toString%28%29.indexOf%28%22about%3Aaddons%22%29%20%21%3D%20-1%3B%0A%09hasUpdater%20%3D%20function%28%29%20%7B%0A%09%09return%20has%3B%0A%09%7D%3B%0A%09return%20has%3B%0A%7D%0Afunction%20checkForAddonsUpdates%28%29%20%7B%0A//%3D%3D%20Check%20for%20Addons%20Updates%20begin%0A%0A//%3D%3D%20Check%20for%20Addons%20Updates%20end%0A%7D%0A%0A%0A%5D%5D%3E%3C/initcode%3E%0A%20%20%3Ccode%3E%3C%21%5BCDATA%5B%20%0A%0A%0A%0A%0A%0A%5D%5D%3E%3C/code%3E%0A%20%20%3Caccelkey%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/accelkey%3E%0A%20%20%3Chelp%3E%3C%21%5BCDATA%5B%5D%5D%3E%3C/help%3E%0A%20%20%3Cattributes/%3E%0A%3C/custombutton%3E

На 87 обновления не работают

Garalf
Bug 1525179 - [about:addons] Use an HTML document at the root of about:addons


Там образуется петля, а это нехорошо,
поэтому, пока ждёшь, попробуй петлю убрать.

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

Выделить код

Код:

/*
		if(!vb) {
			win.setTimeout(processAddonsTab, 20, win);
			return;
		}
*/
		if(!vb) {
			if(HTMLHtmlElement.isInstance(doc.documentElement))
				vb = browser;
			else {
				win.setTimeout(processAddonsTab, 20, win);
				return;
			}
		}

Dumby
Работает отлично. Спасибо

Dumby пишет

Bug 1525179 - [about:addons] Use an HTML document at the root of about:addons

Уфф, добрался… обновил, огромное спасибо!

Упс. На что то старое отвечал. DEL

СКМ по расширению в списке стал вкл/выкл расширение.
Т.е. кроме перехода на страницу расширения в about:addons ещё и переключает вкл/выкл.
Это только у меня?

momo2000 пишет

СКМ по расширению в списке стал вкл/выкл расширение.
Т.е. кроме перехода на страницу расширения в about:addons ещё и переключает вкл/выкл.

Какие-то новые обратно-несовместимые улучшения:


https://bugzilla.mozilla.org/show_bug.cgi?id=1704948
Allow obtaining the mouse button for menuitem clicks from the command event
(Firefox 89+)

Bug 1469148 added a click event listener to WebExtension context menu items, which manually fires a command event and closes the menu.

Вот это вообще эпично: не понимаю, зачем ради расширений ломать вообще все меню.


https://bugzilla.mozilla.org/show_bug.cgi?id=1469148
Web Extension menus should be able to react to middle click
(Firefox 64+)

12-07-2021 21:26:27
Подправил: https://github.com/Infocatcher/Custom_B … 56524762ad
В Firefox 89+ должно работать.
В Firefox 64-88, видимо, поломано, не проверял.

12-07-2021 21:32:03
А еще, судя по https://searchfox.org/mozilla-central/r … js#460-476 и предыдущему коду, на каждый пункт меню добавляется по два слушателя событий. Ну а что, памяти нынче много, не жалко.

Dumby
Выложите пожалуйста код   [CB]Toggle Restartless Add-ons для актуальной версии ФФ