Bug 925418 - replace richgrid.children with .items references, plus minor nits. r=mbrubeck
authorSam Foster <sfoster@mozilla.com>
Mon, 14 Oct 2013 09:33:12 -0700
changeset 150629 8406b4a9ed0d0398d0aa91990973789be467eaae
parent 150628 1c0baa3cf12ca8bb523ad8a542bc2610a52ac367
child 150630 8804ec54fbcbde6e92df7c3464f34a75962ef5b8
push id3022
push usersfoster@mozilla.com
push dateMon, 14 Oct 2013 16:35:12 +0000
treeherderfx-team@8406b4a9ed0d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmbrubeck
bugs925418
milestone27.0a1
Bug 925418 - replace richgrid.children with .items references, plus minor nits. r=mbrubeck
browser/metro/base/content/bindings/grid.xml
browser/metro/base/content/startui/TopSitesView.js
browser/metro/base/tests/mochitest/browser_tiles.js
browser/metro/base/tests/mochitest/browser_topsites.js
--- a/browser/metro/base/content/bindings/grid.xml
+++ b/browser/metro/base/content/bindings/grid.xml
@@ -21,16 +21,20 @@
     <implementation implements="nsIDOMXULSelectControlElement">
       <property name="_grid" readonly="true" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'grid');"/>
 
       <property name="isBound" readonly="true" onget="return !!this._grid"/>
       <property name="isArranging" readonly="true" onget="return !!this._scheduledArrangeItemsTimerId"/>
 
       <field name="controller">null</field>
 
+      <!-- collection of child items excluding empty tiles -->
+      <property name="items" readonly="true" onget="return this.querySelectorAll('richgriditem');"/>
+      <property name="itemCount" readonly="true" onget="return this.items.length;"/>
+
       <!-- nsIDOMXULMultiSelectControlElement (not fully implemented) -->
 
       <method name="clearSelection">
         <body>
           <![CDATA[
             // 'selection' and 'selected' are confusingly overloaded here
             // as richgrid is adopting multi-select behavior, but select/selected are already being
             // used to describe triggering the default action of a tile
@@ -153,18 +157,16 @@
             // returns Set
             return verbSet;
           ]]>
         </getter>
       </property>
 
     <!-- nsIDOMXULSelectControlElement -->
 
-      <property name="itemCount" readonly="true" onget="return this.children.length;"/>
-
       <field name="_selectedItem">null</field>
       <property name="selectedItem" onget="return this._selectedItem;">
         <setter>
           <![CDATA[
             this.selectItem(val);
           ]]>
         </setter>
       </property>
@@ -197,17 +199,17 @@
       </property>
 
       <method name="appendItem">
         <parameter name="aLabel"/>
         <parameter name="aValue"/>
         <parameter name="aSkipArrange"/>
         <body>
           <![CDATA[
-            let addition = this.createItemElement(aLabel, aValue);
+            let addition = this._createItemElement(aLabel, aValue);
             this.appendChild(addition);
             if (!aSkipArrange)
               this.arrangeItems();
             return addition;
           ]]>
         </body>
       </method>
 
