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 165492 8406b4a9ed0d0398d0aa91990973789be467eaae
parent 165491 1c0baa3cf12ca8bb523ad8a542bc2610a52ac367
child 165493 8804ec54fbcbde6e92df7c3464f34a75962ef5b8
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmbrubeck
bugs925418
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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");