home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 May / maximum-cd-2009-05.iso / DiscContents / Firefox Setup 3.0.6.exe / nonlocalized / chrome / toolkit.jar / content / mozapps / extensions / extensions.js < prev    next >
Encoding:
Text File  |  2008-05-09  |  100.6 KB  |  2,761 lines

  1. //@line 40 "/e/fx19rel/WINNT_5.2_Depend/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  2.  
  3. ///////////////////////////////////////////////////////////////////////////////
  4. // Globals
  5. const nsIExtensionManager    = Components.interfaces.nsIExtensionManager;
  6. const nsIUpdateItem          = Components.interfaces.nsIUpdateItem;
  7. const nsIFilePicker          = Components.interfaces.nsIFilePicker;
  8. const nsIIOService           = Components.interfaces.nsIIOService;
  9. const nsIFileProtocolHandler = Components.interfaces.nsIFileProtocolHandler;
  10. const nsIURL                 = Components.interfaces.nsIURL;
  11. const nsIAppStartup          = Components.interfaces.nsIAppStartup;
  12.  
  13. var gView             = null;
  14. var gExtensionManager = null;
  15. var gExtensionsView   = null;
  16. var gExtensionStrings = null;
  17. var gCurrentTheme     = "classic/1.0";
  18. var gDefaultTheme     = "classic/1.0";
  19. var gDownloadManager  = null;
  20. var gObserverIndex    = -1;
  21. var gInSafeMode       = false;
  22. var gCheckCompat      = true;
  23. var gCheckUpdateSecurity = true;
  24. var gUpdatesOnly      = false;
  25. var gAppID            = "";
  26. var gPref             = null;
  27. var gPriorityCount    = 0;
  28. var gInstalling       = false;
  29. var gPendingActions   = false;
  30. var gPlugins          = null;
  31. var gPluginsDS        = null;
  32. var gSearchDS         = null;
  33. var gAddonRepository  = null;
  34. var gShowGetAddonsPane = false;
  35. var gRetrievedResults = false;
  36. var gRecommendedAddons = null;
  37. var gRDF              = null;
  38. var gPendingInstalls  = {};
  39. var gNewAddons        = [];
  40.  
  41. const PREF_EM_CHECK_COMPATIBILITY           = "extensions.checkCompatibility";
  42. const PREF_EM_CHECK_UPDATE_SECURITY         = "extensions.checkUpdateSecurity";
  43. const PREF_EXTENSIONS_GETMORETHEMESURL      = "extensions.getMoreThemesURL";
  44. const PREF_EXTENSIONS_GETMOREEXTENSIONSURL  = "extensions.getMoreExtensionsURL";
  45. const PREF_EXTENSIONS_GETMOREPLUGINSURL     = "extensions.getMorePluginsURL";
  46. const PREF_EXTENSIONS_DSS_ENABLED           = "extensions.dss.enabled";
  47. const PREF_EXTENSIONS_DSS_SWITCHPENDING     = "extensions.dss.switchPending";
  48. const PREF_EXTENSIONS_HIDE_INSTALL_BTN      = "extensions.hideInstallButton";
  49. const PREF_DSS_SKIN_TO_SELECT               = "extensions.lastSelectedSkin";
  50. const PREF_GENERAL_SKINS_SELECTEDSKIN       = "general.skins.selectedSkin";
  51. const PREF_UPDATE_NOTIFYUSER                = "extensions.update.notifyUser";
  52. const PREF_GETADDONS_SHOWPANE               = "extensions.getAddons.showPane";
  53. const PREF_GETADDONS_REPOSITORY             = "extensions.getAddons.repository";
  54. const PREF_GETADDONS_MAXRESULTS             = "extensions.getAddons.maxResults";
  55.  
  56. const URI_GENERIC_ICON_XPINSTALL      = "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png";
  57. const URI_GENERIC_ICON_THEME          = "chrome://mozapps/skin/extensions/themeGeneric.png";
  58.  
  59. //@line 101 "/e/fx19rel/WINNT_5.2_Depend/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  60. const URI_NOTIFICATION_ICON_INFO      = "chrome://global/skin/icons/information-16.png";
  61. const URI_NOTIFICATION_ICON_WARNING   = "chrome://global/skin/icons/warning-16.png";
  62. //@line 104 "/e/fx19rel/WINNT_5.2_Depend/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  63.  
  64. const RDFURI_ITEM_ROOT    = "urn:mozilla:item:root";
  65. const PREFIX_ITEM_URI     = "urn:mozilla:item:";
  66. const PREFIX_NS_EM        = "http://www.mozilla.org/2004/em-rdf#";
  67. const kXULNSURI           = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  68. const XMLURI_PARSE_ERROR  = "http://www.mozilla.org/newlayout/xml/parsererror.xml"
  69.  
  70. const OP_NONE                         = "";
  71. const OP_NEEDS_INSTALL                = "needs-install";
  72. const OP_NEEDS_UPGRADE                = "needs-upgrade";
  73. const OP_NEEDS_UNINSTALL              = "needs-uninstall";
  74. const OP_NEEDS_ENABLE                 = "needs-enable";
  75. const OP_NEEDS_DISABLE                = "needs-disable";
  76.  
  77. Components.utils.import("resource://gre/modules/PluralForm.jsm");
  78. Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
  79.  
  80. ///////////////////////////////////////////////////////////////////////////////
  81. // Utility Functions
  82. function setElementDisabledByID(aID, aDoDisable) {
  83.   var element = document.getElementById(aID);
  84.   if (element) {
  85.     if (aDoDisable)
  86.       element.setAttribute("disabled", "true");
  87.     else
  88.       element.removeAttribute("disabled");
  89.   }
  90. }
  91.  
  92. /**
  93.  * This returns the richlistitem element for the theme with the given
  94.  * internalName
  95.  */
  96. function getItemForInternalName(aInternalName) {
  97.   var property = gRDF.GetResource(PREFIX_NS_EM + "internalName");
  98.   var name = gRDF.GetLiteral(aInternalName);
  99.   var id = gExtensionManager.datasource.GetSource(property, name, true)
  100.   if (id && id instanceof Components.interfaces.nsIRDFResource)
  101.     return document.getElementById(id.ValueUTF8);
  102.   return null;
  103. }
  104.  
  105. function isSafeURI(aURI) {
  106.   try {
  107.     var uri = makeURI(aURI);
  108.     var scheme = uri.scheme;
  109.   } catch (ex) {}
  110.   return (uri && (scheme == "http" || scheme == "https" || scheme == "ftp"));
  111. }
  112.  
  113. function getBrandShortName() {
  114.   var brandStrings = document.getElementById("brandStrings");
  115.   return brandStrings.getString("brandShortName");
  116. }
  117.  
  118. function getExtensionString(key, strings) {
  119.   if (strings)
  120.     return gExtensionStrings.getFormattedString(key, strings);
  121.   return gExtensionStrings.getString(key);
  122. }
  123.  
  124. function MessageButton(aLabel, aAccesskey, aData) {
  125.   this.label = aLabel;
  126.   this.accessKey = aAccesskey;
  127.   this.data = aData || "addons-message-dismiss";
  128. }
  129. MessageButton.prototype = {
  130.   label: null,
  131.   accessKey: null,
  132.   data: null,
  133.  
  134.   callback: function (aNotification, aButton) {
  135.     var os = Components.classes["@mozilla.org/observer-service;1"]
  136.                        .getService(Components.interfaces.nsIObserverService);
  137.     os.notifyObservers(null, "addons-message-notification", aButton.data);
  138.     aNotification.close();
  139.     return true;
  140.   }
  141. };
  142.  
  143. function showMessage(aIconURL, aMessage, aButtonLabel, aButtonAccesskey,
  144.                      aShowCloseButton, aNotifyData) {
  145.   var addonsMsg = document.getElementById("addonsMsg");
  146.   var buttons = null;
  147.   if (aButtonLabel)
  148.     buttons = [new MessageButton(aButtonLabel, aButtonAccesskey, aNotifyData)];
  149.   var oldMessage = addonsMsg.getNotificationWithValue(aMessage);
  150.   if (oldMessage && oldMessage.parentNode)
  151.     addonsMsg.removeNotification(oldMessage);
  152.   if (addonsMsg.currentNotification)
  153.     gPriorityCount += 0.0001;
  154.   else
  155.     gPriorityCount = 0;
  156.   addonsMsg.appendNotification(aMessage, aMessage, aIconURL,
  157.                                addonsMsg.PRIORITY_WARNING_LOW + gPriorityCount,
  158.                                buttons).hideclose = !aShowCloseButton;
  159. }
  160.  
  161. // dynamically creates a template
  162. var AddonsViewBuilder = {
  163.   // if aActionList is null aBindingList will be used to generate actions
  164.   updateView: function(aRulesList, aURIList, aBindingList, aActionList)
  165.   {
  166.     var actionList = aActionList ? aActionList : aBindingList;
  167.  
  168.     this.clearChildren(gExtensionsView);
  169.     var template = document.createElementNS(kXULNSURI, "template");
  170.     gExtensionsView.appendChild(template);
  171.     for (var i = 0; i < aRulesList.length; ++i)
  172.       template.appendChild(this.createRule(aRulesList[i], aURIList[i], aBindingList[i], actionList[i]));
  173.  
  174.     gExtensionsView.builder.rebuild();
  175.   },
  176.  
  177.   clearChildren: function(aEl)
  178.   {
  179.     while (aEl.hasChildNodes())
  180.       aEl.removeChild(aEl.lastChild);
  181.   },
  182.  
  183.   createRule: function(aTriplesList, aURI, aBindingList, aActionList)
  184.   {
  185.     var rule = document.createElementNS(kXULNSURI, "rule");
  186.     var conditions = document.createElementNS(kXULNSURI, "conditions");
  187.     rule.appendChild(conditions);
  188.  
  189.     var content = document.createElementNS(kXULNSURI, "content");
  190.     content.setAttribute("uri", "?uri");
  191.     conditions.appendChild(content);
  192.  
  193.     var member = this.createMember("?uri", "?" + aURI);
  194.     conditions.appendChild(member);
  195.  
  196.     for (var i = 0; i < aTriplesList.length; ++i)
  197.       conditions.appendChild(this.createTriple("?" + aURI, PREFIX_NS_EM + aTriplesList[i][0], aTriplesList[i][1], aTriplesList[i][2]));
  198.  
  199.     var bindings = document.createElementNS(kXULNSURI, "bindings");
  200.     rule.appendChild(bindings);
  201.     for (i = 0; i < aBindingList.length; ++i)
  202.       bindings.appendChild(this.createBinding(aBindingList[i], aURI));
  203.  
  204.     var action = document.createElementNS(kXULNSURI, "action");
  205.     rule.appendChild(action);
  206.     var extension = document.createElementNS(kXULNSURI, aURI);
  207.     action.appendChild(extension);
  208.     extension.setAttribute("uri", "?" + aURI);
  209.     for (i = 0; i < aActionList.length; ++i)
  210.       extension.setAttribute(aActionList[i][0], aActionList[i][1]);
  211.  
  212.     return rule;
  213.   },
  214.  
  215.   createTriple: function(aSubject, aPredicate, aObject, aParseType)
  216.   {
  217.     var triple = document.createElementNS(kXULNSURI, "triple");
  218.     triple.setAttribute("subject", aSubject);
  219.     triple.setAttribute("predicate", aPredicate);
  220.     triple.setAttribute("object", aObject);
  221.     if (aParseType)
  222.       triple.setAttribute("parsetype", aParseType);
  223.     return triple;
  224.   },
  225.  
  226.   createBinding: function(aPredicateObjectList, aURI)
  227.   {
  228.     var binding = document.createElementNS(kXULNSURI, "binding");
  229.     binding.setAttribute("subject", "?" + aURI);
  230.     binding.setAttribute("predicate", PREFIX_NS_EM + aPredicateObjectList[0]);
  231.     binding.setAttribute("object", aPredicateObjectList[1]);
  232.     return binding;
  233.   },
  234.  
  235.   createMember: function(aContainer, aChild)
  236.   {
  237.     var member = document.createElementNS(kXULNSURI, "member");
  238.     member.setAttribute("container", aContainer);
  239.     member.setAttribute("child", aChild);
  240.  
  241.     return member;
  242.   }
  243. };
  244.  
  245. function showView(aView) {
  246.   if (gView == aView)
  247.     return;
  248.  
  249.   updateLastSelected(aView);
  250.   gView = aView;
  251.  
  252.   // Using disabled to represent add-on state in regards to the EM causes evil
  253.   // focus behavior when used as an element attribute when the element isn't
  254.   // really disabled.
  255.   var bindingList = [ [ ["aboutURL", "?aboutURL"],
  256.                         ["addonID", "?addonID"],
  257.                         ["availableUpdateURL", "?availableUpdateURL"],
  258.                         ["availableUpdateVersion", "?availableUpdateVersion"],
  259.                         ["blocklisted", "?blocklisted"],
  260.                         ["compatible", "?compatible"],
  261.                         ["description", "?description"],
  262.                         ["downloadURL", "?downloadURL"],
  263.                         ["isDisabled", "?isDisabled"],
  264.                         ["hidden", "?hidden"],
  265.                         ["homepageURL", "?homepageURL"],
  266.                         ["iconURL", "?iconURL"],
  267.                         ["internalName", "?internalName"],
  268.                         ["locked", "?locked"],
  269.                         ["name", "?name"],
  270.                         ["optionsURL", "?optionsURL"],
  271.                         ["opType", "?opType"],
  272.                         ["plugin", "?plugin"],
  273.                         ["previewImage", "?previewImage"],
  274.                         ["satisfiesDependencies", "?satisfiesDependencies"],
  275.                         ["providesUpdatesSecurely", "?providesUpdatesSecurely"],
  276.                         ["type", "?type"],
  277.                         ["updateable", "?updateable"],
  278.                         ["updateURL", "?updateURL"],
  279.                         ["version", "?version"] ] ];
  280.   var displays = [ "richlistitem" ];
  281.  
  282.   var prefURL;
  283.   var showInstallFile = true;
  284.   try {
  285.     showInstallFile = !gPref.getBoolPref(PREF_EXTENSIONS_HIDE_INSTALL_BTN);
  286.   }
  287.   catch (e) { }
  288.   var showCheckUpdatesAll = true;
  289.   var showInstallUpdatesAll = false;
  290.   var showSkip = false;
  291.   var showContinue = false;
  292.   switch (aView) {
  293.     case "search":
  294.       var bindingList = [ [ ["action", "?action"],
  295.                             ["addonID", "?addonID"],
  296.                             ["description", "?description"],
  297.                             ["eula", "?eula"],
  298.                             ["homepageURL", "?homepageURL"],
  299.                             ["iconURL", "?iconURL"],
  300.                             ["name", "?name"],
  301.                             ["previewImage", "?previewImage"],
  302.                             ["rating", "?rating"],
  303.                             ["addonType", "?addonType"],
  304.                             ["thumbnailURL", "?thumbnailURL"],
  305.                             ["version", "?version"],
  306.                             ["xpiHash", "?xpiHash"],
  307.                             ["xpiURL", "?xpiURL"],
  308.                             ["typeName", "searchResult"] ],
  309.                           [ ["type", "?type"],
  310.                             ["typeName", "status"],
  311.                             ["count", "?count"],
  312.                             ["link", "?link" ] ] ];
  313.       var types = [ [ ["searchResult", "true", null] ],
  314.                     [ ["statusMessage", "true", null] ] ];
  315.       var displays = [ "richlistitem", "vbox" ];
  316.       showCheckUpdatesAll = false;
  317.       document.getElementById("searchbox").disabled = isOffline("offlineSearchMsg");
  318.       break;
  319.     case "extensions":
  320.       prefURL = PREF_EXTENSIONS_GETMOREEXTENSIONSURL;
  321.       types = [ [ ["type", nsIUpdateItem.TYPE_EXTENSION, "Integer"] ] ];
  322.       break;
  323.     case "themes":
  324.       prefURL = PREF_EXTENSIONS_GETMORETHEMESURL;
  325.       types = [ [ ["type", nsIUpdateItem.TYPE_THEME, "Integer"] ] ];
  326.       break;
  327.     case "locales":
  328.       types = [ [ ["type", nsIUpdateItem.TYPE_LOCALE, "Integer"] ] ];
  329.       break;
  330.     case "plugins":
  331.       prefURL = PREF_EXTENSIONS_GETMOREPLUGINSURL;
  332.       types = [ [ ["plugin", "true", null] ] ];
  333.       showCheckUpdatesAll = false;
  334.       break;
  335.     case "updates":
  336.       document.getElementById("updates-view").hidden = false;
  337.       showInstallFile = false;
  338.       showCheckUpdatesAll = false;
  339.       showInstallUpdatesAll = true;
  340.       if (gUpdatesOnly)
  341.         showSkip = true;
  342.       bindingList = [ [ ["aboutURL", "?aboutURL"],
  343.                         ["availableUpdateURL", "?availableUpdateURL"],
  344.                         ["availableUpdateVersion", "?availableUpdateVersion"],
  345.                         ["availableUpdateInfo", "?availableUpdateInfo"],
  346.                         ["blocklisted", "?blocklisted"],
  347.                         ["homepageURL", "?homepageURL"],
  348.                         ["iconURL", "?iconURL"],
  349.                         ["internalName", "?internalName"],
  350.                         ["locked", "?locked"],
  351.                         ["name", "?name"],
  352.                         ["opType", "?opType"],
  353.                         ["previewImage", "?previewImage"],
  354.                         ["satisfiesDependencies", "?satisfiesDependencies"],
  355.                         ["providesUpdatesSecurely", "?providesUpdatesSecurely"],
  356.                         ["type", "?type"],
  357.                         ["updateURL", "?updateURL"],
  358.                         ["version", "?version"],
  359.                         ["typeName", "update"] ] ];
  360.       types = [ [ ["availableUpdateVersion", "?availableUpdateVersion", null],
  361.                   ["updateable", "true", null] ] ];
  362.       break;
  363.     case "installs":
  364.       document.getElementById("installs-view").hidden = false;
  365.       showInstallFile = false;
  366.       showCheckUpdatesAll = false;
  367.       showInstallUpdatesAll = false;
  368.       if (gUpdatesOnly)
  369.         showContinue = true;
  370.       bindingList = [ [ ["aboutURL", "?aboutURL"],
  371.                         ["addonID", "?addonID"],
  372.                         ["availableUpdateURL", "?availableUpdateURL"],
  373.                         ["availableUpdateVersion", "?availableUpdateVersion"],
  374.                         ["blocklisted", "?blocklisted"],
  375.                         ["compatible", "?compatible"],
  376.                         ["description", "?description"],
  377.                         ["downloadURL", "?downloadURL"],
  378.                         ["incompatibleUpdate", "?incompatibleUpdate"],
  379.                         ["isDisabled", "?isDisabled"],
  380.                         ["hidden", "?hidden"],
  381.                         ["homepageURL", "?homepageURL"],
  382.                         ["iconURL", "?iconURL"],
  383.                         ["internalName", "?internalName"],
  384.                         ["locked", "?locked"],
  385.                         ["name", "?name"],
  386.                         ["optionsURL", "?optionsURL"],
  387.                         ["opType", "?opType"],
  388.                         ["previewImage", "?previewImage"],
  389.                         ["progress", "?progress"],
  390.                         ["state", "?state"],
  391.                         ["type", "?type"],
  392.                         ["updateable", "?updateable"],
  393.                         ["updateURL", "?updateURL"],
  394.                         ["version", "?version"],
  395.                         ["newVersion", "?newVersion"],
  396.                         ["typeName", "install"] ] ];
  397.       types = [ [ ["state", "?state", null] ] ];
  398.       break;
  399.   }
  400.  
  401.   var showGetMore = false;
  402.   var getMore = document.getElementById("getMore");
  403.   if (prefURL && !gShowGetAddonsPane) {
  404.     try {
  405.       getMore.setAttribute("value", getMore.getAttribute("value" + aView));
  406.       var getMoreURL = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
  407.                                  .getService(Components.interfaces.nsIURLFormatter)
  408.                                  .formatURLPref(prefURL);
  409.       getMore.setAttribute("getMoreURL", getMoreURL);
  410.       showGetMore = getMoreURL == "about:blank" ? false : true;
  411.     }
  412.     catch (e) { }
  413.   }
  414.   getMore.hidden = !showGetMore;
  415.  
  416.   var isThemes = aView == "themes";
  417.  
  418.   if (aView == "themes" || aView == "extensions") {
  419.     var el = document.getElementById("installFileButton");
  420.     el.setAttribute("tooltiptext", el.getAttribute(isThemes ? "tooltiptextthemes" :
  421.                                                               "tooltiptextaddons"));
  422.     el = document.getElementById("checkUpdatesAllButton");
  423.     el.setAttribute("tooltiptext", el.getAttribute(isThemes ? "tooltiptextthemes" :
  424.                                                               "tooltiptextaddons"));
  425.   }
  426.  
  427.   document.getElementById("installFileButton").hidden = !showInstallFile;
  428.   document.getElementById("checkUpdatesAllButton").hidden = !showCheckUpdatesAll;
  429.   document.getElementById("installUpdatesAllButton").hidden = !showInstallUpdatesAll;
  430.   document.getElementById("skipDialogButton").hidden = !showSkip;
  431.   document.getElementById("continueDialogButton").hidden = !showContinue;
  432.   document.getElementById("themePreviewArea").hidden = !isThemes;
  433.   document.getElementById("themeSplitter").hidden = !isThemes;
  434.   document.getElementById("showUpdateInfoButton").hidden = aView != "updates";
  435.   document.getElementById("hideUpdateInfoButton").hidden = true;
  436.   document.getElementById("searchPanel").hidden = aView != "search";
  437.  
  438.   AddonsViewBuilder.updateView(types, displays, bindingList, null);
  439.  
  440.   if (aView == "updates" || aView == "installs")
  441.     gExtensionsView.selectedItem = gExtensionsView.children[0];
  442.  
  443.   if (showSkip) {
  444.     var button = document.getElementById("installUpdatesAllButton");
  445.     button.setAttribute("default", "true");
  446.     window.setTimeout(function () { button.focus(); }, 0);
  447.   } else
  448.     document.getElementById("installUpdatesAllButton").removeAttribute("default");
  449.  
  450.   if (showContinue)
  451.     document.getElementById("continueDialogButton").setAttribute("default", "true");
  452.   else
  453.     document.getElementById("continueDialogButton").removeAttribute("default");
  454.  
  455.   if (isThemes)
  456.     onAddonSelect();
  457.   updateGlobalCommands();
  458. }
  459.  
  460. // manages the last-selected attribute for the view buttons and richlistbox
  461. function updateLastSelected(aView) {
  462.   var viewGroup = document.getElementById("viewGroup");
  463.   if (viewGroup.hasAttribute("last-selected"))
  464.     var lastSelectedView = viewGroup.getAttribute("last-selected");
  465.  
  466.   if (lastSelectedView && lastSelectedView == gView) {
  467.     var lastViewButton = document.getElementById(lastSelectedView + "-view");
  468.     if (lastViewButton.hasAttribute("persist")) {
  469.       if (gExtensionsView.selectedItem)
  470.         lastViewButton.setAttribute("last-selected", gExtensionsView.selectedItem.id);
  471.       else if (lastViewButton.hasAttribute("last-selected"))
  472.         lastViewButton.removeAttribute("last-selected");
  473.     }
  474.   }
  475.   var viewButton = document.getElementById(aView + "-view");
  476.   if (viewButton.hasAttribute("last-selected")) {
  477.     gExtensionsView.setAttribute("last-selected", viewButton.getAttribute("last-selected"));
  478.   }
  479.   else if (gExtensionsView.hasAttribute("last-selected")) {
  480.     gExtensionsView.clearSelection();
  481.     gExtensionsView.removeAttribute("last-selected");
  482.   }
  483.   viewGroup.selectedItem = viewButton;
  484.   // Only set last-selected for view buttons that have a persist attribute
  485.   // (e.g. they themselves persist the last selected add-on in the view).
  486.   // This prevents opening updates and installs views when they were the last
  487.   // view selected and instead this will open the previously selected
  488.   // extensions, themes, locales, plug-ins, etc. view.
  489.   if (viewButton.hasAttribute("persist"))
  490.     viewGroup.setAttribute("last-selected", aView);
  491. }
  492.  
  493. function LOG(msg) {
  494.   dump("*** " + msg + "\n");
  495. }
  496.  
  497. function getIDFromResourceURI(aURI)
  498. {
  499.   if (aURI.substring(0, PREFIX_ITEM_URI.length) == PREFIX_ITEM_URI)
  500.     return aURI.substring(PREFIX_ITEM_URI.length);
  501.   return aURI;
  502. }
  503.  
  504. function showProgressBar() {
  505.   var progressBox = document.getElementById("progressBox");
  506.   var height = document.defaultView.getComputedStyle(progressBox.parentNode, "")
  507.                        .getPropertyValue("height");
  508.   progressBox.parentNode.style.height = height;
  509.   document.getElementById("viewGroup").hidden = true;
  510.   progressBox.hidden = false;
  511. }
  512.  
  513. function flushDataSource()
  514. {
  515.   var rds = gExtensionManager.datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
  516.   if (rds)
  517.     rds.Flush();
  518. }
  519.  
  520. function noUpdatesDismiss(aEvent)
  521. {
  522.   window.removeEventListener("select", noUpdatesDismiss, true);
  523.  
  524.   var children = gExtensionsView.children;
  525.   for (var i = 0; i < children.length; ++i) {
  526.     var child = children[i];
  527.     if (child.hasAttribute("updateStatus"))
  528.       child.removeAttribute("updateStatus");
  529.   }
  530.  
  531.   if (aEvent.target.localName != "notification")
  532.     document.getElementById("addonsMsg").removeCurrentNotification();
  533. }
  534.  
  535. function clearRestartMessage()
  536. {
  537.   var children = gExtensionsView.children;
  538.   for (var i = 0; i < children.length; ++i) {
  539.     var item = children[i];
  540.     if (item.hasAttribute("oldDescription")) {
  541.       item.setAttribute("description", item.getAttribute("oldDescription"));
  542.       item.removeAttribute("oldDescription");
  543.     }
  544.   }
  545. }
  546.  
  547. function setRestartMessage(aItem)
  548. {
  549.   var themeName = aItem.getAttribute("name");
  550.   var restartMessage = getExtensionString("dssSwitchAfterRestart",
  551.                                           [getBrandShortName()]);
  552.   aItem.setAttribute("oldDescription", aItem.getAttribute("description"));
  553.   aItem.setAttribute("description", restartMessage);
  554. }
  555.  
  556. // Removes any assertions in the datasource about a given resource
  557. function cleanResource(ds, resource) {
  558.   // Remove outward arcs
  559.   var arcs = ds.ArcLabelsOut(resource);
  560.   while (arcs.hasMoreElements()) {
  561.     var arc = arcs.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  562.     var targets = ds.GetTargets(resource, arc, true);
  563.     while (targets.hasMoreElements()) {
  564.       var value = targets.getNext().QueryInterface(Components.interfaces.nsIRDFNode);
  565.       if (value)
  566.         ds.Unassert(resource, arc, value);
  567.     }
  568.   }
  569. }
  570.  
  571. // Wipes the datasource clean of assertions
  572. function cleanDataSource(ds, rootctr) {
  573.   // Remove old entries from the list
  574.   var nodes = rootctr.GetElements();
  575.   while (nodes.hasMoreElements()) {
  576.     var node = nodes.getNext()
  577.                     .QueryInterface(Components.interfaces.nsIRDFResource);
  578.     rootctr.RemoveElement(node, false);
  579.     cleanResource(ds, node);
  580.   }
  581. }
  582.  
  583. // Displays the search status message
  584. function displaySearchThrobber(aKey) {
  585.   var rdfCU = Components.classes["@mozilla.org/rdf/container-utils;1"]
  586.                         .getService(Components.interfaces.nsIRDFContainerUtils);
  587.   var rootctr = rdfCU.MakeSeq(gSearchDS, gRDF.GetResource(RDFURI_ITEM_ROOT));
  588.  
  589.   cleanDataSource(gSearchDS, rootctr);
  590.  
  591.   var labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:header");
  592.   rootctr.AppendElement(labelNode);
  593.   gSearchDS.Assert(labelNode,
  594.                    gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
  595.                    gRDF.GetLiteral("true"),
  596.                    true);
  597.   gSearchDS.Assert(labelNode,
  598.                    gRDF.GetResource(PREFIX_NS_EM + "type"),
  599.                    gRDF.GetLiteral(aKey),
  600.                    true);
  601. }
  602.  
  603. // Clears the search box and updates the result list
  604. function resetSearch() {
  605.   var searchbox = document.getElementById("searchbox");
  606.   searchbox.value = "";
  607.   searchbox.focus();
  608.   retrieveRepositoryAddons("");
  609. }
  610.  
  611. // Searches for results
  612. function retrieveRepositoryAddons(aTerms) {
  613.   if (gAddonRepository.isSearching)
  614.     gAddonRepository.cancelSearch();
  615.   if (aTerms) {
  616.     displaySearchThrobber("retrieve-search");
  617.     gAddonRepository.searchAddons(aTerms,
  618.                                   gPref.getIntPref(PREF_GETADDONS_MAXRESULTS),
  619.                                   AddonSearchResults);
  620.   }
  621.   else {
  622.     if (gRecommendedAddons) {
  623.       displaySearchResults(gRecommendedAddons, -1, true);
  624.     }
  625.     else {
  626.       displaySearchThrobber("retrieve-recommended");
  627.       gAddonRepository.retrieveRecommendedAddons(gPref.getIntPref(PREF_GETADDONS_MAXRESULTS),
  628.                                                  RecommendedSearchResults);
  629.     }
  630.   }
  631.   gRetrievedResults = true;
  632. }
  633.  
  634. // Puts search results into the search datasource
  635. function displaySearchResults(addons, count, isRecommended) {
  636.   var rdfCU = Components.classes["@mozilla.org/rdf/container-utils;1"]
  637.                         .getService(Components.interfaces.nsIRDFContainerUtils);
  638.   var rootctr = rdfCU.MakeSeq(gSearchDS, gRDF.GetResource(RDFURI_ITEM_ROOT));
  639.  
  640.   gSearchDS.beginUpdateBatch();
  641.  
  642.   cleanDataSource(gSearchDS, rootctr);
  643.  
  644.   if (isRecommended) {
  645.     var labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:header");
  646.     rootctr.AppendElement(labelNode);
  647.     gSearchDS.Assert(labelNode,
  648.                      gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
  649.                      gRDF.GetLiteral("true"),
  650.                      true);
  651.     gSearchDS.Assert(labelNode,
  652.                      gRDF.GetResource(PREFIX_NS_EM + "type"),
  653.                      gRDF.GetLiteral("header-recommended"),
  654.                      true);
  655.  
  656.     // Case insensitive sort
  657.     function compare(a, b) {
  658.       if (a.name.toLowerCase() < b.name.toLowerCase())
  659.         return -1;
  660.       if (a.name.toLowerCase() > b.name.toLowerCase())
  661.         return 1;
  662.       return 0;
  663.     }
  664.     addons.sort(compare);
  665.   }
  666.   
  667.   if (addons.length == 0 && (isRecommended || count > 0)) {
  668.     var labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:noresults");
  669.     rootctr.AppendElement(labelNode);
  670.     gSearchDS.Assert(labelNode,
  671.                      gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
  672.                      gRDF.GetLiteral("true"),
  673.                      true);
  674.     if (isRecommended) {
  675.       gSearchDS.Assert(labelNode,
  676.                        gRDF.GetResource(PREFIX_NS_EM + "type"),
  677.                        gRDF.GetLiteral("message-norecommended"),
  678.                        true);
  679.     }
  680.     else {
  681.       gSearchDS.Assert(labelNode,
  682.                        gRDF.GetResource(PREFIX_NS_EM + "type"),
  683.                        gRDF.GetLiteral("message-nosearchresults"),
  684.                        true);
  685.     }
  686.   }
  687.  
  688.   var urlproperties = [ "iconURL", "homepageURL", "thumbnailURL", "xpiURL" ];
  689.   var properties = [ "name", "eula", "iconURL", "homepageURL", "thumbnailURL", "xpiURL", "xpiHash" ];
  690.   for (var i = 0; i < addons.length; i++) {
  691.     var addon = addons[i];
  692.     // Strip out any items with potentially unsafe urls
  693.     var unsafe = false;
  694.     for (var j = 0; j < urlproperties.length; j++) {
  695.       if (!isSafeURI(addon[urlproperties[j]])) {
  696.         unsafe = true;
  697.         break;
  698.       }
  699.     }
  700.     if (unsafe)
  701.       continue;
  702.  
  703.     var resultNode = gRDF.GetResource("urn:mozilla:addons:search:" + addon.xpiURL);
  704.     gSearchDS.Assert(resultNode,
  705.                      gRDF.GetResource(PREFIX_NS_EM + "addonID"),
  706.                      gRDF.GetLiteral(addon.id),
  707.                      true);
  708.     // Use the short summary for our "description"
  709.     gSearchDS.Assert(resultNode,
  710.                      gRDF.GetResource(PREFIX_NS_EM + "description"),
  711.                      gRDF.GetLiteral(addon.summary),
  712.                      true);
  713.     gSearchDS.Assert(resultNode,
  714.                      gRDF.GetResource(PREFIX_NS_EM + "addonType"),
  715.                      gRDF.GetIntLiteral(addon.type),
  716.                      true);
  717.     if (addon.rating >= 0) {
  718.       gSearchDS.Assert(resultNode,
  719.                        gRDF.GetResource(PREFIX_NS_EM + "rating"),
  720.                        gRDF.GetIntLiteral(addon.rating),
  721.                        gRDF.GetIntLiteral(3),
  722.                        true);
  723.     }
  724.  
  725.     for (var j = 0; j < properties.length; j++) {
  726.       gSearchDS.Assert(resultNode,
  727.                        gRDF.GetResource(PREFIX_NS_EM + properties[j]),
  728.                        gRDF.GetLiteral(addon[properties[j]]),
  729.                        true);
  730.     }
  731.     gSearchDS.Assert(resultNode,
  732.                      gRDF.GetResource(PREFIX_NS_EM + "searchResult"),
  733.                      gRDF.GetLiteral("true"),
  734.                      true);
  735.     rootctr.AppendElement(resultNode);
  736.   }
  737.  
  738.   labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:footer");
  739.   rootctr.AppendElement(labelNode);
  740.   gSearchDS.Assert(labelNode,
  741.                    gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
  742.                    gRDF.GetLiteral("true"),
  743.                    true);
  744.   if (isRecommended) {
  745.     gSearchDS.Assert(labelNode,
  746.                      gRDF.GetResource(PREFIX_NS_EM + "type"),
  747.                      gRDF.GetLiteral("footer-recommended"),
  748.                      true);
  749.     var url = gAddonRepository.getRecommendedURL();
  750.   }
  751.   else {
  752.     gSearchDS.Assert(labelNode,
  753.                      gRDF.GetResource(PREFIX_NS_EM + "type"),
  754.                      gRDF.GetLiteral("footer-search"),
  755.                      true);
  756.     gSearchDS.Assert(labelNode,
  757.                      gRDF.GetResource(PREFIX_NS_EM + "count"),
  758.                      gRDF.GetIntLiteral(count),
  759.                      true);
  760.     var searchbox = document.getElementById("searchbox");
  761.     // The value attribute will be the persisted value of the last search run
  762.     url = gAddonRepository.getSearchURL(searchbox.getAttribute("value"));
  763.   }
  764.   gSearchDS.Assert(labelNode,
  765.                    gRDF.GetResource(PREFIX_NS_EM + "link"),
  766.                    gRDF.GetLiteral(url),
  767.                    true);
  768.  
  769.   gSearchDS.endUpdateBatch();
  770. }
  771.  
  772. // Displays the search failure status message
  773. function displaySearchFailure(isRecommended) {
  774.   var rdfCU = Components.classes["@mozilla.org/rdf/container-utils;1"]
  775.                         .getService(Components.interfaces.nsIRDFContainerUtils);
  776.   var rootctr = rdfCU.MakeSeq(gSearchDS, gRDF.GetResource(RDFURI_ITEM_ROOT));
  777.  
  778.   cleanDataSource(gSearchDS, rootctr);
  779.  
  780.   var labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:header");
  781.   rootctr.AppendElement(labelNode);
  782.   gSearchDS.Assert(labelNode,
  783.                    gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
  784.                    gRDF.GetLiteral("true"),
  785.                    true);
  786.   gSearchDS.Assert(labelNode,
  787.                    gRDF.GetResource(PREFIX_NS_EM + "type"),
  788.                    gRDF.GetLiteral(isRecommended ? "recommended-failure" : "search-failure"),
  789.                    true);
  790. }
  791.  
  792. // nsIAddonSearchResultsCallback for the recommended search
  793. var RecommendedSearchResults = {
  794.   searchSucceeded: function(aAddons, aAddonCount, aTotalResults) {
  795.     gRecommendedAddons = aAddons;
  796.     displaySearchResults(aAddons, aTotalResults, true);
  797.   },
  798.  
  799.   searchFailed: function() {
  800.     displaySearchFailure(true);
  801.   }
  802. }
  803.  
  804. // nsIAddonSearchResultsCallback for a standard search
  805. var AddonSearchResults = {
  806.   searchSucceeded: function(aAddons, aAddonCount, aTotalResults) {
  807.     displaySearchResults(aAddons, aTotalResults, false);
  808.   },
  809.  
  810.   searchFailed: function() {
  811.     displaySearchFailure(false);
  812.   }
  813. }
  814.  
  815. // Initialises the search repository and the results datasource
  816. function initSearchDS() {
  817.   var repository = "@mozilla.org/extensions/addon-repository;1";
  818.   try {
  819.     var repo = gPref.getCharPref(PREF_GETADDONS_REPOSITORY);
  820.     if (repo in Components.classes)
  821.       repository = repo;
  822.   } catch (e) { }
  823.   gAddonRepository = Components.classes[repository]
  824.                                .createInstance(Components.interfaces.nsIAddonRepository);
  825.   var browseAddons = document.getElementById("browseAddons");
  826.   var homepage = gAddonRepository.homepageURL;
  827.   if (homepage)
  828.     browseAddons.setAttribute("homepageURL", homepage);
  829.   else
  830.     browseAddons.hidden = true;
  831.   gSearchDS = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"]
  832.                         .createInstance(Components.interfaces.nsIRDFDataSource);
  833.   gExtensionsView.database.AddDataSource(gSearchDS);
  834.   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  835.                             .getService(nsIIOService);
  836.   if (!ioService.offline)
  837.     retrieveRepositoryAddons(document.getElementById("searchbox").value);
  838. }
  839.  
  840. function initPluginsDS()
  841. {
  842.   gPluginsDS = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"]
  843.                          .createInstance(Components.interfaces.nsIRDFDataSource);
  844.   rebuildPluginsDS();
  845. }
  846.  
  847. function rebuildPluginsDS()
  848. {
  849.   var phs = Components.classes["@mozilla.org/plugin/host;1"]
  850.                       .getService(Components.interfaces.nsIPluginHost);
  851.   var plugins = phs.getPluginTags({ });
  852.   var rdfCU = Components.classes["@mozilla.org/rdf/container-utils;1"]
  853.                         .getService(Components.interfaces.nsIRDFContainerUtils);
  854.   var rootctr = rdfCU.MakeSeq(gPluginsDS, gRDF.GetResource(RDFURI_ITEM_ROOT));
  855.   gPlugins = { };
  856.   
  857.   // Running in a batch stops the template builder from running
  858.   gPluginsDS.beginUpdateBatch();
  859.  
  860.   cleanDataSource(gPluginsDS, rootctr);
  861.  
  862.   // Case insensitive sort
  863.   function compare(a, b) {
  864.     if (a.name.toLowerCase() < b.name.toLowerCase())
  865.       return -1;
  866.     if (a.name.toLowerCase() > b.name.toLowerCase())
  867.       return 1;
  868.     return 0;
  869.   }
  870.   plugins.sort(compare);
  871.  
  872.   for (var i = 0; i < plugins.length; i++) {
  873.     var plugin = plugins[i];
  874.     var name = plugin.name;
  875.     if (!(name in gPlugins))
  876.       gPlugins[name] = { };
  877.  
  878.     // Removes all html markup in a plugin's description
  879.     var desc = plugin.description.replace(/<\/?[a-z][^>]*>/gi, " ");
  880.     if (!(desc in gPlugins[name])) {
  881.       var homepageURL = null;
  882.       // Some plugins (e.g. QuickTime) add an anchor to their description to
  883.       // provide a link to the plugin's homepage in about:plugins. This can be
  884.       // used to provide access to a plugins homepage in the add-ons mgr.
  885.       if (/<A\s+HREF=[^>]*>/i.test(plugin.description))
  886.         homepageURL = /<A\s+HREF=["']?([^>"'\s]*)/i.exec(plugin.description)[1];
  887.  
  888.       gPlugins[name][desc] = { filename    : plugin.filename,
  889.                                homepageURL : homepageURL,
  890.                                disabled    : plugin.disabled,
  891.                                blocklisted : plugin.blocklisted,
  892.                                plugins     : [] };
  893.     }
  894.     gPlugins[name][desc].plugins.push(plugin);
  895.   }
  896.  
  897.   for (var pluginName in gPlugins) {
  898.     for (var pluginDesc in gPlugins[pluginName]) {
  899.       plugin = gPlugins[pluginName][pluginDesc];
  900.       var pluginNode = gRDF.GetResource(PREFIX_ITEM_URI + plugin.filename);
  901.       rootctr.AppendElement(pluginNode);
  902.       gPluginsDS.Assert(pluginNode,
  903.                         gRDF.GetResource(PREFIX_NS_EM + "name"),
  904.                         gRDF.GetLiteral(pluginName),
  905.                         true);
  906.       gPluginsDS.Assert(pluginNode,
  907.                         gRDF.GetResource(PREFIX_NS_EM + "addonID"),
  908.                         gRDF.GetLiteral(plugin.filename),
  909.                         true);
  910.       gPluginsDS.Assert(pluginNode,
  911.                         gRDF.GetResource(PREFIX_NS_EM + "description"),
  912.                         gRDF.GetLiteral(pluginDesc),
  913.                         true);
  914.       if (plugin.homepageURL)
  915.         gPluginsDS.Assert(pluginNode,
  916.                           gRDF.GetResource(PREFIX_NS_EM + "homepageURL"),
  917.                           gRDF.GetLiteral(plugin.homepageURL),
  918.                           true);
  919.       gPluginsDS.Assert(pluginNode,
  920.                         gRDF.GetResource(PREFIX_NS_EM + "isDisabled"),
  921.                         gRDF.GetLiteral((plugin.disabled ||
  922.                                          plugin.blocklisted) ? "true" : "false"),
  923.                         true);
  924.       gPluginsDS.Assert(pluginNode,
  925.                         gRDF.GetResource(PREFIX_NS_EM + "blocklisted"),
  926.                         gRDF.GetLiteral(plugin.blocklisted ? "true" : "false"),
  927.                         true);
  928.       gPluginsDS.Assert(pluginNode,
  929.                         gRDF.GetResource(PREFIX_NS_EM + "compatible"),
  930.                         gRDF.GetLiteral("true"),
  931.                         true);
  932.       gPluginsDS.Assert(pluginNode,
  933.                         gRDF.GetResource(PREFIX_NS_EM + "plugin"),
  934.                         gRDF.GetLiteral("true"),
  935.                         true);
  936.     }
  937.   }
  938.   
  939.   gPluginsDS.endUpdateBatch();
  940. }
  941.  
  942. function togglePluginDisabled(aName, aDesc)
  943. {
  944.   var plugin = gPlugins[aName][aDesc];
  945.   plugin.disabled = !plugin.disabled;
  946.   for (var i = 0; i < plugin.plugins.length; ++i)
  947.     plugin.plugins[i].disabled = plugin.disabled;
  948.   var isDisabled = plugin.disabled || plugin.blocklisted;
  949.   gPluginsDS.Change(gRDF.GetResource(PREFIX_ITEM_URI + plugin.filename),
  950.                     gRDF.GetResource(PREFIX_NS_EM + "isDisabled"),
  951.                     gRDF.GetLiteral(isDisabled ? "false" : "true"),
  952.                     gRDF.GetLiteral(isDisabled ? "true" : "false"));
  953.   gExtensionsViewController.onCommandUpdate();
  954.   gExtensionsView.selectedItem.focus();
  955. }
  956.  
  957. ///////////////////////////////////////////////////////////////////////////////
  958. // Startup, Shutdown
  959. function Startup()
  960. {
  961.   gExtensionStrings = document.getElementById("extensionsStrings");
  962.   gPref = Components.classes["@mozilla.org/preferences-service;1"]
  963.                     .getService(Components.interfaces.nsIPrefBranch2);
  964.   var defaultPref = gPref.QueryInterface(Components.interfaces.nsIPrefService)
  965.                          .getDefaultBranch(null);
  966.   try {
  967.     gCurrentTheme = gPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  968.     gDefaultTheme = defaultPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  969.     if (gPref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING))
  970.       gCurrentTheme = gPref.getCharPref(PREF_DSS_SKIN_TO_SELECT);
  971.   }
  972.   catch (e) { }
  973.  
  974.   gExtensionsView = document.getElementById("extensionsView");
  975.   gExtensionManager = Components.classes["@mozilla.org/extensions/manager;1"]
  976.                                 .getService(nsIExtensionManager);
  977.   var appInfo = Components.classes["@mozilla.org/xre/app-info;1"]
  978.                           .getService(Components.interfaces.nsIXULAppInfo)
  979.                           .QueryInterface(Components.interfaces.nsIXULRuntime);
  980.   gInSafeMode = appInfo.inSafeMode;
  981.   gAppID = appInfo.ID;
  982.  
  983.   try {
  984.     gCheckCompat = gPref.getBoolPref(PREF_EM_CHECK_COMPATIBILITY);
  985.   } catch(e) { }
  986.  
  987.   try {
  988.     gCheckUpdateSecurity = gPref.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY);
  989.   } catch(e) { }
  990.  
  991.   gPref.addObserver(PREF_DSS_SKIN_TO_SELECT, gPrefObserver, false);
  992.   gPref.addObserver(PREF_GENERAL_SKINS_SELECTEDSKIN, gPrefObserver, false);
  993.  
  994.   try {
  995.     gShowGetAddonsPane = gPref.getBoolPref(PREF_GETADDONS_SHOWPANE);
  996.   } catch(e) { }
  997.  
  998.   // Sort on startup and anytime an add-on is installed or upgraded.
  999.   gExtensionManager.sortTypeByProperty(nsIUpdateItem.TYPE_ANY, "name", true);
  1000.   // Extension Command Updating is handled by a command controller.
  1001.   gExtensionsView.controllers.appendController(gExtensionsViewController);
  1002.   gExtensionsView.addEventListener("select", onAddonSelect, false);
  1003.  
  1004.   gRDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]
  1005.                    .getService(Components.interfaces.nsIRDFService);
  1006.  
  1007.   initPluginsDS();
  1008.   gExtensionsView.database.AddDataSource(gPluginsDS);
  1009.   if (gShowGetAddonsPane)
  1010.     initSearchDS();
  1011.   gExtensionsView.database.AddDataSource(gExtensionManager.datasource);
  1012.   gExtensionsView.setAttribute("ref", RDFURI_ITEM_ROOT);
  1013.  
  1014.   document.getElementById("search-view").hidden = !gShowGetAddonsPane;
  1015.   updateOptionalViews();
  1016.  
  1017.   var viewGroup = document.getElementById("viewGroup");
  1018.  
  1019.   gExtensionsView.focus();
  1020.   gExtensionsViewController.onCommandUpdate();
  1021.  
  1022.   // Now look and see if we're being opened by XPInstall
  1023.   gDownloadManager = new XPInstallDownloadManager();
  1024.   var os = Components.classes["@mozilla.org/observer-service;1"]
  1025.                      .getService(Components.interfaces.nsIObserverService);
  1026.   os.addObserver(gDownloadManager, "xpinstall-download-started", false);
  1027.   os.addObserver(gAddonsMsgObserver, "addons-message-notification", false);
  1028.   os.addObserver(gPluginObserver, "plugins-list-updated", false);
  1029.  
  1030.   gObserverIndex = gExtensionManager.addInstallListener(gDownloadManager);
  1031.  
  1032.   if (!gCheckCompat) {
  1033.     var msgText = getExtensionString("disabledCompatMsg");
  1034.     var buttonLabel = getExtensionString("enableButtonLabel");
  1035.     var buttonAccesskey = getExtensionString("enableButtonAccesskey");
  1036.     var notifyData = "addons-enable-compatibility";
  1037.     showMessage(URI_NOTIFICATION_ICON_WARNING,
  1038.                 msgText, buttonLabel, buttonAccesskey,
  1039.                 true, notifyData);
  1040.   }
  1041.   if (!gCheckUpdateSecurity) {
  1042.     var defaultCheckSecurity = true;
  1043.     try {
  1044.       defaultCheckSecurity = defaultPref.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY);
  1045.     } catch (e) { }
  1046.  
  1047.     // App has update security checking enabled by default so show warning
  1048.     if (defaultCheckSecurity) {
  1049.       var msgText = getExtensionString("disabledUpdateSecurityMsg");
  1050.       var buttonLabel = getExtensionString("enableButtonLabel");
  1051.       var buttonAccesskey = getExtensionString("enableButtonAccesskey");
  1052.       var notifyData = "addons-enable-updatesecurity";
  1053.       showMessage(URI_NOTIFICATION_ICON_WARNING,
  1054.                   msgText, buttonLabel, buttonAccesskey,
  1055.                   true, notifyData);
  1056.     }
  1057.   }
  1058.   if (gInSafeMode) {
  1059.     showMessage(URI_NOTIFICATION_ICON_INFO,
  1060.                 getExtensionString("safeModeMsg"),
  1061.                 null, null, true, null);
  1062.   }
  1063.  
  1064.   gExtensionsView.builder.addListener(TemplateBuilderListener);
  1065.  
  1066.   if ("arguments" in window) {
  1067.     try {
  1068.       var params = window.arguments[0].QueryInterface(Components.interfaces.nsIDialogParamBlock);
  1069.       var manager = window.arguments[1].QueryInterface(Components.interfaces.nsIObserver);
  1070.       gDownloadManager.addDownloads(params, manager);
  1071.     }
  1072.     catch (e) {
  1073.       if (window.arguments[0] == "updates-only") {
  1074.         gUpdatesOnly = true;
  1075. //@line 1117 "/e/fx19rel/WINNT_5.2_Depend/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  1076.         // If we are Firefox when updating on startup don't display context
  1077.         // menuitems that can open a browser window.
  1078.         gUpdateContextMenus = gUpdateContextMenusNoBrowser;
  1079. //@line 1121 "/e/fx19rel/WINNT_5.2_Depend/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  1080.         document.getElementById("viewGroup").hidden = true;
  1081.         document.getElementById("extensionsView").setAttribute("norestart", "");
  1082.         showView("updates");
  1083.         showMessage(URI_NOTIFICATION_ICON_INFO,
  1084.                     getExtensionString("newUpdatesAvailableMsg"),
  1085.                     null, null, true, null);
  1086.         document.title = getExtensionString("newUpdateWindowTitle", [getBrandShortName()]);
  1087.       }
  1088.       else if (window.arguments.length == 2) {
  1089.         gNewAddons = window.arguments[1].split(",");
  1090.         var installMsg = PluralForm.get(gNewAddons.length, getExtensionString("newAddonsNotificationMsg2"));
  1091.         installMsg = installMsg.replace("%S", gNewAddons.length);
  1092.         showMessage(URI_NOTIFICATION_ICON_INFO,
  1093.                     installMsg, null, null, true, null);
  1094.         var extensionCount = 0;
  1095.         var themeCount = 0;
  1096.         var localeCount = 0;
  1097.         for (var i = 0; i < gNewAddons.length; i++) {
  1098.           var item = gExtensionManager.getItemForID(gNewAddons[i]);
  1099.           switch (item.type) {
  1100.             case Components.interfaces.nsIUpdateItem.TYPE_EXTENSION:
  1101.               extensionCount++;
  1102.               break;
  1103.             case Components.interfaces.nsIUpdateItem.TYPE_THEME:
  1104.               themeCount++;
  1105.               break;
  1106.             case Components.interfaces.nsIUpdateItem.TYPE_LOCALE:
  1107.               localeCount++;
  1108.               break;
  1109.           }
  1110.         }
  1111.         if (themeCount > extensionCount && themeCount > localeCount)
  1112.           showView("themes");
  1113.         else if (localeCount > extensionCount && localeCount > themeCount)
  1114.           showView("locales");
  1115.         else
  1116.           showView("extensions");
  1117.       }
  1118.       else
  1119.         showView(window.arguments[0]);
  1120.     }
  1121.   }
  1122.   else if (viewGroup.hasAttribute("last-selected") &&
  1123.            document.getElementById(viewGroup.getAttribute("last-selected") + "-view") &&
  1124.            !document.getElementById(viewGroup.getAttribute("last-selected") + "-view").hidden)
  1125.     showView(viewGroup.getAttribute("last-selected"));
  1126.   else
  1127.     showView("search");
  1128.  
  1129.   if (gExtensionsView.selectedItem)
  1130.     gExtensionsView.scrollBoxObject.scrollToElement(gExtensionsView.selectedItem);
  1131.  
  1132.   gPref.setBoolPref(PREF_UPDATE_NOTIFYUSER, false);
  1133.  
  1134.   if (gUpdatesOnly && gExtensionsView.children.length == 0)
  1135.     window.close();
  1136. }
  1137.  
  1138. function Shutdown()
  1139. {
  1140.   gExtensionsView.builder.removeListener(TemplateBuilderListener);
  1141.  
  1142.   gPref.removeObserver(PREF_DSS_SKIN_TO_SELECT, gPrefObserver);
  1143.   gPref.removeObserver(PREF_GENERAL_SKINS_SELECTEDSKIN, gPrefObserver);
  1144.   if (gAddonRepository && gAddonRepository.isSearching)
  1145.     gAddonRepository.cancelSearch();
  1146.  
  1147.   gRDF = null;
  1148.   gPref = null;
  1149.   gExtensionsView.removeEventListener("select", onAddonSelect, false);
  1150.   gExtensionsView.database.RemoveDataSource(gExtensionManager.datasource);
  1151.  
  1152.   gExtensionManager.removeInstallListenerAt(gObserverIndex);
  1153.  
  1154.   var os = Components.classes["@mozilla.org/observer-service;1"]
  1155.                      .getService(Components.interfaces.nsIObserverService);
  1156.   os.removeObserver(gAddonsMsgObserver, "addons-message-notification");
  1157.   os.removeObserver(gDownloadManager, "xpinstall-download-started");
  1158.   os.removeObserver(gPluginObserver, "plugins-list-updated");
  1159.   var currentNotification = document.getElementById("addonsMsg").currentNotification;
  1160.   if (currentNotification && currentNotification.value == "addons-no-updates")
  1161.     window.removeEventListener("select", noUpdatesDismiss, true);
  1162. }
  1163.  
  1164. var TemplateBuilderListener = {
  1165.   willRebuild: function(aBuilder) {
  1166.   },
  1167.  
  1168.   didRebuild: function(aBuilder) {
  1169.     // Display has been rebuilt, update necessary attributes
  1170.     if (gView == "extensions" || gView == "themes" || gView == "locales") {
  1171.       for (var i = 0; i < gNewAddons.length; i++) {
  1172.         var item = document.getElementById(PREFIX_ITEM_URI + gNewAddons[i]);
  1173.         if (item)
  1174.           item.setAttribute("newAddon", "true");
  1175.       }
  1176.     }
  1177.  
  1178.     if (gView == "themes") {
  1179.       if (gPref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING)) {
  1180.         var item = getItemForInternalName(gCurrentTheme);
  1181.         if (item)
  1182.           setRestartMessage(item);
  1183.       }
  1184.     }
  1185.   },
  1186.  
  1187.   QueryInterface: function (aIID)
  1188.   {
  1189.     if (!aIID.equals(Components.interfaces.nsIXULBuilderListener) &&
  1190.         !aIID.equals(Components.interfaces.nsISupports))
  1191.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1192.     return this;
  1193.   }
  1194. };
  1195.  
  1196. ///////////////////////////////////////////////////////////////////////////////
  1197. //
  1198. // XPInstall
  1199. //
  1200.  
  1201. function getURLSpecFromFile(aFile)
  1202. {
  1203.   var ioServ = Components.classes["@mozilla.org/network/io-service;1"]
  1204.                          .getService(nsIIOService);
  1205.   var fph = ioServ.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  1206.   return fph.getURLSpecFromFile(aFile);
  1207. }
  1208.  
  1209. function XPInstallDownloadManager()
  1210. {
  1211. }
  1212.  
  1213. XPInstallDownloadManager.prototype = {
  1214.   observe: function (aSubject, aTopic, aData)
  1215.   {
  1216.     switch (aTopic) {
  1217.       case "xpinstall-download-started":
  1218.         var params = aSubject.QueryInterface(Components.interfaces.nsISupportsArray);
  1219.         var paramBlock = params.GetElementAt(0).QueryInterface(Components.interfaces.nsISupportsInterfacePointer);
  1220.         paramBlock = paramBlock.data.QueryInterface(Components.interfaces.nsIDialogParamBlock);
  1221.         var manager = params.GetElementAt(1).QueryInterface(Components.interfaces.nsISupportsInterfacePointer);
  1222.         manager = manager.data.QueryInterface(Components.interfaces.nsIObserver);
  1223.         this.addDownloads(paramBlock, manager);
  1224.         break;
  1225.     }
  1226.   },
  1227.  
  1228.   addDownloads: function (aParams, aManager)
  1229.   {
  1230.     var numXPInstallItems = aParams.GetInt(1);
  1231.     var items = [];
  1232.     var switchPane = false;
  1233.     for (var i = 0; i < numXPInstallItems;) {
  1234.       var displayName = aParams.GetString(i++);
  1235.       var url = aParams.GetString(i++);
  1236.       var iconURL = aParams.GetString(i++);
  1237.       var uri = Components.classes["@mozilla.org/network/io-service;1"]
  1238.                           .getService(nsIIOService).newURI(url, null, null);
  1239.       var isTheme = uri.QueryInterface(nsIURL).fileExtension.toLowerCase() == "jar";
  1240.       if (!iconURL) {
  1241.         iconURL = isTheme ? "chrome://mozapps/skin/extensions/themeGeneric.png" :
  1242.                             "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png";
  1243.       }
  1244.  
  1245.       var type = isTheme ? nsIUpdateItem.TYPE_THEME : nsIUpdateItem.TYPE_EXTENSION;
  1246.       var item = Components.classes["@mozilla.org/updates/item;1"]
  1247.                            .createInstance(Components.interfaces.nsIUpdateItem);
  1248.       item.init(url, " ", "app-profile", "", "", displayName, url, "", iconURL, "", "", type, "");
  1249.       items.push(item);
  1250.  
  1251.       // Advance the enumerator
  1252.       var certName = aParams.GetString(i++);
  1253.  
  1254.       // Check whether the install was triggered from the Get Add-ons pane.
  1255.       if (url in gPendingInstalls) {
  1256.         // Update the installation status
  1257.         gSearchDS.Assert(gRDF.GetResource(gPendingInstalls[url]),
  1258.                          gRDF.GetResource(PREFIX_NS_EM + "action"),
  1259.                          gRDF.GetLiteral("installing"),
  1260.                          true);
  1261.         delete gPendingInstalls[url];
  1262.       }
  1263.       else {
  1264.         switchPane = true;
  1265.       }
  1266.     }
  1267.  
  1268.     gInstalling = true;
  1269.     gExtensionManager.addDownloads(items, items.length, aManager);
  1270.     updateOptionalViews();
  1271.     updateGlobalCommands();
  1272.     // Only switch to the installs pane if there was an not started by the
  1273.     // Get Add-ons pane
  1274.     if (switchPane)
  1275.       showView("installs");
  1276.   },
  1277.  
  1278.   getElementForAddon: function(aAddon)
  1279.   {
  1280.     var element = document.getElementById(PREFIX_ITEM_URI + aAddon.id);
  1281.     if (aAddon.id == aAddon.xpiURL)
  1282.       element = document.getElementById(aAddon.xpiURL);
  1283.     return element;
  1284.   },
  1285.  
  1286.   /////////////////////////////////////////////////////////////////////////////
  1287.   // nsIAddonInstallListener
  1288.   onDownloadStarted: function(aAddon)
  1289.   {
  1290.   },
  1291.  
  1292.   onDownloadEnded: function(aAddon)
  1293.   {
  1294.   },
  1295.  
  1296.   onInstallStarted: function(aAddon)
  1297.   {
  1298.   },
  1299.   
  1300.   onCompatibilityCheckStarted: function(aAddon)
  1301.   {
  1302.   },
  1303.   
  1304.   onCompatibilityCheckEnded: function(aAddon, aStatus)
  1305.   {
  1306.   },
  1307.  
  1308.   onInstallEnded: function(aAddon, aStatus)
  1309.   {
  1310.     // From nsInstall.h
  1311.     // USER_CANCELLED = -210
  1312.     // All other xpinstall errors are <= -200
  1313.     // Any errors from the EM will have been displayed directly by the EM
  1314.     if (aStatus > -200 || aStatus == -210)
  1315.       return;
  1316.  
  1317.     var xpinstallStrings = document.getElementById("xpinstallStrings");
  1318.     try {
  1319.       var msg = xpinstallStrings.getString("error" + aStatus);
  1320.     }
  1321.     catch (e) {
  1322.       msg = xpinstallStrings.getFormattedString("unknown.error", [aStatus]);
  1323.     }
  1324.     var title = getExtensionString("errorInstallTitle");
  1325.     var message = getExtensionString("errorInstallMsg", [getBrandShortName(),
  1326.                                                          aAddon.xpiURL, msg]);
  1327.     var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  1328.                        .getService(Components.interfaces.nsIPromptService);
  1329.     ps.alert(window, title, message + "\n" + aStatus);
  1330.   },
  1331.  
  1332.   onInstallsCompleted: function()
  1333.   {
  1334.     gInstalling = false;
  1335.     gExtensionManager.sortTypeByProperty(nsIUpdateItem.TYPE_ANY, "name", true);
  1336.     if (gUpdatesOnly) {
  1337.       setElementDisabledByID("cmd_continue", false);
  1338.       document.getElementById("continueDialogButton").focus();
  1339.     }
  1340.     else {
  1341.       updateOptionalViews();
  1342.       updateGlobalCommands();
  1343.     }
  1344.   },
  1345.  
  1346.   _urls: { },
  1347.   onDownloadProgress: function (aAddon, aValue, aMaxValue)
  1348.   {
  1349.     var element = this.getElementForAddon(aAddon);
  1350.     if (!element)
  1351.       return;
  1352.     var percent = Math.round((aValue / aMaxValue) * 100);
  1353.     if (percent > 1 && !(aAddon.xpiURL in this._urls))
  1354.       this._urls[aAddon.xpiURL] = true;
  1355.  
  1356.     var statusPrevious = element.getAttribute("status");
  1357.     var statusCurrent = DownloadUtils.getTransferTotal(aValue, aMaxValue);
  1358.     if (statusCurrent != statusPrevious)
  1359.       element.setAttribute("status", statusCurrent);
  1360.   },
  1361.  
  1362.   /////////////////////////////////////////////////////////////////////////////
  1363.   // nsISupports
  1364.   QueryInterface: function (aIID)
  1365.   {
  1366.     if (!aIID.equals(Components.interfaces.nsIAddonInstallListener) &&
  1367.         !aIID.equals(Components.interfaces.nsISupports))
  1368.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1369.     return this;
  1370.   }
  1371. };
  1372.  
  1373. ///////////////////////////////////////////////////////////////////////////////
  1374. //
  1375. // Update Listener
  1376. //
  1377. function UpdateCheckListener() {
  1378. }
  1379. UpdateCheckListener.prototype = {
  1380.   _updateFound: false,
  1381.   _totalCount: 0,
  1382.   _completedCount: 0,
  1383.  
  1384.   /**
  1385.    * See nsIExtensionManager.idl
  1386.    */
  1387.   onUpdateStarted: function() {
  1388.     gExtensionsView.setAttribute("update-operation", "checking");
  1389.     gExtensionsViewController.onCommandUpdate();
  1390.     updateGlobalCommands();
  1391.     this._totalCount = gExtensionsView.children.length;
  1392.   },
  1393.  
  1394.   /**
  1395.    * See nsIExtensionManager.idl
  1396.    */
  1397.   onUpdateEnded: function() {
  1398.     if (!document)
  1399.       return;
  1400.     document.getElementById("progressBox").hidden = true;
  1401.     var viewGroup = document.getElementById("viewGroup");
  1402.     viewGroup.hidden = false;
  1403.     gExtensionsView.removeAttribute("update-operation");
  1404.     gExtensionsViewController.onCommandUpdate();
  1405.     updateOptionalViews();
  1406.     updateGlobalCommands();
  1407.     if (this._updateFound)
  1408.       showView("updates");
  1409.     else {
  1410.       showMessage(URI_NOTIFICATION_ICON_INFO,
  1411.                   getExtensionString("noUpdatesMsg"),
  1412.                   null, null, true, "addons-no-updates");
  1413.       window.addEventListener("select", noUpdatesDismiss, true);
  1414.     }
  1415.   },
  1416.  
  1417.   /**
  1418.    * See nsIExtensionManager.idl
  1419.    */
  1420.   onAddonUpdateStarted: function(addon) {
  1421.     if (!document)
  1422.       return;
  1423.     var element = document.getElementById(PREFIX_ITEM_URI + addon.id);
  1424.     element.setAttribute("loading", "true");
  1425.     element.setAttribute("updateStatus", getExtensionString("updatingMsg"));
  1426.   },
  1427.  
  1428.   /**
  1429.    * See nsIExtensionManager.idl
  1430.    */
  1431.   onAddonUpdateEnded: function(addon, status) {
  1432.     if (!document)
  1433.       return;
  1434.     var element = document.getElementById(PREFIX_ITEM_URI + addon.id);
  1435.     element.removeAttribute("loading");
  1436.     const nsIAUCL = Components.interfaces.nsIAddonUpdateCheckListener;
  1437.     switch (status) {
  1438.     case nsIAUCL.STATUS_UPDATE:
  1439.       var statusMsg = getExtensionString("updateAvailableMsg", [addon.version]);
  1440.       this._updateFound = true;
  1441.       break;
  1442.     case nsIAUCL.STATUS_VERSIONINFO:
  1443.       statusMsg = getExtensionString("updateCompatibilityMsg");
  1444.       break;
  1445.     case nsIAUCL.STATUS_FAILURE:
  1446.       var name = element.getAttribute("name");
  1447.       statusMsg = getExtensionString("updateErrorMessage", [name]);
  1448.       break;
  1449.     case nsIAUCL.STATUS_DISABLED:
  1450.       name = element.getAttribute("name");
  1451.       statusMsg = getExtensionString("updateDisabledMessage", [name]);
  1452.       break;
  1453.     case nsIAUCL.STATUS_APP_MANAGED:
  1454.     case nsIAUCL.STATUS_NO_UPDATE:
  1455.       statusMsg = getExtensionString("updateNoUpdateMsg");
  1456.       break;
  1457.     case nsIAUCL.STATUS_NOT_MANAGED:
  1458.       statusMsg = getExtensionString("updateNotManagedMessage", [getBrandShortName()]);
  1459.       break;
  1460.     case nsIAUCL.STATUS_READ_ONLY:
  1461.       statusMsg = getExtensionString("updateReadOnlyMessage");
  1462.       break;
  1463.     default:
  1464.       statusMsg = getExtensionString("updateNoUpdateMsg");
  1465.     }
  1466.     element.setAttribute("updateStatus", statusMsg);
  1467.     ++this._completedCount;
  1468.     document.getElementById("progressStatus").value = getExtensionString("finishedUpdateCheck", [addon.name]);
  1469.     document.getElementById("addonsProgress").value = Math.ceil((this._completedCount / this._totalCount) * 100);
  1470.   },
  1471.  
  1472.   /**
  1473.    * See nsISupports.idl
  1474.    */
  1475.   QueryInterface: function(iid) {
  1476.     if (!iid.equals(Components.interfaces.nsIAddonUpdateCheckListener) &&
  1477.         !iid.equals(Components.interfaces.nsISupports))
  1478.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1479.     return this;
  1480.   }
  1481. };
  1482.  
  1483.  
  1484. ///////////////////////////////////////////////////////////////////////////////
  1485. //
  1486. // View Event Handlers
  1487. //
  1488. function onViewDoubleClick(aEvent)
  1489. {
  1490.   if (aEvent.button != 0 || !gExtensionsView.selectedItem)
  1491.     return;
  1492.  
  1493.   switch (gView) {
  1494.     case "extensions":
  1495.       gExtensionsViewController.doCommand('cmd_options');
  1496.       break;
  1497.     case "themes":
  1498.       gExtensionsViewController.doCommand('cmd_useTheme');
  1499.       break;
  1500.     case "updates":
  1501.       gExtensionsViewController.doCommand('cmd_includeUpdate');
  1502.       break;
  1503.   }
  1504. }
  1505.  
  1506. function onAddonSelect(aEvent)
  1507. {
  1508.   var viewButton = document.getElementById("viewGroup").selectedItem;
  1509.   if (viewButton.hasAttribute("persist") && gExtensionsView.selectedItem)
  1510.     viewButton.setAttribute("last-selected", gExtensionsView.selectedItem.id);
  1511.  
  1512.   if (!document.getElementById("themePreviewArea").hidden) {
  1513.     var previewImageDeck = document.getElementById("previewImageDeck");
  1514.     if (gView == "themes") {
  1515.       var previewImage = document.getElementById("previewImage");
  1516.       if (!gExtensionsView.selectedItem) {
  1517.         previewImageDeck.selectedIndex = 0;
  1518.         if (previewImage.hasAttribute("src"))
  1519.           previewImage.removeAttribute("src");
  1520.       }
  1521.       else {
  1522.         var url = gExtensionsView.selectedItem.getAttribute("previewImage");
  1523.         if (url) {
  1524.           previewImageDeck.selectedIndex = 2;
  1525.           previewImage.setAttribute("src", url);
  1526.         }
  1527.         else {
  1528.           previewImageDeck.selectedIndex = 1;
  1529.           if (previewImage.hasAttribute("src"))
  1530.             previewImage.removeAttribute("src");
  1531.         }
  1532.       }
  1533.     }
  1534.     else if (gView == "updates") {
  1535.       UpdateInfoLoader.cancelLoad();
  1536.       if (!gExtensionsView.selectedItem) {
  1537.         previewImageDeck.selectedIndex = 3;
  1538.       }
  1539.       else {
  1540.         var uri = gExtensionsView.selectedItem.getAttribute("availableUpdateInfo");
  1541.         if (isSafeURI(uri))
  1542.           UpdateInfoLoader.loadInfo(uri);
  1543.         else
  1544.           previewImageDeck.selectedIndex = 4;
  1545.       }
  1546.     }
  1547.   }
  1548. }
  1549.  
  1550. /**
  1551.  * Manages the retrieval of update information and the xsl stylesheet
  1552.  * used to format the inforation into chrome.
  1553.  */
  1554. var UpdateInfoLoader = {
  1555.   _stylesheet: null,
  1556.   _styleRequest: null,
  1557.   _infoDocument: null,
  1558.   _infoRequest: null,
  1559.   
  1560.   // Called once both stylesheet and info requests have completed
  1561.   displayInfo: function()
  1562.   {
  1563.     var processor = Components.classes["@mozilla.org/document-transformer;1?type=xslt"]
  1564.                               .createInstance(Components.interfaces.nsIXSLTProcessor);
  1565.     processor.flags |= Components.interfaces.nsIXSLTProcessorPrivate.DISABLE_ALL_LOADS;
  1566.     
  1567.     processor.importStylesheet(this._stylesheet);
  1568.     var fragment = processor.transformToFragment(this._infoDocument, document);
  1569.     document.getElementById("infoDisplay").appendChild(fragment);
  1570.     document.getElementById("previewImageDeck").selectedIndex = 7;
  1571.   },
  1572.   
  1573.   onStylesheetLoaded: function(event)
  1574.   {
  1575.     var request = event.target;
  1576.     this._styleRequest = null;
  1577.     this._stylesheet = request.responseXML;
  1578.  
  1579.     if (!this._stylesheet ||
  1580.         this._stylesheet.documentElement.namespaceURI == XMLURI_PARSE_ERROR ||
  1581.         (request.status != 200 && request.status != 0)) {
  1582.       // The stylesheet load failing is a bad sign
  1583.       document.getElementById("previewImageDeck").selectedIndex = 6;
  1584.       return;
  1585.     }
  1586.  
  1587.     if (this._infoDocument)
  1588.       this.displayInfo();
  1589.   },
  1590.   
  1591.   onInfoLoaded: function(event)
  1592.   {
  1593.     var request = event.target;
  1594.     this._infoRequest = null;
  1595.     this._infoDocument = request.responseXML;
  1596.     
  1597.     if (!this._infoDocument ||
  1598.         this._infoDocument.documentElement.namespaceURI == XMLURI_PARSE_ERROR ||
  1599.         (request.status != 200 && request.status != 0)) {
  1600.       // Should attempt to parse request.responseText with the html parser
  1601.       document.getElementById("previewImageDeck").selectedIndex = 6;
  1602.       return;
  1603.     }
  1604.  
  1605.     if (this._stylesheet)
  1606.       this.displayInfo();
  1607.   },
  1608.   
  1609.   onError: function(event)
  1610.   {
  1611.     if (event.request == this._infoRequest)
  1612.       this._infoRequest = null;
  1613.     else // Means the stylesheet load has failed which is pretty bad news
  1614.       this.cancelRequest();
  1615.  
  1616.     document.getElementById("previewImageDeck").selectedIndex = 6;
  1617.   },
  1618.   
  1619.   loadInfo: function(url)
  1620.   {
  1621.     this.cancelLoad();
  1622.     this._infoDocument = null;
  1623.     document.getElementById("previewImageDeck").selectedIndex = 5;
  1624.     var display = document.getElementById("infoDisplay");
  1625.     while (display.lastChild)
  1626.       display.removeChild(display.lastChild);
  1627.  
  1628.     this._infoRequest = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
  1629.                                   .createInstance(Components.interfaces.nsIXMLHttpRequest);
  1630.     this._infoRequest.open("GET", url, true);
  1631.     
  1632.     var self = this;
  1633.     this._infoRequest.onerror = function(event) { self.onError(event); };
  1634.     this._infoRequest.onload = function(event) { self.onInfoLoaded(event); };
  1635.     this._infoRequest.send(null);
  1636.  
  1637.     // We may have the stylesheet cached from a previous load, or may still be
  1638.     // loading it.
  1639.     if (this._stylesheet || this._styleRequest)
  1640.       return;
  1641.  
  1642.     this._styleRequest = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
  1643.                                    .createInstance(Components.interfaces.nsIXMLHttpRequest);
  1644.     this._styleRequest.open("GET", "chrome://mozapps/content/extensions/updateinfo.xsl", true);
  1645.     this._styleRequest.overrideMimeType("text/xml");
  1646.     
  1647.     this._styleRequest.onerror = function(event) { self.onError(event); };
  1648.     this._styleRequest.onload = function(event) { self.onStylesheetLoaded(event); };
  1649.     this._styleRequest.send(null);
  1650.   },
  1651.   
  1652.   cancelLoad: function()
  1653.   {
  1654.     // Leave the stylesheet loader running, there's a good chance we'll need it
  1655.     if (this._infoRequest)
  1656.       this._infoRequest.abort();
  1657.     this._infoRequest = null;
  1658.   }
  1659. }
  1660.  
  1661. ///////////////////////////////////////////////////////////////////////////////
  1662. // View Context Menus
  1663. var gAddonContextMenus = ["menuitem_useTheme", "menuitem_options", "menuitem_homepage",
  1664.                           "menuitem_about",  "menuseparator_1", "menuitem_uninstall",
  1665.                           "menuitem_cancelUninstall", "menuitem_cancelInstall",
  1666.                           "menuitem_cancelUpgrade", "menuitem_checkUpdate",
  1667.                           "menuitem_enable", "menuitem_disable"];
  1668. var gUpdateContextMenus = ["menuitem_homepage", "menuitem_about", "menuseparator_1",
  1669.                            "menuitem_installUpdate", "menuitem_includeUpdate"];
  1670. // For Firefox don't display context menuitems that can open a browser window.
  1671. var gUpdateContextMenusNoBrowser = ["menuitem_installUpdate", "menuitem_includeUpdate"];
  1672. var gInstallContextMenus = ["menuitem_homepage", "menuitem_about"];
  1673. var gSearchContextMenus = ["menuitem_learnMore", "menuitem_installSearchResult"];
  1674.  
  1675. function buildContextMenu(aEvent)
  1676. {
  1677.   var popup = document.getElementById("addonContextMenu");
  1678.   var selectedItem = gExtensionsView.selectedItem;
  1679.   if (aEvent.target !== popup || !selectedItem)
  1680.     return false;
  1681.  
  1682.   while (popup.hasChildNodes())
  1683.     popup.removeChild(popup.firstChild);
  1684.  
  1685.   switch (gView) {
  1686.   case "search":
  1687.     var menus = gSearchContextMenus;
  1688.     break;
  1689.   case "extensions":
  1690.   case "themes":
  1691.   case "locales":
  1692.   case "plugins":
  1693.     menus = gAddonContextMenus;
  1694.     break;
  1695.   case "updates":
  1696.     menus = gUpdateContextMenus;
  1697.     break;
  1698.   case "installs":
  1699.     menus = gInstallContextMenus;
  1700.     break;
  1701.   }
  1702.  
  1703.   for (var i = 0; i < menus.length; ++i) {
  1704.     var clonedMenu = document.getElementById(menus[i]).cloneNode(true);
  1705.     clonedMenu.id = clonedMenu.id + "_clone";
  1706.     popup.appendChild(clonedMenu);
  1707.   }
  1708.  
  1709.   // All views support about
  1710.   var menuitem_about = document.getElementById("menuitem_about_clone");
  1711.   var name = selectedItem ? selectedItem.getAttribute("name") : "";
  1712.   menuitem_about.setAttribute("label", getExtensionString("aboutAddon", [name]));
  1713.  
  1714.   /* When an update or install is pending allow canceling the update or install
  1715.      and don't allow uninstall. When an uninstall is pending allow canceling the
  1716.      uninstall.*/
  1717.   if (gView != "updates" && gView != "installs") {
  1718.     var canEnable = gExtensionsViewController.isCommandEnabled("cmd_cancelUninstall");
  1719.     document.getElementById("menuitem_cancelUninstall_clone").hidden = !canEnable;
  1720.     var canCancelInstall = gExtensionsViewController.isCommandEnabled("cmd_cancelInstall");
  1721.     document.getElementById("menuitem_cancelInstall_clone").hidden = !canCancelInstall;
  1722.     var canCancelUpgrade = gExtensionsViewController.isCommandEnabled("cmd_cancelUpgrade");
  1723.     document.getElementById("menuitem_cancelUpgrade_clone").hidden = !canCancelUpgrade;
  1724.     document.getElementById("menuitem_uninstall_clone").hidden = canEnable || canCancelInstall || canCancelUpgrade;
  1725.   }
  1726.  
  1727.   switch (gView) {
  1728.   case "extensions":
  1729.     canEnable = gExtensionsViewController.isCommandEnabled("cmd_reallyEnable");
  1730.     document.getElementById("menuitem_enable_clone").hidden = !canEnable;
  1731.     document.getElementById("menuitem_disable_clone").hidden = canEnable;
  1732.     document.getElementById("menuitem_useTheme_clone").hidden = true;
  1733.     break;
  1734.   case "themes":
  1735.     var enableMenu = document.getElementById("menuitem_enable_clone");
  1736.     if (!selectedItem.isCompatible || selectedItem.isBlocklisted ||
  1737.         !selectedItem.satisfiesDependencies || selectedItem.isDisabled)
  1738.       // don't let the user activate incompatible themes, but show a (disabled) Enable
  1739.       // menuitem to give visual feedback; it's disabled because cmd_enable returns false
  1740.       enableMenu.hidden = false;
  1741.     else
  1742.       enableMenu.hidden = true;
  1743.     document.getElementById("menuitem_options_clone").hidden = true;
  1744.     document.getElementById("menuitem_disable_clone").hidden = true;
  1745.     break;
  1746.   case "plugins":
  1747.     document.getElementById("menuitem_about_clone").hidden = true;
  1748.     document.getElementById("menuitem_uninstall_clone").hidden = true;
  1749.     document.getElementById("menuitem_checkUpdate_clone").hidden = true;
  1750.   case "locales":
  1751.     canEnable = gExtensionsViewController.isCommandEnabled("cmd_reallyEnable");
  1752.     document.getElementById("menuitem_enable_clone").hidden = !canEnable;
  1753.     document.getElementById("menuitem_disable_clone").hidden = canEnable;
  1754.     document.getElementById("menuitem_useTheme_clone").hidden = true;
  1755.     document.getElementById("menuitem_options_clone").hidden = true;
  1756.     break;
  1757.   case "updates":
  1758.     var includeUpdate = document.getAnonymousElementByAttribute(selectedItem, "anonid", "includeUpdate");
  1759.     var menuitem_includeUpdate = document.getElementById("menuitem_includeUpdate_clone");
  1760.     menuitem_includeUpdate.setAttribute("checked", includeUpdate.checked ? "true" : "false");
  1761.     break;
  1762.   case "installs":
  1763.     break;
  1764.   }
  1765.  
  1766.   return true;
  1767. }
  1768.  
  1769. ///////////////////////////////////////////////////////////////////////////////
  1770. // Drag and Drop
  1771.  
  1772. var gExtensionsDNDObserver =
  1773. {
  1774.   _ioServ: null,
  1775.   _canDrop: false,
  1776.  
  1777.   _ensureServices: function ()
  1778.   {
  1779.     if (!this._ioServ)
  1780.       this._ioServ = Components.classes["@mozilla.org/network/io-service;1"]
  1781.                                .getService(nsIIOService);
  1782.   },
  1783.  
  1784.   // returns a JS object whose properties are used by xpinstall
  1785.   _getDataFromDragSession: function (aDragSession, aPosition)
  1786.   {
  1787.     var fileData = { };
  1788.     // if this fails we do not have valid data to drop
  1789.     try {
  1790.       var xfer = Components.classes["@mozilla.org/widget/transferable;1"]
  1791.                            .createInstance(Components.interfaces.nsITransferable);
  1792.       xfer.addDataFlavor("text/x-moz-url");
  1793.       xfer.addDataFlavor("application/x-moz-file", "nsIFile");
  1794.       aDragSession.getData(xfer, aPosition);
  1795.  
  1796.       var flavour = { }, data = { }, length = { };
  1797.       xfer.getAnyTransferData(flavour, data, length);
  1798.       var selectedFlavour = this.getSupportedFlavours().flavourTable[flavour.value];
  1799.       var xferData = new FlavourData(data.value, length.value, selectedFlavour);
  1800.  
  1801.       var fileURL = transferUtils.retrieveURLFromData(xferData.data,
  1802.                                                       xferData.flavour.contentType);
  1803.       fileData.fileURL = fileURL;
  1804.  
  1805.       var uri = this._ioServ.newURI(fileURL, null, null);
  1806.       var url = uri.QueryInterface(nsIURL);
  1807.       fileData.fileName = url.fileName;
  1808.  
  1809.       switch (url.fileExtension) {
  1810.         case "xpi":
  1811.           fileData.type = nsIUpdateItem.TYPE_EXTENSION;
  1812.           break;
  1813.         case "jar":
  1814.           fileData.type = nsIUpdateItem.TYPE_THEME;
  1815.           break;
  1816.         default:
  1817.           return null;
  1818.       }
  1819.     }
  1820.     catch (e) {
  1821.       return null;
  1822.     }
  1823.  
  1824.     return fileData;
  1825.   },
  1826.  
  1827.   canDrop: function (aEvent, aDragSession) { return this._canDrop; },
  1828.  
  1829.   onDragEnter: function (aEvent, aDragSession)
  1830.   {
  1831.     // XXXrstrong - bug 269568, GTK2 drag and drop is returning invalid data for
  1832.     // dragenter and dragover. To workaround this we always set canDrop to true
  1833.     // and just use the xfer data returned in ondrop which is valid.
  1834. //@line 1876 "/e/fx19rel/WINNT_5.2_Depend/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  1835.     this._ensureServices();
  1836.  
  1837.     var count = aDragSession.numDropItems;
  1838.     for (var i = 0; i < count; ++i) {
  1839.       var fileData = this._getDataFromDragSession(aDragSession, i);
  1840.       if (!fileData) {
  1841.         this._canDrop = false;
  1842.         return;
  1843.       }
  1844.     }
  1845. //@line 1887 "/e/fx19rel/WINNT_5.2_Depend/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  1846.     this._canDrop = true;
  1847.   },
  1848.  
  1849.   onDragOver: function (aEvent, aFlavor, aDragSession) { },
  1850.  
  1851.   onDrop: function(aEvent, aXferData, aDragSession)
  1852.   {
  1853.     if (!isXPInstallEnabled())
  1854.       return;
  1855.  
  1856.     this._ensureServices();
  1857.  
  1858.     var xpinstallObj = { };
  1859.     var themes = { };
  1860.     var xpiCount = 0;
  1861.     var themeCount = 0;
  1862.  
  1863.     var count = aDragSession.numDropItems;
  1864.     for (var i = 0; i < count; ++i) {
  1865.       var fileData = this._getDataFromDragSession(aDragSession, i);
  1866.       if (!fileData)
  1867.         continue;
  1868.  
  1869.       xpinstallObj[fileData.fileName] = {
  1870.         URL: fileData.fileURL,
  1871.         toString: function() { return this.URL; }
  1872.       };
  1873.       ++xpiCount;
  1874.       if (fileData.type == nsIUpdateItem.TYPE_THEME)
  1875.         xpinstallObj[fileData.fileName].IconURL = URI_GENERIC_ICON_THEME;
  1876.       else
  1877.         xpinstallObj[fileData.fileName].IconURL = URI_GENERIC_ICON_XPINSTALL;
  1878.     }
  1879.  
  1880.     if (xpiCount > 0)
  1881.       InstallTrigger.install(xpinstallObj);
  1882.   },
  1883.   _flavourSet: null,
  1884.   getSupportedFlavours: function ()
  1885.   {
  1886.     if (!this._flavourSet) {
  1887.       this._flavourSet = new FlavourSet();
  1888.       this._flavourSet.appendFlavour("text/x-moz-url");
  1889.       this._flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  1890.     }
  1891.     return this._flavourSet;
  1892.   }
  1893. };
  1894.  
  1895. ///////////////////////////////////////////////////////////////////////////////
  1896. // Notification Messages
  1897. const gAddonsMsgObserver = {
  1898.   observe: function (aSubject, aTopic, aData)
  1899.   {
  1900.     switch (aData) {
  1901.     case "addons-enable-xpinstall":
  1902.       gPref.setBoolPref("xpinstall.enabled", true);
  1903.       break;
  1904.     case "addons-enable-compatibility":
  1905.       gPref.clearUserPref(PREF_EM_CHECK_COMPATIBILITY);
  1906.       gCheckCompat = true;
  1907.       break;
  1908.     case "addons-enable-updatesecurity":
  1909.       gPref.clearUserPref(PREF_EM_CHECK_UPDATE_SECURITY);
  1910.       gCheckUpdateSecurity = true;
  1911.       break;
  1912.     case "addons-no-updates":
  1913.       var children = gExtensionsView.children;
  1914.       for (var i = 0; i < children.length; ++i) {
  1915.         var child = children[i];
  1916.         if (child.hasAttribute("updateStatus"))
  1917.           child.removeAttribute("updateStatus");
  1918.       }
  1919.       break;
  1920.     case "addons-go-online":
  1921.       var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  1922.                                 .getService(nsIIOService);
  1923.       ioService.offline = false;
  1924.       // If no results have been retrieved start pulling some
  1925.       if (!gRetrievedResults)
  1926.         retrieveRepositoryAddons(document.getElementById("searchbox").value);
  1927.       if (gView == "search")
  1928.         document.getElementById("searchbox").disabled = false;
  1929.       break;
  1930.     case "addons-message-dismiss":
  1931.       break;
  1932.     case "addons-restart-app":
  1933.       restartApp();
  1934.       break;
  1935.     }
  1936.     if (gExtensionsView.selectedItem)
  1937.       gExtensionsView.selectedItem.focus();
  1938.   }
  1939. };
  1940.  
  1941. const gPrefObserver = {
  1942.   observe: function (aSubject, aTopic, aData)
  1943.   {
  1944.     if (aData == PREF_GENERAL_SKINS_SELECTEDSKIN) {
  1945.       // Changed as the result of a dynamic theme switch
  1946.       gCurrentTheme = gPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  1947.     }
  1948.     else if (aData == PREF_DSS_SKIN_TO_SELECT) {
  1949.       // Either a new skin has been selected or the switch has been cancelled
  1950.       if (gPref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING))
  1951.         gCurrentTheme = gPref.getCharPref(PREF_DSS_SKIN_TO_SELECT);
  1952.       else
  1953.         gCurrentTheme = gPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  1954.       updateOptionalViews();
  1955.       updateGlobalCommands();
  1956.     }
  1957.   }
  1958. };
  1959.  
  1960. const gPluginObserver = {
  1961.   observe: function (aSubject, aTopic, aData)
  1962.   {
  1963.     rebuildPluginsDS();
  1964.   }
  1965. };
  1966.  
  1967. function isXPInstallEnabled() {
  1968.   var enabled = false;
  1969.   var locked = false;
  1970.   try {
  1971.     enabled = gPref.getBoolPref("xpinstall.enabled");
  1972.     if (enabled)
  1973.       return true;
  1974.     locked = gPref.prefIsLocked("xpinstall.enabled");
  1975.   }
  1976.   catch (e) { }
  1977.  
  1978.   var msgText = getExtensionString(locked ? "xpinstallDisabledMsgLocked" :
  1979.                                             "xpinstallDisabledMsg");
  1980.   var buttonLabel = locked ? null : getExtensionString("enableButtonLabel");
  1981.   var buttonAccesskey = locked ? null : getExtensionString("enableButtonAccesskey");
  1982.   var notifyData = locked ? null : "addons-enable-xpinstall";
  1983.   showMessage(URI_NOTIFICATION_ICON_WARNING,
  1984.               msgText, buttonLabel, buttonAccesskey,
  1985.               !locked, notifyData);
  1986.   return false;
  1987. }
  1988.  
  1989. function isOffline(messageKey) {
  1990.   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  1991.                             .getService(nsIIOService);
  1992.   if (ioService.offline) {
  1993.     showMessage(URI_NOTIFICATION_ICON_WARNING,
  1994.                 getExtensionString(messageKey, [getBrandShortName()]),
  1995.                 getExtensionString("goOnlineButtonLabel"),
  1996.                 getExtensionString("goOnlineButtonAccesskey"),
  1997.                 true, "addons-go-online");
  1998.   }
  1999.   return ioService.offline;
  2000. }
  2001.  
  2002. ///////////////////////////////////////////////////////////////////////////////
  2003. // Command Updating and Command Handlers
  2004.  
  2005. function canWriteToLocation(element)
  2006. {
  2007.   var installLocation = null;
  2008.   if (element) {
  2009.     var id = getIDFromResourceURI(element.id)
  2010.     installLocation = gExtensionManager.getInstallLocation(id);
  2011.   }
  2012.   return installLocation ? installLocation.canAccess : false;
  2013. }
  2014.  
  2015. function enableRestartButton() {
  2016.   var addonsMsg = document.getElementById("addonsMsg");
  2017.   var notification = addonsMsg.getNotificationWithValue("restart-app");
  2018.   if (!notification) {
  2019.     var appname = getBrandShortName();
  2020.     var message = getExtensionString("restartMessage", [appname]);
  2021.     var buttons = [ new MessageButton(getExtensionString("restartButton", [appname]),
  2022.                                       getExtensionString("restartAccessKey"),
  2023.                                       "addons-restart-app") ];
  2024.     addonsMsg.appendNotification(message, "restart-app",
  2025.                                  URI_NOTIFICATION_ICON_INFO,
  2026.                                  addonsMsg.PRIORITY_WARNING_HIGH, buttons);
  2027.   }
  2028. }
  2029.  
  2030. function disableRestartButton() {
  2031.   var addonsMsg = document.getElementById("addonsMsg");
  2032.   var notification = addonsMsg.getNotificationWithValue("restart-app");
  2033.   if (notification)
  2034.     notification.close();
  2035. }
  2036.  
  2037. function updateOptionalViews() {
  2038.   var ds = gExtensionsView.database;
  2039.   var ctr = Components.classes["@mozilla.org/rdf/container;1"]
  2040.                       .createInstance(Components.interfaces.nsIRDFContainer);
  2041.   ctr.Init(ds, gRDF.GetResource(RDFURI_ITEM_ROOT));
  2042.   var elements = ctr.GetElements();
  2043.   var showLocales = false;
  2044.   var showUpdates = false;
  2045.   var showInstalls = gInstalling;
  2046.   gPendingActions = false;
  2047.  
  2048.   var stateArc = gRDF.GetResource(PREFIX_NS_EM + "state");
  2049.   var opTypeArc = gRDF.GetResource(PREFIX_NS_EM + "opType");
  2050.  
  2051.   while (elements.hasMoreElements()) {
  2052.     var e = elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  2053.     if (!showLocales) {
  2054.       var typeArc = gRDF.GetResource(PREFIX_NS_EM + "type");
  2055.       var type = ds.GetTarget(e, typeArc, true);
  2056.       if (type && type instanceof Components.interfaces.nsIRDFInt) {
  2057.         if (type.Value & nsIUpdateItem.TYPE_LOCALE)
  2058.           showLocales = true;
  2059.       }
  2060.     }
  2061.  
  2062.     if (!gInstalling || !showInstalls) {
  2063.       var state = ds.GetTarget(e, stateArc, true);
  2064.       if (state) {
  2065.         showInstalls = true;
  2066.         if (state instanceof Components.interfaces.nsIRDFLiteral &&
  2067.             state.Value != "success" && state.Value != "failure")
  2068.           gInstalling = true;
  2069.       }
  2070.     }
  2071.  
  2072.     if (!gPendingActions) {
  2073.       var opType = ds.GetTarget(e, opTypeArc, true);
  2074.       if (opType) {
  2075.         if (opType instanceof Components.interfaces.nsIRDFLiteral &&
  2076.             opType.Value != OP_NONE)
  2077.           gPendingActions = true;
  2078.       }
  2079.     }
  2080.  
  2081.     if (!showUpdates) {
  2082.       var updateURLArc = gRDF.GetResource(PREFIX_NS_EM + "availableUpdateURL");
  2083.       var updateURL = ds.GetTarget(e, updateURLArc, true);
  2084.       if (updateURL) {
  2085.         var updateableArc = gRDF.GetResource(PREFIX_NS_EM + "updateable");
  2086.         var updateable = ds.GetTarget(e, updateableArc, true);
  2087.         updateable = updateable.QueryInterface(Components.interfaces.nsIRDFLiteral);
  2088.         if (updateable.Value == "true")
  2089.           showUpdates = true;
  2090.       }
  2091.     }
  2092.   }
  2093.   document.getElementById("locales-view").hidden = !showLocales;
  2094.   document.getElementById("updates-view").hidden = !showUpdates;
  2095.   document.getElementById("installs-view").hidden = !showInstalls;
  2096. }
  2097.  
  2098. function updateGlobalCommands() {
  2099.   var disableInstallFile = false;
  2100.   var disableUpdateCheck = true;
  2101.   var disableInstallUpdate = true;
  2102.  
  2103.   if (gExtensionsView.hasAttribute("update-operation")) {
  2104.     disableInstallFile = true;
  2105.     disableRestartButton();
  2106.   }
  2107.   else if (gView == "updates") {
  2108.     disableInstallUpdate = false;
  2109.     disableRestartButton();
  2110.   }
  2111.   else {
  2112.     var children = gExtensionsView.children;
  2113.     for (var i = 0; i < children.length; ++i) {
  2114.       if (children[i].getAttribute("updateable") == "true") {
  2115.         disableUpdateCheck = false;
  2116.         break;
  2117.       }
  2118.     }
  2119.  
  2120.     if (!gInstalling &&
  2121.         (gPendingActions || gPref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING)))
  2122.       enableRestartButton();
  2123.     else
  2124.       disableRestartButton();
  2125.   }
  2126.  
  2127.   setElementDisabledByID("cmd_checkUpdatesAll", disableUpdateCheck);
  2128.   setElementDisabledByID("cmd_installUpdatesAll", disableInstallUpdate);
  2129.   setElementDisabledByID("cmd_installFile", disableInstallFile);
  2130. }
  2131.  
  2132. function showUpdateInfo()
  2133. {
  2134.   document.getElementById("themePreviewArea").hidden = false;
  2135.   document.getElementById("themeSplitter").hidden = false;
  2136.   document.getElementById("showUpdateInfoButton").hidden = true;
  2137.   document.getElementById("hideUpdateInfoButton").hidden = false;
  2138.   onAddonSelect();
  2139. }
  2140.  
  2141. function hideUpdateInfo()
  2142. {
  2143.   UpdateInfoLoader.cancelLoad();
  2144.   document.getElementById("themePreviewArea").hidden = true;
  2145.   document.getElementById("themeSplitter").hidden = true;
  2146.   document.getElementById("showUpdateInfoButton").hidden = false;
  2147.   document.getElementById("hideUpdateInfoButton").hidden = true;
  2148. }
  2149.  
  2150. function checkUpdatesAll() {
  2151.   if (isOffline("offlineUpdateMsg"))
  2152.     return;
  2153.  
  2154.   if (!isXPInstallEnabled())
  2155.     return;
  2156.  
  2157.   // To support custom views we check the add-ons displayed in the list
  2158.   var items = [];
  2159.   var children = gExtensionsView.children;
  2160.   for (var i = 0; i < children.length; ++i) {
  2161.     if (children[i].getAttribute("updateable") != "false")
  2162.       items.push(gExtensionManager.getItemForID(getIDFromResourceURI(children[i].id)));
  2163.   }
  2164.  
  2165.   if (items.length > 0) {
  2166.     showProgressBar();
  2167.     var listener = new UpdateCheckListener();
  2168.     gExtensionManager.update(items, items.length,
  2169.                              nsIExtensionManager.UPDATE_CHECK_NEWVERSION,
  2170.                              listener);
  2171.   }
  2172.   if (gExtensionsView.selectedItem)
  2173.     gExtensionsView.selectedItem.focus();
  2174.  
  2175.   gPref.setBoolPref(PREF_UPDATE_NOTIFYUSER, false);
  2176. }
  2177.  
  2178. function installUpdatesAll() {
  2179.   if (isOffline("offlineUpdateMsg"))
  2180.     return;
  2181.  
  2182.   if (!isXPInstallEnabled())
  2183.     return;
  2184.  
  2185.   if (gUpdatesOnly) {
  2186.     var notifications = document.getElementById("addonsMsg");
  2187.     if (notifications.currentNotification)
  2188.       notifications.removeCurrentNotification();
  2189.   }
  2190.  
  2191.   var items = [];
  2192.   var children = gExtensionsView.children;
  2193.   for (var i = 0; i < children.length; ++i) {
  2194.     var includeUpdate = document.getAnonymousElementByAttribute(children[i], "anonid", "includeUpdate");
  2195.     if (includeUpdate && includeUpdate.checked)
  2196.       items.push(gExtensionManager.getItemForID(getIDFromResourceURI(children[i].id)));
  2197.   }
  2198.   if (items.length > 0) {
  2199.     gInstalling = true;
  2200.     gExtensionManager.addDownloads(items, items.length, null);
  2201.     showView("installs");
  2202.     // Remove the updates view if there are no add-ons left to update
  2203.     updateOptionalViews();
  2204.     updateGlobalCommands();
  2205.   }
  2206. }
  2207.  
  2208. function restartApp() {
  2209.  
  2210.   // Notify all windows that an application quit has been requested.
  2211.   var os = Components.classes["@mozilla.org/observer-service;1"]
  2212.                      .getService(Components.interfaces.nsIObserverService);
  2213.   var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
  2214.                              .createInstance(Components.interfaces.nsISupportsPRBool);
  2215.   os.notifyObservers(cancelQuit, "quit-application-requested", "restart");
  2216.  
  2217.   // Something aborted the quit process.
  2218.   if (cancelQuit.data)
  2219.     return;
  2220.  
  2221.   Components.classes["@mozilla.org/toolkit/app-startup;1"].getService(nsIAppStartup)
  2222.             .quit(nsIAppStartup.eRestart | nsIAppStartup.eAttemptQuit);
  2223. }
  2224.  
  2225. function installWithFilePicker() {
  2226.   if (!isXPInstallEnabled())
  2227.     return;
  2228.  
  2229.   if (gView == "themes")
  2230.     installSkin();
  2231.   else
  2232.     installExtension();
  2233. }
  2234.  
  2235. function closeEM() {
  2236.   closeWindow(true);
  2237. }
  2238.  
  2239. function confirmOperation(aName, aTitle, aQueryMsg, aAcceptBtn, aCancelBtn,
  2240.                           aWarnMsg, aDependantItems) {
  2241.   var params = {
  2242.     message2: getExtensionString(aQueryMsg, [aName]),
  2243.     title: getExtensionString(aTitle, [aName]),
  2244.     buttons: {
  2245.       accept: { label: getExtensionString(aAcceptBtn) },
  2246.       cancel: { label: getExtensionString(aCancelBtn), focused: true }
  2247.     }
  2248.   }
  2249.   if (aDependantItems.length > 0)
  2250.     params.message1 = getExtensionString(aWarnMsg, [aName]);
  2251.   var names = [];
  2252.   for (var i = 0; i < aDependantItems.length; ++i)
  2253.     names.push(aDependantItems[i].name + " " + aDependantItems[i].version);
  2254.  
  2255.   window.openDialog("chrome://mozapps/content/extensions/list.xul", "",
  2256.                     "titlebar,modal,centerscreen", names, params);
  2257.   return params.result == "accept";
  2258. }
  2259.  
  2260. function installCallback(item, status) {
  2261.   var resultNode = gRDF.GetResource(item.id);
  2262.   var actionArc = gRDF.GetResource(PREFIX_NS_EM + "action");
  2263.  
  2264.   // Strip out old status
  2265.   var targets = gSearchDS.GetTargets(resultNode, actionArc, true);
  2266.   while (targets.hasMoreElements()) {
  2267.     var value = targets.getNext().QueryInterface(Components.interfaces.nsIRDFNode);
  2268.     if (value)
  2269.       gSearchDS.Unassert(resultNode, actionArc, value);
  2270.   }
  2271.  
  2272.   if (status == -210) {
  2273.     // User cancelled
  2274.     if (item.getAttribute("xpiURL") in gPendingInstalls)
  2275.       delete gPendingInstalls[item.getAttribute("xpiURL")];
  2276.     return;
  2277.   }
  2278.   if (status < 0) {
  2279.     // Some other failure
  2280.     gSearchDS.Assert(resultNode,
  2281.                      actionArc,
  2282.                      gRDF.GetLiteral("failed"),
  2283.                      true);
  2284.   }
  2285.   else {
  2286.     // Success
  2287.     gSearchDS.Assert(resultNode,
  2288.                      actionArc,
  2289.                      gRDF.GetLiteral("installed"),
  2290.                      true);
  2291.   }
  2292. }
  2293.  
  2294. var gExtensionsViewController = {
  2295.   supportsCommand: function (aCommand)
  2296.   {
  2297.     var commandNode = document.getElementById(aCommand);
  2298.     return commandNode && (commandNode.parentNode == document.getElementById("extensionsCommands"));
  2299.   },
  2300.  
  2301.   isCommandEnabled: function (aCommand)
  2302.   {
  2303.     var selectedItem = gExtensionsView.selectedItem;
  2304.     if (!selectedItem)
  2305.       return false;
  2306.  
  2307.     if (selectedItem.hasAttribute("downloadURL") &&
  2308.         selectedItem.getAttribute("downloadURL") != "") {
  2309.       if (aCommand == "cmd_uninstall")
  2310.         return true;
  2311.       return false;
  2312.     }
  2313.     switch (aCommand) {
  2314.     case "cmd_installSearchResult":
  2315.       return true;
  2316.     case "cmd_useTheme":
  2317.       return selectedItem.type == nsIUpdateItem.TYPE_THEME &&
  2318.              !selectedItem.isDisabled &&
  2319.              selectedItem.opType != OP_NEEDS_UNINSTALL &&
  2320.              gCurrentTheme != selectedItem.getAttribute("internalName");
  2321.     case "cmd_options":
  2322.       return selectedItem.type == nsIUpdateItem.TYPE_EXTENSION &&
  2323.              !selectedItem.isDisabled &&
  2324.              !gInSafeMode &&
  2325.              !selectedItem.opType &&
  2326.              selectedItem.getAttribute("optionsURL") != "";
  2327.     case "cmd_about":
  2328.       return selectedItem.opType != OP_NEEDS_INSTALL &&
  2329.              selectedItem.getAttribute("plugin") != "true";
  2330.     case "cmd_homepage":
  2331.       return selectedItem.getAttribute("homepageURL") != "";
  2332.     case "cmd_uninstall":
  2333.       return (selectedItem.type != nsIUpdateItem.TYPE_THEME ||
  2334.              selectedItem.type == nsIUpdateItem.TYPE_THEME &&
  2335.              selectedItem.getAttribute("internalName") != gDefaultTheme) &&
  2336.              selectedItem.opType != OP_NEEDS_UNINSTALL &&
  2337.              selectedItem.getAttribute("locked") != "true" &&
  2338.              canWriteToLocation(selectedItem) &&
  2339.              !gExtensionsView.hasAttribute("update-operation");
  2340.     case "cmd_cancelUninstall":
  2341.       return selectedItem.opType == OP_NEEDS_UNINSTALL;
  2342.     case "cmd_cancelInstall":
  2343.       return selectedItem.opType == OP_NEEDS_INSTALL;
  2344.     case "cmd_cancelUpgrade":
  2345.       return selectedItem.opType == OP_NEEDS_UPGRADE;
  2346.     case "cmd_checkUpdate":
  2347.       return selectedItem.getAttribute("updateable") != "false" &&
  2348.              !gExtensionsView.hasAttribute("update-operation");
  2349.     case "cmd_installUpdate":
  2350.       return selectedItem.hasAttribute("availableUpdateURL") &&
  2351.              !gExtensionsView.hasAttribute("update-operation");
  2352.     case "cmd_includeUpdate":
  2353.       return selectedItem.hasAttribute("availableUpdateURL") &&
  2354.              !gExtensionsView.hasAttribute("update-operation");
  2355.     case "cmd_reallyEnable":
  2356.     // controls whether to show Enable or Disable in extensions' context menu
  2357.       return selectedItem.isDisabled &&
  2358.              selectedItem.opType != OP_NEEDS_ENABLE ||
  2359.              selectedItem.opType == OP_NEEDS_DISABLE;
  2360.     case "cmd_enable":
  2361.       return selectedItem.type != nsIUpdateItem.TYPE_THEME &&
  2362.              (selectedItem.isDisabled ||
  2363.              (!selectedItem.opType ||
  2364.              selectedItem.opType == "needs-disable")) &&
  2365.              !selectedItem.isBlocklisted &&
  2366.              (!gCheckUpdateSecurity || selectedItem.providesUpdatesSecurely) &&
  2367.              (!gCheckCompat || selectedItem.isCompatible) &&
  2368.              selectedItem.satisfiesDependencies &&
  2369.              !gExtensionsView.hasAttribute("update-operation");
  2370.     case "cmd_disable":
  2371.       return selectedItem.type != nsIUpdateItem.TYPE_THEME &&
  2372.              (!selectedItem.isDisabled &&
  2373.              !selectedItem.opType ||
  2374.              selectedItem.opType == OP_NEEDS_ENABLE) &&
  2375.              !selectedItem.isBlocklisted &&
  2376.              selectedItem.satisfiesDependencies &&
  2377.              !gExtensionsView.hasAttribute("update-operation");
  2378.     }
  2379.     return false;
  2380.   },
  2381.  
  2382.   doCommand: function (aCommand)
  2383.   {
  2384.     if (this.isCommandEnabled(aCommand))
  2385.       this.commands[aCommand](gExtensionsView.selectedItem);
  2386.   },
  2387.  
  2388.   onCommandUpdate: function ()
  2389.   {
  2390.     var extensionsCommands = document.getElementById("extensionsCommands");
  2391.     for (var i = 0; i < extensionsCommands.childNodes.length; ++i)
  2392.       this.updateCommand(extensionsCommands.childNodes[i]);
  2393.   },
  2394.  
  2395.   updateCommand: function (command)
  2396.   {
  2397.     if (this.isCommandEnabled(command.id))
  2398.       command.removeAttribute("disabled");
  2399.     else
  2400.       command.setAttribute("disabled", "true");
  2401.   },
  2402.  
  2403.   commands: {
  2404.     cmd_installSearchResult: function (aSelectedItem)
  2405.     {
  2406.       if (!isXPInstallEnabled())
  2407.         return;
  2408.  
  2409.       if (aSelectedItem.hasAttribute("eula")) {
  2410.         var eula = {
  2411.           name: aSelectedItem.getAttribute("name"),
  2412.           text: aSelectedItem.getAttribute("eula"),
  2413.           accepted: false
  2414.         };
  2415.         window.openDialog("chrome://mozapps/content/extensions/eula.xul", "_blank",
  2416.                           "chrome,dialog,modal,centerscreen,resizable=no", eula);
  2417.         if (!eula.accepted)
  2418.           return;
  2419.       }
  2420.  
  2421.       var details = {
  2422.         URL: aSelectedItem.getAttribute("xpiURL"),
  2423.         Hash: aSelectedItem.getAttribute("xpiHash"),
  2424.         IconURL: aSelectedItem.getAttribute("iconURL"),
  2425.         toString: function () { return this.URL; }
  2426.       };
  2427.       var params = [];
  2428.       params[aSelectedItem.getAttribute("name")] = details;
  2429.  
  2430.       gSearchDS.Assert(gRDF.GetResource(aSelectedItem.id),
  2431.                        gRDF.GetResource(PREFIX_NS_EM + "action"),
  2432.                        gRDF.GetLiteral("connecting"),
  2433.                        true);
  2434.       // Remember this install so we can update the status when install starts
  2435.       gPendingInstalls[details.URL] = aSelectedItem.id;
  2436.       InstallTrigger.install(params, function(url, status) { installCallback(aSelectedItem, status); });
  2437.     },
  2438.  
  2439.     cmd_close: function (aSelectedItem)
  2440.     {
  2441.       closeWindow(true);
  2442.     },
  2443.  
  2444.     cmd_useTheme: function (aSelectedItem)
  2445.     {
  2446.       gCurrentTheme = aSelectedItem.getAttribute("internalName");
  2447.  
  2448.       // If choosing the current skin just reset the pending change
  2449.       if (gCurrentTheme == gPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN)) {
  2450.         gPref.clearUserPref(PREF_EXTENSIONS_DSS_SWITCHPENDING);
  2451.         gPref.clearUserPref(PREF_DSS_SKIN_TO_SELECT);
  2452.         clearRestartMessage();
  2453.       }
  2454.       else {
  2455.         if (gPref.getBoolPref(PREF_EXTENSIONS_DSS_ENABLED)) {
  2456.           gPref.setCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN, gCurrentTheme);
  2457.         }
  2458.         else {
  2459.           // Theme change will happen on next startup, this flag tells
  2460.           // the Theme Manager that it needs to show "This theme will
  2461.           // be selected after a restart" text in the selected theme
  2462.           // item.
  2463.           gPref.setBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING, true);
  2464.           gPref.setCharPref(PREF_DSS_SKIN_TO_SELECT, gCurrentTheme);
  2465.           clearRestartMessage();
  2466.           setRestartMessage(aSelectedItem);
  2467.         }
  2468.       }
  2469.  
  2470.       // Flush preference change to disk
  2471.       gPref.QueryInterface(Components.interfaces.nsIPrefService)
  2472.            .savePrefFile(null);
  2473.  
  2474.       // disable the useThemeButton
  2475.       gExtensionsViewController.onCommandUpdate();
  2476.     },
  2477.  
  2478.     cmd_options: function (aSelectedItem)
  2479.     {
  2480.       if (!aSelectedItem) return;
  2481.       var optionsURL = aSelectedItem.getAttribute("optionsURL");
  2482.       if (optionsURL == "")
  2483.         return;
  2484.  
  2485.       var windows = Components.classes['@mozilla.org/appshell/window-mediator;1']
  2486.                               .getService(Components.interfaces.nsIWindowMediator)
  2487.                               .getEnumerator(null);
  2488.       while (windows.hasMoreElements()) {
  2489.         var win = windows.getNext();
  2490.         if (win.document.documentURI == optionsURL) {
  2491.           win.focus();
  2492.           return;
  2493.         }
  2494.       }
  2495.  
  2496.       var features;
  2497.       try {
  2498.         var instantApply = gPref.getBoolPref("browser.preferences.instantApply");
  2499.         features = "chrome,titlebar,toolbar,centerscreen" + (instantApply ? ",dialog=no" : ",modal");
  2500.       }
  2501.       catch (e) {
  2502.         features = "chrome,titlebar,toolbar,centerscreen,modal";
  2503.       }
  2504.       openDialog(optionsURL, "", features);
  2505.     },
  2506.  
  2507.     cmd_homepage: function (aSelectedItem)
  2508.     {
  2509.       if (!aSelectedItem) return;
  2510.       var homepageURL = aSelectedItem.getAttribute("homepageURL");
  2511.       // only allow http(s) homepages
  2512.       if (isSafeURI(homepageURL))
  2513.         openURL(homepageURL);
  2514.     },
  2515.  
  2516.     cmd_about: function (aSelectedItem)
  2517.     {
  2518.       if (!aSelectedItem) return;
  2519.       var aboutURL = aSelectedItem.getAttribute("aboutURL");
  2520.       if (aboutURL != "")
  2521.         openDialog(aboutURL, "", "chrome,centerscreen,modal");
  2522.       else
  2523.         openDialog("chrome://mozapps/content/extensions/about.xul", "", "chrome,centerscreen,modal", aSelectedItem.id, gExtensionsView.database);
  2524.     },
  2525.  
  2526.     cmd_checkUpdate: function (aSelectedItem)
  2527.     {
  2528.       if (isOffline("offlineUpdateMsg"))
  2529.         return;
  2530.  
  2531.       if (!isXPInstallEnabled())
  2532.         return;
  2533.  
  2534.       var id = getIDFromResourceURI(aSelectedItem.id);
  2535.       var items = [gExtensionManager.getItemForID(id)];
  2536.       var listener = new UpdateCheckListener();
  2537.       gExtensionManager.update(items, items.length,
  2538.                                nsIExtensionManager.UPDATE_CHECK_NEWVERSION,
  2539.                                listener);
  2540.     },
  2541.  
  2542.     cmd_installUpdate: function (aSelectedItem)
  2543.     {
  2544.       if (isOffline("offlineUpdateMsg"))
  2545.         return;
  2546.  
  2547.       if (!isXPInstallEnabled())
  2548.         return;
  2549.  
  2550.       showView("installs");
  2551.       var item = gExtensionManager.getItemForID(getIDFromResourceURI(aSelectedItem.id));
  2552.       gInstalling = true;
  2553.       gExtensionManager.addDownloads([item], 1, null);
  2554.       // Remove the updates view if there are no add-ons left to update
  2555.       updateOptionalViews();
  2556.       updateGlobalCommands();
  2557.     },
  2558.  
  2559.     cmd_includeUpdate: function (aSelectedItem)
  2560.     {
  2561.       var includeUpdate = document.getAnonymousElementByAttribute(aSelectedItem, "anonid", "includeUpdate");
  2562.       includeUpdate.checked = !includeUpdate.checked;
  2563.     },
  2564.  
  2565.     cmd_uninstall: function (aSelectedItem)
  2566.     {
  2567.       // Confirm the uninstall
  2568.       var name = aSelectedItem.getAttribute("name");
  2569.       var id = getIDFromResourceURI(aSelectedItem.id);
  2570.       var dependentItems = gExtensionManager.getDependentItemListForID(id, true, { });
  2571.       var result = confirmOperation(name, "uninstallTitle", "uninstallQueryMessage",
  2572.                                     "uninstallButton", "cancelButton",
  2573.                                     "uninstallWarnDependMsg", dependentItems);
  2574.       if (!result)
  2575.         return;
  2576.  
  2577.       if (aSelectedItem.type == nsIUpdateItem.TYPE_THEME) {
  2578.         var theme = aSelectedItem.getAttribute("internalName");
  2579.         var selectedTheme = gPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  2580.         if (theme == gCurrentTheme) {
  2581.           if (gPref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING)) {
  2582.             var item = getItemForInternalName(selectedTheme);
  2583.             if (item && item.getAttribute("opType") == OP_NEEDS_UNINSTALL) {
  2584.               // We're uninstalling the theme to be switched to, but the current
  2585.               // theme is already marked for uninstall so switch to the default
  2586.               // theme
  2587.               this.cmd_useTheme(document.getElementById(PREFIX_ITEM_URI + "{972ce4c6-7e08-4474-a285-3208198ce6fd}"));
  2588.             }
  2589.             else {
  2590.               // The theme being uninstalled is the theme to be changed to on
  2591.               // restart so clear the pending theme change.
  2592.               gPref.clearUserPref(PREF_EXTENSIONS_DSS_SWITCHPENDING);
  2593.               gPref.clearUserPref(PREF_DSS_SKIN_TO_SELECT);
  2594.               clearRestartMessage();
  2595.             }
  2596.           }
  2597.           else {
  2598.             // The theme being uninstalled is the current theme, we need to reselect
  2599.             // the default.
  2600.             this.cmd_useTheme(document.getElementById(PREFIX_ITEM_URI + "{972ce4c6-7e08-4474-a285-3208198ce6fd}"));
  2601.           }
  2602.         }
  2603.  
  2604.         // If the theme is not the current theme then it will vanish and nothing
  2605.         // will be selected so update the selection now.
  2606.         if (theme != selectedTheme) {
  2607.           if (!gExtensionsView.goDown())
  2608.             gExtensionsView.goUp();
  2609.         }
  2610.       }
  2611.       gExtensionManager.uninstallItem(getIDFromResourceURI(aSelectedItem.id));
  2612.       gExtensionsViewController.onCommandUpdate();
  2613.       if (gExtensionsView.selectedItem)
  2614.         gExtensionsView.selectedItem.focus();
  2615.       updateOptionalViews();
  2616.       updateGlobalCommands();
  2617.     },
  2618.  
  2619.     cmd_cancelUninstall: function (aSelectedItem)
  2620.     {
  2621.       gExtensionManager.cancelUninstallItem(getIDFromResourceURI(aSelectedItem.id));
  2622.       gExtensionsViewController.onCommandUpdate();
  2623.       gExtensionsView.selectedItem.focus();
  2624.       updateOptionalViews();
  2625.       updateGlobalCommands();
  2626.     },
  2627.  
  2628.     cmd_cancelInstall: function (aSelectedItem)
  2629.     {
  2630.       var name = aSelectedItem.getAttribute("name");
  2631.       var result = false;
  2632.       // Confirm cancelling the operation
  2633.       switch (aSelectedItem.opType)
  2634.       {
  2635.         case OP_NEEDS_INSTALL:
  2636.           result = confirmOperation(name, "cancelInstallTitle", "cancelInstallQueryMessage",
  2637.                                     "cancelInstallButton", "cancelCancelInstallButton",
  2638.                                     null, []);
  2639.           break;
  2640.         case OP_NEEDS_UPGRADE:
  2641.           result = confirmOperation(name, "cancelUpgradeTitle", "cancelUpgradeQueryMessage",
  2642.                                     "cancelUpgradeButton", "cancelCancelUpgradeButton",
  2643.                                     null, []);
  2644.           break;
  2645.       }
  2646.       if (!result)
  2647.         return;
  2648.  
  2649.       var id = getIDFromResourceURI(aSelectedItem.id);
  2650.       gExtensionManager.cancelInstallItem(id);
  2651.       if (gSearchDS) {
  2652.         // Check for a search result for this entry
  2653.         var searchResult = gSearchDS.GetSource(gRDF.GetResource(PREFIX_NS_EM + "addonID"),
  2654.                                                gRDF.GetLiteral(id),
  2655.                                                true);
  2656.         if (searchResult) {
  2657.           // Remove the installed status
  2658.           gSearchDS.Unassert(searchResult,
  2659.                              gRDF.GetResource(PREFIX_NS_EM + "action"),
  2660.                              gRDF.GetLiteral("installed"),
  2661.                              true);
  2662.         }
  2663.       }
  2664.       gExtensionsViewController.onCommandUpdate();
  2665.       gExtensionsView.selectedItem.focus();
  2666.       updateOptionalViews();
  2667.       updateGlobalCommands();
  2668.     },
  2669.  
  2670.     cmd_cancelUpgrade: function (aSelectedItem)
  2671.     {
  2672.       this.cmd_cancelInstall(aSelectedItem);
  2673.     },
  2674.  
  2675.     cmd_disable: function (aSelectedItem)
  2676.     {
  2677.       if (aSelectedItem.getAttribute("plugin") == "true") {
  2678.         var name = aSelectedItem.getAttribute("name");
  2679.         var desc = aSelectedItem.getAttribute("description");
  2680.         togglePluginDisabled(name, desc);
  2681.         return;
  2682.       }
  2683.  
  2684.       var id = getIDFromResourceURI(aSelectedItem.id);
  2685.       var dependentItems = gExtensionManager.getDependentItemListForID(id, false, { });
  2686.  
  2687.       if (dependentItems.length > 0) {
  2688.         name = aSelectedItem.getAttribute("name");
  2689.         var result = confirmOperation(name, "disableTitle", "disableQueryMessage",
  2690.                                       "disableButton", "cancelButton",
  2691.                                       "disableWarningDependMessage", dependentItems);
  2692.         if (!result)
  2693.           return;
  2694.       }
  2695.       gExtensionManager.disableItem(id);
  2696.       gExtensionsViewController.onCommandUpdate();
  2697.       gExtensionsView.selectedItem.focus();
  2698.       updateOptionalViews();
  2699.       updateGlobalCommands();
  2700.     },
  2701.  
  2702.     cmd_enable: function (aSelectedItem)
  2703.     {
  2704.       if (aSelectedItem.getAttribute("plugin") == "true") {
  2705.         var name = aSelectedItem.getAttribute("name");
  2706.         var desc = aSelectedItem.getAttribute("description");
  2707.         togglePluginDisabled(name, desc);
  2708.         return;
  2709.       }
  2710.  
  2711.       gExtensionManager.enableItem(getIDFromResourceURI(aSelectedItem.id));
  2712.       gExtensionsViewController.onCommandUpdate();
  2713.       gExtensionsView.selectedItem.focus();
  2714.       updateOptionalViews();
  2715.       updateGlobalCommands();
  2716.     }
  2717.   }
  2718. };
  2719.  
  2720. //////////////////////////////////////////////////////////////////////////
  2721. // functions to support installing of themes in apps other than firefox //
  2722. //////////////////////////////////////////////////////////////////////////
  2723. function installSkin()
  2724. {
  2725.   // 1) Prompt the user for the location of the theme to install.
  2726.   var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  2727.   fp.init(window, getExtensionString("installThemePickerTitle"), nsIFilePicker.modeOpen);
  2728.   fp.appendFilter(getExtensionString("themesFilter"), "*.jar");
  2729.   fp.appendFilters(nsIFilePicker.filterAll);
  2730.  
  2731.   var ret = fp.show();
  2732.   if (ret == nsIFilePicker.returnOK)
  2733.   {
  2734.     var ioService = Components.classes['@mozilla.org/network/io-service;1'].getService(nsIIOService);
  2735.     var fileProtocolHandler =
  2736.     ioService.getProtocolHandler("file").QueryInterface(nsIFileProtocolHandler);
  2737.     var url = fileProtocolHandler.newFileURI(fp.file).QueryInterface(nsIURL);
  2738.     InstallTrigger.installChrome(InstallTrigger.SKIN, url.spec, decodeURIComponent(url.fileBaseName));
  2739.   }
  2740. }
  2741.  
  2742. function installExtension()
  2743. {
  2744.   var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  2745.   fp.init(window, getExtensionString("installExtensionPickerTitle"), nsIFilePicker.modeOpen);
  2746.   fp.appendFilter(getExtensionString("extensionFilter"), "*.xpi");
  2747.   fp.appendFilters(nsIFilePicker.filterAll);
  2748.  
  2749.   var ret = fp.show();
  2750.   if (ret == nsIFilePicker.returnOK)
  2751.   {
  2752.     var ioService = Components.classes['@mozilla.org/network/io-service;1'].getService(nsIIOService);
  2753.     var fileProtocolHandler =
  2754.     ioService.getProtocolHandler("file").QueryInterface(nsIFileProtocolHandler);
  2755.     var url = fileProtocolHandler.newFileURI(fp.file).QueryInterface(nsIURL);
  2756.     var xpi = {};
  2757.     xpi[decodeURIComponent(url.fileBaseName)] = url.spec;
  2758.     InstallTrigger.install(xpi);
  2759.   }
  2760. }
  2761.