@@ -227,17 +229,17 @@
       <method name="insertItemAt">
         <parameter name="anIndex"/>
         <parameter name="aLabel"/>
         <parameter name="aValue"/>
         <parameter name="aSkipArrange"/>
         <body>
           <![CDATA[
             let existing = this.getItemAtIndex(anIndex);
-            let addition = this.createItemElement(aLabel, aValue);
+            let addition = this._createItemElement(aLabel, aValue);
             if (existing) {
               this.insertBefore(addition, existing);
             } else {
               this.appendChild(addition);
             }
             if (!aSkipArrange)
               this.arrangeItems();
             return addition;
@@ -245,57 +247,60 @@
         </body>
       </method>
       <method name="removeItemAt">
         <parameter name="anIndex"/>
         <parameter name="aSkipArrange"/>
         <body>
           <![CDATA[
             let item = this.getItemAtIndex(anIndex);
-            return item ? this.removeItem(item, aSkipArrange) : null;
+            if (!item)
+              return null;
+            return this.removeItem(item, aSkipArrange);
           ]]>
         </body>
       </method>
 
       <method name="removeItem">
         <parameter name="aItem"/>
         <parameter name="aSkipArrange"/>
         <body>
           <![CDATA[
-            let removal = aItem.parentNode == this && this.removeChild(aItem);
+            if (!aItem || Array.indexOf(this.items, aItem) < 0)
+              return null;
+            let removal = this.removeChild(aItem);
             if (removal && !aSkipArrange)
                 this.arrangeItems();
 
             // note that after removal the node is unbound
             // so none of the richgriditem binding methods & properties are available
             return removal;
           ]]>
         </body>
       </method>
 
-
       <method name="getIndexOfItem">
         <parameter name="anItem"/>
         <body>
           <![CDATA[
             if (!anItem)
               return -1;
 
-            return Array.indexOf(this.children, anItem);
+            return Array.indexOf(this.items, anItem);
           ]]>
         </body>
       </method>
 
       <method name="getItemAtIndex">
         <parameter name="anIndex"/>
         <body>
           <![CDATA[
             if (!this._isIndexInBounds(anIndex))
               return null;
-            return this.children.item(anIndex);
+            return this.items.item(anIndex);
           ]]>
         </body>
       </method>
 
       <method name="getItemsByUrl">
         <parameter name="aUrl"/>
         <body>
           <![CDATA[
@@ -604,26 +609,28 @@
         <parameter name="anIndex"/>
         <body>
           <![CDATA[
             return anIndex >= 0 && anIndex < this.itemCount;
           ]]>
         </body>
       </method>
 
-      <method name="createItemElement">
+      <method name="_createItemElement">
         <parameter name="aLabel"/>
         <parameter name="aValue"/>
         <body>
           <![CDATA[
             let item = this.ownerDocument.createElement("richgriditem");
-            item.setAttribute("label", aLabel);
             if (aValue) {
               item.setAttribute("value", aValue);
             }
+            if (aLabel) {
+              item.setAttribute("label", aLabel);
+            }
             if(this.hasAttribute("tiletype")) {
               item.setAttribute("tiletype", this.getAttribute("tiletype"));
             }
             return item;
           ]]>
         </body>
       </method>
 
@@ -855,17 +862,17 @@
             this.refreshBackgroundImage();
           ]]>
         </body>
       </method>
 
       <property name="control">
         <getter><![CDATA[
           let parent = this.parentNode;
-          while (parent) {
+          while (parent && parent != this.ownerDocument.documentElement) {
             if (parent instanceof Components.interfaces.nsIDOMXULSelectControlElement)
               return parent;
             parent = parent.parentNode;
           }
           return null;
         ]]></getter>
       </property>
 
--- a/browser/metro/base/content/startui/TopSitesView.js
+++ b/browser/metro/base/content/startui/TopSitesView.js
@@ -95,17 +95,17 @@ TopSitesView.prototype = Util.extend(Obj
           // stop the appbar from dismissing,
           // the selectionchange event will trigger re-population of the context appbar
           aEvent.preventDefault();
         }
         break;
       case "pin":
         let pinIndices = [];
         Array.forEach(selectedTiles, function(aNode) {
-          pinIndices.push( Array.indexOf(aNode.control.children, aNode) );
+          pinIndices.push( Array.indexOf(aNode.control.items, aNode) );
           aNode.contextActions.delete('pin');
           aNode.contextActions.add('unpin');
         });
         TopSites.pinSites(sites, pinIndices);
         break;
       case "unpin":
         Array.forEach(selectedTiles, function(aNode) {
           aNode.contextActions.delete('unpin');
@@ -148,63 +148,61 @@ TopSitesView.prototype = Util.extend(Obj
         if (tileNode) {
           this.updateTile(tileNode, new Site(site));
         }
       }
     } else {
         // flush, recreate all
       this.isUpdating = true;
       // destroy and recreate all item nodes, skip calling arrangeItems
-      grid.clearAll(true);
       this.populateGrid();
     }
   },
 
   updateTile: function(aTileNode, aSite, aArrangeGrid) {
     this._updateFavicon(aTileNode, Util.makeURI(aSite.url));
 
     Task.spawn(function() {
       let filepath = PageThumbsStorage.getFilePathForURL(aSite.url);
       if (yield OS.File.exists(filepath)) {
         aSite.backgroundImage = 'url("'+PageThumbs.getThumbnailURL(aSite.url)+'")';
-        aTileNode.setAttribute("customImage", aSite.backgroundImage);
-        if (aTileNode.refresh) {
-          aTileNode.refresh()
+        if ('backgroundImage' in aTileNode) {
+          aTileNode.backgroundImage = aSite.backgroundImage;
+        } else {
+          aTileNode.setAttribute("customImage", aSite.backgroundImage);
         }
       }
     });
 
     aSite.applyToTileNode(aTileNode);
+    if (aTileNode.refresh) {
+      aTileNode.refresh();
+    }
     if (aArrangeGrid) {
       this._set.arrangeItems();
     }
   },
 
   populateGrid: function populateGrid() {
     this.isUpdating = true;
 
     let sites = TopSites.getSites();
-    let length = Math.min(sites.length, this._topSitesMax || Infinity);
+    if (this._topSitesMax) {
+      sites = sites.slice(0, this._topSitesMax);
+    }
     let tileset = this._set;
+    tileset.clearAll(true);
 
-    // if we're updating with a collection that is smaller than previous
-    // remove any extra tiles
-    while (tileset.children.length > length) {
-      tileset.removeChild(tileset.children[tileset.children.length -1]);
-    }
-
-    for (let idx=0; idx < length; idx++) {
-      let isNew = !tileset.children[idx],
-          site = sites[idx];
-      let item = isNew ? tileset.createItemElement(site.title, site.url) : tileset.children[idx];
+    for (let site of sites) {
+      // call to private _createItemElement is a temp measure
+      // we'll eventually just request the next slot
+      let item = tileset._createItemElement(site.title, site.url);
 
       this.updateTile(item, site);
-      if (isNew) {
-        tileset.appendChild(item);
-      }
+      tileset.appendChild(item);
     }
     tileset.arrangeItems();
     this.isUpdating = false;
   },
 
   forceReloadOfThumbnail: function forceReloadOfThumbnail(url) {
     let nodes = this._set.querySelectorAll('richgriditem[value="'+url+'"]');
     for (let item of nodes) {
--- a/browser/metro/base/tests/mochitest/browser_tiles.js
+++ b/browser/metro/base/tests/mochitest/browser_tiles.js
@@ -13,28 +13,28 @@ gTests.push({
   desc: "richgrid binding is applied",
   run: function() {
     ok(doc, "doc got defined");
 
     let grid = doc.querySelector("#grid1");
     ok(grid, "#grid1 is found");
     is(typeof grid.clearSelection, "function", "#grid1 has the binding applied");
 
-    is(grid.children.length, 2, "#grid1 has a 2 items");
-    is(grid.children[0].control, grid, "#grid1 item's control points back at #grid1'");
+    is(grid.items.length, 2, "#grid1 has a 2 items");
+    is(grid.items[0].control, grid, "#grid1 item's control points back at #grid1'");
   }
 });
 
 gTests.push({
   desc: "item clicks are handled",
   run: function() {
     let grid = doc.querySelector("#grid1");
     is(typeof grid.handleItemClick, "function", "grid.handleItemClick is a function");
     let handleStub = stubMethod(grid, 'handleItemClick');
-    let itemId = "grid1_item1"; // grid.children[0].getAttribute("id");
+    let itemId = "grid1_item1"; // grid.items[0].getAttribute("id");
 
     // send click to item and wait for next tick;
     EventUtils.sendMouseEvent({type: 'click'}, itemId, doc.defaultView);
     yield waitForMs(0);
 
     is(handleStub.callCount, 1, "handleItemClick was called when we clicked an item");
     handleStub.restore();
 
@@ -109,19 +109,18 @@ gTests.push({
     is(grid.itemCount, 3, "grid has 3 items initially");
     is(grid.rowCount, 2, "grid has 2 rows initially");
     is(grid.columnCount, 2, "grid has 2 cols initially");
 
     let arrangeSpy = spyOnMethod(grid, "arrangeItems");
     grid.clearAll();
 
     is(grid.itemCount, 0, "grid has 0 itemCount after clearAll");
-    is(grid.children.length, 0, "grid has 0 children after clearAll");
-    is(grid.rowCount, 0, "grid has 0 rows when empty");
-    is(grid.columnCount, 0, "grid has 0 cols when empty");
+    is(grid.items.length, 0, "grid has 0 items after clearAll");
+    // now that we use slots, an empty grid may still have non-zero rows & columns
 
     is(arrangeSpy.callCount, 1, "arrangeItems is called once when we clearAll");
     arrangeSpy.restore();
   }
 });
 
 gTests.push({
   desc: "empty grid",
@@ -145,23 +144,23 @@ gTests.push({
 gTests.push({
   desc: "appendItem",
   run: function() {
      // implements an appendItem with signature title, uri, returns item element
      // appendItem triggers arrangeItems
     let grid = doc.querySelector("#emptygrid");
 
     is(grid.itemCount, 0, "0 itemCount when empty");
-    is(grid.children.length, 0, "0 children when empty");
+    is(grid.items.length, 0, "0 items when empty");
     is(typeof grid.appendItem, "function", "appendItem is a function on the grid");
 
     let arrangeStub = stubMethod(grid, "arrangeItems");
     let newItem = grid.appendItem("test title", "about:blank");
 
-    ok(newItem && grid.children[0]==newItem, "appendItem gives back the item");
+    ok(newItem && grid.items[0]==newItem, "appendItem gives back the item");
     is(grid.itemCount, 1, "itemCount is incremented when we appendItem");
     is(newItem.getAttribute("label"), "test title", "title ends up on label attribute");
     is(newItem.getAttribute("value"), "about:blank", "url ends up on value attribute");
 
     is(arrangeStub.callCount, 1, "arrangeItems is called when we appendItem");
     arrangeStub.restore();
   }
 });
@@ -188,17 +187,17 @@ gTests.push({
     is(grid.itemCount, 2, "2 items initially");
     is(typeof grid.removeItemAt, "function", "removeItemAt is a function on the grid");
 
     let arrangeStub = stubMethod(grid, "arrangeItems");
     let removedItem = grid.removeItemAt(0);
 
     ok(removedItem, "removeItemAt gives back an item");
     is(removedItem.getAttribute("id"), "grid2_item1", "removeItemAt gives back the correct item");
-    is(grid.children[0].getAttribute("id"), "grid2_item2", "2nd item becomes the first item");
+    is(grid.items[0].getAttribute("id"), "grid2_item2", "2nd item becomes the first item");
     is(grid.itemCount, 1, "itemCount is decremented when we removeItemAt");
 
     is(arrangeStub.callCount, 1, "arrangeItems is called when we removeItemAt");
     arrangeStub.restore();
   }
 });
 
 gTests.push({
@@ -210,20 +209,20 @@ gTests.push({
 
     is(grid.itemCount, 2, "2 items initially");
     is(typeof grid.insertItemAt, "function", "insertItemAt is a function on the grid");
 
     let arrangeStub = stubMethod(grid, "arrangeItems");
     let insertedItem = grid.insertItemAt(1, "inserted item", "http://example.com/inserted");
 
     ok(insertedItem, "insertItemAt gives back an item");
-    is(grid.children[1], insertedItem, "item is inserted at the correct index");
+    is(grid.items[1], insertedItem, "item is inserted at the correct index");
     is(insertedItem.getAttribute("label"), "inserted item", "insertItemAt creates item with the correct label");
     is(insertedItem.getAttribute("value"), "http://example.com/inserted", "insertItemAt creates item with the correct url value");
-    is(grid.children[2].getAttribute("id"), "grid3_item2", "following item ends up at the correct index");
+    is(grid.items[2].getAttribute("id"), "grid3_item2", "following item ends up at the correct index");
     is(grid.itemCount, 3, "itemCount is incremented when we insertItemAt");
 
     is(arrangeStub.callCount, 1, "arrangeItems is called when we insertItemAt");
     arrangeStub.restore();
   }
 });
 
 gTests.push({
@@ -270,21 +269,21 @@ gTests.push({
   desc: "removeItem",
   run: function() {
     let grid = doc.querySelector("#grid5");
 
     is(grid.itemCount, 4, "4 items total");
     is(typeof grid.removeItem, "function", "removeItem is a function on the grid");
 
     let arrangeStub = stubMethod(grid, "arrangeItems");
-    let removedFirst = grid.removeItem( grid.children[0] );
+    let removedFirst = grid.removeItem( grid.items[0] );
 
     is(arrangeStub.callCount, 1, "arrangeItems is called when we removeItem");
 
-    let removed2nd = grid.removeItem( grid.children[0], true);
+    let removed2nd = grid.removeItem( grid.items[0], true);
     is(removed2nd.getAttribute("label"), "2nd item", "the next item was returned");
     is(grid.itemCount, 2, "2 items remain");
 
     // callCount should still be at 1
     is(arrangeStub.callCount, 1, "arrangeItems is not called when we pass the truthy skipArrange param");
 
     let otherItem = grid.ownerDocument.querySelector("#grid6_item1");
     let removedFail = grid.removeItem(otherItem);
@@ -311,51 +310,51 @@ gTests.push({
     is(typeof grid.clearSelection, "function", "clearSelection is a function on the grid");
     is(typeof grid.selectedItems, "object", "selectedItems is a property on the grid");
     is(typeof grid.toggleItemSelection, "function", "toggleItemSelection is function on the grid");
     is(typeof grid.selectItem, "function", "selectItem is a function on the grid");
 
     is(grid.itemCount, 2, "2 items initially");
     is(grid.selectedItems.length, 0, "nothing selected initially");
 
-    grid.toggleItemSelection(grid.children[1]);
-    ok(grid.children[1].selected, "toggleItemSelection sets truthy selected prop on previously-unselected item");
+    grid.toggleItemSelection(grid.items[1]);
+    ok(grid.items[1].selected, "toggleItemSelection sets truthy selected prop on previously-unselected item");
     is(grid.selectedIndex, 1, "selectedIndex is correct");
 
-    grid.toggleItemSelection(grid.children[1]);
-    ok(!grid.children[1].selected, "toggleItemSelection sets falsy selected prop on previously-selected item");
+    grid.toggleItemSelection(grid.items[1]);
+    ok(!grid.items[1].selected, "toggleItemSelection sets falsy selected prop on previously-selected item");
     is(grid.selectedIndex, -1, "selectedIndex reports correctly with nothing selected");
 
     // item selection
-    grid.selectItem(grid.children[1]);
-    ok(grid.children[1].selected, "Item selected property is truthy after grid.selectItem");
-    ok(grid.children[1].getAttribute("selected"), "Item selected attribute is truthy after grid.selectItem");
+    grid.selectItem(grid.items[1]);
+    ok(grid.items[1].selected, "Item selected property is truthy after grid.selectItem");
+    ok(grid.items[1].getAttribute("selected"), "Item selected attribute is truthy after grid.selectItem");
     ok(grid.selectedItems.length, "There are selectedItems after grid.selectItem");
 
     // clearSelection
-    grid.selectItem(grid.children[0]);
-    grid.selectItem(grid.children[1]);
+    grid.selectItem(grid.items[0]);
+    grid.selectItem(grid.items[1]);
     grid.clearSelection();
     is(grid.selectedItems.length, 0, "Nothing selected when we clearSelection");
     is(grid.selectedIndex, -1, "selectedIndex resets after clearSelection");
 
     // select events
     // in seltype=single mode, select is like the default action for the tile
     // (think <a>, not <select multiple>)
     let handler = {
       handleEvent: function(aEvent) {}
     };
     let handlerStub = stubMethod(handler, "handleEvent");
     doc.defaultView.addEventListener("select", handler, false);
     info("select listener added");
 
-    info("calling selectItem, currently it is:" + grid.children[0].selected);
+    info("calling selectItem, currently it is:" + grid.items[0].selected);
     // Note: A richgrid in seltype=single mode fires "select" events from selectItem
-    grid.selectItem(grid.children[0]);
-    info("calling selectItem, now it is:" + grid.children[0].selected);
+    grid.selectItem(grid.items[0]);
+    info("calling selectItem, now it is:" + grid.items[0].selected);
     yield waitForMs(0);
 
     is(handlerStub.callCount, 1, "select event handler was called when we selected an item");
     is(handlerStub.calledWith[0].type, "select", "handler got a select event");
     is(handlerStub.calledWith[0].target, grid, "select event had the originating grid as the target");
     handlerStub.restore();
     doc.defaultView.removeEventListener("select", handler, false);
   }
@@ -373,51 +372,48 @@ gTests.push({
     is(typeof grid.clearSelection, "function", "clearSelection is a function on the grid");
     is(typeof grid.selectedItems, "object", "selectedItems is a property on the grid");
     is(typeof grid.toggleItemSelection, "function", "toggleItemSelection is function on the grid");
     is(typeof grid.selectItem, "function", "selectItem is a function on the grid");
 
     is(grid.itemCount, 2, "2 items initially");
     is(grid.selectedItems.length, 0, "nothing selected initially");
 
-    grid.toggleItemSelection(grid.children[1]);
-    ok(grid.children[1].selected, "toggleItemSelection sets truthy selected prop on previously-unselected item");
+    grid.toggleItemSelection(grid.items[1]);
+    ok(grid.items[1].selected, "toggleItemSelection sets truthy selected prop on previously-unselected item");
     is(grid.selectedItems.length, 1, "1 item selected when we first toggleItemSelection");
-    is(grid.selectedItems[0], grid.children[1], "the right item is selected");
+    is(grid.selectedItems[0], grid.items[1], "the right item is selected");
     is(grid.selectedIndex, 1, "selectedIndex is correct");
 
-    grid.toggleItemSelection(grid.children[1]);
+    grid.toggleItemSelection(grid.items[1]);
     is(grid.selectedItems.length, 0, "Nothing selected when we toggleItemSelection again");
 
     // clearSelection
-    grid.children[0].selected=true;
-    grid.children[1].selected=true;
+    grid.items[0].selected=true;
+    grid.items[1].selected=true;
     is(grid.selectedItems.length, 2, "Both items are selected before calling clearSelection");
     grid.clearSelection();
     is(grid.selectedItems.length, 0, "Nothing selected when we clearSelection");
-    ok(!(grid.children[0].selected || grid.children[1].selected), "selected properties all falsy when we clearSelection");
+    ok(!(grid.items[0].selected || grid.items[1].selected), "selected properties all falsy when we clearSelection");
 
     // selectionchange events
     // in seltype=multiple mode, we track selected state on all items
     // (think <select multiple> not <a>)
     let handler = {
       handleEvent: function(aEvent) {}
     };
     let handlerStub = stubMethod(handler, "handleEvent");
     doc.defaultView.addEventListener("selectionchange", handler, false);
     info("selectionchange listener added");
 
-    info("calling toggleItemSelection, currently it is:" + grid.children[0].selected);
+    info("calling toggleItemSelection, currently it is:" + grid.items[0].selected);
     // Note: A richgrid in seltype=single mode fires "select" events from selectItem
-    grid.toggleItemSelection(grid.children[0]);
-    info("/calling toggleItemSelection, now it is:" + grid.children[0].selected);
+    grid.toggleItemSelection(grid.items[0]);
+    info("/calling toggleItemSelection, now it is:" + grid.items[0].selected);
     yield waitForMs(0);
 
     is(handlerStub.callCount, 1, "selectionchange event handler was called when we selected an item");
     is(handlerStub.calledWith[0].type, "selectionchange", "handler got a selectionchange event");
     is(handlerStub.calledWith[0].target, grid, "select event had the originating grid as the target");
     handlerStub.restore();
     doc.defaultView.removeEventListener("selectionchange", handler, false);
   }
 });
-
-     // implements a getItemAtIndex method (or grid.children[idx] ?)
-
--- a/browser/metro/base/tests/mochitest/browser_topsites.js
+++ b/browser/metro/base/tests/mochitest/browser_topsites.js
@@ -189,17 +189,17 @@ gTests.push({
 
     let arrangedPromise = waitForEvent(grid, "arranged");
     yield TopSitesTestHelper.updatePagesAndWait();
     // pause until the update has fired and the view is finishd updating
     yield arrangedPromise;
   },
   run: function() {
     let grid = TopSitesTestHelper.grid;
-    let items = grid.children;
+    let items = grid.items;
     is(items.length, 8, "should be 8 topsites"); // i.e. not 10
     if(items.length) {
       let firstitem = items[0];
       is(
         firstitem.getAttribute("label"),
         "brian",
         "first item label should be 'brian': " + firstitem.getAttribute("label")
       );
@@ -225,17 +225,17 @@ gTests.push({
     // pause until the update has fired and the view is finishd updating
     let arrangedPromise = waitForEvent(TopSitesTestHelper.grid, "arranged");
     yield TopSitesTestHelper.updatePagesAndWait();
     yield arrangedPromise;
   },
   run: function() {
     // test that pinned state of each site as rendered matches our expectations
     let pins = this.pins.split(",");
-    let items = TopSitesTestHelper.grid.children;
+    let items = TopSitesTestHelper.grid.items;
     is(items.length, 8, "should be 8 topsites in the grid");
 
     is(TopSitesTestHelper.document.querySelectorAll("#start-topsites-grid > [pinned]").length, 3, "should be 3 children with 'pinned' attribute");
     try {
       Array.forEach(items, function(aItem, aIndex){
         // pinned state should agree with the pins array
         is(
             aItem.hasAttribute("pinned"), !!pins[aIndex],
@@ -268,35 +268,35 @@ gTests.push({
     yield TopSitesTestHelper.updatePagesAndWait();
     yield arrangedPromise;
   },
   run: function() {
     // pin a site
     // test that site is pinned as expected
     // and that sites fill positions around it
     let grid = TopSitesTestHelper.grid,
-        items = grid.children;
+        items = grid.items;
     is(items.length, 4, this.desc + ": should be 4 topsites");
 
-    let tile = grid.children[2],
+    let tile = grid.items[2],
         url = tile.getAttribute("value"),
         title = tile.getAttribute("label");
 
     info(this.desc + ": pinning site at index 2");
     TopSites.pinSites([{
           url: url,
           title: title
         }], [2]);
 
     // pinning shouldn't require re-arranging - just wait for isUpdating flag to flip
     yield waitForCondition(function(){
       return !grid.controller.isUpdating;
     });
 
-    let thirdTile = grid.children[2];
+    let thirdTile = grid.items[2];
     ok( thirdTile.hasAttribute("pinned"), thirdTile.getAttribute("value")+ " should look pinned" );
 
     // visit some more sites
     yield TopSitesTestHelper.fillHistory( TopSitesTestHelper.mockLinks("brian,dougal,dylan,ermintrude,florence,moose") );
 
     // force flush and repopulation of links cache
     yield TopSites.prepareCache(true);
     // pause until the update has fired and the view is finishd updating
@@ -324,34 +324,34 @@ gTests.push({
     let arrangedPromise = waitForEvent(TopSitesTestHelper.grid, "arranged");
     yield TopSitesTestHelper.updatePagesAndWait();
     yield arrangedPromise;
   },
   run: function() {
     // unpin a pinned site
     // test that sites are unpinned as expected
     let grid = TopSitesTestHelper.grid,
-        items = grid.children;
+        items = grid.items;
     is(items.length, 8, this.desc + ": should be 8 topsites");
     let site = {
       url: items[1].getAttribute("value"),
       title: items[1].getAttribute("label")
     };
     // verify assumptions before unpinning this site
     ok( NewTabUtils.pinnedLinks.isPinned(site), "2nd item is pinned" );
     ok( items[1].hasAttribute("pinned"), "2nd item has pinned attribute" );
 
     // unpinning shouldn't require re-arranging - just wait for isUpdating flag to flip
     TopSites.unpinSites([site]);
 
     yield waitForCondition(function(){
       return !grid.controller.isUpdating;
     });
 
-    let secondTile = grid.children[1];
+    let secondTile = grid.items[1];
     ok( !secondTile.hasAttribute("pinned"), "2nd item should no longer be marked as pinned" );
     ok( !NewTabUtils.pinnedLinks.isPinned(site), "2nd item should no longer be pinned" );
   }
 });
 
 gTests.push({
   desc: "block/unblock sites",
   setUp: function() {
@@ -366,17 +366,17 @@ gTests.push({
     yield TopSitesTestHelper.updatePagesAndWait();
     yield arrangedPromise;
   },
   run: function() {
     try {
       // block a site
       // test that sites are removed from the grid as expected
       let grid = TopSitesTestHelper.grid,
-          items = grid.children;
+          items = grid.items;
       is(items.length, 8, this.desc + ": should be 8 topsites");
 
       let brianSite = TopSitesTestHelper.siteFromNode(items[0]);
       let dougalSite = TopSitesTestHelper.siteFromNode(items[1]);
       let dylanSite = TopSitesTestHelper.siteFromNode(items[2]);
 
       let arrangedPromise = waitForEvent(grid, "arranged");
       // we'll block brian (he's not pinned)
@@ -421,17 +421,17 @@ gTests.push({
       // verify brian, dougal and dyland are unblocked and back in the grid
       ok( !NewTabUtils.blockedLinks.isBlocked(brianSite), "site was unblocked" );
       is( grid.querySelectorAll("[value='"+brianSite.url+"']").length, 1, "Unblocked site is back in the grid");
 
       ok( !NewTabUtils.blockedLinks.isBlocked(dougalSite), "site was unblocked" );
       is( grid.querySelectorAll("[value='"+dougalSite.url+"']").length, 1, "Unblocked site is back in the grid");
       // ..and that a previously pinned site is re-pinned after being blocked, then restored
       ok( NewTabUtils.pinnedLinks.isPinned(dougalSite), "Restoring previously pinned site makes it pinned again" );
-      is( grid.children[1].getAttribute("value"), dougalSite.url, "Blocked Site restored to pinned index" );
+      is( grid.items[1].getAttribute("value"), dougalSite.url, "Blocked Site restored to pinned index" );
 
       ok( !NewTabUtils.blockedLinks.isBlocked(dylanSite), "site was unblocked" );
       is( grid.querySelectorAll("[value='"+dylanSite.url+"']").length, 1, "Unblocked site is back in the grid");
 
     } catch(ex) {
 
       ok(false, this.desc+": Caught exception in test: " + ex);
       info("trace: " + ex.stack);
@@ -453,17 +453,17 @@ gTests.push({
     let arrangedPromise = waitForEvent(TopSitesTestHelper.grid, "arranged");
     yield TopSitesTestHelper.updatePagesAndWait();
     yield arrangedPromise;
   },
   run: function() {
     // delete a both pinned and unpinned sites
     // test that sites are removed from the grid
     let grid = TopSitesTestHelper.grid,
-        items = grid.children;
+        items = grid.items;
     is(items.length, 4, this.desc + ": should be 4 topsites");
 
     let brianTile = grid.querySelector('richgriditem[value$="brian"]');
     let dougalTile = grid.querySelector('richgriditem[value$="dougal"]')
 
     // verify assumptions before deleting sites
     ok( brianTile, "Tile for Brian was created");
     ok( dougalTile, "Tile for Dougal was created");