merge m-c to fx-team
authorTim Taubert <ttaubert@mozilla.com>
Mon, 20 Aug 2012 09:09:42 -0700
changeset 108253 5b057a27cd0e77f2208705bdf9dad9624bb28dd7
parent 108245 dad400d69b0eea34567189a9bf2622691f28da9d (current diff)
parent 108252 0212d089434135a28ec36162a7b2524e9c21bdad (diff)
child 108254 36e366621f46dbd6f8fca83a06499cc28e9df5c8
child 108371 94b79a2eb30dd6845c418ac81ed2046339a38812
push idunknown
push userunknown
push dateunknown
milestone17.0a1
merge m-c to fx-team
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1123,16 +1123,22 @@ pref("browser.panorama.animate_zoom", tr
 // Defines the url to be used for new tabs.
 pref("browser.newtab.url", "about:newtab");
 // Activates preloading of the new tab url.
 pref("browser.newtab.preload", false);
 
 // Toggles the content of 'about:newtab'. Shows the grid when enabled.
 pref("browser.newtabpage.enabled", true);
 
+// number of rows of newtab grid
+pref("browser.newtabpage.rows", 3);
+
+// number of columns of newtab grid
+pref("browser.newtabpage.columns", 3);
+
 // Enable the DOM fullscreen API.
 pref("full-screen-api.enabled", true);
 
 // True if the fullscreen API requires approval upon a domain entering fullscreen.
 // Domains that have already had fullscreen permission granted won't re-request
 // approval.
 pref("full-screen-api.approval-required", true);
 
--- a/browser/base/content/newtab/grid.js
+++ b/browser/base/content/newtab/grid.js
@@ -17,41 +17,32 @@ let gGrid = {
   /**
    * The cached DOM fragment for sites.
    */
   _siteFragment: null,
 
   /**
    * All cells contained in the grid.
    */
-  get cells() {
-    let cells = [];
-    let children = this.node.querySelectorAll(".newtab-cell");
-    for (let i = 0; i < children.length; i++)
-      cells.push(new Cell(this, children[i]));
-
-    // Replace the getter with our cached value.
-    Object.defineProperty(this, "cells", {value: cells, enumerable: true});
-
-    return cells;
-  },
+  _cells: null,
+  get cells() this._cells,
 
   /**
    * All sites contained in the grid's cells. Sites may be empty.
    */
   get sites() [cell.site for each (cell in this.cells)],
 
   /**
    * Initializes the grid.
    * @param aSelector The query selector of the grid.
    */
   init: function Grid_init() {
     this._node = document.getElementById("newtab-grid");
     this._createSiteFragment();
-    this._draw();
+    this._render();
   },
 
   /**
    * Creates a new site in the grid.
    * @param aLink The new site's link.
    * @param aCell The cell that will contain the new site.
    * @return The newly created site.
    */
@@ -69,18 +60,18 @@ let gGrid = {
     this.cells.forEach(function (cell) {
       let node = cell.node;
       let child = node.firstElementChild;
 
       if (child)
         node.removeChild(child);
     }, this);
 
-    // Draw the grid again.
-    this._draw();
+    // Render the grid again.
+    this._render();
   },
 
   /**
    * Locks the grid to block all pointer events.
    */
   lock: function Grid_lock() {
     this.node.setAttribute("locked", "true");
   },
@@ -88,16 +79,42 @@ let gGrid = {
   /**
    * Unlocks the grid to allow all pointer events.
    */
   unlock: function Grid_unlock() {
     this.node.removeAttribute("locked");
   },
 
   /**
+   * Creates the newtab grid.
+   */
+  _renderGrid: function Grid_renderGrid() {
+    let row = document.createElementNS(HTML_NAMESPACE, "div");
+    let cell = document.createElementNS(HTML_NAMESPACE, "div");
+    row.classList.add("newtab-row");
+    cell.classList.add("newtab-cell");
+
+    // Clear the grid
+    this._node.innerHTML = "";
+
+    // Creates the structure of one row
+    for (let i = 0; i < gGridPrefs.gridColumns; i++) {
+      row.appendChild(cell.cloneNode(true));
+    }
+    // Creates the grid
+    for (let j = 0; j < gGridPrefs.gridRows; j++) {
+      this._node.appendChild(row.cloneNode(true));
+    }
+
+    // (Re-)initialize all cells.
+    let cellElements = this.node.querySelectorAll(".newtab-cell");
+    this._cells = [new Cell(this, cell) for (cell of cellElements)];
+  },
+
+  /**
    * Creates the DOM fragment that is re-used when creating sites.
    */
   _createSiteFragment: function Grid_createSiteFragment() {
     let site = document.createElementNS(HTML_NAMESPACE, "div");
     site.classList.add("newtab-site");
     site.setAttribute("draggable", "true");
 
     // Create the site's inner HTML code.
@@ -111,23 +128,41 @@ let gGrid = {
       '<input type="button" title="' + newTabString("block") + '"' +
       '       class="newtab-control newtab-control-block"/>';
 
     this._siteFragment = document.createDocumentFragment();
     this._siteFragment.appendChild(site);
   },
 
   /**
-   * Draws the grid, creates all sites and puts them into their cells.
+   * Renders the sites, creates all sites and puts them into their cells.
    */
-  _draw: function Grid_draw() {
+  _renderSites: function Grid_renderSites() {
     let cells = this.cells;
-
     // Put sites into the cells.
     let links = gLinks.getLinks();
     let length = Math.min(links.length, cells.length);
 
     for (let i = 0; i < length; i++) {
       if (links[i])
         this.createSite(links[i], cells[i]);
     }
+  },
+
+  /**
+   * Renders the grid.
+   */
+  _render: function Grid_render() {
+    if (this._shouldRenderGrid()) {
+      this._renderGrid();
+    }
+
+    this._renderSites();
+  },
+
+  _shouldRenderGrid : function Grid_shouldRenderGrid() {
+    let rowsLength = this._node.querySelectorAll(".newtab-row").length;
+    let cellsLength = this._node.querySelectorAll(".newtab-cell").length;
+
+    return (rowsLength != gGridPrefs.gridRows ||
+            cellsLength != (gGridPrefs.gridRows * gGridPrefs.gridColumns));
   }
 };
--- a/browser/base/content/newtab/newTab.js
+++ b/browser/base/content/newtab/newTab.js
@@ -15,17 +15,18 @@ Cu.import("resource:///modules/NewTabUti
 XPCOMUtils.defineLazyModuleGetter(this, "Rect",
   "resource://gre/modules/Geometry.jsm");
 
 let {
   links: gLinks,
   allPages: gAllPages,
   linkChecker: gLinkChecker,
   pinnedLinks: gPinnedLinks,
-  blockedLinks: gBlockedLinks
+  blockedLinks: gBlockedLinks,
+  gridPrefs: gGridPrefs
 } = NewTabUtils;
 
 XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
   return Services.strings.
     createBundle("chrome://browser/locale/newTab.properties");
 });
 
 function newTabString(name) gStringBundle.GetStringFromName('newtab.' + name);
--- a/browser/base/content/newtab/newTab.xul
+++ b/browser/base/content/newtab/newTab.xul
@@ -21,31 +21,16 @@
 
     <div id="newtab-vertical-margin">
       <div id="newtab-margin-top"/>
 
       <div id="newtab-horizontal-margin">
         <div class="newtab-side-margin"/>
 
         <div id="newtab-grid">
-          <div class="newtab-row">
-            <div class="newtab-cell"/>
-            <div class="newtab-cell"/>
-            <div class="newtab-cell"/>
-          </div>
-          <div class="newtab-row">
-            <div class="newtab-cell"/>
-            <div class="newtab-cell"/>
-            <div class="newtab-cell"/>
-          </div>
-          <div class="newtab-row">
-            <div class="newtab-cell"/>
-            <div class="newtab-cell"/>
-            <div class="newtab-cell"/>
-          </div>
         </div>
 
         <div class="newtab-side-margin"/>
       </div>
 
       <div id="newtab-margin-bottom"/>
     </div>
     <input id="newtab-toggle" type="button"/>
--- a/browser/base/content/test/newtab/Makefile.in
+++ b/browser/base/content/test/newtab/Makefile.in
@@ -23,14 +23,15 @@ include $(topsrcdir)/config/rules.mk
 	browser_newtab_unpin.js \
 	browser_newtab_bug721442.js \
 	browser_newtab_bug722273.js \
 	browser_newtab_bug723102.js \
 	browser_newtab_bug723121.js \
 	browser_newtab_bug725996.js \
 	browser_newtab_bug734043.js \
 	browser_newtab_bug735987.js \
+	browser_newtab_bug752841.js \
 	browser_newtab_bug765628.js \
 	head.js \
 	$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_bug752841.js
@@ -0,0 +1,53 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const PREF_NEWTAB_ROWS = "browser.newtabpage.rows";
+const PREF_NEWTAB_COLUMNS = "browser.newtabpage.columns";
+
+function runTests() {
+  let testValues = [
+    {row: 0, column: 0},
+    {row: -1, column: -1},
+    {row: -1, column: 0},
+    {row: 0, column: -1},
+    {row: 2, column: 4},
+    {row: 2, column: 5},
+  ];
+
+  // Expected length of grid
+  let expectedValues = [1, 1, 1, 1, 8, 10];
+
+   // Values before setting new pref values (9 is the default value -> 3 x 3)
+  let previousValues = [9, 1, 1, 1, 1, 8];
+
+  let existingTab, existingTabGridLength, newTab, newTabGridLength;
+  yield addNewTabPageTab();
+  existingTab = gBrowser.selectedTab;
+
+  for (let i = 0; i < expectedValues.length; i++) {
+    gBrowser.selectedTab = existingTab;
+    existingTabGridLength = getGrid().cells.length;
+    is(existingTabGridLength, previousValues[i],
+      "Grid length of existing page before update is correctly.");
+
+    Services.prefs.setIntPref(PREF_NEWTAB_ROWS, testValues[i].row);
+    Services.prefs.setIntPref(PREF_NEWTAB_COLUMNS, testValues[i].column);
+
+    existingTabGridLength = getGrid().cells.length;
+    is(existingTabGridLength, expectedValues[i],
+      "Existing page grid is updated correctly.");
+
+    yield addNewTabPageTab();
+    newTab = gBrowser.selectedTab;
+    newTabGridLength = getGrid().cells.length;
+    is(newTabGridLength, expectedValues[i],
+      "New page grid is updated correctly.");
+
+    gBrowser.removeTab(newTab);
+  }
+
+  gBrowser.removeTab(existingTab);
+
+  Services.prefs.clearUserPref(PREF_NEWTAB_ROWS);
+  Services.prefs.clearUserPref(PREF_NEWTAB_COLUMNS);
+}
--- a/browser/devtools/webconsole/WebConsoleUtils.jsm
+++ b/browser/devtools/webconsole/WebConsoleUtils.jsm
@@ -904,58 +904,73 @@ function JSPropertyProvider(aScope, aInp
 
   let completionPart = aInputValue.substring(beginning.startPos);
 
   // Don't complete on just an empty string.
   if (completionPart.trim() == "") {
     return null;
   }
 
-  let properties = completionPart.split(".");
-  let matchProp;
-  if (properties.length > 1) {
-    matchProp = properties.pop().trimLeft();
-    for (let i = 0; i < properties.length; i++) {
-      let prop = properties[i].trim();
-      if (!prop) {
-        return null;
-      }
+  let matches = null;
+  let matchProp = "";
+
+  let lastDot = completionPart.lastIndexOf(".");
+  if (lastDot > 0 &&
+      (completionPart[0] == "'" || completionPart[0] == '"') &&
+      completionPart[lastDot - 1] == completionPart[0]) {
+    // We are completing a string literal.
+    obj = obj.String.prototype;
+    matchProp = completionPart.slice(lastDot + 1);
+
+  }
+  else {
+    // We are completing a variable / a property lookup.
 
-      // If obj is undefined or null (which is what "== null" does),
-      // then there is no chance to run completion on it. Exit here.
-      if (obj == null) {
-        return null;
-      }
+    let properties = completionPart.split(".");
+    if (properties.length > 1) {
+      matchProp = properties.pop().trimLeft();
+      for (let i = 0; i < properties.length; i++) {
+        let prop = properties[i].trim();
+        if (!prop) {
+          return null;
+        }
 
-      // Check if prop is a getter function on obj. Functions can change other
-      // stuff so we can't execute them to get the next object. Stop here.
-      if (WCU.isNonNativeGetter(obj, prop)) {
-        return null;
-      }
-      try {
-        obj = obj[prop];
-      }
-      catch (ex) {
-        return null;
+        // If obj is undefined or null (which is what "== null" does),
+        // then there is no chance to run completion on it. Exit here.
+        if (obj == null) {
+          return null;
+        }
+
+        // Check if prop is a getter function on obj. Functions can change other
+        // stuff so we can't execute them to get the next object. Stop here.
+        if (WCU.isNonNativeGetter(obj, prop)) {
+          return null;
+        }
+        try {
+          obj = obj[prop];
+        }
+        catch (ex) {
+          return null;
+        }
       }
     }
-  }
-  else {
-    matchProp = properties[0].trimLeft();
-  }
+    else {
+      matchProp = properties[0].trimLeft();
+    }
 
-  // If obj is undefined or null (which is what "== null" does),
-  // then there is no chance to run completion on it. Exit here.
-  if (obj == null) {
-    return null;
-  }
+    // If obj is undefined or null (which is what "== null" does),
+    // then there is no chance to run completion on it. Exit here.
+    if (obj == null) {
+      return null;
+    }
 
-  // Skip Iterators and Generators.
-  if (WCU.isIteratorOrGenerator(obj)) {
-    return null;
+    // Skip Iterators and Generators.
+    if (WCU.isIteratorOrGenerator(obj)) {
+      return null;
+    }
   }
 
   let matches = Object.keys(getMatchedProps(obj, {matchProp:matchProp}));
 
   return {
     matchProp: matchProp,
     matches: matches.sort(),
   };
--- a/browser/devtools/webconsole/test/browser_webconsole_completion.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_completion.js
@@ -100,13 +100,20 @@ function testCompletion(hud) {
 
   // Test non-object autocompletion.
   input.value = "Object.name.sl";
   jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
   yield;
 
   is(jsterm.completeNode.value, "              ice", "non-object completion");
 
+  // Test string literal autocompletion.
+  input.value = "'Asimov'.sl";
+  jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+  yield;
+
+  is(jsterm.completeNode.value, "           ice", "string literal completion");
+
   testDriver = jsterm = input = null;
   executeSoon(finishTest);
   yield;
 }
 
--- a/browser/modules/NewTabUtils.jsm
+++ b/browser/modules/NewTabUtils.jsm
@@ -19,16 +19,22 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyGetter(this, "gPrincipal", function () {
   let uri = Services.io.newURI("about:newtab", null, null);
   return Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
 });
 
 // The preference that tells whether this feature is enabled.
 const PREF_NEWTAB_ENABLED = "browser.newtabpage.enabled";
 
+// The preference that tells the number of rows of the newtab grid.
+const PREF_NEWTAB_ROWS = "browser.newtabpage.rows";
+
+// The preference that tells the number of columns of the newtab grid.
+const PREF_NEWTAB_COLUMNS = "browser.newtabpage.columns";
+
 // The maximum number of results we want to retrieve from history.
 const HISTORY_RESULTS_LIMIT = 100;
 
 // The gather telemetry topic.
 const TOPIC_GATHER_TELEMETRY = "gather-telemetry";
 
 /**
  * Singleton that provides storage functionality.
@@ -179,16 +185,70 @@ let AllPages = {
     this._addObserver = function () {};
   },
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference])
 };
 
 /**
+ * Singleton that keeps Grid preferences
+ */
+let GridPrefs = {
+  /**
+   * Cached value that tells the number of rows of newtab grid.
+   */
+  _gridRows: null,
+  get gridRows() {
+    if (!this._gridRows) {
+      this._gridRows = Math.max(1, Services.prefs.getIntPref(PREF_NEWTAB_ROWS));
+    }
+
+    return this._gridRows;
+  },
+
+  /**
+   * Cached value that tells the number of columns of newtab grid.
+   */
+  _gridColumns: null,
+  get gridColumns() {
+    if (!this._gridColumns) {
+      this._gridColumns = Math.max(1, Services.prefs.getIntPref(PREF_NEWTAB_COLUMNS));
+    }
+
+    return this._gridColumns;
+  },
+
+
+  /**
+   * Initializes object. Adds a preference observer
+   */
+  init: function GridPrefs_init() {
+    Services.prefs.addObserver(PREF_NEWTAB_ROWS, this, false);
+    Services.prefs.addObserver(PREF_NEWTAB_COLUMNS, this, false);
+  },
+
+  /**
+   * Implements the nsIObserver interface to get notified when the preference
+   * value changes.
+   */
+  observe: function GridPrefs_observe(aSubject, aTopic, aData) {
+    if (aData == PREF_NEWTAB_ROWS) {
+      this._gridRows = null;
+    } else {
+      this._gridColumns = null;
+    }
+
+    AllPages.update();
+  }
+};
+
+GridPrefs.init();
+
+/**
  * Singleton that keeps track of all pinned links and their positions in the
  * grid.
  */
 let PinnedLinks = {
   /**
    * The cached list of pinned links.
    */
   _links: null,
@@ -601,10 +661,11 @@ let NewTabUtils = {
       AllPages.update();
     }, true);
   },
 
   links: Links,
   allPages: AllPages,
   linkChecker: LinkChecker,
   pinnedLinks: PinnedLinks,
-  blockedLinks: BlockedLinks
+  blockedLinks: BlockedLinks,
+  gridPrefs: GridPrefs
 };
--- a/caps/tests/mochitest/test_bug292789.html.in
+++ b/caps/tests/mochitest/test_bug292789.html.in
@@ -8,17 +8,18 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=292789">Mozilla Bug 292789</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   <script src="chrome://global/content/strres.js"></script>
-  <script src="chrome://mozapps/content/xpinstall/xpinstallConfirm.js"></script>
+  <script type="application/javascript;version=1.8" src="chrome://mozapps/content/xpinstall/xpinstallConfirm.js"></script>
+  <script id="resjs" type="application/javascript;version=1.8"></script>
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 292789
  **
  ** Selectively allow access to whitelisted chrome packages
  ** even for ALLOW_CHROME mechanisms (<script>, <img> etc)
@@ -31,23 +32,23 @@ function testScriptSrc(aCallback) {
     is(typeof srGetStrBundle, "function",
        "content can still load <script> from chrome://global");
     is(typeof XPInstallConfirm, "undefined",
        "content should not be able to load <script> from chrome://mozapps");
     
     /** make sure the last one didn't pass because someone
      ** moved the resource
      **/
-    var resjs = document.createElement("script");
+    var resjs = document.getElementById("resjs");
+    resjs.onload = scriptOnload;
 #ifdef MOZ_CHROME_FILE_FORMAT_JAR
     resjs.src = "jar:resource://gre/chrome/toolkit.jar!/content/mozapps/xpinstall/xpinstallConfirm.js";
 #else
     resjs.src = "resource://gre/chrome/toolkit/content/mozapps/xpinstall/xpinstallConfirm.js";
 #endif
-    resjs.onload = scriptOnload;
     document.getElementById("content").appendChild(resjs);
 
     function scriptOnload() {
       is(typeof XPInstallConfirm, "object",
          "xpinstallConfirm.js has not moved unexpectedly");
   
       // trigger the callback
       if (aCallback)
--- a/toolkit/mozapps/extensions/AddonRepository.jsm
+++ b/toolkit/mozapps/extensions/AddonRepository.jsm
@@ -1018,64 +1018,64 @@ var AddonRepository = {
               addon.type = "dictionary";
               break;
             default:
               WARN("Unknown type id when parsing addon: " + id);
           }
           break;
         case "authors":
           let authorNodes = node.getElementsByTagName("author");
-          Array.forEach(authorNodes, function(aAuthorNode) {
-            let name = self._getDescendantTextContent(aAuthorNode, "name");
-            let link = self._getDescendantTextContent(aAuthorNode, "link");
+          for (let authorNode of authorNodes) {
+            let name = self._getDescendantTextContent(authorNode, "name");
+            let link = self._getDescendantTextContent(authorNode, "link");
             if (name == null || link == null)
-              return;
+              continue;
 
             let author = new AddonManagerPrivate.AddonAuthor(name, link);
             if (addon.creator == null)
               addon.creator = author;
             else {
               if (addon.developers == null)
                 addon.developers = [];
 
               addon.developers.push(author);
             }
-          });
+          }
           break;
         case "previews":
           let previewNodes = node.getElementsByTagName("preview");
-          Array.forEach(previewNodes, function(aPreviewNode) {
-            let full = self._getUniqueDescendant(aPreviewNode, "full");
+          for (let previewNode of previewNodes) {
+            let full = self._getUniqueDescendant(previewNode, "full");
             if (full == null)
-              return;
+              continue;
 
             let fullURL = self._getTextContent(full);
             let fullWidth = full.getAttribute("width");
             let fullHeight = full.getAttribute("height");
 
             let thumbnailURL, thumbnailWidth, thumbnailHeight;
-            let thumbnail = self._getUniqueDescendant(aPreviewNode, "thumbnail");
+            let thumbnail = self._getUniqueDescendant(previewNode, "thumbnail");
             if (thumbnail) {
               thumbnailURL = self._getTextContent(thumbnail);
               thumbnailWidth = thumbnail.getAttribute("width");
               thumbnailHeight = thumbnail.getAttribute("height");
             }
-            let caption = self._getDescendantTextContent(aPreviewNode, "caption");
+            let caption = self._getDescendantTextContent(previewNode, "caption");
             let screenshot = new AddonManagerPrivate.AddonScreenshot(fullURL, fullWidth, fullHeight,
                                                                      thumbnailURL, thumbnailWidth,
                                                                      thumbnailHeight, caption);
 
             if (addon.screenshots == null)
               addon.screenshots = [];
 
-            if (aPreviewNode.getAttribute("primary") == 1)
+            if (previewNode.getAttribute("primary") == 1)
               addon.screenshots.unshift(screenshot);
             else
               addon.screenshots.push(screenshot);
-          });
+          }
           break;
         case "learnmore":
           addon.homepageURL = addon.homepageURL || this._getTextContent(node);
           break;
         case "contribution_data":
           let meetDevelopers = this._getDescendantTextContent(node, "meet_developers");
           let suggestedAmount = this._getDescendantTextContent(node, "suggested_amount");
           if (meetDevelopers != null) {
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -2145,19 +2145,16 @@ var XPIProvider = {
 
     let changed = false;
     let profileLocation = this.installLocationsByName[KEY_APP_PROFILE];
 
     let entries = distroDir.directoryEntries
                            .QueryInterface(Ci.nsIDirectoryEnumerator);
     let entry;
     while (entry = entries.nextFile) {
-      // Should never happen really
-      if (!(entry instanceof Ci.nsIFile))
-        continue;
 
       let id = entry.leafName;
 
       if (entry.isFile()) {
         if (id.substring(id.length - 4).toLowerCase() == ".xpi") {
           id = id.substring(0, id.length - 4);
         }
         else {
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -2417,32 +2417,30 @@ var gListView = {
   addItem: function gListView_addItem(aObj, aIsInstall) {
     if (aObj.type != this._type)
       return;
 
     if (aIsInstall && aObj.existingAddon)
       return;
 
     let prop = aIsInstall ? "mInstall" : "mAddon";
-    for (let i = 0; i < this._listBox.itemCount; i++) {
-      let item = this._listBox.childNodes[i];
+    for (let item of this._listBox.childNodes) {
       if (item[prop] == aObj)
         return;
     }
 
     let item = createItem(aObj, aIsInstall);
     this._listBox.insertBefore(item, this._listBox.firstChild);
     this.showEmptyNotice(false);
   },
 
   removeItem: function gListView_removeItem(aObj, aIsInstall) {
     let prop = aIsInstall ? "mInstall" : "mAddon";
 
-    for (let i = 0; i < this._listBox.itemCount; i++) {
-      let item = this._listBox.childNodes[i];
+    for (let item of this._listBox.childNodes) {
       if (item[prop] == aObj) {
         this._listBox.removeChild(item);
         this.showEmptyNotice(this._listBox.itemCount == 0);
         return;
       }
     }
   },
 
@@ -2648,22 +2646,23 @@ var gDetailView = {
       this._autoUpdate.hidden = true;
       document.getElementById("detail-findUpdates-btn").hidden = false;
     }
 
     document.getElementById("detail-prefs-btn").hidden = !aIsRemote &&
       !gViewController.commands.cmd_showItemPreferences.isEnabled(aAddon);
     
     var gridRows = document.querySelectorAll("#detail-grid rows row");
-    for (var i = 0, first = true; i < gridRows.length; ++i) {
-      if (first && window.getComputedStyle(gridRows[i], null).getPropertyValue("display") != "none") {
-        gridRows[i].setAttribute("first-row", true);
+    let first = true;
+    for (let gridRow of gridRows) {
+      if (first && window.getComputedStyle(gridRow, null).getPropertyValue("display") != "none") {
+        gridRow.setAttribute("first-row", true);
         first = false;
       } else {
-        gridRows[i].removeAttribute("first-row");
+        gridRow.removeAttribute("first-row");
       }
     }
 
     this.fillSettingsRows(aScrollToPreferences, (function updateView_fillSettingsRows() {
       this.updateState();
       gViewController.notifyViewChanged();
     }).bind(this));
   },
--- a/toolkit/mozapps/extensions/content/xpinstallConfirm.js
+++ b/toolkit/mozapps/extensions/content/xpinstallConfirm.js
@@ -25,35 +25,35 @@ XPInstallConfirm.init = function ()
                           .getService(Components.interfaces.nsIPrefBranch);
     var delay_in_milliseconds = prefs.getIntPref("security.dialog_enable_delay");
     _installCountdownLength = Math.round(delay_in_milliseconds / 500);
   } catch (ex) { }
   
   var itemList = document.getElementById("itemList");
   
   var numItemsToInstall = args.installs.length;
-  for (var i = 0; i < numItemsToInstall; ++i) {
+  for (let install of args.installs) {
     var installItem = document.createElement("installitem");
     itemList.appendChild(installItem);
 
-    installItem.name = args.installs[i].addon.name;
-    installItem.url = args.installs[i].sourceURI.spec;
-    var icon = args.installs[i].iconURL;
+    installItem.name = install.addon.name;
+    installItem.url = install.sourceURI.spec;
+    var icon = install.iconURL;
     if (icon)
       installItem.icon = icon;
-    var type = args.installs[i].type;
+    var type = install.type;
     if (type)
       installItem.type = type;
-    if (args.installs[i].certName) {
-      installItem.cert = bundle.getFormattedString("signed", [args.installs[i].certName]);
+    if (install.certName) {
+      installItem.cert = bundle.getFormattedString("signed", [install.certName]);
     }
     else {
       installItem.cert = bundle.getString("unverified");
     }
-    installItem.signed = args.installs[i].certName ? "true" : "false";
+    installItem.signed = install.certName ? "true" : "false";
   }
   
   var introString = bundle.getString("itemWarnIntroSingle");
   if (numItemsToInstall > 4)
     introString = bundle.getFormattedString("itemWarnIntroMultiple", [numItemsToInstall]);
   var textNode = document.createTextNode(introString);
   var introNode = document.getElementById("itemWarningIntro");
   while (introNode.hasChildNodes())
--- a/toolkit/mozapps/extensions/content/xpinstallConfirm.xul
+++ b/toolkit/mozapps/extensions/content/xpinstallConfirm.xul
@@ -12,17 +12,17 @@
 
 <dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         id="xpinstallConfirm" title="&dialog.title;" style="&dialog.style;" 
         windowtype="Addons:Install"
         onload="XPInstallConfirm.init()" 
         ondialogaccept="return XPInstallConfirm.onOK();"
         ondialogcancel="return XPInstallConfirm.onCancel();">
 
-  <script src="chrome://mozapps/content/xpinstall/xpinstallConfirm.js"/>
+  <script src="chrome://mozapps/content/xpinstall/xpinstallConfirm.js" type="application/javascript"/>
 
   <stringbundle id="xpinstallConfirmStrings" 
                 src="chrome://mozapps/locale/xpinstall/xpinstallConfirm.properties"/>
 
   <vbox flex="1" id="dialogContentBox">
     <hbox id="xpinstallheader" align="start">
       <image class="alert-icon"/>
       <vbox flex="1">
--- a/toolkit/mozapps/extensions/test/browser/browser_bug557956.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_bug557956.js
@@ -158,18 +158,18 @@ function wait_for_page(aWindow, aPageId,
     executeSoon(function() {
       aCallback(aWindow);
     });
   }, false);
 }
 
 function get_list_names(aList) {
   var items = [];
-  for (let i = 0; i < aList.childNodes.length; i++)
-    items.push(aList.childNodes[i].label);
+  for (let listItem of aList.childNodes)
+    items.push(listItem.label);
   items.sort();
   return items;
 }
 
 // Tests that the right add-ons show up in the mismatch dialog and updates can
 // be installed
 add_test(function() {
   install_test_addons(function() {
@@ -214,26 +214,26 @@ add_test(function() {
             is(items[0], "Addon7 2.0", "Should have seen update for addon7");
             is(items[1], "Addon8 2.0", "Should have seen update for addon8");
             is(items[2], "Addon9 2.0", "Should have seen update for addon9");
 
             ok(!doc.documentElement.getButton("next").disabled,
                "Next button should be enabled");
 
             // Uncheck all
-            for (let i = 0; i < list.childNodes.length; i++)
-              EventUtils.synthesizeMouse(list.childNodes[i], 2, 2, { }, aWindow);
+            for (let listItem of list.childNodes)
+              EventUtils.synthesizeMouse(listItem, 2, 2, { }, aWindow);
 
             ok(doc.documentElement.getButton("next").disabled,
                "Next button should not be enabled");
 
             // Check the ones we want to install
-            for (let i = 0; i < list.childNodes.length; i++) {
-              if (list.childNodes[i].label != "Addon7 2.0")
-                EventUtils.synthesizeMouse(list.childNodes[i], 2, 2, { }, aWindow);
+            for (let listItem of list.childNodes) {
+              if (listItem.label != "Addon7 2.0")
+                EventUtils.synthesizeMouse(listItem, 2, 2, { }, aWindow);
             }
 
             var button = doc.documentElement.getButton("next");
             EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
 
             wait_for_page(aWindow, "finished", function(aWindow) {
               var button = doc.documentElement.getButton("finish");
               ok(!button.hidden, "Finish button should not be hidden");
@@ -308,19 +308,19 @@ add_test(function() {
             var list = doc.getElementById("found.updates");
             var items = get_list_names(list);
             is(items.length, 3, "Should have seen 3 updates available");
             is(items[0], "Addon7 2.0", "Should have seen update for addon7");
             is(items[1], "Addon8 2.0", "Should have seen update for addon8");
             is(items[2], "Addon9 2.0", "Should have seen update for addon9");
 
             // Unheck the ones we don't want to install
-            for (let i = 0; i < list.childNodes.length; i++) {
-              if (list.childNodes[i].label != "Addon7 2.0")
-                EventUtils.synthesizeMouse(list.childNodes[i], 2, 2, { }, aWindow);
+            for (let listItem of list.childNodes) {
+              if (listItem.label != "Addon7 2.0")
+                EventUtils.synthesizeMouse(listItem, 2, 2, { }, aWindow);
             }
 
             var button = doc.documentElement.getButton("next");
             EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
 
             wait_for_page(aWindow, "installerrors", function(aWindow) {
               var button = doc.documentElement.getButton("finish");
               ok(!button.hidden, "Finish button should not be hidden");
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -1165,19 +1165,19 @@ if ("nsIWindowsRegKey" in AM_Ci) {
 
     getValueName: function(aIndex) {
       if (!this.values || aIndex >= this.values.length)
         throw Components.results.NS_ERROR_FAILURE;
       return this.values[aIndex].name;
     },
 
     readStringValue: function(aName) {
-      for (let i = 0; i < this.values.length; i++) {
-        if (this.values[i].name == aName)
-          return this.values[i].value;
+      for (let value of this.values) {
+        if (value.name == aName)
+          return value.value;
       }
     }
   };
 
   var WinRegFactory = {
     createInstance: function(aOuter, aIid) {
       if (aOuter != null)
         throw Components.results.NS_ERROR_NO_AGGREGATION;