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) – открыть страницу дополнения в управлении дополнениями
ПКМ – открыть настройки дополнения (если есть)

Скриншот:
https://raw.github.com/Infocatcher/Custom_Buttons/master/Toggle_Restartless_Add-ons/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% решение, задавливание делается один раз и можно спокойно - жёстко в коде.
Ещё раз спасибо - в целом :)

У меня в ласт ESR версий кнопка показывает только плагины (ставил отсюда https://github.com/Infocatcher/Custom_B … ss_Add-ons)
Как показывать установленные дополнения?

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 я бы мог (надеюсь) реализовать самостоятельно. А с остальными - напряжёнка...

Infocatcher пишет:

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);
    });
}

Ааа... вот как получается. У меня то стоят как раз таки которые требуют.

Спасибо, работает!

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 пишет:

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

Эмм, показывает:
https://i.imgur.com/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,