home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2005 October / maximum-cd-2005-10.iso / Software / Apps / FirefoxSetup1.0.6.exe / browser.xpi / bin / chrome / toolkit.jar / content / mozapps / extensions / extensions.js < prev    next >
Encoding:
Text File  |  2004-10-08  |  32.5 KB  |  858 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Globals
  3.  
  4. const kObserverServiceProgID = "@mozilla.org/observer-service;1";
  5. const nsIUpdateItem = Components.interfaces.nsIUpdateItem;
  6.  
  7. var gExtensionManager = null;
  8. var gExtensionsView   = null;
  9. var gWindowState      = "";
  10. var gURIPrefix        = ""; // extension or theme prefix
  11. var gDSRoot           = ""; // extension or theme root
  12. var gGetMoreURL       = "";
  13. var gCurrentTheme     = "";
  14. var gDownloadManager  = null;
  15. var gObserverIndex    = -1;
  16. var gItemType         = -1;
  17.  
  18. const PREF_APP_ID                           = "app.id";
  19. const PREF_EXTENSIONS_GETMORETHEMESURL      = "extensions.getMoreThemesURL";
  20. const PREF_EXTENSIONS_GETMOREEXTENSIONSURL  = "extensions.getMoreExtensionsURL";
  21. const PREF_EXTENSIONS_DSS_ENABLED           = "extensions.dss.enabled";
  22. const PREF_EXTENSIONS_DSS_SWITCHPENDING     = "extensions.dss.switchPending";
  23. const PREF_EM_LAST_SELECTED_SKIN            = "extensions.lastSelectedSkin";
  24. const PREF_GENERAL_SKINS_SELECTEDSKIN       = "general.skins.selectedSkin";
  25.  
  26. const KEY_DEFAULT_THEME = "classic/1.0";
  27.  
  28. ///////////////////////////////////////////////////////////////////////////////
  29. // Utility Functions 
  30.  
  31. const PREFIX_EXTENSION  = "urn:mozilla:extension:";
  32. const PREFIX_THEME      = "urn:mozilla:theme:";
  33.  
  34. function getItemPrefix(aItemType)
  35. {
  36.   var prefix = "";
  37.   if (aItemType & nsIUpdateItem.TYPE_EXTENSION) 
  38.     prefix = PREFIX_EXTENSION;
  39.   else if (aItemType & nsIUpdateItem.TYPE_THEME)
  40.     prefix = PREFIX_THEME;
  41.   return prefix;
  42. }
  43.  
  44. function stripPrefix(aURI, aItemType)
  45. {
  46.   var val = aURI;
  47.   if (aItemType == nsIUpdateItem.TYPE_ADDON)
  48.     val = stripPrefix(aURI, getItemType(aURI));
  49.   else {
  50.     var prefix = getItemPrefix(aItemType);
  51.     if (prefix && aURI.substr(0, prefix.length) == prefix)  
  52.       val = aURI.substr(prefix.length, aURI.length);
  53.   }
  54.   return val;
  55. }
  56.  
  57. function openURL(aURL)
  58. {
  59.   openDialog("chrome://browser/content/browser.xul", "_blank", "chrome,all,dialog=no", aURL, null, null);
  60. }
  61.  
  62. function flushDataSource()
  63. {
  64.   var rds = gExtensionManager.datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
  65.   if (rds)
  66.     rds.Flush();
  67. }
  68.  
  69. function setRestartMessage(aItem)
  70. {
  71.   var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
  72.                       .getService(Components.interfaces.nsIStringBundleService);
  73.   var extensionStrings = sbs.createBundle("chrome://mozapps/locale/extensions/extensions.properties");
  74.   var brandStrings = sbs.createBundle("chrome://global/locale/brand.properties");
  75.   var brandShortName = brandStrings.GetStringFromName("brandShortName");
  76.   var themeName = aItem.getAttribute("name");
  77.   var restartMessage = extensionStrings.formatStringFromName("dssSwitchAfterRestart", 
  78.                                                              [brandShortName], 1);
  79.   aItem.setAttribute("creator", restartMessage);
  80. }
  81.  
  82. ///////////////////////////////////////////////////////////////////////////////
  83. // Event Handlers
  84. function onExtensionSelect(aEvent)
  85. {
  86.   if (aEvent.target.selected)
  87.     aEvent.target.setAttribute("last-selected", aEvent.target.selected.id);
  88.   else
  89.     aEvent.target.removeAttribute("last-selected");
  90. }
  91.  
  92. ///////////////////////////////////////////////////////////////////////////////
  93. // Startup, Shutdown
  94. function Startup() 
  95. {
  96.   gWindowState = window.location.search.substr("?type=".length, window.location.search.length);
  97.   
  98.   var isExtensions = gWindowState == "extensions";
  99.   gURIPrefix  = isExtensions ? "urn:mozilla:extension:" : "urn:mozilla:theme:";
  100.   gDSRoot     = isExtensions ? "urn:mozilla:extension:root" : "urn:mozilla:theme:root";
  101.   gItemType   = isExtensions ? nsIUpdateItem.TYPE_EXTENSION : nsIUpdateItem.TYPE_THEME;
  102.   
  103.   document.documentElement.setAttribute("windowtype", document.documentElement.getAttribute("windowtype") + "-" + gWindowState);
  104.  
  105.   gExtensionsView = document.getElementById("extensionsView");
  106.   gExtensionsView.setAttribute("state", gWindowState);
  107.   gExtensionManager = Components.classes["@mozilla.org/extensions/manager;1"]
  108.                                 .getService(Components.interfaces.nsIExtensionManager);
  109.   
  110.   // Extension Command Updating is handled by a command controller.
  111.   gExtensionsView.controllers.appendController(gExtensionsViewController);
  112.  
  113.   // This persists the last-selected extension
  114.   gExtensionsView.addEventListener("richview-select", onExtensionSelect, false);
  115.  
  116.   // Finally, update the UI. 
  117.   gExtensionsView.database.AddDataSource(gExtensionManager.datasource);
  118.   gExtensionsView.setAttribute("ref", gDSRoot);
  119.   gExtensionsView.focus();
  120.   
  121.   var pref = Components.classes["@mozilla.org/preferences-service;1"]
  122.                        .getService(Components.interfaces.nsIPrefBranch);
  123.   if (!isExtensions) {
  124.     gExtensionsView.addEventListener("richview-select", onThemeSelect, false);
  125.  
  126.     if (pref.prefHasUserValue(PREF_GENERAL_SKINS_SELECTEDSKIN))
  127.       gCurrentTheme = pref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  128.     else
  129.       gCurrentTheme = KEY_DEFAULT_THEME;
  130.       
  131.     var useThemeButton = document.getElementById("useThemeButton");
  132.     useThemeButton.hidden = false;
  133.  
  134.     var optionsButton = document.getElementById("optionsButton");
  135.     optionsButton.hidden = true;
  136.     
  137.     var pref = Components.classes["@mozilla.org/preferences-service;1"]
  138.                          .getService(Components.interfaces.nsIPrefBranch);
  139.     if (!pref.getBoolPref(PREF_EXTENSIONS_DSS_ENABLED) && 
  140.         pref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING)) {
  141.       var lastSelectedSkin = pref.getCharPref(PREF_EM_LAST_SELECTED_SKIN);
  142.       for (var i = 0; i < gExtensionsView.childNodes.length; ++i) {
  143.         var item = gExtensionsView.childNodes[i];
  144.         if (item.getAttribute("internalName") == lastSelectedSkin) {
  145.           setRestartMessage(item);
  146.           break;
  147.         }
  148.       }
  149.     }
  150.   }
  151.   
  152.   // Restore the last-selected extension
  153.   var lastSelected = gExtensionsView.getAttribute("last-selected");
  154.   if (lastSelected != "")
  155.     lastSelected = document.getElementById(lastSelected);
  156.   if (!lastSelected) 
  157.     gExtensionsView.selectionForward();
  158.   else
  159.     gExtensionsView.selected = lastSelected;
  160.  
  161.   var extensionsStrings = document.getElementById("extensionsStrings");
  162.   document.documentElement.setAttribute("title", extensionsStrings.getString(gWindowState + "Title"));
  163.   
  164.   gExtensionsViewController.onCommandUpdate(); 
  165.   
  166.   gGetMoreURL = pref.getComplexValue(isExtensions ? PREF_EXTENSIONS_GETMOREEXTENSIONSURL 
  167.                                                   : PREF_EXTENSIONS_GETMORETHEMESURL, 
  168.                                      Components.interfaces.nsIPrefLocalizedString).data;
  169.   gGetMoreURL = gGetMoreURL.replace(/%APPID%/g, pref.getCharPref(PREF_APP_ID));
  170.   // Update various pieces of state-dependant UI
  171.   var getMore = document.getElementById("getMore");
  172.   getMore.setAttribute("value", getMore.getAttribute(isExtensions ? "valueextensions" : "valuethemes"));
  173.   getMore.setAttribute("tooltiptext", getMore.getAttribute(isExtensions ? "tooltiptextextensions" : "tooltiptextthemes"));
  174.   
  175.   if (!isExtensions) {
  176.     var themePreviewArea = document.getElementById("themePreviewArea");
  177.     themePreviewArea.hidden = false;
  178.     gExtensionsView.removeAttribute("flex");
  179.   }
  180.   
  181.   // Set Initial Size
  182.   var win = document.documentElement;
  183.   if (!win.hasAttribute("width") || !win.hasAttribute("height")) {
  184.     win.setAttribute("width", isExtensions ? 400 : 500);
  185.     win.setAttribute("height", isExtensions ? 300 : 380);
  186.   }
  187.  
  188.   // Now look and see if we're being opened by XPInstall
  189.   gDownloadManager = new XPInstallDownloadManager();
  190.   var os = Components.classes["@mozilla.org/observer-service;1"]
  191.                      .getService(Components.interfaces.nsIObserverService);
  192.   os.addObserver(gDownloadManager, "xpinstall-download-started", false);
  193.  
  194.   gObserverIndex = gExtensionManager.addDownloadObserver(gDownloadManager);
  195.   
  196.   if ("arguments" in window) {
  197.     try {
  198.       var params = window.arguments[0].QueryInterface(Components.interfaces.nsIDialogParamBlock);
  199.       gDownloadManager.addDownloads(params);
  200.     }
  201.     catch (e) { }
  202.   }
  203.   
  204.   // Set the tooltips
  205.   if (!isExtensions) {
  206.     var extensionsStrings = document.getElementById("extensionsStrings");
  207.     document.getElementById("uninstallButton").setAttribute("tooltiptext", extensionsStrings.getString("cmdUninstallTooltipTheme"));
  208.     document.getElementById("updateButton").setAttribute("tooltiptext", extensionsStrings.getString("cmdUpdateTooltipTheme"));
  209.   }
  210. }
  211.  
  212. function Shutdown() 
  213. {
  214.   if (gWindowState != "extensions")
  215.     gExtensionsView.removeEventListener("richview-select", onThemeSelect, false);
  216.   
  217.   gExtensionManager.removeDownloadObserverAt(gObserverIndex);
  218.  
  219.   var os = Components.classes["@mozilla.org/observer-service;1"]
  220.                      .getService(Components.interfaces.nsIObserverService);
  221.   if (gDownloadManager) 
  222.     os.removeObserver(gDownloadManager, "xpinstall-download-started");
  223. }
  224.  
  225. ///////////////////////////////////////////////////////////////////////////////
  226. //
  227. // XPInstall
  228. //
  229.  
  230. function getURLSpecFromFile(aFile)
  231. {
  232.   var ioServ = Components.classes["@mozilla.org/network/io-service;1"]
  233.                           .getService(Components.interfaces.nsIIOService);
  234.   var fph = ioServ.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  235.   return fph.getURLSpecFromFile(aFile);
  236. }
  237.  
  238. function XPInstallDownloadManager()
  239. {
  240.   var extensionsStrings = document.getElementById("extensionsStrings");
  241.   this._statusFormatKBMB  = extensionsStrings.getString("statusFormatKBMB");
  242.   this._statusFormatKBKB  = extensionsStrings.getString("statusFormatKBKB");
  243.   this._statusFormatMBMB  = extensionsStrings.getString("statusFormatMBMB");
  244. }
  245.  
  246. XPInstallDownloadManager.prototype = {
  247.   _statusFormat     : null,
  248.   _statusFormatKBMB : null,
  249.   _statusFormatKBKB : null,
  250.   _statusFormatMBMB : null,
  251.   
  252.   observe: function (aSubject, aTopic, aData) 
  253.   {
  254.     switch (aTopic) {
  255.     case "xpinstall-download-started":
  256.       var params = aSubject.QueryInterface(Components.interfaces.nsISupportsArray);
  257.       var paramBlock = params.GetElementAt(0).QueryInterface(Components.interfaces.nsISupportsInterfacePointer);
  258.       paramBlock = paramBlock.data.QueryInterface(Components.interfaces.nsIDialogParamBlock);
  259.       this.addDownloads(paramBlock);
  260.       break;
  261.     }
  262.   },
  263.   
  264.   addDownloads: function (aParams)
  265.   {
  266.     var numXPInstallItems = aParams.GetInt(1);
  267.     var isExtensions = gWindowState == "extensions";
  268.     
  269.     var items = [];
  270.     for (var i = 0; i < numXPInstallItems;) {
  271.       var displayName = aParams.GetString(i++);
  272.       var url = aParams.GetString(i++);
  273.       var iconURL = aParams.GetString(i++);
  274.       if (!iconURL) { 
  275.         iconURL = isExtensions ? "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png" : 
  276.                                  "chrome://mozapps/skin/extensions/themeGeneric.png";
  277.       }
  278.       
  279.       var type = isExtensions ? nsIUpdateItem.TYPE_EXTENSION : nsIUpdateItem.TYPE_THEME;
  280.       // gExtensionManager.addDownload(displayName, url, iconURL, type);
  281.       var item = Components.classes["@mozilla.org/updates/item;1"]
  282.                            .createInstance(Components.interfaces.nsIUpdateItem);
  283.       item.init(url, " ", "", "", displayName, -1, url, iconURL, "", type);
  284.       items.push(item);
  285.  
  286.       // Advance the enumerator
  287.       var certName = aParams.GetString(i++);
  288.     }
  289.     
  290.     gExtensionManager.addDownloads(items, items.length);
  291.   },
  292.  
  293.   removeDownload: function (aEvent)
  294.   {
  295.   
  296.   },
  297.   
  298.   /////////////////////////////////////////////////////////////////////////////  
  299.   // nsIExtensionDownloadProgressListener
  300.   onStateChange: function (aURL, aState, aValue)
  301.   {
  302.     const nsIXPIProgressDialog = Components.interfaces.nsIXPIProgressDialog;
  303.     var element = document.getElementById(aURL);
  304.     if (!element) return;
  305.     switch (aState) {
  306.     case nsIXPIProgressDialog.DOWNLOAD_START:
  307.       element.setAttribute("state", "waiting");
  308.       element.setAttribute("progress", "0");
  309.       break;
  310.     case nsIXPIProgressDialog.DOWNLOAD_DONE:
  311.       element.setAttribute("progress", "100");
  312.       break;
  313.     case nsIXPIProgressDialog.INSTALL_START:
  314.       element.setAttribute("state", "installing");
  315.       break;
  316.     case nsIXPIProgressDialog.INSTALL_DONE:
  317.       dump("*** state change = " + aURL + ", state = " + aState + ", value = " + aValue + "\n");
  318.       element.setAttribute("state", "done");
  319.       var msg;
  320.       if (aValue != 0) {
  321.         var xpinstallStrings = document.getElementById("xpinstallStrings");
  322.         try {
  323.           msg = xpinstallStrings.getString("error" + aValue);
  324.         }
  325.         catch (e) {
  326.           msg = xpinstallStrings.getFormattedString("unknown.error", [aValue]);
  327.         }
  328.         var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
  329.                             .getService(Components.interfaces.nsIStringBundleService);
  330.         var extensionStrings = sbs.createBundle("chrome://mozapps/locale/extensions/extensions.properties");
  331.         var title = extensionStrings.GetStringFromName("errorInstallTitle");
  332.  
  333.         var brandStrings = sbs.createBundle("chrome://global/locale/brand.properties");
  334.         var brandShortName = brandStrings.GetStringFromName("brandShortName");
  335.         var params = [brandShortName, aURL, msg];
  336.         var message = extensionStrings.formatStringFromName("errorInstallMessage", params, params.length);
  337.         
  338.         var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  339.                            .getService(Components.interfaces.nsIPromptService);
  340.         ps.alert(window, title, message);
  341.         element.setAttribute("status", msg);
  342.  
  343.       }
  344.       // Remove the dummy, since we installed successfully
  345.       var type = gWindowState == "extensions" ? nsIUpdateItem.TYPE_EXTENSION 
  346.                                               : nsIUpdateItem.TYPE_THEME;
  347.       gExtensionManager.removeDownload(aURL, type);
  348.       break;
  349.     case nsIXPIProgressDialog.DIALOG_CLOSE:
  350.       break;
  351.     }
  352.   },
  353.   
  354.   _urls: { },
  355.   onProgress: function (aURL, aValue, aMaxValue)
  356.   {
  357.     var element = document.getElementById(aURL);
  358.     if (!element) return;
  359.     var percent = Math.round((aValue / aMaxValue) * 100);
  360.     if (percent > 1 && !(aURL in this._urls)) {
  361.       this._urls[aURL] = true;
  362.       element.setAttribute("state", "downloading");
  363.     }
  364.     element.setAttribute("progress", percent);
  365.     
  366.     var KBProgress = parseInt(aValue/1024 + .5);
  367.     var KBTotal = parseInt(aMaxValue/1024 + .5);
  368.     element.setAttribute("status", this._formatKBytes(KBProgress, KBTotal));
  369.   },
  370.   
  371.   _replaceInsert: function ( text, index, value ) 
  372.   {
  373.     var result = text;
  374.     var regExp = new RegExp( "#"+index );
  375.     result = result.replace( regExp, value );
  376.     return result;
  377.   },
  378.   
  379.   // aBytes     aTotalKBytes    returns:
  380.   // x, < 1MB   y < 1MB         x of y KB
  381.   // x, < 1MB   y >= 1MB        x KB of y MB
  382.   // x, >= 1MB  y >= 1MB        x of y MB
  383.   _formatKBytes: function (aKBytes, aTotalKBytes)
  384.   {
  385.     var progressHasMB = parseInt(aKBytes/1000) > 0;
  386.     var totalHasMB = parseInt(aTotalKBytes/1000) > 0;
  387.     
  388.     var format = "";
  389.     if (!progressHasMB && !totalHasMB) {
  390.       format = this._statusFormatKBKB;
  391.       format = this._replaceInsert(format, 1, aKBytes);
  392.       format = this._replaceInsert(format, 2, aTotalKBytes);
  393.     }
  394.     else if (progressHasMB && totalHasMB) {
  395.       format = this._statusFormatMBMB;
  396.       format = this._replaceInsert(format, 1, (aKBytes / 1000).toFixed(1));
  397.       format = this._replaceInsert(format, 2, (aTotalKBytes / 1000).toFixed(1));
  398.     }
  399.     else if (totalHasMB && !progressHasMB) {
  400.       format = this._statusFormatKBMB;
  401.       format = this._replaceInsert(format, 1, aKBytes);
  402.       format = this._replaceInsert(format, 2, (aTotalKBytes / 1000).toFixed(1));
  403.     }
  404.     else {
  405.       // This is an undefined state!
  406.       dump("*** huh?!\n");
  407.     }
  408.     
  409.     return format;  
  410.   },
  411.  
  412.   /////////////////////////////////////////////////////////////////////////////
  413.   // nsISupports
  414.   QueryInterface: function (aIID) 
  415.   {
  416.     if (!aIID.equals(Components.interfaces.nsIExtensionDownloadProgressListener) &&
  417.         !aIID.equals(Components.interfaces.nsISupports))
  418.       throw Components.results.NS_ERROR_NO_INTERFACE;
  419.     return this;
  420.   }
  421. };
  422.  
  423. ///////////////////////////////////////////////////////////////////////////////
  424. //
  425. // View Event Handlers
  426. //
  427. function onViewDoubleClick(aEvent)
  428. {
  429.   if (aEvent.button != 0)
  430.     return;
  431.  
  432.   switch (gWindowState) {
  433.   case "extensions":
  434.     gExtensionsViewController.doCommand('cmd_options');
  435.     break;
  436.   case "themes":
  437.     gExtensionsViewController.doCommand('cmd_useTheme');
  438.     break;
  439.   }
  440. }
  441.  
  442. function onThemeSelect(aEvent)
  443. {
  444.   if (gWindowState != "themes")
  445.     return;
  446.  
  447.   var previewImageDeck = document.getElementById("previewImageDeck");
  448.   if (!gExtensionsView.selected) {
  449.     previewImageDeck.setAttribute("selectedIndex", "0");
  450.     return;
  451.   }
  452.   var url = gExtensionsView.selected.getAttribute("previewImage");
  453.   if (url) {
  454.     previewImageDeck.setAttribute("selectedIndex", "2");
  455.     var previewImage = document.getElementById("previewImage");
  456.     previewImage.setAttribute("src", url);
  457.   }
  458.   else
  459.     previewImageDeck.setAttribute("selectedIndex", "1");
  460. }
  461.  
  462. ///////////////////////////////////////////////////////////////////////////////
  463. // View Context Menus
  464. var gExtensionContextMenus = ["menuitem_options", "menuitem_homepage", "menuitem_about", 
  465.                               "menuseparator_1", "menuitem_uninstall", "menuitem_update",
  466.                               "menuitem_enable", "menuitem_disable", "menuseparator_2", 
  467.                               "menuitem_moveTop", "menuitem_moveUp", "menuitem_moveDn"];
  468. var gThemeContextMenus = ["menuitem_useTheme", "menuitem_homepage", "menuitem_about", 
  469.                           "menuseparator_1", "menuitem_uninstall", "menuitem_update",
  470.                           "menuitem_enable"];
  471.  
  472. function buildContextMenu(aEvent)
  473. {
  474.   if (aEvent.target.id != "extensionContextMenu")
  475.     return false;
  476.     
  477.   var popup = document.getElementById("extensionContextMenu");
  478.   while (popup.hasChildNodes())
  479.     popup.removeChild(popup.firstChild);
  480.  
  481.   var isExtensions = gWindowState == "extensions";
  482.  
  483.   var menus = isExtensions ? gExtensionContextMenus : gThemeContextMenus;  
  484.   for (var i = 0; i < menus.length; ++i) {
  485.     var clonedMenu = document.getElementById(menus[i]).cloneNode(true);
  486.     clonedMenu.id = clonedMenu.id + "_clone";
  487.     popup.appendChild(clonedMenu);
  488.   }
  489.  
  490.   var extensionsStrings = document.getElementById("extensionsStrings");
  491.   var menuitem_about = document.getElementById("menuitem_about_clone");
  492.   var selectedItem = gExtensionsView.selected;
  493.   var name = selectedItem ? selectedItem.getAttribute("name") : "";
  494.   menuitem_about.setAttribute("label", extensionsStrings.getFormattedString("aboutExtension", [name]));
  495.   
  496.   if (isExtensions) {
  497.     var canEnable = gExtensionsViewController.isCommandEnabled("cmd_reallyEnable");
  498.     var menuitemToShow, menuitemToHide;
  499.     if (canEnable) {
  500.       menuitemToShow = document.getElementById("menuitem_enable_clone");
  501.       menuitemToHide = document.getElementById("menuitem_disable_clone");
  502.     }
  503.     else {
  504.       menuitemToShow = document.getElementById("menuitem_disable_clone");
  505.       menuitemToHide = document.getElementById("menuitem_enable_clone");
  506.     }
  507.     menuitemToShow.hidden = false;
  508.     menuitemToHide.hidden = true;
  509.   }
  510.   else {
  511.     var enableMenu = document.getElementById("menuitem_enable_clone");
  512.     if (gExtensionsView.selected.getAttribute("compatible") == "false" ||
  513.         gExtensionsView.selected.disabled) 
  514.       // don't let the user activate incompatible themes, but show a (disabled) Enable
  515.       // menuitem to give visual feedback; it's disabled because cmd_enable returns false
  516.       enableMenu.hidden = false;
  517.     else {
  518.       enableMenu.hidden = true;
  519.     }
  520.   }
  521.     
  522.   return true;
  523. }
  524.  
  525. ///////////////////////////////////////////////////////////////////////////////
  526. // Drag and Drop
  527.  
  528. var gExtensionsDNDObserver =
  529. {
  530.   _ioServ: null,
  531.   _filePH: null,
  532.   
  533.   _ensureServices: function ()
  534.   {
  535.     if (!this._ioServ) {
  536.       this._ioServ = Components.classes["@mozilla.org/network/io-service;1"]
  537.                                .getService(Components.interfaces.nsIIOService);
  538.       this._filePH = this._ioServ.getProtocolHandler("file")
  539.                          .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  540.     }
  541.   },
  542.   
  543.   onDragOver: function (aEvent, aFlavor, aDragSession)
  544.   {
  545.     this._ensureServices();
  546.   
  547.     aDragSession.canDrop = true;
  548.     var count = aDragSession.numDropItems;
  549.     for (var i = 0; i < count; ++i) {
  550.       var xfer = Components.classes["@mozilla.org/widget/transferable;1"]
  551.                           .createInstance(Components.interfaces.nsITransferable);
  552.       xfer.addDataFlavor("text/x-moz-url");
  553.       aDragSession.getData(xfer, i);
  554.       
  555.       var data = { }, length = { };
  556.       xfer.getTransferData("text/x-moz-url", data, length);
  557.       var fileURL = data.value.QueryInterface(Components.interfaces.nsISupportsString).data;
  558.  
  559.       var fileURI = this._ioServ.newURI(fileURL, null, null);
  560.       var url = fileURI.QueryInterface(Components.interfaces.nsIURL);
  561.       if (url.fileExtension != "jar" && url.fileExtension != "xpi") {
  562.         aDragSession.canDrop = false;
  563.         break;
  564.       }
  565.     }
  566.   },
  567.   
  568.   onDrop: function(aEvent, aXferData, aDragSession)
  569.   {
  570.     this._ensureServices();
  571.     
  572.     var xpinstallObj = {};
  573.     var themes = {};
  574.     var xpiCount = 0;
  575.     var themeCount = 0;
  576.     
  577.     var count = aDragSession.numDropItems;
  578.     for (var i = 0; i < count; ++i) {
  579.       var xfer = Components.classes["@mozilla.org/widget/transferable;1"]
  580.                           .createInstance(Components.interfaces.nsITransferable);
  581.       xfer.addDataFlavor("text/x-moz-url");
  582.       aDragSession.getData(xfer, i);
  583.       
  584.       var data = { }, length = { };
  585.       xfer.getTransferData("text/x-moz-url", data, length);
  586.       var fileURL = data.value.QueryInterface(Components.interfaces.nsISupportsString).data;
  587.       var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  588.                           .createInstance(Components.interfaces.nsIURI);
  589.       uri.spec = fileURL;
  590.       var url = uri.QueryInterface(Components.interfaces.nsIURL);
  591.       if (url.fileExtension == "xpi") {
  592.         xpinstallObj[url.fileName] = fileURL;
  593.         ++xpiCount;
  594.       }
  595.       else if (url.fileExtension == "jar") {
  596.         themes[url.fileName] = fileURL;
  597.         ++themeCount;
  598.       }
  599.     }
  600.     if (xpiCount > 0) 
  601.       InstallTrigger.install(xpinstallObj);
  602.     if (themeCount > 0) {
  603.       for (var fileName in themes)
  604.         InstallTrigger.installChrome(InstallTrigger.SKIN, themes[fileName], fileName);
  605.     }
  606.   },
  607.   _flavourSet: null,  
  608.   getSupportedFlavours: function ()
  609.   {
  610.     if (!this._flavourSet) {
  611.       this._flavourSet = new FlavourSet();
  612.       this._flavourSet.appendFlavour("text/x-moz-url");
  613.     }
  614.     return this._flavourSet;
  615.   }
  616. }
  617.  
  618. ///////////////////////////////////////////////////////////////////////////////
  619. // Command Updating and Command Handlers
  620.  
  621. var gExtensionsViewController = {
  622.   supportsCommand: function (aCommand)
  623.   {
  624.     var commandNode = document.getElementById(aCommand);
  625.     return commandNode && (commandNode.parentNode == document.getElementById("extensionsCommands"));
  626.   },
  627.   
  628.   isCommandEnabled: function (aCommand)
  629.   {
  630.     var selectedItem = gExtensionsView.selected;
  631.     switch (aCommand) {
  632.     case "cmd_close":
  633.       return true;
  634.     case "cmd_useTheme":
  635.       return selectedItem &&
  636.              !selectedItem.disabled &&
  637.              selectedItem.getAttribute("toBeUninstalled") != "true" &&
  638.              gCurrentTheme != selectedItem.getAttribute("internalName");
  639.     case "cmd_options":
  640.       return selectedItem &&
  641.              !selectedItem.disabled &&
  642.              selectedItem.getAttribute("toBeUninstalled") != "true" &&
  643.              selectedItem.getAttribute("optionsURL") != "";
  644.     case "cmd_about":
  645.       return selectedItem && (selectedItem.disabled ? selectedItem.getAttribute("aboutURL") == "" : true);
  646.     case "cmd_homepage":
  647.       return selectedItem && selectedItem.getAttribute("homepageURL") != "";
  648.     case "cmd_uninstall":
  649.       if (gWindowState != "extensions") {
  650.         // uninstall is only available if the selected item isn't the 
  651.         // default theme.
  652.         return (selectedItem && 
  653.                 selectedItem.getAttribute("internalName") != KEY_DEFAULT_THEME);
  654.       }
  655.       return selectedItem &&
  656.              selectedItem.getAttribute("toBeUninstalled") != "true" &&
  657.              selectedItem.getAttribute("locked") != "true";
  658.     case "cmd_update":
  659.       return !selectedItem ||
  660.              (selectedItem &&
  661.               selectedItem.getAttribute("toBeUninstalled") != "true" &&
  662.               selectedItem.getAttribute("toBeInstalled") != "true");
  663.     case "cmd_reallyEnable":
  664.     // controls whether to show Enable or Disable in extensions' context menu
  665.       return selectedItem && 
  666.              selectedItem.disabled && 
  667.              !gExtensionManager.inSafeMode;
  668.     case "cmd_enable":
  669.     //controls wheter the Enable/Disable menuitem is enabled
  670.       return selectedItem && 
  671.              selectedItem.disabled && 
  672.              !gExtensionManager.inSafeMode && 
  673.              selectedItem.getAttribute("toBeUninstalled") != "true" &&
  674.              selectedItem.getAttribute("compatible") != "false";
  675.     case "cmd_disable":
  676.       return selectedItem &&
  677.              !selectedItem.disabled &&
  678.              selectedItem.getAttribute("toBeUninstalled") != "true" &&
  679.              selectedItem.getAttribute("locked") != "true";
  680.     case "cmd_movetop":
  681.       return selectedItem && (gExtensionsView.children[0] != selectedItem);
  682.     case "cmd_moveup":
  683.       return selectedItem && (gExtensionsView.children[0] != selectedItem);
  684.     case "cmd_movedn":
  685.       var children = gExtensionsView.children;
  686.       return selectedItem && (children[children.length-1] != selectedItem);
  687.     }
  688.     return false;
  689.   },
  690.  
  691.   doCommand: function (aCommand)
  692.   {
  693.     if (this.isCommandEnabled(aCommand))
  694.       this.commands[aCommand](gExtensionsView.selected);
  695.   },  
  696.   
  697.   onCommandUpdate: function ()
  698.   {
  699.     var extensionsCommands = document.getElementById("extensionsCommands");
  700.     for (var i = 0; i < extensionsCommands.childNodes.length; ++i) {
  701.       var command = extensionsCommands.childNodes[i];
  702.       if (this.isCommandEnabled(command.id))
  703.         command.removeAttribute("disabled");
  704.       else
  705.         command.setAttribute("disabled", "true");
  706.     }
  707.   },
  708.   
  709.   commands: { 
  710.     cmd_close: function (aSelectedItem)
  711.     {
  712.       closeWindow(true);
  713.     },  
  714.   
  715.     cmd_useTheme: function (aSelectedItem)
  716.     {
  717.       var pref = Components.classes["@mozilla.org/preferences-service;1"]
  718.                            .getService(Components.interfaces.nsIPrefBranch);
  719.       gCurrentTheme = aSelectedItem.getAttribute("internalName");
  720.       // Set this pref so the user can reset the theme in safe mode
  721.       pref.setCharPref(PREF_EM_LAST_SELECTED_SKIN, gCurrentTheme);
  722.  
  723.       if (pref.getBoolPref(PREF_EXTENSIONS_DSS_ENABLED)) {
  724.         pref.setCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN, gCurrentTheme);
  725.       }
  726.       else {
  727.         // Theme change will happen on next startup, this flag tells
  728.         // the Theme Manager that it needs to show "This theme will
  729.         // be selected after a restart" text in the selected theme
  730.         // item.
  731.         pref.setBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING, true);
  732.         // Update the view
  733.         setRestartMessage(aSelectedItem);
  734.       }
  735.       
  736.       // disable the useThemeButton
  737.       gExtensionsViewController.onCommandUpdate();
  738.     },
  739.       
  740.     cmd_options: function (aSelectedItem)
  741.     {
  742.       if (!aSelectedItem) return;
  743.       var optionsURL = aSelectedItem.getAttribute("optionsURL");
  744.       if (optionsURL != "")
  745.         openDialog(optionsURL, "", "chrome,modal");
  746.     },
  747.     
  748.     cmd_homepage: function (aSelectedItem)
  749.     {
  750.       if (!aSelectedItem) return;
  751.       var homepageURL = aSelectedItem.getAttribute("homepageURL");
  752.       if (homepageURL != "")
  753.         openURL(homepageURL);
  754.     },
  755.     
  756.     cmd_about: function (aSelectedItem)
  757.     {
  758.       if (!aSelectedItem) return;
  759.       var aboutURL = aSelectedItem.getAttribute("aboutURL");
  760.       if (aboutURL != "")
  761.         openDialog(aboutURL, "", "chrome,modal");
  762.       else
  763.         openDialog("chrome://mozapps/content/extensions/about.xul", "", "chrome,modal", aSelectedItem.id, gExtensionsView.database);
  764.     },  
  765.     
  766.     cmd_movetop: function (aSelectedItem)
  767.     {
  768.       var movingID = aSelectedItem.id;
  769.       gExtensionManager.moveTop(stripPrefix(movingID, gItemType));
  770.       gExtensionsView.selected = document.getElementById(movingID);
  771.     },
  772.     
  773.     cmd_moveup: function (aSelectedItem)
  774.     {
  775.       var movingID = aSelectedItem.id;
  776.       gExtensionManager.moveUp(stripPrefix(movingID, gItemType));
  777.       gExtensionsView.selected = document.getElementById(movingID);
  778.     },
  779.     
  780.     cmd_movedn: function (aSelectedItem)
  781.     {
  782.       var movingID = aSelectedItem.id;
  783.       gExtensionManager.moveDown(stripPrefix(movingID, gItemType));
  784.       gExtensionsView.selected = document.getElementById(movingID);
  785.     },
  786.     
  787.     cmd_update: function (aSelectedItem)
  788.     { 
  789.       var id = aSelectedItem ? stripPrefix(aSelectedItem.id, gItemType) : null;
  790.       var itemType = gWindowState == "extensions" ? nsIUpdateItem.TYPE_EXTENSION : nsIUpdateItem.TYPE_THEME;
  791.       var items = gExtensionManager.getItemList(id, itemType, { });
  792.       var updates = Components.classes["@mozilla.org/updates/update-service;1"]
  793.                               .getService(Components.interfaces.nsIUpdateService);
  794.       updates.checkForUpdates(items, items.length, itemType, 
  795.                               Components.interfaces.nsIUpdateService.SOURCE_EVENT_USER,
  796.                               window);
  797.     },
  798.  
  799.     cmd_uninstall: function (aSelectedItem)
  800.     {
  801.       // Confirm the uninstall
  802.       var extensionsStrings = document.getElementById("extensionsStrings");
  803.       var brandStrings = document.getElementById("brandStrings");
  804.  
  805.       var name = aSelectedItem.getAttribute("name");
  806.       var title = extensionsStrings.getFormattedString("queryUninstallTitle", [name]);
  807.       if (gWindowState == "extensions")
  808.         message = extensionsStrings.getFormattedString("queryUninstallExtensionMessage", [name, name]);
  809.       else if (gWindowState == "themes")
  810.         message = extensionsStrings.getFormattedString("queryUninstallThemeMessage", [name]);
  811.  
  812.       // XXXben - improve the wording on the buttons here!
  813.       var promptSvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  814.                                 .getService(Components.interfaces.nsIPromptService);
  815.       if (!promptSvc.confirm(window, title, message))
  816.         return;
  817.  
  818.       var selectedID = aSelectedItem.id;
  819.       var selectedElement = document.getElementById(selectedID);
  820.       var nextElement = selectedElement.nextSibling;
  821.       if (!nextElement)
  822.         nextElement = selectedElement.previousSibling;
  823.       nextElement = nextElement.id;
  824.       
  825.       if (gWindowState == "extensions")
  826.         gExtensionManager.uninstallExtension(stripPrefix(selectedID, gItemType));
  827.       else if (gWindowState == "themes") {
  828.         // If the theme being uninstalled is the current theme, we need to reselect
  829.         // the default. 
  830.         var pref = Components.classes["@mozilla.org/preferences-service;1"]
  831.                              .getService(Components.interfaces.nsIPrefBranch);
  832.         var currentTheme = pref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  833.         if (aSelectedItem.getAttribute("internalName") == currentTheme)
  834.           this.cmd_useTheme(document.getElementById("urn:mozilla:theme:{972ce4c6-7e08-4474-a285-3208198ce6fd}"));
  835.         gExtensionManager.uninstallTheme(stripPrefix(selectedID, gItemType));
  836.  
  837.       }
  838.       
  839.       gExtensionsView.selected = document.getElementById(nextElement);
  840.     },
  841.     
  842.     cmd_disable: function (aSelectedItem)
  843.     {
  844.       gExtensionManager.disableExtension(stripPrefix(aSelectedItem.id, gItemType));
  845.     },
  846.     
  847.     cmd_enable: function (aSelectedItem)
  848.     {
  849.       if (gWindowState == "extensions")
  850.         gExtensionManager.enableExtension(stripPrefix(aSelectedItem.id, gItemType));
  851.       else
  852.         gExtensionManager.enableTheme(stripPrefix(aSelectedItem.id, gItemType));
  853.     },
  854.   }
  855. };
  856.  
  857.  
  858.