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