-
-
Save LouCypher/9bef48285237609c1193 to your computer and use it in GitHub Desktop.
Supports more add-on types in bootstrap.js for https://addons.mozilla.org/addon/addons-manager-hilite/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Components.utils.import("resource://gre/modules/AddonManager.jsm"); | |
Components.utils.import("resource://gre/modules/Services.jsm"); | |
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); | |
var doAlphaSort = null; // for pref (alphabetical vs by-state sorting) | |
var updatedSort = false; // for pref (sort by last updated) | |
var dontSort = false; // ignore sort pref in category-userstyles (provides own sorting) | |
var restore = null; // for pref (restore hilite after closing AoM) | |
var showUI = null; // for pref (whether to create/display ac menu) | |
var UIwidth = null; // for pref (ac menu size) | |
var showVersionNumber = null; // for pref (whether to show version number in ac menu) | |
var spacer = " "; | |
var UIextra = null; // for restore-on-demand hidden pref | |
var extraRows = null; | |
var extArray = null; | |
var themeArray = null; | |
var pluginArray = null; | |
var userstyleArray = null; | |
var serviceArray = null; | |
var userscriptArray = null; | |
var scriptishArray = null; | |
var custombuttonsArray = null; | |
var dictionaryArray = null; | |
var localeArray = null; | |
var savedAddonName = null; | |
var displayDropdown = null; // used for Seamonkey & Tbird workaround | |
const LISTVIEW = 2; | |
const DETAILVIEW = 4; | |
var supportedCats = [ "category-extension", "category-theme", "category-plugin", "category-userstyle", | |
"category-service", "category-greasemonkey-user-script", "category-userscript", | |
"category-custombuttons", "category-dictionary", "category-locale" ]; | |
// from http://erikvold.com/blog/index.cfm/2011/6/14/restartless-firefox-addons-part-6-better-includes | |
// Thanks, Erik! | |
(function(global) { | |
global.include = function include(src) { | |
var o = {}; | |
Components.utils.import("resource://gre/modules/Services.jsm", o); | |
var uri = o.Services.io.newURI(src, null, o.Services.io.newURI(__SCRIPT_URI_SPEC__, null, null)); | |
o.Services.scriptloader.loadSubScript(uri.spec, global); | |
}; | |
})(this); | |
include("components/addonList_autocomplete.js"); | |
function startup(data, reason) { | |
Services.obs.addObserver(ChromeDocObserver, "chrome-document-global-created", false); | |
var defPrefs = Services.prefs.getDefaultBranch("extensions.addonsmgrhilte@cfl."); | |
defPrefs.setBoolPref("restore", true); | |
defPrefs.setBoolPref("alphaSort", false); | |
defPrefs.setBoolPref("updatedSort", false); | |
defPrefs.setBoolPref("extraRows", false); | |
defPrefs.setBoolPref("showUI", true); // should we default this to true now?????? | |
defPrefs.setIntPref("listboxSize", 18); | |
defPrefs.setBoolPref("UIextra", false); | |
defPrefs.setBoolPref("showVersion", false); | |
// register our custom autocomplete component | |
Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar).registerFactory(CLASS_ID, | |
CLASS_NAME, CONTRACT_ID, NSGetFactory(CLASS_ID)); | |
if (reason == ADDON_ENABLE || reason == ADDON_INSTALL) { | |
var mgrs = findAddonsMgrs(); | |
var i; | |
for (i = 0; i < mgrs.length; i++) { | |
mgrs[i].location.reload(); | |
} | |
} | |
} | |
function shutdown(data, reason) { | |
Services.obs.removeObserver(ChromeDocObserver, "chrome-document-global-created"); | |
// call flush due to the bundle service cache (for aomhilite.properties string bundle) | |
Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService) | |
.flushBundles(); | |
// unregister our custom autocomplete component | |
Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar).unregisterFactory(CLASS_ID, | |
NSGetFactory(CLASS_ID)); | |
// remove stylesheets | |
removeStylesheet("chrome://aomhilite/content/aomhilite.css"); | |
removeStylesheet("chrome://aomhilite/content/aomhiliteLG.css"); | |
removeStylesheet("chrome://aomhilite/content/aomhiliteOSX.css"); | |
if (reason == ADDON_DISABLE) { | |
// remove any UI from any open Add-ons Manager tabs and revert to default sorting | |
var mgrs = findAddonsMgrs(); | |
var i; | |
for (i = 0; i < mgrs.length; i++) { | |
AddonsMgrOnUnload.call(mgrs[i]); | |
// reverts to default sort; | |
// also allows aomhilite.xml to be removed from memory w/o waiting for user to close AoM | |
mgrs[i].location.reload(); | |
} | |
} | |
} | |
function install(data, reason) { | |
} | |
function uninstall(data, reason) { | |
// don't remove user's selection when updating ext (as opposed to actual uninstall) | |
if (reason != "ADDON_UNINSTALL") { | |
return; | |
} | |
var RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService); | |
var localstore = RDF.GetDataSource('rdf:local-store'); | |
var subj = RDF.GetResource('about:addons#addon-list'); | |
var pred = RDF.GetResource('aomhilite'); | |
var target = localstore.GetTarget(subj, pred, true); | |
if (target == null) { | |
return; | |
} // if it's an empty string we want to remove it's entry | |
target = target.QueryInterface(Components.interfaces.nsIRDFLiteral); | |
var obj = RDF.GetLiteral(target.Value); | |
localstore.Unassert(subj, pred, obj, true); | |
} | |
function ChromeDocObserver(aSubject, aTopic, aData) { | |
try { | |
if (aTopic != "chrome-document-global-created") { | |
return; | |
} | |
var win = aSubject; | |
var uri = win.document.documentURI; | |
// if Add-ons Manager Dialog Returns add-on is installed, uri will be about:blank until loaded | |
if (uri == "about:addons" || uri == "about:blank") { | |
win.addEventListener("load", AddonsMgrOnload, false); | |
} | |
} catch (e) { | |
Services.console.logStringMessage("Exception in ChromeDocObserver"); | |
} | |
} | |
function AddonsMgrOnload() { | |
// removing this load listener is req'd to prevent mem leak | |
// if we're at about:blank we need to do that *now* | |
// might as well do them all here | |
// listener no longer needed since if the mgr is reloaded via F5, | |
// unload is called, then ChromeDocObserver re-adds the listener | |
this.removeEventListener("load", AddonsMgrOnload, false); | |
if (this.document.documentURI != "about:addons") { | |
return; | |
} | |
this.addEventListener("unload", AddonsMgrOnUnload, false); | |
var AMdoc = this.document; // document obj of Addons Mgr window | |
var addonList = AMdoc.getElementById("addon-list"); | |
var prefs = Components.classes["@mozilla.org/preferences-service;1"] | |
.getService(Components.interfaces.nsIPrefService); | |
prefs = prefs.getBranch("extensions.addonsmgrhilte@cfl."); | |
doAlphaSort = prefs.getBoolPref("alphaSort"); | |
updatedSort = prefs.getBoolPref("updatedSort"); | |
restore = prefs.getBoolPref("restore"); | |
UIextra = prefs.getBoolPref("UIextra"); | |
showUI = prefs.getBoolPref("showUI"); | |
extraRows = prefs.getBoolPref("extraRows"); | |
// restore-on-demand useless if already auto-restored, or the UI not even visible | |
if (restore || !showUI) { | |
UIextra = false; | |
} | |
UIwidth = prefs.getIntPref("listboxSize"); | |
UIwidth = (UIwidth > 50) ? 50 : UIwidth; | |
UIwidth = (UIwidth < 10) ? 10 : UIwidth; | |
if (showUI) { | |
initUI(AMdoc); | |
} | |
if (!restore) { | |
addonList.setAttribute('aomhilite', ""); | |
} | |
this.addEventListener("ViewChanged", onViewChange, false); | |
var cat = AMdoc.getElementById("categories"); | |
if (!cat || !addonList) { | |
return; | |
} | |
var attr = addonList.getAttribute("persist"); // 'persist' enables this info to survive a restart of fx | |
if (!attr) { | |
addonList.setAttribute("persist", "aomhilite"); | |
} else if (attr.indexOf("aomhilite") < 0) { | |
addonList.setAttribute("persist", attr + " aomhilite"); | |
} | |
addonList.addEventListener("select", onSelect, false); | |
} | |
var addonListener = { | |
onInstalled : function(addon) { | |
updateListboxContents(addon, "add"); | |
updateAllListboxes(); | |
}, | |
/* | |
* due to the 'undo' option remaining available until aom closed/reopened, this won't get called until current | |
* instance (tab) is closed, because that's when the actual uninstall occurs (and when we should remove item from | |
* dropdown list) | |
*/ | |
onUninstalled : function(addon) { | |
updateListboxContents(addon, "remove"); | |
updateAllListboxes(); | |
} | |
}; | |
function initUI(AMdoc) { | |
var acListboxStyle = "margin-left: 1em; margin-right: 1em; width: " + UIwidth + "em;"; | |
var acAddonList = AMdoc.createElement("textbox"); | |
acAddonList.setAttribute("id", "aomhilite_ac_menu"); | |
acAddonList.setAttribute("style", acListboxStyle); | |
acAddonList.setAttribute("type", "autocomplete"); | |
// acAddonList.setAttribute("size", 24); // seems to have no effect; set via css width instead | |
acAddonList.setAttribute("autocompletesearch", "addonList_autocomplete"); | |
acAddonList.setAttribute("enablehistory", true); | |
// acAddonList.setAttribute("completedefaultindex", true); | |
acAddonList.setAttribute("forcecomplete", true); // ensures selection is valid | |
// only applies to typing in box; see aomhilite.xml | |
acAddonList.setAttribute("maxrows", 10); // default is about 6 | |
var notifyListbox = "var evt = document.createEvent('Events'); " + "evt.initEvent('textentered', true, true); " + | |
"this.dispatchEvent(evt);"; | |
acAddonList.setAttribute("ontextentered", notifyListbox); | |
var strbundle = Components.classes["@mozilla.org/intl/stringbundle;1"].getService( | |
Components.interfaces.nsIStringBundleService).createBundle("chrome://aomhilite/locale/aomhilite.properties"); | |
var selectaddon = strbundle.GetStringFromName("placeholderString"); | |
acAddonList.setAttribute("placeholder", selectaddon); | |
/* set up stylesheets */ | |
var osString = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULRuntime).OS; | |
addStylesheet("chrome://aomhilite/content/aomhilite.css"); | |
if (osString == "Darwin") { | |
addStylesheet("chrome://aomhilite/content/aomhiliteOSX.css"); | |
} | |
var updateBtn = AMdoc.getElementById("header-utils-btn"); | |
var head = AMdoc.getElementById("header"); | |
head.insertBefore(acAddonList, updateBtn); | |
// prevents "Extension cannot be installed because Nightly cannot modify the needed file" | |
// error when updating this ext (bug 719180) | |
// although 71980 is fixed in fx 19+, using (tested on fx 21.0a1): | |
// acAddonList.style.MozBinding = "url(chrome://aomhilite/content/aomhilite.xml#ac_menu_aomhilite)"; | |
// leaves the aomhilite.xml file in memory even when AoM is closed and aomhilite is disabled! | |
var chromeReg = Components.classes["@mozilla.org/chrome/chrome-registry;1"] | |
.getService(Components.interfaces.nsIChromeRegistry); | |
var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); | |
var bindingUri; | |
if (extraRows) { | |
bindingUri = ioService.newURI("chrome://aomhilite/content/aomhiliteLG.xml#ac_menu_aomhilite", null, null); | |
} else { | |
bindingUri = ioService.newURI("chrome://aomhilite/content/aomhilite.xml#ac_menu_aomhilite", null, null); | |
} | |
var convertedBindingUri = chromeReg.convertChromeURL(bindingUri); | |
acAddonList.style.MozBinding = 'url("' + convertedBindingUri.spec + '")'; | |
const | |
FIREFOX_ID = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"; | |
var appInfo = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULAppInfo); | |
if (appInfo.ID != FIREFOX_ID) { // workaround - Seamonkey/Tbird (bug 708520) aren't opening popup by default | |
var arrow = AMdoc.getAnonymousElementByAttribute(acAddonList, "anonid", "historydropmarker"); | |
displayDropdown = function() { | |
acAddonList.showHistoryPopup(); | |
}; | |
arrow.addEventListener("click", displayDropdown, false); | |
} | |
acAddonList.addEventListener("textentered", onACaddonListSelection, false); | |
AddonManager.addAddonListener(addonListener); | |
if (UIextra) { | |
var addonList = AMdoc.getElementById("addon-list"); | |
addonList.setAttribute('restoreondemand', addonList.getAttribute('aomhilite')); | |
} | |
// (do here since addonListCallback will require data initialized above) | |
AddonManager.getAddonsByTypes([ "extension" ], function(addons) { | |
addonListCallback(addons, AMdoc, "extension"); | |
}); | |
AddonManager.getAddonsByTypes([ "theme" ], function(addons) { | |
addonListCallback(addons, AMdoc, "theme"); | |
}); | |
AddonManager.getAddonsByTypes([ "plugin" ], function(addons) { | |
addonListCallback(addons, AMdoc, "plugin"); | |
}); | |
AddonManager.getAddonsByTypes([ "userstyle" ], function(addons) { | |
addonListCallback(addons, AMdoc, "userstyle"); | |
}); | |
AddonManager.getAddonsByTypes([ "service" ], function(addons) { | |
addonListCallback(addons, AMdoc, "service"); | |
}); | |
// Greasemonkey | |
AddonManager.getAddonsByTypes([ "greasemonkey-user-script" ], function(addons) { | |
addonListCallback(addons, AMdoc, "greasemonkey-user-script"); | |
}); | |
// Scriptish | |
AddonManager.getAddonsByTypes([ "userscript" ], function(addons) { | |
addonListCallback(addons, AMdoc, "userscript"); | |
}); | |
// Custom Buttons | |
AddonManager.getAddonsByTypes([ "custombuttons" ], function(addons) { | |
addonListCallback(addons, AMdoc, "custombuttons"); | |
}); | |
AddonManager.getAddonsByTypes([ "dictionary" ], function(addons) { | |
addonListCallback(addons, AMdoc, "dictionary"); | |
}); | |
AddonManager.getAddonsByTypes([ "locale" ], function(addons) { | |
addonListCallback(addons, AMdoc, "locale"); | |
}); | |
} | |
function addStylesheet(sheet) { | |
var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"] | |
.getService(Components.interfaces.nsIStyleSheetService); | |
var ios = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService); | |
var uri = ios.newURI(sheet, null, null); | |
if (!sss.sheetRegistered(uri, sss.USER_SHEET)) { | |
sss.loadAndRegisterSheet(uri, sss.USER_SHEET); | |
} | |
} | |
function removeStylesheet(sheet) { | |
var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"] | |
.getService(Components.interfaces.nsIStyleSheetService); | |
var ios = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService); | |
var uri = ios.newURI(sheet, null, null); | |
if (sss.sheetRegistered(uri, sss.USER_SHEET)) { | |
sss.unregisterSheet(uri, sss.USER_SHEET); | |
} | |
} | |
function findAddonsMgrs() { | |
// find all open mgrs | |
var mgrs = []; | |
var windows = Services.wm.getEnumerator("navigator:browser"); | |
var window; | |
while (windows.hasMoreElements()) { | |
window = windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindow); | |
window.gBrowser.browsers.forEach(findMgrTab); | |
} | |
function findMgrTab(browser) { | |
if (browser.currentURI.spec == "about:addons") { | |
mgrs.push(browser.contentWindow); | |
} | |
} | |
// Mgr in dialog window (for Add-ons Manager Dialog Returns compatibility) | |
var topWin = Services.wm.getMostRecentWindow(null); | |
if (topWin.document.documentURI == "about:addons") { | |
mgrs.push(topWin); | |
} | |
return mgrs; | |
} | |
function updateListboxContents(addon, action) { | |
if (action != "add" && action != "remove") { | |
return; | |
} | |
var currentArray = null; | |
switch (addon.type) { | |
case "extension": | |
currentArray = extArray; | |
break; | |
case "theme": | |
currentArray = themeArray; | |
break; | |
case "plugin": | |
currentArray = pluginArray; | |
break; | |
case "userstyle": | |
currentArray = userstyleArray; | |
break; | |
case "service": | |
currentArray = serviceArray; | |
break; | |
case "greasemonkey-user-script": | |
currentArray = userscriptArray; | |
break; | |
case "userscript": | |
currentArray = scriptishArray; | |
break; | |
case "custombuttons": | |
currentArray = custombuttonsArray; | |
break; | |
case "dictionary": | |
currentArray = dictionaryArray; | |
break; | |
case "locale": | |
currentArray = localeArray; | |
break; | |
default: | |
Services.console.logStringMessage("Addons Manager Hilite encountered an unsupported Add-on type: " + | |
addon.type + " " + addon.name); | |
} | |
var entryFound = false; | |
var element; | |
for (element = 0; element < currentArray.length; element++) { | |
let | |
entry = currentArray[element]; | |
if (entry.indexOf(addon.name) != -1) { // found item | |
entryFound = true; | |
if (showVersionNumber && action == "add") { // version number needs updated | |
var nameVersion = entry.split(spacer, 2); | |
nameVersion[1] = (nameVersion[0].indexOf("<") == 0) ? addon.version + ">" : addon.version; | |
entry = nameVersion.join(spacer); | |
currentArray[element] = entry; | |
} else { | |
if (action == "remove") { | |
currentArray.splice(element, 1); | |
} | |
} | |
// process restoreondemand entry, if any + actual entry | |
if (entry.indexOf("<") != 0) { | |
break; | |
} | |
} // end if found | |
} // end for | |
if (!entryFound && action == "add") { // item not present; needs added | |
var entryToAdd = addon.name; | |
if (showVersionNumber) { | |
entryToAdd = entryToAdd + spacer + addon.version; | |
} | |
currentArray.push(entryToAdd); | |
currentArray.sort(function(addonItem1, addonItem2) { | |
var addon1Name = addonItem1.toLowerCase(); | |
var addon2Name = addonItem2.toLowerCase(); | |
return addon1Name.localeCompare(addon2Name); | |
}); | |
} | |
} | |
function updateAllListboxes() { | |
var mgrs = findAddonsMgrs(); | |
var i; | |
for (i = 0; i < mgrs.length; i++) { | |
var AMdoc = mgrs[i].document; | |
var acAddonList = AMdoc.getElementById("aomhilite_ac_menu"); | |
var cat = AMdoc.getElementById('categories'); | |
var selCat = cat.selectedItem.id; | |
switch (selCat) { // select the proper menulist for the current category | |
case "category-extension": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(extArray)); | |
break; | |
case "category-theme": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(themeArray)); | |
break; | |
case "category-plugin": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(pluginArray)); | |
break; | |
case "category-userstyle": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(userstyleArray)); | |
break; | |
case "category-service": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(serviceArray)); | |
break; | |
case "category-greasemonkey-user-script": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(userscriptArray)); | |
break; | |
case "category-userscript": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(scriptishArray)); | |
break; | |
case "category-custombuttons": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(custombuttonsArray)); | |
break; | |
case "category-dictionary": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(dictionaryArray)); | |
break; | |
case "category-locale": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(localeArray)); | |
break; | |
} | |
} | |
} | |
function restoreHilite(AMdoc) { | |
// purpose: retrieve saved selection and restore it | |
// content.document does not get document we want if AoM was opened in background via session restore | |
var selAddon; | |
var addonList = AMdoc.getElementById('addon-list'); | |
var savedSelections = addonList.getAttribute('aomhilite'); | |
var cat = AMdoc.getElementById('categories'); | |
var selCat = cat.selectedItem.id; // category-extension, etc. | |
var selectionArray = savedSelections.split(","); | |
var lastSel = selectionArray[supportedCats.indexOf(selCat)]; | |
if (lastSel) { | |
selAddon = addonList.getElementsByAttribute('value', lastSel); | |
} | |
if (!lastSel || !selAddon || !selAddon[0]) { | |
// no lastSel will occur on newly opened AoM if (always) restore pref is false | |
// otherwise typically occurs when selected category has no installed items or has never had a saved selection | |
var acAddonList = AMdoc.getElementById("aomhilite_ac_menu"); | |
if (acAddonList) { | |
acAddonList.value = ""; | |
} // onSelect not triggered (see below); need to clear this now | |
return; | |
} | |
addonList.selectItem(selAddon[0]); // will trigger onSelect | |
addonList.scrollBoxObject.scrollToElement(selAddon[0]); | |
addonList.focus(); | |
} | |
function saveUpdatedSel(addonList, selCat, newSelId) { | |
var savedSelections = addonList.getAttribute('aomhilite'); | |
var selectionArray = savedSelections.split(","); | |
selectionArray[supportedCats.indexOf(selCat)] = newSelId; | |
var updatedSel = selectionArray.toString(); | |
addonList.setAttribute('aomhilite', updatedSel); | |
} | |
function onSelect() { | |
var currentSel = this.selectedItem.mAddon.id; | |
var AMdoc = this.ownerDocument; | |
var cat = AMdoc.getElementById('categories'); | |
var selCat = cat.selectedItem.id; | |
if (!currentSel || (supportedCats.indexOf(selCat) == -1)) { | |
return; | |
} | |
saveUpdatedSel(this, selCat, currentSel); | |
var acAddonList = AMdoc.getElementById("aomhilite_ac_menu"); | |
if (!acAddonList || !acAddonList.value) { | |
return; | |
} | |
if (acAddonList.value.indexOf(this.selectedItem.mAddon.name) < 0) { | |
acAddonList.value = ""; // clear ac list input field, rather than show name of a now unselected item | |
} | |
} | |
function onACaddonListSelection() { | |
// called when selection made from ac dropdown list or pressing ENTER in input field | |
var AMdoc = this.ownerDocument; | |
var cat = AMdoc.getElementById('categories'); | |
var selCat = cat.selectedItem.id; | |
var acAddonList = AMdoc.getElementById("aomhilite_ac_menu"); | |
// setting selectionStart & selectionEnd to same value sets the cursor position to that position | |
// set to beginning so text looks cropped on right instead of on left | |
acAddonList.inputField.selectionStart = 0; | |
acAddonList.inputField.selectionEnd = 0; | |
var sel = AMdoc.getElementById("aomhilite_ac_menu").value; | |
if (UIextra && sel.indexOf("<") == 0 && sel.lastIndexOf(">") == sel.length - 1) { | |
sel = sel.slice(1, sel.length - 1); // remove angle brackets | |
} | |
if (showVersionNumber) { | |
let | |
nameEnd = sel.lastIndexOf(spacer); | |
if (nameEnd > 0) { // remove spacer and version #, if found (should be there, but...) | |
sel = sel.slice(0, nameEnd); | |
} | |
} | |
var addonList = AMdoc.getElementById('addon-list'); | |
var selAddon = addonList.getElementsByAttribute('name', sel); | |
if (selAddon && selAddon[0]) { | |
var newSelId = selAddon[0].mAddon.id; | |
if (!newSelId) { | |
return; | |
} | |
saveUpdatedSel(addonList, selCat, newSelId); | |
var view = AMdoc.getElementById('view-port'); | |
if (view.getAttribute('selectedIndex') == LISTVIEW) { | |
restoreHilite(AMdoc); | |
} else { | |
selAddon[0].showInDetailView(); | |
} | |
} else { | |
/* | |
* Workaround issue that occurs when using nav arrow takes us back into detail view of a non-current category, | |
* resulting in 'addon-list' element that is no longer populated with the list of add-ons, thus there are no | |
* elements with the name we are looking for | |
*/ | |
savedAddonName = sel; | |
// repopulates the list, finish workaround in the resulting onViewChange | |
cat.selectedItem.click(); | |
} | |
} | |
function onViewChange() { | |
var AMdoc = this.document; | |
var acAddonList = AMdoc.getElementById("aomhilite_ac_menu"); | |
var view = AMdoc.getElementById('view-port'); | |
var cat = AMdoc.getElementById('categories'); | |
var selCat = cat.selectedItem.id; | |
if (selCat == "category-userstyle" || selCat == "category-greasemonkey-user-script" || | |
selCat == "category-custombuttons") { | |
dontSort = true; | |
} | |
if (view && view.getAttribute('selectedIndex') == LISTVIEW) { | |
if (savedAddonName) { | |
// finish workaround from onACaddonListSelection - display add-on in detail view | |
var addonList = AMdoc.getElementById('addon-list'); | |
// prevents annoying flash of list view before detail view appears | |
addonList.setAttribute('hidden', true); | |
var selAddon = addonList.getElementsByAttribute('name', savedAddonName); | |
if (selAddon && selAddon[0]) { | |
selAddon[0].showInDetailView(); | |
var newSelId = selAddon[0].mAddon.id; | |
saveUpdatedSel(addonList, selCat, newSelId); | |
} | |
addonList.removeAttribute('hidden'); | |
savedAddonName = null; | |
// workaround finished, we're now in detail view, which retriggers viewchange | |
// (if we unexpectedly fail to find add-on for detail view, just continue in list view) | |
if (selAddon && selAddon[0]) { | |
return; | |
} | |
} | |
// need to recheck pref, since we're not using pref observer | |
var prefs = Components.classes["@mozilla.org/preferences-service;1"] | |
.getService(Components.interfaces.nsIPrefService); | |
prefs = prefs.getBranch("extensions.addonsmgrhilte@cfl."); | |
doAlphaSort = prefs.getBoolPref("alphaSort"); | |
updatedSort = prefs.getBoolPref("updatedSort"); | |
if (doAlphaSort || updatedSort) { | |
resort(AMdoc); | |
} | |
restoreHilite(AMdoc); | |
} else if (view && view.getAttribute('selectedIndex') == DETAILVIEW) { | |
// if we are in this ext's detail view | |
if (AMdoc.getElementById("detail-name").textContent == "Addons Manager Hilite") { | |
// set input field of numeric setting to sensible size & disable if not applicable | |
var setting = AMdoc.getElementById("aomhilite_size"); | |
var inputField = AMdoc.getAnonymousElementByAttribute(setting, "anonid", "input"); | |
inputField.setAttribute("style", "max-width: 3em;"); | |
} | |
} | |
// if our menu has not been created yet or the UI is pref'ed off, nothing else to do | |
if (!acAddonList) { | |
return; | |
} | |
switch (selCat) { // select the proper menulist for the current category | |
case "category-extension": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(extArray)); | |
break; | |
case "category-theme": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(themeArray)); | |
break; | |
case "category-plugin": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(pluginArray)); | |
break; | |
case "category-userstyle": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(userstyleArray)); | |
break; | |
case "category-service": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(serviceArray)); | |
break; | |
case "category-greasemonkey-user-script": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(userscriptArray)); | |
break; | |
case "category-userscript": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(scriptishArray)); | |
break; | |
case "category-custombuttons": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(custombuttonsArray)); | |
break; | |
case "category-dictionary": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(dictionaryArray)); | |
break; | |
case "category-locale": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(localeArray)); | |
break; | |
default: | |
acAddonList.setAttribute('hidden', 'true'); // hide UI in unsupported cats | |
return; | |
} | |
acAddonList.removeAttribute('hidden'); // show UI | |
} | |
function resort(AMdoc) { | |
// use alphabetical (or optionally updated) sort instead of by-state sort implemented by Bug 624808 | |
if (dontSort) { | |
dontSort = false; | |
return; | |
} | |
var addonList = AMdoc.getElementById("addon-list"); | |
if (!updatedSort) { | |
var sortby = [ "name" ]; | |
AMdoc.defaultView.sortList(addonList, sortby, true); // true = ascending | |
return; | |
} | |
// most recently updated | |
var list = addonList.children; | |
list.sort(function(addonItem1, addonItem2) { | |
var addon1Time = Date.parse(addonItem1.mAddon.updateDate); | |
var addon2Time = Date.parse(addonItem2.mAddon.updateDate); | |
if (addon1Time > addon2Time) { | |
return -1; | |
} | |
if (addon1Time < addon2Time) { | |
return 1; | |
} | |
var addon1Name = addonItem1.mAddon.name.toLowerCase(); | |
var addon2Name = addonItem2.mAddon.name.toLowerCase(); | |
return addon1Name.localeCompare(addon2Name); | |
}); | |
var i; | |
for (i = 0; i < list.length; i++) { | |
addonList.appendChild(list[i]); | |
} | |
} | |
function addonListCallback(addons, AMdoc, addonType) { | |
var addonList = AMdoc.getElementById("addon-list"); | |
var prevHilite = addonList.getAttribute("restoreondemand"); | |
var hiliteArray = prevHilite.split(","); | |
var currentArray = null; | |
var currentCat = null; | |
addons.sort(function(addonItem1, addonItem2) { | |
var addon1Name = addonItem1.name.toLowerCase(); | |
var addon2Name = addonItem2.name.toLowerCase(); | |
return addon1Name.localeCompare(addon2Name); | |
}); | |
switch (addonType) { | |
case "extension": | |
extArray = []; | |
currentArray = extArray; | |
currentCat = "category-extension"; | |
break; | |
case "theme": | |
themeArray = []; | |
currentArray = themeArray; | |
currentCat = "category-theme"; | |
break; | |
case "plugin": | |
pluginArray = []; | |
currentArray = pluginArray; | |
currentCat = "category-plugin"; | |
break; | |
case "userstyle": | |
userstyleArray = []; | |
currentArray = userstyleArray; | |
currentCat = "category-userstyle"; | |
break; | |
case "service": | |
serviceArray = []; | |
currentArray = serviceArray; | |
currentCat = "category-service"; | |
break; | |
case "greasemonkey-user-script": | |
userscriptArray = []; | |
currentArray = userscriptArray; | |
currentCat = "category-greasemonkey-user-script"; | |
break; | |
case "userscript": | |
scriptishArray = []; | |
currentArray = scriptishArray; | |
currentCat = "category-userscript"; | |
break; | |
case "custombuttons": | |
custombuttonsArray = []; | |
currentArray = custombuttonsArray; | |
currentCat = "category-custombuttons"; | |
break; | |
case "dictionary": | |
dictionaryArray = []; | |
currentArray = dictionaryArray; | |
currentCat = "category-dictionary"; | |
break; | |
case "locale": | |
localeArray = []; | |
currentArray = localeArray; | |
currentCat = "category-locale"; | |
break; | |
} | |
var i; | |
// need to recheck pref, since we're not using pref observer | |
var prefs = Components.classes["@mozilla.org/preferences-service;1"] | |
.getService(Components.interfaces.nsIPrefService); | |
prefs = prefs.getBranch("extensions.addonsmgrhilte@cfl."); | |
showVersionNumber = prefs.getBoolPref("showVersion"); | |
for (i = 0; i < addons.length; i++) { | |
if (showVersionNumber && addons[i].version) { | |
currentArray.push(addons[i].name + spacer + addons[i].version); | |
} else { | |
currentArray.push(addons[i].name); | |
} // for vers # opt off | |
if (UIextra && hiliteArray[supportedCats.indexOf(currentCat)] == addons[i].id) { | |
// if this is the previously hilited item, add it to the top of list for easy access | |
var entry = "<" + addons[i].name; | |
if (showVersionNumber) { | |
entry = entry + spacer + addons[i].version; | |
} | |
entry = entry + ">"; | |
currentArray.unshift(entry); | |
} | |
} | |
// wait for all 5 requests to arrive | |
if (!(extArray || themeArray || pluginArray || userstyleArray || serviceArray || | |
userscriptArray || scriptishArray || custombuttonsArray || dictionaryArray || localeArray)) { | |
return; | |
} | |
var acAddonList = AMdoc.getElementById("aomhilite_ac_menu"); | |
var cat = AMdoc.getElementById("categories"); | |
var selCat = cat.selectedItem.id; | |
if (acAddonList) { | |
switch (selCat) { | |
case "category-extension": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(extArray)); | |
break; | |
case "category-theme": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(themeArray)); | |
break; | |
case "category-plugin": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(pluginArray)); | |
break; | |
case "category-userstyle": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(userstyleArray)); | |
break; | |
case "category-service": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(serviceArray)); | |
break; | |
case "category-greasemonkey-user-script": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(userscriptArray)); | |
break; | |
case "category-userscript": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(scriptishArray)); | |
break; | |
case "category-custombuttons": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(custombuttonsArray)); | |
break; | |
case "category-dictionary": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(dictionaryArray)); | |
break; | |
case "category-locale": | |
acAddonList.setAttribute("autocompletesearchparam", JSON.stringify(localeArray)); | |
break; | |
} | |
} | |
var view = AMdoc.getElementById('view-port'); | |
// check if we're in list view of a supported category; sort and hilite | |
if ((supportedCats.indexOf(selCat) != -1) && view.getAttribute('selectedIndex') == LISTVIEW) { | |
if (selCat == "category-userstyle" || selCat == "category-greasemonkey-user-script" || | |
selCat == "category-custombuttons") { | |
dontSort = true; | |
} | |
if (doAlphaSort || updatedSort) { | |
resort(AMdoc); | |
} | |
restoreHilite(AMdoc); | |
} | |
if (acAddonList && supportedCats.indexOf(selCat) != -1) { | |
acAddonList.removeAttribute('hidden'); // hide ac menu in unsupported categories | |
} else if (acAddonList) { | |
acAddonList.setAttribute('hidden', true); | |
} | |
} | |
function AddonsMgrOnUnload() { | |
AddonManager.removeAddonListener(addonListener); | |
this.removeEventListener("unload", AddonsMgrOnUnload, false); | |
this.removeEventListener("ViewChanged", onViewChange, false); | |
var addonList = this.document.getElementById("addon-list"); | |
addonList.removeEventListener("select", onSelect, false); | |
var acAddonList = this.document.getElementById("aomhilite_ac_menu"); | |
if (acAddonList) { | |
acAddonList.removeEventListener("textentered", onACaddonListSelection, false); | |
acAddonList.removeEventListener("change", onACaddonListSelection, false); | |
acAddonList.popup.removeEventListener("click", onACaddonListSelection, false); | |
var arrow = this.document.getAnonymousElementByAttribute(acAddonList, "anonid", "historydropmarker"); | |
if (arrow && displayDropdown) { | |
arrow.removeEventListener("click", displayDropdown, false); | |
displayDropdown = null; | |
} | |
var head = this.document.getElementById("header"); | |
head.removeChild(acAddonList); | |
} | |
if (UIextra && addonList.hasAttribute("restoreondemand")) { | |
// save needed info to aomhite so it will survive fx restart | |
var savedSelections = addonList.getAttribute('aomhilite'); | |
var selectionArray = savedSelections.split(","); | |
var prevHilites = addonList.getAttribute('restoreondemand'); | |
var hiliteArray = prevHilites.split(","); | |
// save previous category selections until new ones have been made | |
var i; | |
for (i = 0; i < hiliteArray.length; i++) { | |
if (hiliteArray[i] && !selectionArray[i]) { | |
selectionArray[i] = hiliteArray[i]; | |
} | |
} | |
var selectionsToSave = selectionArray.toString(); | |
addonList.setAttribute('aomhilite', selectionsToSave); | |
} | |
extArray = null; | |
themeArray = null; | |
pluginArray = null; | |
userstyleArray = null; | |
serviceArray = null; | |
userscriptArray = null; | |
scriptishArray = null; | |
custombuttonsArray = null; | |
dictionaryArray = null; | |
localeArray = null; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment