Bug 1222490 - part 1: remove browser/components/tabview and its references, r=ttaubert
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Tue, 01 Dec 2015 10:48:10 +0000
changeset 274721 35b7fa5ebd585c2bee84c6e504cb693d44d6b150
parent 274720 c7e233816aaad80639b32fbc79c8b5a1470f0778
child 274722 29c12e8bf172db76c88090912d1204acf42ddb64
push id16478
push usergijskruitbosch@gmail.com
push dateTue, 01 Dec 2015 14:09:10 +0000
treeherderfx-team@fbb5323919c3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersttaubert
bugs1222490
milestone45.0a1
Bug 1222490 - part 1: remove browser/components/tabview and its references, r=ttaubert
browser/components/moz.build
browser/components/tabview/content.js
browser/components/tabview/drag.js
browser/components/tabview/favicons.js
browser/components/tabview/groupitems.js
browser/components/tabview/iq.js
browser/components/tabview/items.js
browser/components/tabview/jar.mn
browser/components/tabview/modules/utils.jsm
browser/components/tabview/moz.build
browser/components/tabview/search.js
browser/components/tabview/storage.js
browser/components/tabview/tabitems.js
browser/components/tabview/tabview.css
browser/components/tabview/tabview.html
browser/components/tabview/tabview.js
browser/components/tabview/telemetry.js
browser/components/tabview/test/browser.ini
browser/components/tabview/test/browser_tabview_alltabs.js
browser/components/tabview/test/browser_tabview_apptabs.js
browser/components/tabview/test/browser_tabview_bug580412.js
browser/components/tabview/test/browser_tabview_bug586553.js
browser/components/tabview/test/browser_tabview_bug587043.js
browser/components/tabview/test/browser_tabview_bug587231.js
browser/components/tabview/test/browser_tabview_bug587276.js
browser/components/tabview/test/browser_tabview_bug587351.js
browser/components/tabview/test/browser_tabview_bug587503.js
browser/components/tabview/test/browser_tabview_bug587990.js
browser/components/tabview/test/browser_tabview_bug588265.js
browser/components/tabview/test/browser_tabview_bug589324.js
browser/components/tabview/test/browser_tabview_bug590606.js
browser/components/tabview/test/browser_tabview_bug591706.js
browser/components/tabview/test/browser_tabview_bug593283.js
browser/components/tabview/test/browser_tabview_bug595191.js
browser/components/tabview/test/browser_tabview_bug595436.js
browser/components/tabview/test/browser_tabview_bug595518.js
browser/components/tabview/test/browser_tabview_bug595521.js
browser/components/tabview/test/browser_tabview_bug595560.js
browser/components/tabview/test/browser_tabview_bug595601.js
browser/components/tabview/test/browser_tabview_bug595804.js
browser/components/tabview/test/browser_tabview_bug595930.js
browser/components/tabview/test/browser_tabview_bug595943.js
browser/components/tabview/test/browser_tabview_bug595965.js
browser/components/tabview/test/browser_tabview_bug596781.js
browser/components/tabview/test/browser_tabview_bug597360.js
browser/components/tabview/test/browser_tabview_bug597399.js
browser/components/tabview/test/browser_tabview_bug597980.js
browser/components/tabview/test/browser_tabview_bug598375.js
browser/components/tabview/test/browser_tabview_bug598600.js
browser/components/tabview/test/browser_tabview_bug599048.js
browser/components/tabview/test/browser_tabview_bug599626.js
browser/components/tabview/test/browser_tabview_bug600645.js
browser/components/tabview/test/browser_tabview_bug600812.js
browser/components/tabview/test/browser_tabview_bug602432.js
browser/components/tabview/test/browser_tabview_bug604098.js
browser/components/tabview/test/browser_tabview_bug606657.js
browser/components/tabview/test/browser_tabview_bug606905.js
browser/components/tabview/test/browser_tabview_bug607108.js
browser/components/tabview/test/browser_tabview_bug608037.js
browser/components/tabview/test/browser_tabview_bug608153.js
browser/components/tabview/test/browser_tabview_bug608158.js
browser/components/tabview/test/browser_tabview_bug608184.js
browser/components/tabview/test/browser_tabview_bug608405.js
browser/components/tabview/test/browser_tabview_bug610208.js
browser/components/tabview/test/browser_tabview_bug610242.js
browser/components/tabview/test/browser_tabview_bug612470.js
browser/components/tabview/test/browser_tabview_bug613541.js
browser/components/tabview/test/browser_tabview_bug616729.js
browser/components/tabview/test/browser_tabview_bug616967.js
browser/components/tabview/test/browser_tabview_bug618816.js
browser/components/tabview/test/browser_tabview_bug618828.js
browser/components/tabview/test/browser_tabview_bug619937.js
browser/components/tabview/test/browser_tabview_bug622835.js
browser/components/tabview/test/browser_tabview_bug623768.js
browser/components/tabview/test/browser_tabview_bug624265_perwindowpb.js
browser/components/tabview/test/browser_tabview_bug624692.js
browser/components/tabview/test/browser_tabview_bug624727_perwindowpb.js
browser/components/tabview/test/browser_tabview_bug624847.js
browser/components/tabview/test/browser_tabview_bug624931.js
browser/components/tabview/test/browser_tabview_bug624953.js
browser/components/tabview/test/browser_tabview_bug625195.js
browser/components/tabview/test/browser_tabview_bug625269.js
browser/components/tabview/test/browser_tabview_bug625424.js
browser/components/tabview/test/browser_tabview_bug625955.js
browser/components/tabview/test/browser_tabview_bug626368.js
browser/components/tabview/test/browser_tabview_bug626455.js
browser/components/tabview/test/browser_tabview_bug626525.js
browser/components/tabview/test/browser_tabview_bug626791.js
browser/components/tabview/test/browser_tabview_bug627736.js
browser/components/tabview/test/browser_tabview_bug628061.js
browser/components/tabview/test/browser_tabview_bug628165.js
browser/components/tabview/test/browser_tabview_bug628270.js
browser/components/tabview/test/browser_tabview_bug628887.js
browser/components/tabview/test/browser_tabview_bug629189.js
browser/components/tabview/test/browser_tabview_bug629195.js
browser/components/tabview/test/browser_tabview_bug630102.js
browser/components/tabview/test/browser_tabview_bug630157.js
browser/components/tabview/test/browser_tabview_bug631662.js
browser/components/tabview/test/browser_tabview_bug631752.js
browser/components/tabview/test/browser_tabview_bug633190.js
browser/components/tabview/test/browser_tabview_bug633788.js
browser/components/tabview/test/browser_tabview_bug634077.js
browser/components/tabview/test/browser_tabview_bug634085.js
browser/components/tabview/test/browser_tabview_bug634672.js
browser/components/tabview/test/browser_tabview_bug635696.js
browser/components/tabview/test/browser_tabview_bug637840.js
browser/components/tabview/test/browser_tabview_bug640765.js
browser/components/tabview/test/browser_tabview_bug641802.js
browser/components/tabview/test/browser_tabview_bug642793.js
browser/components/tabview/test/browser_tabview_bug643392.js
browser/components/tabview/test/browser_tabview_bug644097.js
browser/components/tabview/test/browser_tabview_bug648882.js
browser/components/tabview/test/browser_tabview_bug649006.js
browser/components/tabview/test/browser_tabview_bug649307.js
browser/components/tabview/test/browser_tabview_bug649319.js
browser/components/tabview/test/browser_tabview_bug650280_perwindowpb.js
browser/components/tabview/test/browser_tabview_bug650573.js
browser/components/tabview/test/browser_tabview_bug651311.js
browser/components/tabview/test/browser_tabview_bug654295.js
browser/components/tabview/test/browser_tabview_bug654721.js
browser/components/tabview/test/browser_tabview_bug654941.js
browser/components/tabview/test/browser_tabview_bug655269.js
browser/components/tabview/test/browser_tabview_bug656778.js
browser/components/tabview/test/browser_tabview_bug656913.js
browser/components/tabview/test/browser_tabview_bug659594.js
browser/components/tabview/test/browser_tabview_bug662266.js
browser/components/tabview/test/browser_tabview_bug663421.js
browser/components/tabview/test/browser_tabview_bug665502.js
browser/components/tabview/test/browser_tabview_bug669694.js
browser/components/tabview/test/browser_tabview_bug673196.js
browser/components/tabview/test/browser_tabview_bug673729.js
browser/components/tabview/test/browser_tabview_bug678374.js
browser/components/tabview/test/browser_tabview_bug681599.js
browser/components/tabview/test/browser_tabview_bug685476.js
browser/components/tabview/test/browser_tabview_bug685692.js
browser/components/tabview/test/browser_tabview_bug686654.js
browser/components/tabview/test/browser_tabview_bug696602.js
browser/components/tabview/test/browser_tabview_bug697390.js
browser/components/tabview/test/browser_tabview_bug705621.js
browser/components/tabview/test/browser_tabview_bug706430.js
browser/components/tabview/test/browser_tabview_bug706736.js
browser/components/tabview/test/browser_tabview_bug707466.js
browser/components/tabview/test/browser_tabview_bug712203.js
browser/components/tabview/test/browser_tabview_bug715454.js
browser/components/tabview/test/browser_tabview_bug716880.js
browser/components/tabview/test/browser_tabview_bug728887.js
browser/components/tabview/test/browser_tabview_bug733115.js
browser/components/tabview/test/browser_tabview_bug749658.js
browser/components/tabview/test/browser_tabview_bug766597.js
browser/components/tabview/test/browser_tabview_click_group.js
browser/components/tabview/test/browser_tabview_dragdrop.js
browser/components/tabview/test/browser_tabview_exit_button.js
browser/components/tabview/test/browser_tabview_expander.js
browser/components/tabview/test/browser_tabview_firstrun_pref.js
browser/components/tabview/test/browser_tabview_group.js
browser/components/tabview/test/browser_tabview_launch.js
browser/components/tabview/test/browser_tabview_layout.js
browser/components/tabview/test/browser_tabview_multiwindow_search.js
browser/components/tabview/test/browser_tabview_pending_tabs.js
browser/components/tabview/test/browser_tabview_privatebrowsing_perwindowpb.js
browser/components/tabview/test/browser_tabview_rtl.js
browser/components/tabview/test/browser_tabview_search.js
browser/components/tabview/test/browser_tabview_snapping.js
browser/components/tabview/test/browser_tabview_startup_transitions.js
browser/components/tabview/test/browser_tabview_undo_group.js
browser/components/tabview/test/dummy_page.html
browser/components/tabview/test/head.js
browser/components/tabview/test/search1.html
browser/components/tabview/test/search2.html
browser/components/tabview/test/test_bug600645.html
browser/components/tabview/test/test_bug644097.html
browser/components/tabview/test/test_bug678374.html
browser/components/tabview/test/test_bug678374_icon16.png
browser/components/tabview/trench.js
browser/components/tabview/ui.js
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -16,17 +16,16 @@ DIRS += [
     'places',
     'pocket',
     'preferences',
     'privatebrowsing',
     'search',
     'sessionstore',
     'shell',
     'selfsupport',
-    'tabview',
     'uitour',
     'translation',
 ]
 
 DIRS += ['build']
 
 XPIDL_SOURCES += [
     'nsIAboutNewTabService.idl',
deleted file mode 100644
--- a/browser/components/tabview/content.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-var Cu = Components.utils;
-var Ci = Components.interfaces;
-
-Cu.import("resource:///modules/tabview/utils.jsm");
-
-// Bug 671101 - directly using webProgress in this context
-// causes docShells to leak
-this.__defineGetter__("webProgress", function () {
-  let ifaceReq = docShell.QueryInterface(Ci.nsIInterfaceRequestor);
-  return ifaceReq.getInterface(Ci.nsIWebProgress);
-});
-
-// ----------
-// WindowEventHandler
-//
-// Handles events dispatched by the content window.
-var WindowEventHandler = {
-  // ----------
-  // Function: onDOMWillOpenModalDialog
-  // Sends a synchronous message when the "onDOMWillOpenModalDialog" event
-  // is fired right before a modal dialog will be opened by the current page.
-  onDOMWillOpenModalDialog: function WEH_onDOMWillOpenModalDialog(event) {
-    // (event.isTrusted == true) when the event is generated by a user action
-    // and does not originate from a script.
-    if (!event.isTrusted)
-      return;
-
-    // we're intentionally sending a synchronous message to handle this event
-    // as quick as possible, switch the selected tab and hide the tabview
-    // before the modal dialog is shown
-    sendSyncMessage("Panorama:DOMWillOpenModalDialog");
-  },
-
-  // ----------
-  // Function: onMozAfterPaint
-  // Sends an asynchronous message when the "onMozAfterPaint" event
-  // is fired.
-  onMozAfterPaint: function WEH_onMozAfterPaint(event) {
-    if (event.clientRects.length > 0) {
-      sendAsyncMessage("Panorama:MozAfterPaint");
-    }
-  }
-};
-
-// add event listeners
-addEventListener("DOMWillOpenModalDialog", WindowEventHandler.onDOMWillOpenModalDialog, false);
-addEventListener("MozAfterPaint", WindowEventHandler.onMozAfterPaint, false);
-
-// ----------
-// WindowMessageHandler
-//
-// Handles messages sent by the chrome process.
-var WindowMessageHandler = {
-  // ----------
-  // Function: isDocumentLoaded
-  // Checks if the currently active document is loaded.
-  isDocumentLoaded: function WMH_isDocumentLoaded(cx) {
-    let isLoaded = (content &&
-                    content.document.readyState != "uninitialized" &&
-                    !webProgress.isLoadingDocument);
-
-    sendAsyncMessage(cx.name, {isLoaded: isLoaded});
-  },
-
-  // ----------
-  // Function: isImageDocument
-  // Checks if the currently active document is an image document or not.
-  isImageDocument: function WMH_isImageDocument(cx) {
-    let isImageDocument = (content &&
-                           content.document instanceof Ci.nsIImageDocument);
-
-    sendAsyncMessage(cx.name, {isImageDocument: isImageDocument});
-  },
-
-  waitForDocumentLoad: function WMH_waitForDocumentLoad() {
-    addEventListener("load", function listener() {
-      removeEventListener("load", listener, true);
-      sendAsyncMessage("Panorama:documentLoaded");
-    }, true);
-  },
-};
-
-// add message listeners
-addMessageListener("Panorama:isDocumentLoaded", WindowMessageHandler.isDocumentLoaded);
-addMessageListener("Panorama:isImageDocument", WindowMessageHandler.isImageDocument);
-addMessageListener("Panorama:waitForDocumentLoad", WindowMessageHandler.waitForDocumentLoad);
deleted file mode 100644
--- a/browser/components/tabview/drag.js
+++ /dev/null
@@ -1,269 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// **********
-// Title: drag.js
-
-// ----------
-// Variable: drag
-// The Drag that's currently in process.
-var drag = {
-  info: null,
-  zIndex: 100,
-  lastMoveTime: 0
-};
-
-//----------
-//Variable: resize
-//The resize (actually a Drag) that is currently in process
-var resize = {
-  info: null,
-  lastMoveTime: 0
-};
-
-// ##########
-// Class: Drag (formerly DragInfo)
-// Helper class for dragging <Item>s
-//
-// ----------
-// Constructor: Drag
-// Called to create a Drag in response to an <Item> draggable "start" event.
-// Note that it is also used partially during <Item>'s resizable method as well.
-//
-// Parameters:
-//   item - The <Item> being dragged
-//   event - The DOM event that kicks off the drag
-function Drag(item, event) {
-  Utils.assert(item && (item.isAnItem || item.isAFauxItem), 
-      'must be an item, or at least a faux item');
-
-  this.item = item;
-  this.el = item.container;
-  this.$el = iQ(this.el);
-  this.parent = this.item.parent;
-  this.startPosition = new Point(event.clientX, event.clientY);
-  this.startTime = Date.now();
-
-  this.item.isDragging = true;
-  this.item.setZ(999999);
-
-  this.safeWindowBounds = Items.getSafeWindowBounds();
-
-  Trenches.activateOthersTrenches(this.el);
-};
-
-Drag.prototype = {
-  // ----------
-  // Function: toString
-  // Prints [Drag (item)] for debug use
-  toString: function Drag_toString() {
-    return "[Drag (" + this.item + ")]";
-  },
-
-  // ----------
-  // Function: snapBounds
-  // Adjusts the given bounds according to the currently active trenches. Used by <Drag.snap>
-  //
-  // Parameters:
-  //   bounds             - (<Rect>) bounds
-  //   stationaryCorner   - which corner is stationary? by default, the top left in LTR mode,
-  //                        and top right in RTL mode.
-  //                        "topleft", "bottomleft", "topright", "bottomright"
-  //   assumeConstantSize - (boolean) whether the bounds' dimensions are sacred or not.
-  //   keepProportional   - (boolean) if assumeConstantSize is false, whether we should resize
-  //                        proportionally or not
-  //   checkItemStatus    - (boolean) make sure this is a valid item which should be snapped
-  snapBounds: function Drag_snapBounds(bounds, stationaryCorner, assumeConstantSize, keepProportional, checkItemStatus) {
-    if (!stationaryCorner)
-      stationaryCorner = UI.rtl ? 'topright' : 'topleft';
-    var update = false; // need to update
-    var updateX = false;
-    var updateY = false;
-    var newRect;
-    var snappedTrenches = {};
-
-    // OH SNAP!
-
-    // if we aren't holding down the meta key or have trenches disabled...
-    if (!Keys.meta && !Trenches.disabled) {
-      // snappable = true if we aren't a tab on top of something else, and
-      // there's no active drop site...
-      let snappable = !(this.item.isATabItem &&
-                       this.item.overlapsWithOtherItems()) &&
-                       !iQ(".acceptsDrop").length;
-      if (!checkItemStatus || snappable) {
-        newRect = Trenches.snap(bounds, stationaryCorner, assumeConstantSize,
-                                keepProportional);
-        if (newRect) { // might be false if no changes were made
-          update = true;
-          snappedTrenches = newRect.snappedTrenches || {};
-          bounds = newRect;
-        }
-      }
-    }
-
-    // make sure the bounds are in the window.
-    newRect = this.snapToEdge(bounds, stationaryCorner, assumeConstantSize,
-                              keepProportional);
-    if (newRect) {
-      update = true;
-      bounds = newRect;
-      Utils.extend(snappedTrenches, newRect.snappedTrenches);
-    }
-
-    Trenches.hideGuides();
-    for (var edge in snappedTrenches) {
-      var trench = snappedTrenches[edge];
-      if (typeof trench == 'object') {
-        trench.showGuide = true;
-        trench.show();
-      }
-    }
-
-    return update ? bounds : false;
-  },
-
-  // ----------
-  // Function: snap
-  // Called when a drag or mousemove occurs. Set the bounds based on the mouse move first, then
-  // call snap and it will adjust the item's bounds if appropriate. Also triggers the display of
-  // trenches that it snapped to.
-  //
-  // Parameters:
-  //   stationaryCorner   - which corner is stationary? by default, the top left in LTR mode,
-  //                        and top right in RTL mode.
-  //                        "topleft", "bottomleft", "topright", "bottomright"
-  //   assumeConstantSize - (boolean) whether the bounds' dimensions are sacred or not.
-  //   keepProportional   - (boolean) if assumeConstantSize is false, whether we should resize
-  //                        proportionally or not
-  snap: function Drag_snap(stationaryCorner, assumeConstantSize, keepProportional) {
-    var bounds = this.item.getBounds();
-    bounds = this.snapBounds(bounds, stationaryCorner, assumeConstantSize, keepProportional, true);
-    if (bounds) {
-      this.item.setBounds(bounds, true);
-      return true;
-    }
-    return false;
-  },
-
-  // --------
-  // Function: snapToEdge
-  // Returns a version of the bounds snapped to the edge if it is close enough. If not,
-  // returns false. If <Keys.meta> is true, this function will simply enforce the
-  // window edges.
-  //
-  // Parameters:
-  //   rect - (<Rect>) current bounds of the object
-  //   stationaryCorner   - which corner is stationary? by default, the top left in LTR mode,
-  //                        and top right in RTL mode.
-  //                        "topleft", "bottomleft", "topright", "bottomright"
-  //   assumeConstantSize - (boolean) whether the rect's dimensions are sacred or not
-  //   keepProportional   - (boolean) if we are allowed to change the rect's size, whether the
-  //                                  dimensions should scaled proportionally or not.
-  snapToEdge: function Drag_snapToEdge(rect, stationaryCorner, assumeConstantSize, keepProportional) {
-
-    var swb = this.safeWindowBounds;
-    var update = false;
-    var updateX = false;
-    var updateY = false;
-    var snappedTrenches = {};
-
-    var snapRadius = (Keys.meta ? 0 : Trenches.defaultRadius);
-    if (rect.left < swb.left + snapRadius ) {
-      if (stationaryCorner.indexOf('right') > -1 && !assumeConstantSize)
-        rect.width = rect.right - swb.left;
-      rect.left = swb.left;
-      update = true;
-      updateX = true;
-      snappedTrenches.left = 'edge';
-    }
-
-    if (rect.right > swb.right - snapRadius) {
-      if (updateX || !assumeConstantSize) {
-        var newWidth = swb.right - rect.left;
-        if (keepProportional)
-          rect.height = rect.height * newWidth / rect.width;
-        rect.width = newWidth;
-        update = true;
-      } else if (!updateX || !Trenches.preferLeft) {
-        rect.left = swb.right - rect.width;
-        update = true;
-      }
-      snappedTrenches.right = 'edge';
-      delete snappedTrenches.left;
-    }
-    if (rect.top < swb.top + snapRadius) {
-      if (stationaryCorner.indexOf('bottom') > -1 && !assumeConstantSize)
-        rect.height = rect.bottom - swb.top;
-      rect.top = swb.top;
-      update = true;
-      updateY = true;
-      snappedTrenches.top = 'edge';
-    }
-    if (rect.bottom > swb.bottom - snapRadius) {
-      if (updateY || !assumeConstantSize) {
-        var newHeight = swb.bottom - rect.top;
-        if (keepProportional)
-          rect.width = rect.width * newHeight / rect.height;
-        rect.height = newHeight;
-        update = true;
-      } else if (!updateY || !Trenches.preferTop) {
-        rect.top = swb.bottom - rect.height;
-        update = true;
-      }
-      snappedTrenches.top = 'edge';
-      delete snappedTrenches.bottom;
-    }
-
-    if (update) {
-      rect.snappedTrenches = snappedTrenches;
-      return rect;
-    }
-    return false;
-  },
-
-  // ----------
-  // Function: drag
-  // Called in response to an <Item> draggable "drag" event.
-  drag: function Drag_drag(event) {
-    this.snap(UI.rtl ? 'topright' : 'topleft', true);
-
-    if (this.parent && this.parent.expanded) {
-      var distance = this.startPosition.distance(new Point(event.clientX, event.clientY));
-      if (distance > 100) {
-        this.parent.remove(this.item);
-        this.parent.collapse();
-      }
-    }
-  },
-
-  // ----------
-  // Function: stop
-  // Called in response to an <Item> draggable "stop" event.
-  //
-  // Parameters:
-  //  immediately - bool for doing the pushAway immediately, without animation
-  stop: function Drag_stop(immediately) {
-    Trenches.hideGuides();
-    this.item.isDragging = false;
-
-    if (this.parent && this.parent != this.item.parent)
-      this.parent.closeIfEmpty();
-
-    if (this.parent && this.parent.expanded)
-      this.parent.arrange();
-
-    if (this.item.parent)
-      this.item.parent.arrange();
-
-    if (this.item.isAGroupItem) {
-      this.item.setZ(drag.zIndex);
-      drag.zIndex++;
-
-      this.item.pushAway(immediately);
-    }
-
-    Trenches.disactivate();
-  }
-};
deleted file mode 100644
--- a/browser/components/tabview/favicons.js
+++ /dev/null
@@ -1,146 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-Components.utils.import('resource://gre/modules/PlacesUtils.jsm');
-
-var FavIcons = {
-  // Pref that controls whether to display site icons.
-  PREF_CHROME_SITE_ICONS: "browser.chrome.site_icons",
-
-  // Pref that controls whether to display fav icons.
-  PREF_CHROME_FAVICONS: "browser.chrome.favicons",
-
-  // Lazy getter for pref browser.chrome.site_icons.
-  get _prefSiteIcons() {
-    delete this._prefSiteIcons;
-    this._prefSiteIcons = Services.prefs.getBoolPref(this.PREF_CHROME_SITE_ICONS);
-  },
-
-  // Lazy getter for pref browser.chrome.favicons.
-  get _prefFavicons() {
-    delete this._prefFavicons;
-    this._prefFavicons = Services.prefs.getBoolPref(this.PREF_CHROME_FAVICONS);
-  },
-
-  get defaultFavicon() {
-    return this._favIconService.defaultFavicon.spec;
-  },
-
-  init: function FavIcons_init() {
-    XPCOMUtils.defineLazyServiceGetter(this, "_favIconService",
-      "@mozilla.org/browser/favicon-service;1", "nsIFaviconService");
-
-    Services.prefs.addObserver(this.PREF_CHROME_SITE_ICONS, this, false);
-    Services.prefs.addObserver(this.PREF_CHROME_FAVICONS, this, false);
-  },
-
-  uninit: function FavIcons_uninit() {
-    Services.prefs.removeObserver(this.PREF_CHROME_SITE_ICONS, this);
-    Services.prefs.removeObserver(this.PREF_CHROME_FAVICONS, this);
-  },
-
-  observe: function FavIcons_observe(subject, topic, data) {
-    let value = Services.prefs.getBoolPref(data);
-
-    if (data == this.PREF_CHROME_SITE_ICONS)
-      this._prefSiteIcons = value;
-    else if (data == this.PREF_CHROME_FAVICONS)
-      this._prefFavicons = value;
-  },
-
-  // ----------
-  // Function: getFavIconUrlForTab
-  // Gets the "favicon link URI" for the given xul:tab, or null if unavailable.
-  getFavIconUrlForTab: function FavIcons_getFavIconUrlForTab(tab, callback) {
-    this._isImageDocument(tab, function (isImageDoc) {
-      if (isImageDoc) {
-        callback(tab.pinned ? tab.image : null);
-      } else {
-        this._getFavIconForNonImageDocument(tab, callback);
-      }
-    }.bind(this));
-  },
-
-  // ----------
-  // Function: _getFavIconForNonImageDocument
-  // Retrieves the favicon for a tab containing a non-image document.
-  _getFavIconForNonImageDocument:
-    function FavIcons_getFavIconForNonImageDocument(tab, callback) {
-
-    if (tab.image)
-      this._getFavIconFromTabImage(tab, callback);
-    else if (this._shouldLoadFavIcon(tab))
-      this._getFavIconForHttpDocument(tab, callback);
-    else
-      callback(null);
-  },
-
-  // ----------
-  // Function: _getFavIconFromTabImage
-  // Retrieves the favicon for tab with a tab image.
-  _getFavIconFromTabImage:
-    function FavIcons_getFavIconFromTabImage(tab, callback) {
-
-    let tabImage = gBrowser.getIcon(tab);
-
-    // If the tab image's url starts with http(s), fetch icon from favicon
-    // service via the moz-anno protocol.
-    if (/^https?:/.test(tabImage)) {
-      let tabImageURI = gWindow.makeURI(tabImage);
-      tabImage = this._favIconService.getFaviconLinkForIcon(tabImageURI).spec;
-    }
-
-    callback(tabImage);
-  },
-
-  // ----------
-  // Function: _getFavIconForHttpDocument
-  // Retrieves the favicon for tab containg a http(s) document.
-  _getFavIconForHttpDocument:
-    function FavIcons_getFavIconForHttpDocument(tab, callback) {
-
-    let {currentURI} = tab.linkedBrowser;
-    this._favIconService.getFaviconURLForPage(currentURI, function (uri) {
-      if (uri) {
-        let icon = this._favIconService.getFaviconLinkForIcon(uri).spec;
-        callback(icon);
-      } else {
-        callback(this.defaultFavicon);
-      }
-    }.bind(this));
-  },
-
-  // ----------
-  // Function: _isImageDocument
-  // Checks whether an image is loaded into the given tab.
-  _isImageDocument: function UI__isImageDocument(tab, callback) {
-    let mm = tab.linkedBrowser.messageManager;
-    let message = "Panorama:isImageDocument";
-
-    mm.addMessageListener(message, function onMessage(cx) {
-      mm.removeMessageListener(cx.name, onMessage);
-      callback(cx.json.isImageDocument);
-    });
-
-    mm.sendAsyncMessage(message);
-  },
-
-  // ----------
-  // Function: _shouldLoadFavIcon
-  // Checks whether fav icon should be loaded for a given tab.
-  _shouldLoadFavIcon: function FavIcons_shouldLoadFavIcon(tab) {
-    // No need to load a favicon if the user doesn't want site or favicons.
-    if (!this._prefSiteIcons || !this._prefFavicons)
-      return false;
-
-    let uri = tab.linkedBrowser.currentURI;
-
-    // Stop here if we don't have a valid nsIURI.
-    if (!uri || !(uri instanceof Ci.nsIURI))
-      return false;
-
-    // Load favicons for http(s) pages only.
-    return uri.schemeIs("http") || uri.schemeIs("https");
-  }
-};
deleted file mode 100644
--- a/browser/components/tabview/groupitems.js
+++ /dev/null
@@ -1,2668 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// **********
-// Title: groupItems.js
-
-// ##########
-// Class: GroupItem
-// A single groupItem in the TabView window. Descended from <Item>.
-// Note that it implements the <Subscribable> interface.
-//
-// ----------
-// Constructor: GroupItem
-//
-// Parameters:
-//   listOfEls - an array of DOM elements for tabs to be added to this groupItem
-//   options - various options for this groupItem (see below). In addition, gets passed
-//     to <add> along with the elements provided.
-//
-// Possible options:
-//   id - specifies the groupItem's id; otherwise automatically generated
-//   userSize - see <Item.userSize>; default is null
-//   bounds - a <Rect>; otherwise based on the locations of the provided elements
-//   container - a DOM element to use as the container for this groupItem; otherwise will create
-//   title - the title for the groupItem; otherwise blank
-//   focusTitle - focus the title's input field after creation
-//   dontPush - true if this groupItem shouldn't push away or snap on creation; default is false
-//   immediately - true if we want all placement immediately, not with animation
-function GroupItem(listOfEls, options) {
-  if (!options)
-    options = {};
-
-  this._inited = false;
-  this._uninited = false;
-  this._children = []; // an array of Items
-  this.isAGroupItem = true;
-  this.id = options.id || GroupItems.getNextID();
-  this._isStacked = false;
-  this.expanded = null;
-  this.hidden = false;
-  this.fadeAwayUndoButtonDelay = 15000;
-  this.fadeAwayUndoButtonDuration = 300;
-
-  this.keepProportional = false;
-  this._frozenItemSizeData = {};
-
-  this._onChildClose = this._onChildClose.bind(this);
-
-  // Variable: _activeTab
-  // The <TabItem> for the groupItem's active tab.
-  this._activeTab = null;
-
-  if (Utils.isPoint(options.userSize))
-    this.userSize = new Point(options.userSize);
-
-  var self = this;
-
-  var rectToBe;
-  if (options.bounds) {
-    Utils.assert(Utils.isRect(options.bounds), "options.bounds must be a Rect");
-    rectToBe = new Rect(options.bounds);
-  }
-
-  if (!rectToBe) {
-    rectToBe = GroupItems.getBoundingBox(listOfEls);
-    rectToBe.inset(-42, -42);
-  }
-
-  var $container = options.container;
-  let immediately = options.immediately || $container ? true : false;
-  if (!$container) {
-    $container = iQ('<div>')
-      .addClass('groupItem')
-      .css({position: 'absolute'})
-      .css(rectToBe);
-  }
-
-  this.bounds = $container.bounds();
-
-  this.isDragging = false;
-  $container
-    .css({zIndex: -100})
-    .attr("data-id", this.id)
-    .appendTo("body");
-
-  // ___ Resizer
-  this.$resizer = iQ("<div>")
-    .addClass('resizer')
-    .appendTo($container)
-    .hide();
-
-  // ___ Titlebar
-  var html =
-    "<div class='title-container'>" +
-      "<input class='name' />" +
-      "<div class='title-shield' />" +
-    "</div>";
-
-  this.$titlebar = iQ('<div>')
-    .addClass('titlebar')
-    .html(html)
-    .appendTo($container);
-
-  this.$closeButton = iQ('<div>')
-    .addClass('close')
-    .click(function() {
-      self.closeAll();
-    })
-    .attr("title", tabviewString("groupItem.closeGroup"))
-    .appendTo($container);
-
-  // ___ Title
-  this.$titleContainer = iQ('.title-container', this.$titlebar);
-  this.$title = iQ('.name', this.$titlebar).attr('placeholder', this.defaultName);
-  this.$titleShield = iQ('.title-shield', this.$titlebar);
-  this.setTitle(options.title);
-
-  var handleKeyPress = function (e) {
-    if (e.keyCode == KeyEvent.DOM_VK_ESCAPE ||
-        e.keyCode == KeyEvent.DOM_VK_RETURN) {
-      (self.$title)[0].blur();
-      self.$title
-        .addClass("transparentBorder")
-        .one("mouseout", function() {
-          self.$title.removeClass("transparentBorder");
-        });
-      e.stopPropagation();
-      e.preventDefault();
-    }
-  };
-
-  var handleKeyUp = function(e) {
-    // NOTE: When user commits or cancels IME composition, the last key
-    //       event fires only a keyup event.  Then, we shouldn't take any
-    //       reactions but we should update our status.
-    self.save();
-  };
-
-  this.$title
-    .blur(function() {
-      self._titleFocused = false;
-      self.$title[0].setSelectionRange(0, 0);
-      self.$titleShield.show();
-      if (self.getTitle())
-        gTabView.firstUseExperienced = true;
-      self.save();
-    })
-    .focus(function() {
-      self._unfreezeItemSize();
-      if (!self._titleFocused) {
-        (self.$title)[0].select();
-        self._titleFocused = true;
-      }
-    })
-    .mousedown(function(e) {
-      e.stopPropagation();
-    })
-    .keypress(handleKeyPress)
-    .keyup(handleKeyUp)
-    .attr("title", tabviewString("groupItem.defaultName"));
-
-  this.$titleShield
-    .mousedown(function(e) {
-      self.lastMouseDownTarget = (Utils.isLeftClick(e) ? e.target : null);
-    })
-    .mouseup(function(e) {
-      var same = (e.target == self.lastMouseDownTarget);
-      self.lastMouseDownTarget = null;
-      if (!same)
-        return;
-
-      if (!self.isDragging)
-        self.focusTitle();
-    })
-    .attr("title", tabviewString("groupItem.defaultName"));
-
-  if (options.focusTitle)
-    this.focusTitle();
-
-  // ___ Stack Expander
-  this.$expander = iQ("<div/>")
-    .addClass("stackExpander")
-    .appendTo($container)
-    .hide();
-
-  // ___ app tabs: create app tab tray and populate it
-  let appTabTrayContainer = iQ("<div/>")
-    .addClass("appTabTrayContainer")
-    .appendTo($container);
-  this.$appTabTray = iQ("<div/>")
-    .addClass("appTabTray")
-    .appendTo(appTabTrayContainer);
-
-  let pinnedTabCount = gBrowser._numPinnedTabs;
-  AllTabs.tabs.forEach(function (xulTab, index) {
-    // only adjust tray when it's the last app tab.
-    if (xulTab.pinned)
-      this.addAppTab(xulTab, {dontAdjustTray: index + 1 < pinnedTabCount});
-  }, this);
-
-  // ___ Undo Close
-  this.$undoContainer = null;
-  this._undoButtonTimeoutId = null;
-
-  // ___ Superclass initialization
-  this._init($container[0]);
-
-  // ___ Children
-  // We explicitly set dontArrange=true to prevent the groupItem from
-  // re-arranging its children after a tabItem has been added. This saves us a
-  // group.arrange() call per child and therefore some tab.setBounds() calls.
-  options.dontArrange = true;
-  listOfEls.forEach(function (el) {
-    self.add(el, options);
-  });
-
-  // ___ Finish Up
-  this._addHandlers($container);
-
-  this.setResizable(true, immediately);
-
-  GroupItems.register(this);
-
-  // ___ Position
-  this.setBounds(rectToBe, immediately);
-  if (options.dontPush) {
-    this.setZ(drag.zIndex);
-    drag.zIndex++; 
-  } else {
-    // Calling snap will also trigger pushAway
-    this.snap(immediately);
-  }
-
-  if (!options.immediately && listOfEls.length > 0)
-    $container.hide().fadeIn();
-
-  this._inited = true;
-  this.save();
-
-  GroupItems.updateGroupCloseButtons();
-};
-
-// ----------
-GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
-  // ----------
-  // Function: toString
-  // Prints [GroupItem id=id] for debug use
-  toString: function GroupItem_toString() {
-    return "[GroupItem id=" + this.id + "]";
-  },
-
-  // ----------
-  // Variable: defaultName
-  // The prompt text for the title field.
-  defaultName: tabviewString('groupItem.defaultName'),
-
-  // -----------
-  // Function: setActiveTab
-  // Sets the active <TabItem> for this groupItem; can be null, but only
-  // if there are no children.
-  setActiveTab: function GroupItem_setActiveTab(tab) {
-    Utils.assertThrow((!tab && this._children.length == 0) || tab.isATabItem,
-        "tab must be null (if no children) or a TabItem");
-
-    this._activeTab = tab;
-
-    if (this.isStacked())
-      this.arrange({immediately: true});
-  },
-
-  // -----------
-  // Function: getActiveTab
-  // Gets the active <TabItem> for this groupItem; can be null, but only
-  // if there are no children.
-  getActiveTab: function GroupItem_getActiveTab() {
-    return this._activeTab;
-  },
-
-  // ----------
-  // Function: getStorageData
-  // Returns all of the info worth storing about this groupItem.
-  getStorageData: function GroupItem_getStorageData() {
-    var data = {
-      bounds: this.getBounds(),
-      userSize: null,
-      title: this.getTitle(),
-      id: this.id
-    };
-
-    if (Utils.isPoint(this.userSize))
-      data.userSize = new Point(this.userSize);
-
-    return data;
-  },
-
-  // ----------
-  // Function: isEmpty
-  // Returns true if the tab groupItem is empty and unnamed.
-  isEmpty: function GroupItem_isEmpty() {
-    return !this._children.length && !this.getTitle();
-  },
-
-  // ----------
-  // Function: isStacked
-  // Returns true if this item is in a stacked groupItem.
-  isStacked: function GroupItem_isStacked() {
-    return this._isStacked;
-  },
-
-  // ----------
-  // Function: isTopOfStack
-  // Returns true if the item is showing on top of this group's stack,
-  // determined by whether the tab is this group's topChild, or
-  // if it doesn't have one, its first child.
-  isTopOfStack: function GroupItem_isTopOfStack(item) {
-    return this.isStacked() && item == this.getTopChild();
-  },
-
-  // ----------
-  // Function: save
-  // Saves this groupItem to persistent storage.
-  save: function GroupItem_save() {
-    if (!this._inited || this._uninited) // too soon/late to save
-      return;
-
-    var data = this.getStorageData();
-    if (GroupItems.groupItemStorageSanity(data))
-      Storage.saveGroupItem(gWindow, data);
-  },
-
-  // ----------
-  // Function: deleteData
-  // Deletes the groupItem in the persistent storage.
-  deleteData: function GroupItem_deleteData() {
-    this._uninited = true;
-    Storage.deleteGroupItem(gWindow, this.id);
-  },
-
-  // ----------
-  // Function: getTitle
-  // Returns the title of this groupItem as a string.
-  getTitle: function GroupItem_getTitle() {
-    return this.$title ? this.$title.val() : '';
-  },
-
-  // ----------
-  // Function: setTitle
-  // Sets the title of this groupItem with the given string
-  setTitle: function GroupItem_setTitle(value) {
-    this.$title.val(value);
-    this.save();
-  },
-
-  // ----------
-  // Function: focusTitle
-  // Hide the title's shield and focus the underlying input field.
-  focusTitle: function GroupItem_focusTitle() {
-    this.$titleShield.hide();
-    this.$title[0].focus();
-  },
-
-  // ----------
-  // Function: adjustAppTabTray
-  // Used to adjust the appTabTray size, to split the appTabIcons across
-  // multiple columns when needed - if the groupItem size is too small.
-  //
-  // Parameters:
-  //   arrangeGroup - rearrange the groupItem if the number of appTab columns
-  //   changes. If true, then this.arrange() is called, otherwise not.
-  adjustAppTabTray: function GroupItem_adjustAppTabTray(arrangeGroup) {
-    let icons = iQ(".appTabIcon", this.$appTabTray);
-    let container = iQ(this.$appTabTray[0].parentNode);
-    if (!icons.length) {
-      // There are no icons, so hide the appTabTray if needed.
-      if (parseInt(container.css("width")) != 0) {
-        this.$appTabTray.css("-moz-column-count", "auto");
-        this.$appTabTray.css("height", 0);
-        container.css("width", 0);
-        container.css("height", 0);
-
-        if (container.hasClass("appTabTrayContainerTruncated"))
-          container.removeClass("appTabTrayContainerTruncated");
-
-        if (arrangeGroup)
-          this.arrange();
-      }
-      return;
-    }
-
-    let iconBounds = iQ(icons[0]).bounds();
-    let boxBounds = this.getBounds();
-    let contentHeight = boxBounds.height -
-                        parseInt(container.css("top")) -
-                        this.$resizer.height();
-    let rows = Math.floor(contentHeight / iconBounds.height);
-    let columns = Math.ceil(icons.length / rows);
-    let columnsGap = parseInt(this.$appTabTray.css("-moz-column-gap"));
-    let iconWidth = iconBounds.width + columnsGap;
-    let maxColumns = Math.floor((boxBounds.width * 0.20) / iconWidth);
-
-    Utils.assert(rows > 0 && columns > 0 && maxColumns > 0,
-      "make sure the calculated rows, columns and maxColumns are correct");
-
-    if (columns > maxColumns)
-      container.addClass("appTabTrayContainerTruncated");
-    else if (container.hasClass("appTabTrayContainerTruncated"))
-      container.removeClass("appTabTrayContainerTruncated");
-
-    // Need to drop the -moz- prefix when Gecko makes it obsolete.
-    // See bug 629452.
-    if (parseInt(this.$appTabTray.css("-moz-column-count")) != columns)
-      this.$appTabTray.css("-moz-column-count", columns);
-
-    if (parseInt(this.$appTabTray.css("height")) != contentHeight) {
-      this.$appTabTray.css("height", contentHeight + "px");
-      container.css("height", contentHeight + "px");
-    }
-
-    let fullTrayWidth = iconWidth * columns - columnsGap;
-    if (parseInt(this.$appTabTray.css("width")) != fullTrayWidth)
-      this.$appTabTray.css("width", fullTrayWidth + "px");
-
-    let trayWidth = iconWidth * Math.min(columns, maxColumns) - columnsGap;
-    if (parseInt(container.css("width")) != trayWidth) {
-      container.css("width", trayWidth + "px");
-
-      // Rearrange the groupItem if the width changed.
-      if (arrangeGroup)
-        this.arrange();
-    }
-  },
-
-  // ----------
-  // Function: getContentBounds
-  // Returns a <Rect> for the groupItem's content area (which doesn't include the title, etc).
-  //
-  // Parameters:
-  //   options - an object with additional parameters, see below
-  //
-  // Possible options:
-  //   stacked - true to get content bounds for stacked mode
-  getContentBounds: function GroupItem_getContentBounds(options) {
-    let box = this.getBounds();
-    let titleHeight = this.$titlebar.height();
-    box.top += titleHeight;
-    box.height -= titleHeight;
-
-    let appTabTrayContainer = iQ(this.$appTabTray[0].parentNode);
-    let appTabTrayWidth = appTabTrayContainer.width();
-    if (appTabTrayWidth)
-      appTabTrayWidth += parseInt(appTabTrayContainer.css(UI.rtl ? "left" : "right"));
-
-    box.width -= appTabTrayWidth;
-    if (UI.rtl) {
-      box.left += appTabTrayWidth;
-    }
-
-    // Make the computed bounds' "padding" and expand button margin actually be
-    // themeable --OR-- compute this from actual bounds. Bug 586546
-    box.inset(6, 6);
-
-    // make some room for the expand button in stacked mode
-    if (options && options.stacked)
-      box.height -= this.$expander.height() + 9; // the button height plus padding
-
-    return box;
-  },
-
-  // ----------
-  // Function: setBounds
-  // Sets the bounds with the given <Rect>, animating unless "immediately" is false.
-  //
-  // Parameters:
-  //   inRect - a <Rect> giving the new bounds
-  //   immediately - true if it should not animate; default false
-  //   options - an object with additional parameters, see below
-  //
-  // Possible options:
-  //   force - true to always update the DOM even if the bounds haven't changed; default false
-  setBounds: function GroupItem_setBounds(inRect, immediately, options) {
-      Utils.assert(Utils.isRect(inRect), 'GroupItem.setBounds: rect is not a real rectangle!');
-
-    // Validate and conform passed in size
-    let validSize = GroupItems.calcValidSize(
-      new Point(inRect.width, inRect.height));
-    let rect = new Rect(inRect.left, inRect.top, validSize.x, validSize.y);
-
-    if (!options)
-      options = {};
-
-    var titleHeight = this.$titlebar.height();
-
-    // ___ Determine what has changed
-    var css = {};
-    var titlebarCSS = {};
-    var contentCSS = {};
-
-    if (rect.left != this.bounds.left || options.force)
-      css.left = rect.left;
-
-    if (rect.top != this.bounds.top || options.force)
-      css.top = rect.top;
-
-    if (rect.width != this.bounds.width || options.force) {
-      css.width = rect.width;
-      titlebarCSS.width = rect.width;
-      contentCSS.width = rect.width;
-    }
-
-    if (rect.height != this.bounds.height || options.force) {
-      css.height = rect.height;
-      contentCSS.height = rect.height - titleHeight;
-    }
-
-    if (Utils.isEmptyObject(css))
-      return;
-
-    var offset = new Point(rect.left - this.bounds.left, rect.top - this.bounds.top);
-    this.bounds = new Rect(rect);
-
-    // Make sure the AppTab icons fit the new groupItem size.
-    if (css.width || css.height)
-      this.adjustAppTabTray();
-
-    // ___ Deal with children
-    if (css.width || css.height) {
-      this.arrange({animate: !immediately}); //(immediately ? 'sometimes' : true)});
-    } else if (css.left || css.top) {
-      this._children.forEach(function(child) {
-        if (!child.getHidden()) {
-          var box = child.getBounds();
-          child.setPosition(box.left + offset.x, box.top + offset.y, immediately);
-        }
-      });
-    }
-
-    // ___ Update our representation
-    if (immediately) {
-      iQ(this.container).css(css);
-      this.$titlebar.css(titlebarCSS);
-    } else {
-      TabItems.pausePainting();
-      iQ(this.container).animate(css, {
-        duration: 350,
-        easing: "tabviewBounce",
-        complete: function() {
-          TabItems.resumePainting();
-        }
-      });
-
-      this.$titlebar.animate(titlebarCSS, {
-        duration: 350
-      });
-    }
-
-    UI.clearShouldResizeItems();
-    this.setTrenches(rect);
-    this.save();
-  },
-
-  // ----------
-  // Function: setZ
-  // Set the Z order for the groupItem's container, as well as its children.
-  setZ: function GroupItem_setZ(value) {
-    this.zIndex = value;
-
-    iQ(this.container).css({zIndex: value});
-
-    var count = this._children.length;
-    if (count) {
-      var topZIndex = value + count + 1;
-      var zIndex = topZIndex;
-      var self = this;
-      this._children.forEach(function(child) {
-        if (child == self.getTopChild())
-          child.setZ(topZIndex + 1);
-        else {
-          child.setZ(zIndex);
-          zIndex--;
-        }
-      });
-    }
-  },
-
-  // ----------
-  // Function: close
-  // Closes the groupItem, removing (but not closing) all of its children.
-  //
-  // Parameters:
-  //   options - An object with optional settings for this call.
-  //
-  // Options:
-  //   immediately - (bool) if true, no animation will be used
-  close: function GroupItem_close(options) {
-    this.removeAll({dontClose: true});
-    GroupItems.unregister(this);
-
-    // remove unfreeze event handlers, if item size is frozen
-    this._unfreezeItemSize({dontArrange: true});
-
-    let self = this;
-    let destroyGroup = function () {
-      iQ(self.container).remove();
-      if (self.$undoContainer) {
-        self.$undoContainer.remove();
-        self.$undoContainer = null;
-      }
-      self.removeTrenches();
-      Items.unsquish();
-      self._sendToSubscribers("close");
-      GroupItems.updateGroupCloseButtons();
-    }
-
-    if (this.hidden || (options && options.immediately)) {
-      destroyGroup();
-    } else {
-      iQ(this.container).animate({
-        opacity: 0,
-        "transform": "scale(.3)",
-      }, {
-        duration: 170,
-        complete: destroyGroup
-      });
-    }
-
-    this.deleteData();
-  },
-
-  // ----------
-  // Function: closeAll
-  // Closes the groupItem and all of its children.
-  closeAll: function GroupItem_closeAll() {
-    if (this._children.length > 0) {
-      this._unfreezeItemSize();
-      this._children.forEach(function(child) {
-        iQ(child.container).hide();
-      });
-
-      iQ(this.container).animate({
-         opacity: 0,
-         "transform": "scale(.3)",
-      }, {
-        duration: 170,
-        complete: function() {
-          iQ(this).hide();
-        }
-      });
-
-      this.droppable(false);
-      this.removeTrenches();
-      this._createUndoButton();
-    } else
-      this.close();
-
-    this._makeLastActiveGroupItemActive();
-  },
-  
-  // ----------
-  // Function: _makeClosestTabActive
-  // Make the closest tab external to this group active.
-  // Used when closing the group.
-  _makeClosestTabActive: function GroupItem__makeClosestTabActive() {
-    let closeCenter = this.getBounds().center();
-    // Find closest tab to make active
-    let closestTabItem = UI.getClosestTab(closeCenter);
-    if (closestTabItem)
-      UI.setActive(closestTabItem);
-  },
-
-  // ----------
-  // Function: _makeLastActiveGroupItemActive
-  // Makes the last active group item active.
-  _makeLastActiveGroupItemActive: function GroupItem__makeLastActiveGroupItemActive() {
-    let groupItem = GroupItems.getLastActiveGroupItem();
-    if (groupItem)
-      UI.setActive(groupItem);
-    else
-      this._makeClosestTabActive();
-  },
-
-  // ----------
-  // Function: closeIfEmpty
-  // Closes the group if it's empty, is closable, and autoclose is enabled
-  // (see pauseAutoclose()). Returns true if the close occurred and false
-  // otherwise.
-  closeIfEmpty: function GroupItem_closeIfEmpty() {
-    if (this.isEmpty() && !UI._closedLastVisibleTab &&
-        !GroupItems.getUnclosableGroupItemId() && !GroupItems._autoclosePaused) {
-      this.close();
-      return true;
-    }
-    return false;
-  },
-
-  // ----------
-  // Function: _unhide
-  // Shows the hidden group.
-  //
-  // Parameters:
-  //   options - various options (see below)
-  //
-  // Possible options:
-  //   immediately - true when no animations should be used
-  _unhide: function GroupItem__unhide(options) {
-    this._cancelFadeAwayUndoButtonTimer();
-    this.hidden = false;
-    this.$undoContainer.remove();
-    this.$undoContainer = null;
-    this.droppable(true);
-    this.setTrenches(this.bounds);
-
-    let self = this;
-
-    let finalize = function () {
-      self._children.forEach(function(child) {
-        iQ(child.container).show();
-      });
-
-      UI.setActive(self);
-      self._sendToSubscribers("groupShown");
-    };
-
-    let $container = iQ(this.container).show();
-
-    if (!options || !options.immediately) {
-      $container.animate({
-        "transform": "scale(1)",
-        "opacity": 1
-      }, {
-        duration: 170,
-        complete: finalize
-      });
-    } else {
-      $container.css({"transform": "none", opacity: 1});
-      finalize();
-    }
-
-    GroupItems.updateGroupCloseButtons();
-  },
-
-  // ----------
-  // Function: closeHidden
-  // Removes the group item, its children and its container.
-  closeHidden: function GroupItem_closeHidden() {
-    let self = this;
-
-    this._cancelFadeAwayUndoButtonTimer();
-
-    // When the last non-empty groupItem is closed and there are no
-    // pinned tabs then create a new group with a blank tab.
-    let remainingGroups = GroupItems.groupItems.filter(function (groupItem) {
-      return (groupItem != self && groupItem.getChildren().length);
-    });
-
-    let tab = null;
-
-    if (!gBrowser._numPinnedTabs && !remainingGroups.length) {
-      let emptyGroups = GroupItems.groupItems.filter(function (groupItem) {
-        return (groupItem != self && !groupItem.getChildren().length);
-      });
-      let group = (emptyGroups.length ? emptyGroups[0] : GroupItems.newGroup());
-      tab = group.newTab(null, {dontZoomIn: true});
-    }
-
-    let closed = this.destroy();
-
-    if (!tab)
-      return;
-
-    if (closed) {
-      // Let's make the new tab the selected tab.
-      UI.goToTab(tab);
-    } else {
-      // Remove the new tab and group, if this group is no longer closed.
-      tab._tabViewTabItem.parent.destroy({immediately: true});
-    }
-  },
-
-  // ----------
-  // Function: destroy
-  // Close all tabs linked to children (tabItems), removes all children and 
-  // close the groupItem.
-  //
-  // Parameters:
-  //   options - An object with optional settings for this call.
-  //
-  // Options:
-  //   immediately - (bool) if true, no animation will be used
-  //
-  // Returns true if the groupItem has been closed, or false otherwise. A group
-  // could not have been closed due to a tab with an onUnload handler (that
-  // waits for user interaction).
-  destroy: function GroupItem_destroy(options) {
-    let self = this;
-
-    // when "TabClose" event is fired, the browser tab is about to close and our 
-    // item "close" event is fired.  And then, the browser tab gets closed. 
-    // In other words, the group "close" event is fired before all browser
-    // tabs in the group are closed.  The below code would fire the group "close"
-    // event only after all browser tabs in that group are closed.
-    this._children.concat().forEach(function(child) {
-      child.removeSubscriber("close", self._onChildClose);
-
-      if (child.close(true)) {
-        self.remove(child, { dontArrange: true });
-      } else {
-        // child.removeSubscriber() must be called before child.close(), 
-        // therefore we call child.addSubscriber() if the tab is not removed.
-        child.addSubscriber("close", self._onChildClose);
-      }
-    });
-
-    if (this._children.length) {
-      if (this.hidden)
-        this.$undoContainer.fadeOut(function() { self._unhide() });
-
-      return false;
-    } else {
-      this.close(options);
-      return true;
-    }
-  },
-
-  // ----------
-  // Function: _fadeAwayUndoButton
-  // Fades away the undo button
-  _fadeAwayUndoButton: function GroupItem__fadeAwayUndoButton() {
-    let self = this;
-
-    if (this.$undoContainer) {
-      // if there is more than one group and other groups are not empty,
-      // fade away the undo button.
-      let shouldFadeAway = false;
-
-      if (GroupItems.groupItems.length > 1) {
-        shouldFadeAway = 
-          GroupItems.groupItems.some(function(groupItem) {
-            return (groupItem != self && groupItem.getChildren().length > 0);
-          });
-      }
-
-      if (shouldFadeAway) {
-        self.$undoContainer.animate({
-          color: "transparent",
-          opacity: 0
-        }, {
-          duration: this._fadeAwayUndoButtonDuration,
-          complete: function() { self.closeHidden(); }
-        });
-      }
-    }
-  },
-
-  // ----------
-  // Function: _createUndoButton
-  // Makes the affordance for undo a close group action
-  _createUndoButton: function GroupItem__createUndoButton() {
-    let self = this;
-    this.$undoContainer = iQ("<div/>")
-      .addClass("undo")
-      .attr("type", "button")
-      .attr("data-group-id", this.id)
-      .appendTo("body");
-    iQ("<span/>")
-      .text(tabviewString("groupItem.undoCloseGroup"))
-      .appendTo(this.$undoContainer);
-    let undoClose = iQ("<span/>")
-      .addClass("close")
-      .attr("title", tabviewString("groupItem.discardClosedGroup"))
-      .appendTo(this.$undoContainer);
-
-    this.$undoContainer.css({
-      left: this.bounds.left + this.bounds.width/2 - iQ(self.$undoContainer).width()/2,
-      top:  this.bounds.top + this.bounds.height/2 - iQ(self.$undoContainer).height()/2,
-      "transform": "scale(.1)",
-      opacity: 0
-    });
-    this.hidden = true;
-
-    // hide group item and show undo container.
-    setTimeout(function() {
-      self.$undoContainer.animate({
-        "transform": "scale(1)",
-        "opacity": 1
-      }, {
-        easing: "tabviewBounce",
-        duration: 170,
-        complete: function() {
-          self._sendToSubscribers("groupHidden");
-        }
-      });
-    }, 50);
-
-    // add click handlers
-    this.$undoContainer.click(function(e) {
-      // don't do anything if the close button is clicked.
-      if (e.target == undoClose[0])
-        return;
-
-      self.$undoContainer.fadeOut(function() { self._unhide(); });
-    });
-
-    undoClose.click(function() {
-      self.$undoContainer.fadeOut(function() { self.closeHidden(); });
-    });
-
-    this.setupFadeAwayUndoButtonTimer();
-    // Cancel the fadeaway if you move the mouse over the undo
-    // button, and restart the countdown once you move out of it.
-    this.$undoContainer.mouseover(function() { 
-      self._cancelFadeAwayUndoButtonTimer();
-    });
-    this.$undoContainer.mouseout(function() {
-      self.setupFadeAwayUndoButtonTimer();
-    });
-
-    GroupItems.updateGroupCloseButtons();
-  },
-
-  // ----------
-  // Sets up fade away undo button timeout. 
-  setupFadeAwayUndoButtonTimer: function GroupItem_setupFadeAwayUndoButtonTimer() {
-    let self = this;
-
-    if (!this._undoButtonTimeoutId) {
-      this._undoButtonTimeoutId = setTimeout(function() { 
-        self._fadeAwayUndoButton(); 
-      }, this.fadeAwayUndoButtonDelay);
-    }
-  },
-  
-  // ----------
-  // Cancels the fade away undo button timeout. 
-  _cancelFadeAwayUndoButtonTimer: function GroupItem__cancelFadeAwayUndoButtonTimer() {
-    clearTimeout(this._undoButtonTimeoutId);
-    this._undoButtonTimeoutId = null;
-  }, 
-
-  // ----------
-  // Function: add
-  // Adds an item to the groupItem.
-  // Parameters:
-  //
-  //   a - The item to add. Can be an <Item>, a DOM element or an iQ object.
-  //       The latter two must refer to the container of an <Item>.
-  //   options - An object with optional settings for this call.
-  //
-  // Options:
-  //
-  //   index - (int) if set, add this tab at this index
-  //   immediately - (bool) if true, no animation will be used
-  //   dontArrange - (bool) if true, will not trigger an arrange on the group
-  add: function GroupItem_add(a, options) {
-    try {
-      var item;
-      var $el;
-      if (a.isAnItem) {
-        item = a;
-        $el = iQ(a.container);
-      } else {
-        $el = iQ(a);
-        item = Items.item($el);
-      }
-
-      // safeguard to remove the item from its previous group
-      if (item.parent && item.parent !== this)
-        item.parent.remove(item);
-
-      item.removeTrenches();
-
-      if (!options)
-        options = {};
-
-      var self = this;
-
-      var wasAlreadyInThisGroupItem = false;
-      var oldIndex = this._children.indexOf(item);
-      if (oldIndex != -1) {
-        this._children.splice(oldIndex, 1);
-        wasAlreadyInThisGroupItem = true;
-      }
-
-      // Insert the tab into the right position.
-      var index = ("index" in options) ? options.index : this._children.length;
-      this._children.splice(index, 0, item);
-
-      item.setZ(this.getZ() + 1);
-
-      if (!wasAlreadyInThisGroupItem) {
-        item.droppable(false);
-        item.groupItemData = {};
-
-        item.addSubscriber("close", this._onChildClose);
-        item.setParent(this);
-        $el.attr("data-group-id", this.id);
-
-        if (typeof item.setResizable == 'function')
-          item.setResizable(false, options.immediately);
-
-        if (item == UI.getActiveTab() || !this._activeTab)
-          this.setActiveTab(item);
-
-        // if it matches the selected tab or no active tab and the browser
-        // tab is hidden, the active group item would be set.
-        if (item.tab.selected ||
-            (!GroupItems.getActiveGroupItem() && !item.tab.hidden))
-          UI.setActive(this);
-      }
-
-      if (!options.dontArrange)
-        this.arrange({animate: !options.immediately});
-
-      this._unfreezeItemSize({dontArrange: true});
-      this._sendToSubscribers("childAdded", { item: item });
-
-      UI.setReorderTabsOnHide(this);
-    } catch(e) {
-      Utils.log('GroupItem.add error', e);
-    }
-  },
-
-  // ----------
-  // Function: _onChildClose
-  // Handles "close" events from the group's children.
-  //
-  // Parameters:
-  //   tabItem - The tabItem that is closed.
-  _onChildClose: function GroupItem__onChildClose(tabItem) {
-    let count = this._children.length;
-    let dontArrange = tabItem.closedManually &&
-                      (this.expanded || !this.shouldStack(count));
-    let dontClose = !tabItem.closedManually && gBrowser._numPinnedTabs > 0;
-    this.remove(tabItem, {dontArrange: dontArrange, dontClose: dontClose});
-
-    if (dontArrange)
-      this._freezeItemSize(count);
-
-    if (this._children.length > 0 && this._activeTab && tabItem.closedManually)
-      UI.setActive(this);
-  },
-
-  // ----------
-  // Function: remove
-  // Removes an item from the groupItem.
-  // Parameters:
-  //
-  //   a - The item to remove. Can be an <Item>, a DOM element or an iQ object.
-  //       The latter two must refer to the container of an <Item>.
-  //   options - An optional object with settings for this call. See below.
-  //
-  // Possible options: 
-  //   dontArrange - don't rearrange the remaining items
-  //   dontClose - don't close the group even if it normally would
-  //   immediately - don't animate
-  remove: function GroupItem_remove(a, options) {
-    try {
-      let $el;
-      let item;
-
-      if (a.isAnItem) {
-        item = a;
-        $el = iQ(item.container);
-      } else {
-        $el = iQ(a);
-        item = Items.item($el);
-      }
-
-      if (!options)
-        options = {};
-
-      let index = this._children.indexOf(item);
-      if (index != -1)
-        this._children.splice(index, 1);
-
-      if (item == this._activeTab || !this._activeTab) {
-        if (this._children.length > 0)
-          this._activeTab = this._children[0];
-        else
-          this._activeTab = null;
-      }
-
-      $el[0].removeAttribute("data-group-id");
-      item.setParent(null);
-      item.removeClass("stacked");
-      item.isStacked = false;
-      item.setHidden(false);
-      item.removeClass("stack-trayed");
-      item.setRotation(0);
-
-      // Force tabItem resize if it's dragged out of a stacked groupItem.
-      // The tabItems's title will be visible and that's why we need to
-      // recalculate its height.
-      if (item.isDragging && this.isStacked())
-        item.setBounds(item.getBounds(), true, {force: true});
-
-      item.droppable(true);
-      item.removeSubscriber("close", this._onChildClose);
-
-      if (typeof item.setResizable == 'function')
-        item.setResizable(true, options.immediately);
-
-      // if a blank tab is selected while restoring a tab the blank tab gets
-      // removed. we need to keep the group alive for the restored tab.
-      if (item.isRemovedAfterRestore)
-        options.dontClose = true;
-
-      let closed = options.dontClose ? false : this.closeIfEmpty();
-      if (closed ||
-          (this._children.length == 0 && !gBrowser._numPinnedTabs &&
-           !item.isDragging)) {
-        this._makeLastActiveGroupItemActive();
-      } else if (!options.dontArrange) {
-        this.arrange({animate: !options.immediately});
-        this._unfreezeItemSize({dontArrange: true});
-      }
-
-      this._sendToSubscribers("childRemoved", { item: item });
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
-  // Function: removeAll
-  // Removes all of the groupItem's children.
-  // The optional "options" param is passed to each remove call. 
-  removeAll: function GroupItem_removeAll(options) {
-    let self = this;
-    let newOptions = {dontArrange: true};
-    if (options)
-      Utils.extend(newOptions, options);
-      
-    let toRemove = this._children.concat();
-    toRemove.forEach(function(child) {
-      self.remove(child, newOptions);
-    });
-  },
-
-  // ----------
-  // Adds the given xul:tab as an app tab in this group's apptab tray
-  //
-  // Parameters:
-  //   xulTab - the xul:tab.
-  //   options - change how the app tab is added.
-  //
-  // Options:
-  //   position - the position of the app tab should be added to.
-  //   dontAdjustTray - (boolean) if true, do not adjust the tray.
-  addAppTab: function GroupItem_addAppTab(xulTab, options) {
-    GroupItems.getAppTabFavIconUrl(xulTab, function(iconUrl) {
-      // The tab might have been removed or unpinned while waiting.
-      if (!Utils.isValidXULTab(xulTab) || !xulTab.pinned)
-        return;
-
-      let self = this;
-      let $appTab = iQ("<img>")
-        .addClass("appTabIcon")
-        .attr("src", iconUrl)
-        .data("xulTab", xulTab)
-        .mousedown(function GroupItem_addAppTab_onAppTabMousedown(event) {
-          // stop mousedown propagation to disable group dragging on app tabs
-          event.stopPropagation();
-        })
-        .click(function GroupItem_addAppTab_onAppTabClick(event) {
-          if (!Utils.isLeftClick(event))
-            return;
-
-          UI.setActive(self, { dontSetActiveTabInGroup: true });
-          UI.goToTab(iQ(this).data("xulTab"));
-        });
-
-      if (options && "position" in options) {
-        let children = this.$appTabTray[0].childNodes;
-
-        if (options.position >= children.length)
-          $appTab.appendTo(this.$appTabTray);
-        else
-          this.$appTabTray[0].insertBefore($appTab[0], children[options.position]);
-      } else {
-        $appTab.appendTo(this.$appTabTray);
-      }
-      if (!options || !options.dontAdjustTray)
-        this.adjustAppTabTray(true);
-
-      this._sendToSubscribers("appTabIconAdded", { item: $appTab });
-    }.bind(this));
-  },
-
-  // ----------
-  // Removes the given xul:tab as an app tab in this group's apptab tray
-  removeAppTab: function GroupItem_removeAppTab(xulTab) {
-    // remove the icon
-    iQ(".appTabIcon", this.$appTabTray).each(function(icon) {
-      let $icon = iQ(icon);
-      if ($icon.data("xulTab") != xulTab)
-        return true;
-        
-      $icon.remove();
-      return false;
-    });
-    
-    // adjust the tray
-    this.adjustAppTabTray(true);
-  },
-
-  // ----------
-  // Arranges the given xul:tab as an app tab in the group's apptab tray
-  arrangeAppTab: function GroupItem_arrangeAppTab(xulTab) {
-    let self = this;
-
-    let elements = iQ(".appTabIcon", this.$appTabTray);
-    let length = elements.length;
-
-    elements.each(function(icon) {
-      let $icon = iQ(icon);
-      if ($icon.data("xulTab") != xulTab)
-        return true;
-
-      let targetIndex = xulTab._tPos;
-
-      $icon.remove({ preserveEventHandlers: true });
-      if (targetIndex < (length - 1))
-        self.$appTabTray[0].insertBefore(
-          icon,
-          iQ(".appTabIcon:nth-child(" + (targetIndex + 1) + ")", self.$appTabTray)[0]);
-      else
-        $icon.appendTo(self.$appTabTray);
-      return false;
-    });
-  },
-
-  // ----------
-  // Function: hideExpandControl
-  // Hide the control which expands a stacked groupItem into a quick-look view.
-  hideExpandControl: function GroupItem_hideExpandControl() {
-    this.$expander.hide();
-  },
-
-  // ----------
-  // Function: showExpandControl
-  // Show the control which expands a stacked groupItem into a quick-look view.
-  showExpandControl: function GroupItem_showExpandControl() {
-    let parentBB = this.getBounds();
-    let childBB = this.getChild(0).getBounds();
-    this.$expander
-        .show()
-        .css({
-          left: parentBB.width/2 - this.$expander.width()/2
-        });
-  },
-
-  // ----------
-  // Function: shouldStack
-  // Returns true if the groupItem, given "count", should stack (instead of 
-  // grid).
-  shouldStack: function GroupItem_shouldStack(count) {
-    let bb = this.getContentBounds();
-    let options = {
-      return: 'widthAndColumns',
-      count: count || this._children.length,
-      hideTitle: false
-    };
-    let arrObj = Items.arrange(this._children, bb, options);
-
-    let shouldStack = arrObj.childWidth < TabItems.minTabWidth * 1.35;
-    this._columns = shouldStack ? null : arrObj.columns;
-
-    return shouldStack;
-  },
-
-  // ----------
-  // Function: _freezeItemSize
-  // Freezes current item size (when removing a child).
-  //
-  // Parameters:
-  //   itemCount - the number of children before the last one was removed
-  _freezeItemSize: function GroupItem__freezeItemSize(itemCount) {
-    let data = this._frozenItemSizeData;
-
-    if (!data.lastItemCount) {
-      let self = this;
-      data.lastItemCount = itemCount;
-
-      // unfreeze item size when tabview is hidden
-      data.onTabViewHidden = () => self._unfreezeItemSize();
-      window.addEventListener('tabviewhidden', data.onTabViewHidden, false);
-
-      // we don't need to observe mouse movement when expanded because the
-      // tray is closed when we leave it and collapse causes unfreezing
-      if (!self.expanded) {
-        // unfreeze item size when cursor is moved out of group bounds
-        data.onMouseMove = function (e) {
-          let cursor = new Point(e.pageX, e.pageY);
-          if (!self.bounds.contains(cursor))
-            self._unfreezeItemSize();
-        }
-        iQ(window).mousemove(data.onMouseMove);
-      }
-    }
-
-    this.arrange({animate: true, count: data.lastItemCount});
-  },
-
-  // ----------
-  // Function: _unfreezeItemSize
-  // Unfreezes and updates item size.
-  //
-  // Parameters:
-  //   options - various options (see below)
-  //
-  // Possible options:
-  //   dontArrange - do not arrange items when unfreezing
-  _unfreezeItemSize: function GroupItem__unfreezeItemSize(options) {
-    let data = this._frozenItemSizeData;
-    if (!data.lastItemCount)
-      return;
-
-    if (!options || !options.dontArrange)
-      this.arrange({animate: true});
-
-    // unbind event listeners
-    window.removeEventListener('tabviewhidden', data.onTabViewHidden, false);
-    if (data.onMouseMove)
-      iQ(window).unbind('mousemove', data.onMouseMove);
-
-    // reset freeze status
-    this._frozenItemSizeData = {};
-  },
-
-  // ----------
-  // Function: arrange
-  // Lays out all of the children.
-  //
-  // Parameters:
-  //   options - passed to <Items.arrange> or <_stackArrange>, except those below
-  //
-  // Options:
-  //   addTab - (boolean) if true, we add one to the child count
-  //   oldDropIndex - if set, we will only set any bounds if the dropIndex has
-  //                  changed
-  //   dropPos - (<Point>) a position where a tab is currently positioned, above
-  //             this group.
-  //   animate - (boolean) if true, movement of children will be animated.
-  //
-  // Returns:
-  //   dropIndex - an index value for where an item would be dropped, if 
-  //               options.dropPos is given.
-  arrange: function GroupItem_arrange(options) {
-    if (!options)
-      options = {};
-
-    let childrenToArrange = [];
-    this._children.forEach(function(child) {
-      if (child.isDragging)
-        options.addTab = true;
-      else
-        childrenToArrange.push(child);
-    });
-
-    if (GroupItems._arrangePaused) {
-      GroupItems.pushArrange(this, options);
-      return false;
-    }
-
-    let shouldStack = this.shouldStack(childrenToArrange.length + (options.addTab ? 1 : 0));
-    let shouldStackArrange = (shouldStack && !this.expanded);
-    let box;
-
-    // if we should stack and we're not expanded
-    if (shouldStackArrange) {
-      this.showExpandControl();
-      box = this.getContentBounds({stacked: true});
-      this._stackArrange(childrenToArrange, box, options);
-      return false;
-    } else {
-      this.hideExpandControl();
-      box = this.getContentBounds();
-      // a dropIndex is returned
-      return this._gridArrange(childrenToArrange, box, options);
-    }
-  },
-
-  // ----------
-  // Function: _stackArrange
-  // Arranges the children in a stack.
-  //
-  // Parameters:
-  //   childrenToArrange - array of <TabItem> children
-  //   bb - <Rect> to arrange within
-  //   options - see below
-  //
-  // Possible "options" properties:
-  //   animate - whether to animate; default: true.
-  _stackArrange: function GroupItem__stackArrange(childrenToArrange, bb, options) {
-    if (!options)
-      options = {};
-    var animate = "animate" in options ? options.animate : true;
-
-    var count = childrenToArrange.length;
-    if (!count)
-      return;
-
-    let itemAspect = TabItems.tabHeight / TabItems.tabWidth;
-    let zIndex = this.getZ() + count + 1;
-    let maxRotation = 35; // degress
-    let scale = 0.7;
-    let newTabsPad = 10;
-    let bbAspect = bb.height / bb.width;
-    let numInPile = 6;
-    let angleDelta = 3.5; // degrees
-
-    // compute size of the entire stack, modulo rotation.
-    let size;
-    if (bbAspect > itemAspect) { // Tall, thin groupItem
-      size = TabItems.calcValidSize(new Point(bb.width * scale, -1),
-        {hideTitle:true});
-     } else { // Short, wide groupItem
-      size = TabItems.calcValidSize(new Point(-1, bb.height * scale),
-        {hideTitle:true});
-     }
-
-    // x is the left margin that the stack will have, within the content area (bb)
-    // y is the vertical margin
-    var x = (bb.width - size.x) / 2;
-    var y = Math.min(size.x, (bb.height - size.y) / 2);
-    var box = new Rect(bb.left + x, bb.top + y, size.x, size.y);
-
-    var self = this;
-    var children = [];
-
-    // ensure topChild is the first item in childrenToArrange
-    let topChild = this.getTopChild();
-    let topChildPos = childrenToArrange.indexOf(topChild);
-    if (topChildPos > 0) {
-      childrenToArrange.splice(topChildPos, 1);
-      childrenToArrange.unshift(topChild);
-    }
-
-    childrenToArrange.forEach(function GroupItem__stackArrange_order(child) {
-      // Children are still considered stacked even if they're hidden later.
-      child.addClass("stacked");
-      child.isStacked = true;
-      if (numInPile-- > 0) {
-        children.push(child);
-      } else {
-        child.setHidden(true);
-      }
-    });
-
-    self._isStacked = true;
-
-    let angleAccum = 0;
-    children.forEach(function GroupItem__stackArrange_apply(child, index) {
-      child.setZ(zIndex);
-      zIndex--;
-
-      // Force a recalculation of height because we've changed how the title
-      // is shown.
-      child.setBounds(box, !animate || child.getHidden(), {force:true});
-      child.setRotation((UI.rtl ? -1 : 1) * angleAccum);
-      child.setHidden(false);
-      angleAccum += angleDelta;
-    });
-  },
-  
-  // ----------
-  // Function: _gridArrange
-  // Arranges the children into a grid.
-  //
-  // Parameters:
-  //   childrenToArrange - array of <TabItem> children
-  //   box - <Rect> to arrange within
-  //   options - see below
-  //
-  // Possible "options" properties:
-  //   animate - whether to animate; default: true.
-  //   z - (int) a z-index to assign the children
-  //   columns - the number of columns to use in the layout, if known in advance
-  //
-  // Returns:
-  //   dropIndex - (int) the index at which a dragged item (if there is one) should be added
-  //               if it is dropped. Otherwise (boolean) false.
-  _gridArrange: function GroupItem__gridArrange(childrenToArrange, box, options) {
-    let arrangeOptions;
-    if (this.expanded) {
-      // if we're expanded, we actually want to use the expanded tray's bounds.
-      box = new Rect(this.expanded.bounds);
-      box.inset(8, 8);
-      arrangeOptions = Utils.extend({}, options, {z: 99999});
-    } else {
-      this._isStacked = false;
-      arrangeOptions = Utils.extend({}, options, {
-        columns: this._columns
-      });
-
-      childrenToArrange.forEach(function(child) {
-        child.removeClass("stacked");
-        child.isStacked = false;
-        child.setHidden(false);
-      });
-    }
-  
-    if (!childrenToArrange.length)
-      return false;
-
-    // Items.arrange will determine where/how the child items should be
-    // placed, but will *not* actually move them for us. This is our job.
-    let result = Items.arrange(childrenToArrange, box, arrangeOptions);
-    let {dropIndex, rects, columns} = result;
-    if ("oldDropIndex" in options && options.oldDropIndex === dropIndex)
-      return dropIndex;
-
-    this._columns = columns;
-    let index = 0;
-    let self = this;
-    childrenToArrange.forEach(function GroupItem_arrange_children_each(child, i) {
-      // If dropIndex spacing is active and this is a child after index,
-      // bump it up one so we actually use the correct rect
-      // (and skip one for the dropPos)
-      if (self._dropSpaceActive && index === dropIndex)
-        index++;
-      child.setBounds(rects[index], !options.animate);
-      child.setRotation(0);
-      if (arrangeOptions.z)
-        child.setZ(arrangeOptions.z);
-      index++;
-    });
-
-    return dropIndex;
-  },
-
-  expand: function GroupItem_expand() {
-    var self = this;
-    // ___ we're stacked, and command is held down so expand
-    UI.setActive(this.getTopChild());
-    
-    var startBounds = this.getChild(0).getBounds();
-    var $tray = iQ("<div>").css({
-      top: startBounds.top,
-      left: startBounds.left,
-      width: startBounds.width,
-      height: startBounds.height,
-      position: "absolute",
-      zIndex: 99998
-    }).appendTo("body");
-    $tray[0].id = "expandedTray";
-
-    var w = 180;
-    var h = w * (TabItems.tabHeight / TabItems.tabWidth) * 1.1;
-    var padding = 20;
-    var col = Math.ceil(Math.sqrt(this._children.length));
-    var row = Math.ceil(this._children.length/col);
-
-    var overlayWidth = Math.min(window.innerWidth - (padding * 2), w*col + padding*(col+1));
-    var overlayHeight = Math.min(window.innerHeight - (padding * 2), h*row + padding*(row+1));
-
-    var pos = {left: startBounds.left, top: startBounds.top};
-    pos.left -= overlayWidth / 3;
-    pos.top  -= overlayHeight / 3;
-
-    if (pos.top < 0)
-      pos.top = 20;
-    if (pos.left < 0)
-      pos.left = 20;
-    if (pos.top + overlayHeight > window.innerHeight)
-      pos.top = window.innerHeight - overlayHeight - 20;
-    if (pos.left + overlayWidth > window.innerWidth)
-      pos.left = window.innerWidth - overlayWidth - 20;
-
-    $tray
-      .animate({
-        width:  overlayWidth,
-        height: overlayHeight,
-        top: pos.top,
-        left: pos.left
-      }, {
-        duration: 200,
-        easing: "tabviewBounce",
-        complete: function GroupItem_expand_animate_complete() {
-          self._sendToSubscribers("expanded");
-        }
-      })
-      .addClass("overlay");
-
-    this._children.forEach(function(child) {
-      child.addClass("stack-trayed");
-      child.setHidden(false);
-    });
-
-    var $shield = iQ('<div>')
-      .addClass('shield')
-      .css({
-        zIndex: 99997
-      })
-      .appendTo('body')
-      .click(function() { // just in case
-        self.collapse();
-      });
-
-    // There is a race-condition here. If there is
-    // a mouse-move while the shield is coming up
-    // it will collapse, which we don't want. Thus,
-    // we wait a little bit before adding this event
-    // handler.
-    setTimeout(function() {
-      $shield.mouseover(function() {
-        self.collapse();
-      });
-    }, 200);
-
-    this.expanded = {
-      $tray: $tray,
-      $shield: $shield,
-      bounds: new Rect(pos.left, pos.top, overlayWidth, overlayHeight)
-    };
-
-    this.arrange();
-  },
-
-  // ----------
-  // Function: collapse
-  // Collapses the groupItem from the expanded "tray" mode.
-  collapse: function GroupItem_collapse() {
-    if (this.expanded) {
-      var z = this.getZ();
-      var box = this.getBounds();
-      let self = this;
-      this.expanded.$tray
-        .css({
-          zIndex: z + 1
-        })
-        .animate({
-          width:  box.width,
-          height: box.height,
-          top: box.top,
-          left: box.left,
-          opacity: 0
-        }, {
-          duration: 350,
-          easing: "tabviewBounce",
-          complete: function GroupItem_collapse_animate_complete() {
-            iQ(this).remove();
-            self._sendToSubscribers("collapsed");
-          }
-        });
-
-      this.expanded.$shield.remove();
-      this.expanded = null;
-
-      this._children.forEach(function(child) {
-        child.removeClass("stack-trayed");
-      });
-
-      this.arrange({z: z + 2});
-      this._unfreezeItemSize({dontArrange: true});
-    }
-  },
-
-  // ----------
-  // Function: _addHandlers
-  // Helper routine for the constructor; adds various event handlers to the container.
-  _addHandlers: function GroupItem__addHandlers(container) {
-    let self = this;
-    let lastMouseDownTarget;
-
-    container.mousedown(function(e) {
-      let target = e.target;
-      // only set the last mouse down target if it is a left click, not on the
-      // close button, not on the expand button, not on the title bar and its
-      // elements
-      if (Utils.isLeftClick(e) &&
-          self.$closeButton[0] != target &&
-          self.$titlebar[0] != target &&
-          self.$expander[0] != target &&
-          !self.$titlebar.contains(target) &&
-          !self.$appTabTray.contains(target)) {
-        lastMouseDownTarget = target;
-      } else {
-        lastMouseDownTarget = null;
-      }
-    });
-    container.mouseup(function(e) {
-      let same = (e.target == lastMouseDownTarget);
-      lastMouseDownTarget = null;
-
-      if (same && !self.isDragging) {
-        if (gBrowser.selectedTab.pinned &&
-            UI.getActiveTab() != self.getActiveTab() &&
-            self.getChildren().length > 0) {
-          UI.setActive(self, { dontSetActiveTabInGroup: true });
-          UI.goToTab(gBrowser.selectedTab);
-        } else {
-          let tabItem = self.getTopChild();
-          if (tabItem)
-            tabItem.zoomIn();
-          else
-            self.newTab();
-        }
-      }
-    });
-
-    let dropIndex = false;
-    let dropSpaceTimer = null;
-
-    // When the _dropSpaceActive flag is turned on on a group, and a tab is
-    // dragged on top, a space will open up.
-    this._dropSpaceActive = false;
-
-    this.dropOptions.over = function GroupItem_dropOptions_over(event) {
-      iQ(this.container).addClass("acceptsDrop");
-    };
-    this.dropOptions.move = function GroupItem_dropOptions_move(event) {
-      let oldDropIndex = dropIndex;
-      let dropPos = drag.info.item.getBounds().center();
-      let options = {dropPos: dropPos,
-                     addTab: self._dropSpaceActive && drag.info.item.parent != self,
-                     oldDropIndex: oldDropIndex};
-      let newDropIndex = self.arrange(options);
-      // If this is a new drop index, start a timer!
-      if (newDropIndex !== oldDropIndex) {
-        dropIndex = newDropIndex;
-        if (this._dropSpaceActive)
-          return;
-          
-        if (dropSpaceTimer) {
-          clearTimeout(dropSpaceTimer);
-          dropSpaceTimer = null;
-        }
-
-        dropSpaceTimer = setTimeout(function GroupItem_arrange_evaluateDropSpace() {
-          // Note that dropIndex's scope is GroupItem__addHandlers, but
-          // newDropIndex's scope is GroupItem_dropOptions_move. Thus,
-          // dropIndex may change with other movement events before we come
-          // back and check this. If it's still the same dropIndex, activate
-          // drop space display!
-          if (dropIndex === newDropIndex) {
-            self._dropSpaceActive = true;
-            dropIndex = self.arrange({dropPos: dropPos,
-                                      addTab: drag.info.item.parent != self,
-                                      animate: true});
-          }
-          dropSpaceTimer = null;
-        }, 250);
-      }
-    };
-    this.dropOptions.drop = function GroupItem_dropOptions_drop(event) {
-      iQ(this.container).removeClass("acceptsDrop");
-      let options = {};
-      if (this._dropSpaceActive)
-        this._dropSpaceActive = false;
-
-      if (dropSpaceTimer) {
-        clearTimeout(dropSpaceTimer);
-        dropSpaceTimer = null;
-        // If we drop this item before the timed rearrange was executed,
-        // we won't have an accurate dropIndex value. Get that now.
-        let dropPos = drag.info.item.getBounds().center();
-        dropIndex = self.arrange({dropPos: dropPos,
-                                  addTab: drag.info.item.parent != self,
-                                  animate: true});
-      }
-
-      if (dropIndex !== false)
-        options = {index: dropIndex};
-      this.add(drag.info.$el, options);
-      UI.setActive(this);
-      dropIndex = false;
-    };
-    this.dropOptions.out = function GroupItem_dropOptions_out(event) {
-      dropIndex = false;
-      if (this._dropSpaceActive)
-        this._dropSpaceActive = false;
-
-      if (dropSpaceTimer) {
-        clearTimeout(dropSpaceTimer);
-        dropSpaceTimer = null;
-      }
-      self.arrange();
-      var groupItem = drag.info.item.parent;
-      if (groupItem)
-        groupItem.remove(drag.info.$el, {dontClose: true});
-      iQ(this.container).removeClass("acceptsDrop");
-    }
-
-    this.draggable();
-    this.droppable(true);
-
-    this.$expander.click(function() {
-      self.expand();
-    });
-  },
-
-  // ----------
-  // Function: setResizable
-  // Sets whether the groupItem is resizable and updates the UI accordingly.
-  setResizable: function GroupItem_setResizable(value, immediately) {
-    var self = this;
-
-    this.resizeOptions.minWidth = GroupItems.minGroupWidth;
-    this.resizeOptions.minHeight = GroupItems.minGroupHeight;
-
-    let start = this.resizeOptions.start;
-    this.resizeOptions.start = function (event) {
-      start.call(self, event);
-      self._unfreezeItemSize();
-    }
-
-    if (value) {
-      immediately ? this.$resizer.show() : this.$resizer.fadeIn();
-      this.resizable(true);
-    } else {
-      immediately ? this.$resizer.hide() : this.$resizer.fadeOut();
-      this.resizable(false);
-    }
-  },
-
-  // ----------
-  // Function: newTab
-  // Creates a new tab within this groupItem.
-  // Parameters:
-  //  url - the new tab should open this url as well
-  //  options - the options object
-  //    dontZoomIn - set to true to not zoom into the newly created tab
-  //    closedLastTab - boolean indicates the last tab has just been closed
-  newTab: function GroupItem_newTab(url, options) {
-    if (options && options.closedLastTab)
-      UI.closedLastTabInTabView = true;
-
-    UI.setActive(this, { dontSetActiveTabInGroup: true });
-
-    let dontZoomIn = !!(options && options.dontZoomIn);
-    return gBrowser.loadOneTab(url || gWindow.BROWSER_NEW_TAB_URL, { inBackground: dontZoomIn });
-  },
-
-  // ----------
-  // Function: reorderTabItemsBasedOnTabOrder
-  // Reorders the tabs in a groupItem based on the arrangment of the tabs
-  // shown in the tab bar. It does it by sorting the children
-  // of the groupItem by the positions of their respective tabs in the
-  // tab bar.
-  reorderTabItemsBasedOnTabOrder: function GroupItem_reorderTabItemsBasedOnTabOrder() {
-    this._children.sort((a,b) => a.tab._tPos - b.tab._tPos);
-
-    this.arrange({animate: false});
-    // this.arrange calls this.save for us
-  },
-
-  // Function: reorderTabsBasedOnTabItemOrder
-  // Reorders the tabs in the tab bar based on the arrangment of the tabs
-  // shown in the groupItem.
-  reorderTabsBasedOnTabItemOrder: function GroupItem_reorderTabsBasedOnTabItemOrder() {
-    let indices;
-    let tabs = this._children.map(tabItem => tabItem.tab);
-
-    tabs.forEach(function (tab, index) {
-      if (!indices)
-        indices = tabs.map(tab => tab._tPos);
-
-      let start = index ? indices[index - 1] + 1 : 0;
-      let end = index + 1 < indices.length ? indices[index + 1] - 1 : Infinity;
-      let targetRange = new Range(start, end);
-
-      if (!targetRange.contains(tab._tPos)) {
-        gBrowser.moveTabTo(tab, start);
-        indices = null;
-      }
-    });
-  },
-
-  // ----------
-  // Function: getTopChild
-  // Gets the <Item> that should be displayed on top when in stack mode.
-  getTopChild: function GroupItem_getTopChild() {
-    if (!this.getChildren().length) {
-      return null;
-    }
-
-    return this.getActiveTab() || this.getChild(0);
-  },
-
-  // ----------
-  // Function: getChild
-  // Returns the nth child tab or null if index is out of range.
-  //
-  // Parameters:
-  //  index - the index of the child tab to return, use negative
-  //          numbers to index from the end (-1 is the last child)
-  getChild: function GroupItem_getChild(index) {
-    if (index < 0)
-      index = this._children.length + index;
-    if (index >= this._children.length || index < 0)
-      return null;
-    return this._children[index];
-  },
-
-  // ----------
-  // Function: getChildren
-  // Returns all children.
-  getChildren: function GroupItem_getChildren() {
-    return this._children;
-  }
-});
-
-// ##########
-// Class: GroupItems
-// Singleton for managing all <GroupItem>s.
-var GroupItems = {
-  groupItems: [],
-  nextID: 1,
-  _inited: false,
-  _activeGroupItem: null,
-  _cleanupFunctions: [],
-  _arrangePaused: false,
-  _arrangesPending: [],
-  _removingHiddenGroups: false,
-  _delayedModUpdates: [],
-  _autoclosePaused: false,
-  minGroupHeight: 110,
-  minGroupWidth: 125,
-  _lastActiveList: null,
-
-  // ----------
-  // Function: toString
-  // Prints [GroupItems] for debug use
-  toString: function GroupItems_toString() {
-    return "[GroupItems count=" + this.groupItems.length + "]";
-  },
-
-  // ----------
-  // Function: init
-  init: function GroupItems_init() {
-    let self = this;
-
-    // setup attr modified handler, and prepare for its uninit
-    function handleAttrModified(event) {
-      self._handleAttrModified(event.target);
-    }
-
-    // make sure any closed tabs are removed from the delay update list
-    function handleClose(event) {
-      let idx = self._delayedModUpdates.indexOf(event.target);
-      if (idx != -1)
-        self._delayedModUpdates.splice(idx, 1);
-    }
-
-    this._lastActiveList = new MRUList();
-
-    AllTabs.register("attrModified", handleAttrModified);
-    AllTabs.register("close", handleClose);
-    this._cleanupFunctions.push(function() {
-      AllTabs.unregister("attrModified", handleAttrModified);
-      AllTabs.unregister("close", handleClose);
-    });
-  },
-
-  // ----------
-  // Function: uninit
-  uninit: function GroupItems_uninit() {
-    // call our cleanup functions
-    this._cleanupFunctions.forEach(function(func) {
-      func();
-    });
-
-    this._cleanupFunctions = [];
-
-    // additional clean up
-    this.groupItems = null;
-  },
-
-  // ----------
-  // Function: newGroup
-  // Creates a new empty group.
-  newGroup: function GroupItems_newGroup() {
-    let bounds = new Rect(20, 20, 250, 200);
-    return new GroupItem([], {bounds: bounds, immediately: true});
-  },
-
-  // ----------
-  // Function: pauseArrange
-  // Bypass arrange() calls and collect for resolution in
-  // resumeArrange()
-  pauseArrange: function GroupItems_pauseArrange() {
-    Utils.assert(this._arrangePaused == false, 
-      "pauseArrange has been called while already paused");
-    Utils.assert(this._arrangesPending.length == 0, 
-      "There are bypassed arrange() calls that haven't been resolved");
-    this._arrangePaused = true;
-  },
-
-  // ----------
-  // Function: pushArrange
-  // Push an arrange() call and its arguments onto an array
-  // to be resolved in resumeArrange()
-  pushArrange: function GroupItems_pushArrange(groupItem, options) {
-    Utils.assert(this._arrangePaused, 
-      "Ensure pushArrange() called while arrange()s aren't paused"); 
-    let i;
-    for (i = 0; i < this._arrangesPending.length; i++)
-      if (this._arrangesPending[i].groupItem === groupItem)
-        break;
-    let arrangeInfo = {
-      groupItem: groupItem,
-      options: options
-    };
-    if (i < this._arrangesPending.length)
-      this._arrangesPending[i] = arrangeInfo;
-    else
-      this._arrangesPending.push(arrangeInfo);
-  },
-
-  // ----------
-  // Function: resumeArrange
-  // Resolve bypassed and collected arrange() calls
-  resumeArrange: function GroupItems_resumeArrange() {
-    this._arrangePaused = false;
-    for (let i = 0; i < this._arrangesPending.length; i++) {
-      let g = this._arrangesPending[i];
-      g.groupItem.arrange(g.options);
-    }
-    this._arrangesPending = [];
-  },
-
-  // ----------
-  // Function: _handleAttrModified
-  // watch for icon changes on app tabs
-  _handleAttrModified: function GroupItems__handleAttrModified(xulTab) {
-    if (!UI.isTabViewVisible()) {
-      if (this._delayedModUpdates.indexOf(xulTab) == -1) {
-        this._delayedModUpdates.push(xulTab);
-      }
-    } else
-      this._updateAppTabIcons(xulTab); 
-  },
-
-  // ----------
-  // Function: flushTabUpdates
-  // Update apptab icons based on xulTabs which have been updated
-  // while the TabView hasn't been visible 
-  flushAppTabUpdates: function GroupItems_flushAppTabUpdates() {
-    let self = this;
-    this._delayedModUpdates.forEach(function(xulTab) {
-      self._updateAppTabIcons(xulTab);
-    });
-    this._delayedModUpdates = [];
-  },
-
-  // ----------
-  // Function: _updateAppTabIcons
-  // Update images of any apptab icons that point to passed in xultab 
-  _updateAppTabIcons: function GroupItems__updateAppTabIcons(xulTab) {
-    if (!xulTab.pinned)
-      return;
-
-    this.getAppTabFavIconUrl(xulTab, function(iconUrl) {
-      iQ(".appTabIcon").each(function GroupItems__updateAppTabIcons_forEach(icon) {
-         let $icon = iQ(icon);
-         if ($icon.data("xulTab") == xulTab && iconUrl != $icon.attr("src"))
-           $icon.attr("src", iconUrl);
-      });
-    });
-  },
-
-  // ----------
-  // Function: getAppTabFavIconUrl
-  // Gets the fav icon url for app tab.
-  getAppTabFavIconUrl: function GroupItems_getAppTabFavIconUrl(xulTab, callback) {
-    FavIcons.getFavIconUrlForTab(xulTab, function GroupItems_getAppTabFavIconUrl_getFavIconUrlForTab(iconUrl) {
-      callback(iconUrl || FavIcons.defaultFavicon);
-    });
-  },
-
-  // ----------
-  // Function: addAppTab
-  // Adds the given xul:tab to the app tab tray in all groups
-  addAppTab: function GroupItems_addAppTab(xulTab) {
-    this.groupItems.forEach(function(groupItem) {
-      groupItem.addAppTab(xulTab);
-    });
-    this.updateGroupCloseButtons();
-  },
-
-  // ----------
-  // Function: removeAppTab
-  // Removes the given xul:tab from the app tab tray in all groups
-  removeAppTab: function GroupItems_removeAppTab(xulTab) {
-    this.groupItems.forEach(function(groupItem) {
-      groupItem.removeAppTab(xulTab);
-    });
-    this.updateGroupCloseButtons();
-  },
-
-  // ----------
-  // Function: arrangeAppTab
-  // Arranges the given xul:tab as an app tab from app tab tray in all groups
-  arrangeAppTab: function GroupItems_arrangeAppTab(xulTab) {
-    this.groupItems.forEach(function(groupItem) {
-      groupItem.arrangeAppTab(xulTab);
-    });
-  },
-
-  // ----------
-  // Function: getNextID
-  // Returns the next unused groupItem ID.
-  getNextID: function GroupItems_getNextID() {
-    var result = this.nextID;
-    this.nextID++;
-    this._save();
-    return result;
-  },
-
-  // ----------
-  // Function: saveAll
-  // Saves GroupItems state, as well as the state of all of the groupItems.
-  saveAll: function GroupItems_saveAll() {
-    this._save();
-    this.groupItems.forEach(function(groupItem) {
-      groupItem.save();
-    });
-  },
-
-  // ----------
-  // Function: _save
-  // Saves GroupItems state.
-  _save: function GroupItems__save() {
-    if (!this._inited) // too soon to save now
-      return;
-
-    let activeGroupId = this._activeGroupItem ? this._activeGroupItem.id : null;
-    Storage.saveGroupItemsData(
-      gWindow,
-      { nextID: this.nextID, activeGroupId: activeGroupId,
-        totalNumber: this.groupItems.length });
-  },
-
-  // ----------
-  // Function: getBoundingBox
-  // Given an array of DOM elements, returns a <Rect> with (roughly) the union of their locations.
-  getBoundingBox: function GroupItems_getBoundingBox(els) {
-    var bounds = els.map(el => iQ(el).bounds());
-    var left   = Math.min.apply({}, bounds.map(b => b.left));
-    var top    = Math.min.apply({}, bounds.map(b => b.top));
-    var right  = Math.max.apply({}, bounds.map(b => b.right));
-    var bottom = Math.max.apply({}, bounds.map(b => b.bottom));
-
-    return new Rect(left, top, right-left, bottom-top);
-  },
-
-  // ----------
-  // Function: reconstitute
-  // Restores to stored state, creating groupItems as needed.
-  reconstitute: function GroupItems_reconstitute(groupItemsData, groupItemData) {
-    try {
-      let activeGroupId;
-
-      if (groupItemsData) {
-        if (groupItemsData.nextID)
-          this.nextID = Math.max(this.nextID, groupItemsData.nextID);
-        if (groupItemsData.activeGroupId)
-          activeGroupId = groupItemsData.activeGroupId;
-      }
-
-      if (groupItemData) {
-        var toClose = this.groupItems.concat();
-        for (var id in groupItemData) {
-          let data = groupItemData[id];
-          if (this.groupItemStorageSanity(data)) {
-            let groupItem = this.groupItem(data.id); 
-            if (groupItem && !groupItem.hidden) {
-              groupItem.userSize = data.userSize;
-              groupItem.setTitle(data.title);
-              groupItem.setBounds(data.bounds, true);
-              
-              let index = toClose.indexOf(groupItem);
-              if (index != -1)
-                toClose.splice(index, 1);
-            } else {
-              var options = {
-                dontPush: true,
-                immediately: true
-              };
-  
-              new GroupItem([], Utils.extend({}, data, options));
-            }
-          }
-        }
-
-        toClose.forEach(function(groupItem) {
-          // all tabs still existing in closed groups will be moved to new
-          // groups. prepare them to be reconnected later.
-          groupItem.getChildren().forEach(function (tabItem) {
-            if (tabItem.parent.hidden)
-              iQ(tabItem.container).show();
-
-            tabItem._reconnected = false;
-
-            // sanity check the tab's groupID
-            let tabData = Storage.getTabData(tabItem.tab);
-
-            if (tabData) {
-              let parentGroup = GroupItems.groupItem(tabData.groupID);
-
-              // the tab's group id could be invalid or point to a non-existing
-              // group. correct it by assigning the active group id or the first
-              // group of the just restored session.
-              if (!parentGroup || -1 < toClose.indexOf(parentGroup)) {
-                tabData.groupID = activeGroupId || Object.keys(groupItemData)[0];
-                Storage.saveTab(tabItem.tab, tabData);
-              }
-            }
-          });
-
-          // this closes the group but not its children
-          groupItem.close({immediately: true});
-        });
-      }
-
-      // set active group item
-      if (activeGroupId) {
-        let activeGroupItem = this.groupItem(activeGroupId);
-        if (activeGroupItem)
-          UI.setActive(activeGroupItem);
-      }
-
-      this._inited = true;
-      this._save(); // for nextID
-    } catch(e) {
-      Utils.log("error in recons: "+e);
-    }
-  },
-
-  // ----------
-  // Function: load
-  // Loads the storage data for groups. 
-  // Returns true if there was global group data.
-  load: function GroupItems_load() {
-    let groupItemsData = Storage.readGroupItemsData(gWindow);
-    let groupItemData = Storage.readGroupItemData(gWindow);
-    this.reconstitute(groupItemsData, groupItemData);
-    
-    return (groupItemsData && !Utils.isEmptyObject(groupItemsData));
-  },
-
-  // ----------
-  // Function: groupItemStorageSanity
-  // Given persistent storage data for a groupItem, returns true if it appears to not be damaged.
-  groupItemStorageSanity: function GroupItems_groupItemStorageSanity(groupItemData) {
-    let sane = true;
-    if (!groupItemData.bounds || !Utils.isRect(groupItemData.bounds)) {
-      Utils.log('GroupItems.groupItemStorageSanity: bad bounds', groupItemData.bounds);
-      sane = false;
-    } else if ((groupItemData.userSize && 
-               !Utils.isPoint(groupItemData.userSize)) ||
-               !groupItemData.id) {
-      sane = false;
-    }
-
-    return sane;
-  },
-
-  // ----------
-  // Function: register
-  // Adds the given <GroupItem> to the list of groupItems we're tracking.
-  register: function GroupItems_register(groupItem) {
-    Utils.assert(groupItem, 'groupItem');
-    Utils.assert(this.groupItems.indexOf(groupItem) == -1, 'only register once per groupItem');
-    this.groupItems.push(groupItem);
-    UI.updateTabButton();
-  },
-
-  // ----------
-  // Function: unregister
-  // Removes the given <GroupItem> from the list of groupItems we're tracking.
-  unregister: function GroupItems_unregister(groupItem) {
-    var index = this.groupItems.indexOf(groupItem);
-    if (index != -1)
-      this.groupItems.splice(index, 1);
-
-    if (groupItem == this._activeGroupItem)
-      this._activeGroupItem = null;
-
-    this._arrangesPending = this._arrangesPending.filter(function (pending) {
-      return groupItem != pending.groupItem;
-    });
-
-    this._lastActiveList.remove(groupItem);
-    UI.updateTabButton();
-  },
-
-  // ----------
-  // Function: groupItem
-  // Given some sort of identifier, returns the appropriate groupItem.
-  // Currently only supports groupItem ids.
-  groupItem: function GroupItems_groupItem(a) {
-    if (!this.groupItems) {
-      // uninit has been called
-      return null;
-    }
-    var result = null;
-    this.groupItems.forEach(function(candidate) {
-      if (candidate.id == a)
-        result = candidate;
-    });
-
-    return result;
-  },
-
-  // ----------
-  // Function: removeAll
-  // Removes all tabs from all groupItems (which automatically closes all unnamed groupItems).
-  removeAll: function GroupItems_removeAll() {
-    var toRemove = this.groupItems.concat();
-    toRemove.forEach(function(groupItem) {
-      groupItem.removeAll();
-    });
-  },
-
-  // ----------
-  // Function: newTab
-  // Given a <TabItem>, files it in the appropriate groupItem.
-  newTab: function GroupItems_newTab(tabItem, options) {
-    let activeGroupItem = this.getActiveGroupItem();
-
-    // 1. Active group
-    // 2. First visible non-app tab (that's not the tab in question)
-    // 3. First group
-    // 4. At this point there should be no groups or tabs (except for app tabs and the
-    // tab in question): make a new group
-
-    if (activeGroupItem && !activeGroupItem.hidden) {
-      activeGroupItem.add(tabItem, options);
-      return;
-    }
-
-    let targetGroupItem;
-    // find first non-app visible tab belongs a group, and add the new tabItem
-    // to that group
-    gBrowser.visibleTabs.some(function(tab) {
-      if (!tab.pinned && tab != tabItem.tab) {
-        if (tab._tabViewTabItem && tab._tabViewTabItem.parent &&
-            !tab._tabViewTabItem.parent.hidden) {
-          targetGroupItem = tab._tabViewTabItem.parent;
-        }
-        return true;
-      }
-      return false;
-    });
-
-    let visibleGroupItems;
-    if (targetGroupItem) {
-      // add the new tabItem to the first group item
-      targetGroupItem.add(tabItem);
-      UI.setActive(targetGroupItem);
-      return;
-    } else {
-      // find the first visible group item
-      visibleGroupItems = this.groupItems.filter(function(groupItem) {
-        return (!groupItem.hidden);
-      });
-      if (visibleGroupItems.length > 0) {
-        visibleGroupItems[0].add(tabItem);
-        UI.setActive(visibleGroupItems[0]);
-        return;
-      }
-    }
-
-    // create new group for the new tabItem
-    tabItem.setPosition(60, 60, true);
-    let newGroupItemBounds = tabItem.getBounds();
-
-    newGroupItemBounds.inset(-40,-40);
-    let newGroupItem = new GroupItem([tabItem], { bounds: newGroupItemBounds });
-    newGroupItem.snap();
-    UI.setActive(newGroupItem);
-  },
-
-  // ----------
-  // Function: getActiveGroupItem
-  // Returns the active groupItem. Active means its tabs are
-  // shown in the tab bar when not in the TabView interface.
-  getActiveGroupItem: function GroupItems_getActiveGroupItem() {
-    return this._activeGroupItem;
-  },
-
-  // ----------
-  // Function: setActiveGroupItem
-  // Sets the active groupItem, thereby showing only the relevant tabs and
-  // setting the groupItem which will receive new tabs.
-  //
-  // Paramaters:
-  //  groupItem - the active <GroupItem>
-  setActiveGroupItem: function GroupItems_setActiveGroupItem(groupItem) {
-    Utils.assert(groupItem, "groupItem must be given");
-
-    if (this._activeGroupItem)
-      iQ(this._activeGroupItem.container).removeClass('activeGroupItem');
-
-    iQ(groupItem.container).addClass('activeGroupItem');
-
-    this._lastActiveList.update(groupItem);
-    this._activeGroupItem = groupItem;
-    this._save();
-  },
-
-  // ----------
-  // Function: getLastActiveGroupItem
-  // Gets last active group item.
-  // Returns the <groupItem>. If nothing is found, return null.
-  getLastActiveGroupItem: function GroupItem_getLastActiveGroupItem() {
-    return this._lastActiveList.peek(function(groupItem) {
-      return (groupItem && !groupItem.hidden && groupItem.getChildren().length > 0)
-    });
-  },
-
-  // ----------
-  // Function: _updateTabBar
-  // Hides and shows tabs in the tab bar based on the active groupItem
-  _updateTabBar: function GroupItems__updateTabBar() {
-    if (!window.UI)
-      return; // called too soon
-
-    Utils.assert(this._activeGroupItem, "There must be something to show in the tab bar!");
-
-    let tabItems = this._activeGroupItem._children;
-    gBrowser.showOnlyTheseTabs(tabItems.map(item => item.tab));
-  },
-
-  // ----------
-  // Function: updateActiveGroupItemAndTabBar
-  // Sets active TabItem and GroupItem, and updates tab bar appropriately.
-  // Parameters:
-  // tabItem - the tab item
-  // options - is passed to UI.setActive() directly
-  updateActiveGroupItemAndTabBar: 
-    function GroupItems_updateActiveGroupItemAndTabBar(tabItem, options) {
-    Utils.assertThrow(tabItem && tabItem.isATabItem, "tabItem must be a TabItem");
-
-    UI.setActive(tabItem, options);
-    this._updateTabBar();
-  },
-
-  // ----------
-  // Function: getNextGroupItemTab
-  // Paramaters:
-  //  reverse - the boolean indicates the direction to look for the next groupItem.
-  // Returns the <tabItem>. If nothing is found, return null.
-  getNextGroupItemTab: function GroupItems_getNextGroupItemTab(reverse) {
-    var groupItems = Utils.copy(GroupItems.groupItems);
-    var activeGroupItem = GroupItems.getActiveGroupItem();
-    var tabItem = null;
-
-    if (reverse)
-      groupItems = groupItems.reverse();
-
-    if (!activeGroupItem) {
-      if (groupItems.length > 0) {
-        groupItems.some(function(groupItem) {
-          if (!groupItem.hidden) {
-            // restore the last active tab in the group
-            let activeTab = groupItem.getActiveTab();
-            if (activeTab) {
-              tabItem = activeTab;
-              return true;
-            }
-            // if no tab is active, use the first one
-            var child = groupItem.getChild(0);
-            if (child) {
-              tabItem = child;
-              return true;
-            }
-          }
-          return false;
-        });
-      }
-    } else {
-      var currentIndex;
-      groupItems.some(function(groupItem, index) {
-        if (!groupItem.hidden && groupItem == activeGroupItem) {
-          currentIndex = index;
-          return true;
-        }
-        return false;
-      });
-      var firstGroupItems = groupItems.slice(currentIndex + 1);
-      firstGroupItems.some(function(groupItem) {
-        if (!groupItem.hidden) {
-          // restore the last active tab in the group
-          let activeTab = groupItem.getActiveTab();
-          if (activeTab) {
-            tabItem = activeTab;
-            return true;
-          }
-          // if no tab is active, use the first one
-          var child = groupItem.getChild(0);
-          if (child) {
-            tabItem = child;
-            return true;
-          }
-        }
-        return false;
-      });
-      if (!tabItem) {
-        var secondGroupItems = groupItems.slice(0, currentIndex);
-        secondGroupItems.some(function(groupItem) {
-          if (!groupItem.hidden) {
-            // restore the last active tab in the group
-            let activeTab = groupItem.getActiveTab();
-            if (activeTab) {
-              tabItem = activeTab;
-              return true;
-            }
-            // if no tab is active, use the first one
-            var child = groupItem.getChild(0);
-            if (child) {
-              tabItem = child;
-              return true;
-            }
-          }
-          return false;
-        });
-      }
-    }
-    return tabItem;
-  },
-
-  // ----------
-  // Function: moveTabToGroupItem
-  // Used for the right click menu in the tab strip; moves the given tab
-  // into the given group. Does nothing if the tab is an app tab.
-  // Paramaters:
-  //  tab - the <xul:tab>.
-  //  groupItemId - the <groupItem>'s id.  If nothing, create a new <groupItem>.
-  moveTabToGroupItem : function GroupItems_moveTabToGroupItem(tab, groupItemId) {
-    if (tab.pinned)
-      return;
-
-    Utils.assertThrow(tab._tabViewTabItem, "tab must be linked to a TabItem");
-
-    // given tab is already contained in target group
-    if (tab._tabViewTabItem.parent && tab._tabViewTabItem.parent.id == groupItemId)
-      return;
-
-    let shouldUpdateTabBar = false;
-    let shouldShowTabView = false;
-    let groupItem;
-
-    // switch to the appropriate tab first.
-    if (tab.selected) {
-      if (gBrowser.visibleTabs.length > 1) {
-        gBrowser._blurTab(tab);
-        shouldUpdateTabBar = true;
-      } else {
-        shouldShowTabView = true;
-      }
-    } else {
-      shouldUpdateTabBar = true
-    }
-
-    // remove tab item from a groupItem
-    if (tab._tabViewTabItem.parent)
-      tab._tabViewTabItem.parent.remove(tab._tabViewTabItem);
-
-    // add tab item to a groupItem
-    if (groupItemId) {
-      groupItem = GroupItems.groupItem(groupItemId);
-      groupItem.add(tab._tabViewTabItem);
-      groupItem.reorderTabsBasedOnTabItemOrder()
-    } else {
-      let pageBounds = Items.getPageBounds();
-      pageBounds.inset(20, 20);
-
-      let box = new Rect(pageBounds);
-      box.width = 250;
-      box.height = 200;
-
-      new GroupItem([ tab._tabViewTabItem ], { bounds: box, immediately: true });
-    }
-
-    if (shouldUpdateTabBar)
-      this._updateTabBar();
-    else if (shouldShowTabView)
-      UI.showTabView();
-  },
-
-  // ----------
-  // Function: removeHiddenGroups
-  // Removes all hidden groups' data and its browser tabs.
-  removeHiddenGroups: function GroupItems_removeHiddenGroups() {
-    if (this._removingHiddenGroups)
-      return;
-    this._removingHiddenGroups = true;
-
-    let groupItems = this.groupItems.concat();
-    groupItems.forEach(function(groupItem) {
-      if (groupItem.hidden)
-        groupItem.closeHidden();
-     });
-
-    this._removingHiddenGroups = false;
-  },
-
-  // ----------
-  // Function: getUnclosableGroupItemId
-  // If there's only one (non-hidden) group, and there are app tabs present, 
-  // returns that group.
-  // Return the <GroupItem>'s Id
-  getUnclosableGroupItemId: function GroupItems_getUnclosableGroupItemId() {
-    let unclosableGroupItemId = null;
-
-    if (gBrowser._numPinnedTabs > 0) {
-      let hiddenGroupItems = 
-        this.groupItems.concat().filter(function(groupItem) {
-          return !groupItem.hidden;
-        });
-      if (hiddenGroupItems.length == 1)
-        unclosableGroupItemId = hiddenGroupItems[0].id;
-    }
-
-    return unclosableGroupItemId;
-  },
-
-  // ----------
-  // Function: updateGroupCloseButtons
-  // Updates group close buttons.
-  updateGroupCloseButtons: function GroupItems_updateGroupCloseButtons() {
-    let unclosableGroupItemId = this.getUnclosableGroupItemId();
-
-    if (unclosableGroupItemId) {
-      let groupItem = this.groupItem(unclosableGroupItemId);
-
-      if (groupItem) {
-        groupItem.$closeButton.hide();
-      }
-    } else {
-      this.groupItems.forEach(function(groupItem) {
-        groupItem.$closeButton.show();
-      });
-    }
-  },
-  
-  // ----------
-  // Function: calcValidSize
-  // Basic measure rules. Assures that item is a minimum size.
-  calcValidSize: function GroupItems_calcValidSize(size, options) {
-    Utils.assert(Utils.isPoint(size), 'input is a Point');
-    Utils.assert((size.x>0 || size.y>0) && (size.x!=0 && size.y!=0), 
-      "dimensions are valid:"+size.x+","+size.y);
-    return new Point(
-      Math.max(size.x, GroupItems.minGroupWidth),
-      Math.max(size.y, GroupItems.minGroupHeight));
-  },
-
-  // ----------
-  // Function: pauseAutoclose()
-  // Temporarily disable the behavior that closes groups when they become
-  // empty. This is used when entering private browsing, to avoid trashing the
-  // user's groups while private browsing is shuffling things around.
-  pauseAutoclose: function GroupItems_pauseAutoclose() {
-    this._autoclosePaused = true;
-  },
-
-  // ----------
-  // Function: unpauseAutoclose()
-  // Re-enables the auto-close behavior.
-  resumeAutoclose: function GroupItems_resumeAutoclose() {
-    this._autoclosePaused = false;
-  }
-};
deleted file mode 100644
--- a/browser/components/tabview/iq.js
+++ /dev/null
@@ -1,765 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// **********
-// Title: iq.js
-// Various helper functions, in the vein of jQuery.
-
-// ----------
-// Function: iQ
-// Returns an iQClass object which represents an individual element or a group
-// of elements. It works pretty much like jQuery(), with a few exceptions,
-// most notably that you can't use strings with complex html,
-// just simple tags like '<div>'.
-function iQ(selector, context) {
-  // The iQ object is actually just the init constructor 'enhanced'
-  return new iQClass(selector, context);
-};
-
-// A simple way to check for HTML strings or ID strings
-// (both of which we optimize for)
-var quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/;
-
-// Match a standalone tag
-var rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/;
-
-// ##########
-// Class: iQClass
-// The actual class of iQ result objects, representing an individual element
-// or a group of elements.
-//
-// ----------
-// Function: iQClass
-// You don't call this directly; this is what's called by iQ().
-function iQClass(selector, context) {
-
-  // Handle $(""), $(null), or $(undefined)
-  if (!selector) {
-    return this;
-  }
-
-  // Handle $(DOMElement)
-  if (selector.nodeType) {
-    this.context = selector;
-    this[0] = selector;
-    this.length = 1;
-    return this;
-  }
-
-  // The body element only exists once, optimize finding it
-  if (selector === "body" && !context) {
-    this.context = document;
-    this[0] = document.body;
-    this.selector = "body";
-    this.length = 1;
-    return this;
-  }
-
-  // Handle HTML strings
-  if (typeof selector === "string") {
-    // Are we dealing with HTML string or an ID?
-
-    let match = quickExpr.exec(selector);
-
-    // Verify a match, and that no context was specified for #id
-    if (match && (match[1] || !context)) {
-
-      // HANDLE $(html) -> $(array)
-      if (match[1]) {
-        let doc = (context ? context.ownerDocument || context : document);
-
-        // If a single string is passed in and it's a single tag
-        // just do a createElement and skip the rest
-        let ret = rsingleTag.exec(selector);
-
-        if (ret) {
-          if (Utils.isPlainObject(context)) {
-            Utils.assert(false, 'does not support HTML creation with context');
-          } else {
-            selector = [doc.createElement(ret[1])];
-          }
-
-        } else {
-          Utils.assert(false, 'does not support complex HTML creation');
-        }
-
-        return Utils.merge(this, selector);
-
-      // HANDLE $("#id")
-      } else {
-        let elem = document.getElementById(match[2]);
-
-        if (elem) {
-          this.length = 1;
-          this[0] = elem;
-        }
-
-        this.context = document;
-        this.selector = selector;
-        return this;
-      }
-
-    // HANDLE $("TAG")
-    } else if (!context && /^\w+$/.test(selector)) {
-      this.selector = selector;
-      this.context = document;
-      selector = document.getElementsByTagName(selector);
-      return Utils.merge(this, selector);
-
-    // HANDLE $(expr, $(...))
-    } else if (!context || context.iq) {
-      return (context || iQ(document)).find(selector);
-
-    // HANDLE $(expr, context)
-    // (which is just equivalent to: $(context).find(expr)
-    } else {
-      return iQ(context).find(selector);
-    }
-
-  // HANDLE $(function)
-  // Shortcut for document ready
-  } else if (typeof selector == "function") {
-    Utils.log('iQ does not support ready functions');
-    return null;
-  }
-
-  if ("selector" in selector) {
-    this.selector = selector.selector;
-    this.context = selector.context;
-  }
-
-  let ret = this || [];
-  if (selector != null) {
-    // The window, strings (and functions) also have 'length'
-    if (selector.length == null || typeof selector == "string" || selector.setInterval) {
-      Array.push(ret, selector);
-    } else {
-      Utils.merge(ret, selector);
-    }
-  }
-  return ret;
-};
-  
-iQClass.prototype = {
-
-  // ----------
-  // Function: toString
-  // Prints [iQ...] for debug use
-  toString: function iQClass_toString() {
-    if (this.length > 1) {
-      if (this.selector)
-        return "[iQ (" + this.selector + ")]";
-      else
-        return "[iQ multi-object]";
-    }
-
-    if (this.length == 1)
-      return "[iQ (" + this[0].toString() + ")]";
-
-    return "[iQ non-object]";
-  },
-
-  // Start with an empty selector
-  selector: "",
-
-  // The default length of a iQ object is 0
-  length: 0,
-
-  // ----------
-  // Function: each
-  // Execute a callback for every element in the matched set.
-  each: function iQClass_each(callback) {
-    if (typeof callback != "function") {
-      Utils.assert(false, "each's argument must be a function");
-      return null;
-    }
-    for (let i = 0; this[i] != null && callback(this[i]) !== false; i++) {}
-    return this;
-  },
-
-  // ----------
-  // Function: addClass
-  // Adds the given class(es) to the receiver.
-  addClass: function iQClass_addClass(value) {
-    Utils.assertThrow(typeof value == "string" && value,
-                      'requires a valid string argument');
-
-    let length = this.length;
-    for (let i = 0; i < length; i++) {
-      let elem = this[i];
-      if (elem.nodeType === 1) {
-        value.split(/\s+/).forEach(function(className) {
-          elem.classList.add(className);
-        });
-      }
-    }
-
-    return this;
-  },
-
-  // ----------
-  // Function: removeClass
-  // Removes the given class(es) from the receiver.
-  removeClass: function iQClass_removeClass(value) {
-    if (typeof value != "string" || !value) {
-      Utils.assert(false, 'does not support function argument');
-      return null;
-    }
-
-    let length = this.length;
-    for (let i = 0; i < length; i++) {
-      let elem = this[i];
-      if (elem.nodeType === 1 && elem.className) {
-        value.split(/\s+/).forEach(function(className) {
-          elem.classList.remove(className);
-        });
-      }
-    }
-
-    return this;
-  },
-
-  // ----------
-  // Function: hasClass
-  // Returns true is the receiver has the given css class.
-  hasClass: function iQClass_hasClass(singleClassName) {
-    let length = this.length;
-    for (let i = 0; i < length; i++) {
-      if (this[i].classList.contains(singleClassName)) {
-        return true;
-      }
-    }
-    return false;
-  },
-
-  // ----------
-  // Function: find
-  // Searches the receiver and its children, returning a new iQ object with
-  // elements that match the given selector.
-  find: function iQClass_find(selector) {
-    let ret = [];
-    let length = 0;
-
-    let l = this.length;
-    for (let i = 0; i < l; i++) {
-      length = ret.length;
-      try {
-        Utils.merge(ret, this[i].querySelectorAll(selector));
-      } catch(e) {
-        Utils.log('iQ.find error (bad selector)', e);
-      }
-
-      if (i > 0) {
-        // Make sure that the results are unique
-        for (let n = length; n < ret.length; n++) {
-          for (let r = 0; r < length; r++) {
-            if (ret[r] === ret[n]) {
-              ret.splice(n--, 1);
-              break;
-            }
-          }
-        }
-      }
-    }
-
-    return iQ(ret);
-  },
-
-  // ----------
-  // Function: contains
-  // Check to see if a given DOM node descends from the receiver.
-  contains: function iQClass_contains(selector) {
-    Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
-
-    // fast path when querySelector() can be used
-    if ('string' == typeof selector)
-      return null != this[0].querySelector(selector);
-
-    let object = iQ(selector);
-    Utils.assert(object.length <= 1, 'does not yet support multi-objects');
-
-    let elem = object[0];
-    if (!elem || !elem.parentNode)
-      return false;
-
-    do {
-      elem = elem.parentNode;
-    } while (elem && this[0] != elem);
-
-    return this[0] == elem;
-  },
-
-  // ----------
-  // Function: remove
-  // Removes the receiver from the DOM.
-  remove: function iQClass_remove(options) {
-    if (!options || !options.preserveEventHandlers)
-      this.unbindAll();
-    for (let i = 0; this[i] != null; i++) {
-      let elem = this[i];
-      if (elem.parentNode) {
-        elem.parentNode.removeChild(elem);
-      }
-    }
-    return this;
-  },
-
-  // ----------
-  // Function: empty
-  // Removes all of the reciever's children and HTML content from the DOM.
-  empty: function iQClass_empty() {
-    for (let i = 0; this[i] != null; i++) {
-      let elem = this[i];
-      while (elem.firstChild) {
-        iQ(elem.firstChild).unbindAll();
-        elem.removeChild(elem.firstChild);
-      }
-    }
-    return this;
-  },
-
-  // ----------
-  // Function: width
-  // Returns the width of the receiver, including padding and border.
-  width: function iQClass_width() {
-    return Math.floor(this[0].offsetWidth);
-  },
-
-  // ----------
-  // Function: height
-  // Returns the height of the receiver, including padding and border.
-  height: function iQClass_height() {
-    return Math.floor(this[0].offsetHeight);
-  },
-
-  // ----------
-  // Function: position
-  // Returns an object with the receiver's position in left and top
-  // properties.
-  position: function iQClass_position() {
-    let bounds = this.bounds();
-    return new Point(bounds.left, bounds.top);
-  },
-
-  // ----------
-  // Function: bounds
-  // Returns a <Rect> with the receiver's bounds.
-  bounds: function iQClass_bounds() {
-    Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
-    let rect = this[0].getBoundingClientRect();
-    return new Rect(Math.floor(rect.left), Math.floor(rect.top),
-                    Math.floor(rect.width), Math.floor(rect.height));
-  },
-
-  // ----------
-  // Function: data
-  // Pass in both key and value to attach some data to the receiver;
-  // pass in just key to retrieve it.
-  data: function iQClass_data(key, value) {
-    let data = null;
-    if (value === undefined) {
-      Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
-      data = this[0].iQData;
-      if (data)
-        return data[key];
-      else
-        return null;
-    }
-
-    for (let i = 0; this[i] != null; i++) {
-      let elem = this[i];
-      data = elem.iQData;
-
-      if (!data)
-        data = elem.iQData = {};
-
-      data[key] = value;
-    }
-
-    return this;
-  },
-
-  // ----------
-  // Function: html
-  // Given a value, sets the receiver's innerHTML to it; otherwise returns
-  // what's already there.
-  html: function iQClass_html(value) {
-    Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
-    if (value === undefined)
-      return this[0].innerHTML;
-
-    this[0].innerHTML = value;
-    return this;
-  },
-
-  // ----------
-  // Function: text
-  // Given a value, sets the receiver's textContent to it; otherwise returns
-  // what's already there.
-  text: function iQClass_text(value) {
-    Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
-    if (value === undefined) {
-      return this[0].textContent;
-    }
-
-    return this.empty().append((this[0] && this[0].ownerDocument || document).createTextNode(value));
-  },
-
-  // ----------
-  // Function: val
-  // Given a value, sets the receiver's value to it; otherwise returns what's already there.
-  val: function iQClass_val(value) {
-    Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
-    if (value === undefined) {
-      return this[0].value;
-    }
-
-    this[0].value = value;
-    return this;
-  },
-
-  // ----------
-  // Function: appendTo
-  // Appends the receiver to the result of iQ(selector).
-  appendTo: function iQClass_appendTo(selector) {
-    Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
-    iQ(selector).append(this);
-    return this;
-  },
-
-  // ----------
-  // Function: append
-  // Appends the result of iQ(selector) to the receiver.
-  append: function iQClass_append(selector) {
-    let object = iQ(selector);
-    Utils.assert(object.length == 1 && this.length == 1, 
-        'does not yet support multi-objects (or null objects)');
-    this[0].appendChild(object[0]);
-    return this;
-  },
-
-  // ----------
-  // Function: attr
-  // Sets or gets an attribute on the element(s).
-  attr: function iQClass_attr(key, value) {
-    Utils.assert(typeof key === 'string', 'string key');
-    if (value === undefined) {
-      Utils.assert(this.length == 1, 'retrieval does not support multi-objects (or null objects)');
-      return this[0].getAttribute(key);
-    }
-
-    for (let i = 0; this[i] != null; i++)
-      this[i].setAttribute(key, value);
-
-    return this;
-  },
-
-  // ----------
-  // Function: css
-  // Sets or gets CSS properties on the receiver. When setting certain numerical properties,
-  // will automatically add "px". A property can be removed by setting it to null.
-  //
-  // Possible call patterns:
-  //   a: object, b: undefined - sets with properties from a
-  //   a: string, b: undefined - gets property specified by a
-  //   a: string, b: string/number - sets property specified by a to b
-  css: function iQClass_css(a, b) {
-    let properties = null;
-
-    if (typeof a === 'string') {
-      let key = a;
-      if (b === undefined) {
-        Utils.assert(this.length == 1, 'retrieval does not support multi-objects (or null objects)');
-
-        return window.getComputedStyle(this[0], null).getPropertyValue(key);
-      }
-      properties = {};
-      properties[key] = b;
-    } else if (a instanceof Rect) {
-      properties = {
-        left: a.left,
-        top: a.top,
-        width: a.width,
-        height: a.height
-      };
-    } else {
-      properties = a;
-    }
-
-    let pixels = {
-      'left': true,
-      'top': true,
-      'right': true,
-      'bottom': true,
-      'width': true,
-      'height': true
-    };
-
-    for (let i = 0; this[i] != null; i++) {
-      let elem = this[i];
-      for (let key in properties) {
-        let value = properties[key];
-
-        if (pixels[key] && typeof value != 'string')
-          value += 'px';
-
-        if (value == null) {
-          elem.style.removeProperty(key);
-        } else if (key.indexOf('-') != -1)
-          elem.style.setProperty(key, value, '');
-        else
-          elem.style[key] = value;
-      }
-    }
-
-    return this;
-  },
-
-  // ----------
-  // Function: animate
-  // Uses CSS transitions to animate the element.
-  //
-  // Parameters:
-  //   css - an object map of the CSS properties to change
-  //   options - an object with various properites (see below)
-  //
-  // Possible "options" properties:
-  //   duration - how long to animate, in milliseconds
-  //   easing - easing function to use. Possibilities include
-  //     "tabviewBounce", "easeInQuad". Default is "ease".
-  //   complete - function to call once the animation is done, takes nothing
-  //     in, but "this" is set to the element that was animated.
-  animate: function iQClass_animate(css, options) {
-    Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
-
-    if (!options)
-      options = {};
-
-    let easings = {
-      tabviewBounce: "cubic-bezier(0.0, 0.63, .6, 1.29)", 
-      easeInQuad: 'ease-in', // TODO: make it a real easeInQuad, or decide we don't care
-      fast: 'cubic-bezier(0.7,0,1,1)'
-    };
-
-    let duration = (options.duration || 400);
-    let easing = (easings[options.easing] || 'ease');
-
-    if (css instanceof Rect) {
-      css = {
-        left: css.left,
-        top: css.top,
-        width: css.width,
-        height: css.height
-      };
-    }
-
-
-    // The latest versions of Firefox do not animate from a non-explicitly
-    // set css properties. So for each element to be animated, go through
-    // and explicitly define 'em.
-    let rupper = /([A-Z])/g;
-    this.each(function(elem) {
-      let cStyle = window.getComputedStyle(elem, null);
-      for (let prop in css) {
-        prop = prop.replace(rupper, "-$1").toLowerCase();
-        iQ(elem).css(prop, cStyle.getPropertyValue(prop));
-      }
-    });
-
-    this.css({
-      'transition-property': Object.keys(css).join(", "),
-      'transition-duration': (duration / 1000) + 's',
-      'transition-timing-function': easing
-    });
-
-    this.css(css);
-
-    let self = this;
-    setTimeout(function() {
-      self.css({
-        'transition-property': 'none',
-        'transition-duration': '',
-        'transition-timing-function': ''
-      });
-
-      if (typeof options.complete == "function")
-        options.complete.apply(self);
-    }, duration);
-
-    return this;
-  },
-
-  // ----------
-  // Function: fadeOut
-  // Animates the receiver to full transparency. Calls callback on completion.
-  fadeOut: function iQClass_fadeOut(callback) {
-    Utils.assert(typeof callback == "function" || callback === undefined, 
-        'does not yet support duration');
-
-    this.animate({
-      opacity: 0
-    }, {
-      duration: 400,
-      complete: function() {
-        iQ(this).css({display: 'none'});
-        if (typeof callback == "function")
-          callback.apply(this);
-      }
-    });
-
-    return this;
-  },
-
-  // ----------
-  // Function: fadeIn
-  // Animates the receiver to full opacity.
-  fadeIn: function iQClass_fadeIn() {
-    this.css({display: ''});
-    this.animate({
-      opacity: 1
-    }, {
-      duration: 400
-    });
-
-    return this;
-  },
-
-  // ----------
-  // Function: hide
-  // Hides the receiver.
-  hide: function iQClass_hide() {
-    this.css({display: 'none', opacity: 0});
-    return this;
-  },
-
-  // ----------
-  // Function: show
-  // Shows the receiver.
-  show: function iQClass_show() {
-    this.css({display: '', opacity: 1});
-    return this;
-  },
-
-  // ----------
-  // Function: bind
-  // Binds the given function to the given event type. Also wraps the function
-  // in a try/catch block that does a Utils.log on any errors.
-  bind: function iQClass_bind(type, func) {
-    let handler = function(event) {
-      return func.apply(this, [event]);
-    };
-
-    for (let i = 0; this[i] != null; i++) {
-      let elem = this[i];
-      if (!elem.iQEventData)
-        elem.iQEventData = {};
-
-      if (!elem.iQEventData[type])
-        elem.iQEventData[type] = [];
-
-      elem.iQEventData[type].push({
-        original: func,
-        modified: handler
-      });
-
-      elem.addEventListener(type, handler, false);
-    }
-
-    return this;
-  },
-
-  // ----------
-  // Function: one
-  // Binds the given function to the given event type, but only for one call;
-  // automatically unbinds after the event fires once.
-  one: function iQClass_one(type, func) {
-    Utils.assert(typeof func == "function", 'does not support eventData argument');
-
-    let handler = function(e) {
-      iQ(this).unbind(type, handler);
-      return func.apply(this, [e]);
-    };
-
-    return this.bind(type, handler);
-  },
-
-  // ----------
-  // Function: unbind
-  // Unbinds the given function from the given event type.
-  unbind: function iQClass_unbind(type, func) {
-    Utils.assert(typeof func == "function", 'Must provide a function');
-
-    for (let i = 0; this[i] != null; i++) {
-      let elem = this[i];
-      let handler = func;
-      if (elem.iQEventData && elem.iQEventData[type]) {
-        let count = elem.iQEventData[type].length;
-        for (let a = 0; a < count; a++) {
-          let pair = elem.iQEventData[type][a];
-          if (pair.original == func) {
-            handler = pair.modified;
-            elem.iQEventData[type].splice(a, 1);
-            if (!elem.iQEventData[type].length) {
-              delete elem.iQEventData[type];
-              if (!Object.keys(elem.iQEventData).length)
-                delete elem.iQEventData;
-            }
-            break;
-          }
-        }
-      }
-
-      elem.removeEventListener(type, handler, false);
-    }
-
-    return this;
-  },
-
-  // ----------
-  // Function: unbindAll
-  // Unbinds all event handlers.
-  unbindAll: function iQClass_unbindAll() {
-    for (let i = 0; this[i] != null; i++) {
-      let elem = this[i];
-
-      for (let j = 0; j < elem.childElementCount; j++)
-        iQ(elem.children[j]).unbindAll();
-
-      if (!elem.iQEventData)
-        continue;
-
-      Object.keys(elem.iQEventData).forEach(function (type) {
-        while (elem.iQEventData && elem.iQEventData[type])
-          this.unbind(type, elem.iQEventData[type][0].original);
-      }, this);
-    }
-
-    return this;
-  }
-};
-
-// ----------
-// Create various event aliases
-var events = [
-  'keyup',
-  'keydown',
-  'keypress',
-  'mouseup',
-  'mousedown',
-  'mouseover',
-  'mouseout',
-  'mousemove',
-  'click',
-  'dblclick',
-  'resize',
-  'change',
-  'blur',
-  'focus'
-];
-
-events.forEach(function(event) {
-  iQClass.prototype[event] = function(func) {
-    return this.bind(event, func);
-  };
-});
deleted file mode 100644
--- a/browser/components/tabview/items.js
+++ /dev/null
@@ -1,1077 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// **********
-// Title: items.js
-
-// ##########
-// Class: Item
-// Superclass for all visible objects (<TabItem>s and <GroupItem>s).
-//
-// If you subclass, in addition to the things Item provides, you need to also provide these methods:
-//   setBounds - function(rect, immediately, options)
-//   setZ - function(value)
-//   close - function()
-//   save - function()
-//
-// Subclasses of Item must also provide the <Subscribable> interface.
-//
-// Make sure to call _init() from your subclass's constructor.
-function Item() {
-  // Variable: isAnItem
-  // Always true for Items
-  this.isAnItem = true;
-
-  // Variable: bounds
-  // The position and size of this Item, represented as a <Rect>.
-  // This should never be modified without using setBounds()
-  this.bounds = null;
-
-  // Variable: zIndex
-  // The z-index for this item.
-  this.zIndex = 0;
-
-  // Variable: container
-  // The outermost DOM element that describes this item on screen.
-  this.container = null;
-
-  // Variable: parent
-  // The groupItem that this item is a child of
-  this.parent = null;
-
-  // Variable: userSize
-  // A <Point> that describes the last size specifically chosen by the user.
-  // Used by unsquish.
-  this.userSize = null;
-
-  // Variable: dragOptions
-  // Used by <draggable>
-  //
-  // Possible properties:
-  //   cancelClass - A space-delimited list of classes that should cancel a drag
-  //   start - A function to be called when a drag starts
-  //   drag - A function to be called each time the mouse moves during drag
-  //   stop - A function to be called when the drag is done
-  this.dragOptions = null;
-
-  // Variable: dropOptions
-  // Used by <draggable> if the item is set to droppable.
-  //
-  // Possible properties:
-  //   accept - A function to determine if a particular item should be accepted for dropping
-  //   over - A function to be called when an item is over this item
-  //   out - A function to be called when an item leaves this item
-  //   drop - A function to be called when an item is dropped in this item
-  this.dropOptions = null;
-
-  // Variable: resizeOptions
-  // Used by <resizable>
-  //
-  // Possible properties:
-  //   minWidth - Minimum width allowable during resize
-  //   minHeight - Minimum height allowable during resize
-  //   aspectRatio - true if we should respect aspect ratio; default false
-  //   start - A function to be called when resizing starts
-  //   resize - A function to be called each time the mouse moves during resize
-  //   stop - A function to be called when the resize is done
-  this.resizeOptions = null;
-
-  // Variable: isDragging
-  // Boolean for whether the item is currently being dragged or not.
-  this.isDragging = false;
-};
-
-Item.prototype = {
-  // ----------
-  // Function: _init
-  // Initializes the object. To be called from the subclass's intialization function.
-  //
-  // Parameters:
-  //   container - the outermost DOM element that describes this item onscreen.
-  _init: function Item__init(container) {
-    Utils.assert(typeof this.addSubscriber == 'function' && 
-        typeof this.removeSubscriber == 'function' && 
-        typeof this._sendToSubscribers == 'function',
-        'Subclass must implement the Subscribable interface');
-    Utils.assert(Utils.isDOMElement(container), 'container must be a DOM element');
-    Utils.assert(typeof this.setBounds == 'function', 'Subclass must provide setBounds');
-    Utils.assert(typeof this.setZ == 'function', 'Subclass must provide setZ');
-    Utils.assert(typeof this.close == 'function', 'Subclass must provide close');
-    Utils.assert(typeof this.save == 'function', 'Subclass must provide save');
-    Utils.assert(Utils.isRect(this.bounds), 'Subclass must provide bounds');
-
-    this.container = container;
-    this.$container = iQ(container);
-
-    iQ(this.container).data('item', this);
-
-    // ___ drag
-    this.dragOptions = {
-      cancelClass: 'close stackExpander',
-      start: function(e, ui) {
-        UI.setActive(this);
-        if (this.isAGroupItem)
-          this._unfreezeItemSize();
-        // if we start dragging a tab within a group, start with dropSpace on.
-        else if (this.parent != null)
-          this.parent._dropSpaceActive = true;
-        drag.info = new Drag(this, e);
-      },
-      drag: function(e) {
-        drag.info.drag(e);
-      },
-      stop: function() {
-        drag.info.stop();
-
-        if (!this.isAGroupItem && !this.parent) {
-          new GroupItem([drag.info.$el], {focusTitle: true});
-          gTabView.firstUseExperienced = true;
-        }
-
-        drag.info = null;
-      },
-      // The minimum the mouse must move after mouseDown in order to move an 
-      // item
-      minDragDistance: 3
-    };
-
-    // ___ drop
-    this.dropOptions = {
-      over: function() {},
-      out: function() {
-        let groupItem = drag.info.item.parent;
-        if (groupItem)
-          groupItem.remove(drag.info.$el, {dontClose: true});
-        iQ(this.container).removeClass("acceptsDrop");
-      },
-      drop: function(event) {
-        iQ(this.container).removeClass("acceptsDrop");
-      },
-      // Function: dropAcceptFunction
-      // Given a DOM element, returns true if it should accept tabs being dropped on it.
-      // Private to this file.
-      accept: function dropAcceptFunction(item) {
-        return (item && item.isATabItem && (!item.parent || !item.parent.expanded));
-      }
-    };
-
-    // ___ resize
-    var self = this;
-    this.resizeOptions = {
-      aspectRatio: self.keepProportional,
-      minWidth: 90,
-      minHeight: 90,
-      start: function(e,ui) {
-        UI.setActive(this);
-        resize.info = new Drag(this, e);
-      },
-      resize: function(e,ui) {
-        resize.info.snap(UI.rtl ? 'topright' : 'topleft', false, self.keepProportional);
-      },
-      stop: function() {
-        self.setUserSize();
-        self.pushAway();
-        resize.info.stop();
-        resize.info = null;
-      }
-    };
-  },
-
-  // ----------
-  // Function: getBounds
-  // Returns a copy of the Item's bounds as a <Rect>.
-  getBounds: function Item_getBounds() {
-    Utils.assert(Utils.isRect(this.bounds), 'this.bounds should be a rect');
-    return new Rect(this.bounds);
-  },
-
-  // ----------
-  // Function: overlapsWithOtherItems
-  // Returns true if this Item overlaps with any other Item on the screen.
-  overlapsWithOtherItems: function Item_overlapsWithOtherItems() {
-    var self = this;
-    var items = Items.getTopLevelItems();
-    var bounds = this.getBounds();
-    return items.some(function(item) {
-      if (item == self) // can't overlap with yourself.
-        return false;
-      var myBounds = item.getBounds();
-      return myBounds.intersects(bounds);
-    } );
-  },
-
-  // ----------
-  // Function: setPosition
-  // Moves the Item to the specified location.
-  //
-  // Parameters:
-  //   left - the new left coordinate relative to the window
-  //   top - the new top coordinate relative to the window
-  //   immediately - if false or omitted, animates to the new position;
-  //   otherwise goes there immediately
-  setPosition: function Item_setPosition(left, top, immediately) {
-    Utils.assert(Utils.isRect(this.bounds), 'this.bounds');
-    this.setBounds(new Rect(left, top, this.bounds.width, this.bounds.height), immediately);
-  },
-
-  // ----------
-  // Function: setSize
-  // Resizes the Item to the specified size.
-  //
-  // Parameters:
-  //   width - the new width in pixels
-  //   height - the new height in pixels
-  //   immediately - if false or omitted, animates to the new size;
-  //   otherwise resizes immediately
-  setSize: function Item_setSize(width, height, immediately) {
-    Utils.assert(Utils.isRect(this.bounds), 'this.bounds');
-    this.setBounds(new Rect(this.bounds.left, this.bounds.top, width, height), immediately);
-  },
-
-  // ----------
-  // Function: setUserSize
-  // Remembers the current size as one the user has chosen.
-  setUserSize: function Item_setUserSize() {
-    Utils.assert(Utils.isRect(this.bounds), 'this.bounds');
-    this.userSize = new Point(this.bounds.width, this.bounds.height);
-    this.save();
-  },
-
-  // ----------
-  // Function: getZ
-  // Returns the zIndex of the Item.
-  getZ: function Item_getZ() {
-    return this.zIndex;
-  },
-
-  // ----------
-  // Function: setRotation
-  // Rotates the object to the given number of degrees.
-  setRotation: function Item_setRotation(degrees) {
-    var value = degrees ? "rotate(%deg)".replace(/%/, degrees) : null;
-    iQ(this.container).css({"transform": value});
-  },
-
-  // ----------
-  // Function: setParent
-  // Sets the receiver's parent to the given <Item>.
-  setParent: function Item_setParent(parent) {
-    this.parent = parent;
-    this.removeTrenches();
-    this.save();
-  },
-
-  // ----------
-  // Function: pushAway
-  // Pushes all other items away so none overlap this Item.
-  //
-  // Parameters:
-  //  immediately - boolean for doing the pushAway without animation
-  pushAway: function Item_pushAway(immediately) {
-    var items = Items.getTopLevelItems();
-
-    // we need at least two top-level items to push something away
-    if (items.length < 2)
-      return;
-
-    var buffer = Math.floor(Items.defaultGutter / 2);
-
-    // setup each Item's pushAwayData attribute:
-    items.forEach(function pushAway_setupPushAwayData(item) {
-      var data = {};
-      data.bounds = item.getBounds();
-      data.startBounds = new Rect(data.bounds);
-      // Infinity = (as yet) unaffected
-      data.generation = Infinity;
-      item.pushAwayData = data;
-    });
-
-    // The first item is a 0-generation pushed item. It all starts here.
-    var itemsToPush = [this];
-    this.pushAwayData.generation = 0;
-
-    var pushOne = function Item_pushAway_pushOne(baseItem) {
-      // the baseItem is an n-generation pushed item. (n could be 0)
-      var baseData = baseItem.pushAwayData;
-      var bb = new Rect(baseData.bounds);
-
-      // make the bounds larger, adding a +buffer margin to each side.
-      bb.inset(-buffer, -buffer);
-      // bbc = center of the base's bounds
-      var bbc = bb.center();
-
-      items.forEach(function Item_pushAway_pushOne_pushEach(item) {
-        if (item == baseItem)
-          return;
-
-        var data = item.pushAwayData;
-        // if the item under consideration has already been pushed, or has a lower
-        // "generation" (and thus an implictly greater placement priority) then don't move it.
-        if (data.generation <= baseData.generation)
-          return;
-
-        // box = this item's current bounds, with a +buffer margin.
-        var bounds = data.bounds;
-        var box = new Rect(bounds);
-        box.inset(-buffer, -buffer);
-
-        // if the item under consideration overlaps with the base item...
-        if (box.intersects(bb)) {
-
-          // Let's push it a little.
-
-          // First, decide in which direction and how far to push. This is the offset.
-          var offset = new Point();
-          // center = the current item's center.
-          var center = box.center();
-
-          // Consider the relationship between the current item (box) + the base item.
-          // If it's more vertically stacked than "side by side"...
-          if (Math.abs(center.x - bbc.x) < Math.abs(center.y - bbc.y)) {
-            // push vertically.
-            if (center.y > bbc.y)
-              offset.y = bb.bottom - box.top;
-            else
-              offset.y = bb.top - box.bottom;
-          } else { // if they're more "side by side" than stacked vertically...
-            // push horizontally.
-            if (center.x > bbc.x)
-              offset.x = bb.right - box.left;
-            else
-              offset.x = bb.left - box.right;
-          }
-
-          // Actually push the Item.
-          bounds.offset(offset);
-
-          // This item now becomes an (n+1)-generation pushed item.
-          data.generation = baseData.generation + 1;
-          // keep track of who pushed this item.
-          data.pusher = baseItem;
-          // add this item to the queue, so that it, in turn, can push some other things.
-          itemsToPush.push(item);
-        }
-      });
-    };
-
-    // push each of the itemsToPush, one at a time.
-    // itemsToPush starts with just [this], but pushOne can add more items to the stack.
-    // Maximally, this could run through all Items on the screen.
-    while (itemsToPush.length)
-      pushOne(itemsToPush.shift());
-
-    // ___ Squish!
-    var pageBounds = Items.getSafeWindowBounds();
-    items.forEach(function Item_pushAway_squish(item) {
-      var data = item.pushAwayData;
-      if (data.generation == 0)
-        return;
-
-      let apply = function Item_pushAway_squish_apply(item, posStep, posStep2, sizeStep) {
-        var data = item.pushAwayData;
-        if (data.generation == 0)
-          return;
-
-        var bounds = data.bounds;
-        bounds.width -= sizeStep.x;
-        bounds.height -= sizeStep.y;
-        bounds.left += posStep.x;
-        bounds.top += posStep.y;
-
-        let validSize;
-        if (item.isAGroupItem) {
-          validSize = GroupItems.calcValidSize(
-            new Point(bounds.width, bounds.height));
-          bounds.width = validSize.x;
-          bounds.height = validSize.y;
-        } else {
-          if (sizeStep.y > sizeStep.x) {
-            validSize = TabItems.calcValidSize(new Point(-1, bounds.height));
-            bounds.left += (bounds.width - validSize.x) / 2;
-            bounds.width = validSize.x;
-          } else {
-            validSize = TabItems.calcValidSize(new Point(bounds.width, -1));
-            bounds.top += (bounds.height - validSize.y) / 2;
-            bounds.height = validSize.y;        
-          }
-        }
-
-        var pusher = data.pusher;
-        if (pusher) {
-          var newPosStep = new Point(posStep.x + posStep2.x, posStep.y + posStep2.y);
-          apply(pusher, newPosStep, posStep2, sizeStep);
-        }
-      }
-
-      var bounds = data.bounds;
-      var posStep = new Point();
-      var posStep2 = new Point();
-      var sizeStep = new Point();
-
-      if (bounds.left < pageBounds.left) {
-        posStep.x = pageBounds.left - bounds.left;
-        sizeStep.x = posStep.x / data.generation;
-        posStep2.x = -sizeStep.x;
-      } else if (bounds.right > pageBounds.right) { // this may be less of a problem post-601534
-        posStep.x = pageBounds.right - bounds.right;
-        sizeStep.x = -posStep.x / data.generation;
-        posStep.x += sizeStep.x;
-        posStep2.x = sizeStep.x;
-      }
-
-      if (bounds.top < pageBounds.top) {
-        posStep.y = pageBounds.top - bounds.top;
-        sizeStep.y = posStep.y / data.generation;
-        posStep2.y = -sizeStep.y;
-      } else if (bounds.bottom > pageBounds.bottom) { // this may be less of a problem post-601534
-        posStep.y = pageBounds.bottom - bounds.bottom;
-        sizeStep.y = -posStep.y / data.generation;
-        posStep.y += sizeStep.y;
-        posStep2.y = sizeStep.y;
-      }
-
-      if (posStep.x || posStep.y || sizeStep.x || sizeStep.y)
-        apply(item, posStep, posStep2, sizeStep);        
-    });
-
-    // ___ Unsquish
-    var pairs = [];
-    items.forEach(function Item_pushAway_setupUnsquish(item) {
-      var data = item.pushAwayData;
-      pairs.push({
-        item: item,
-        bounds: data.bounds
-      });
-    });
-
-    Items.unsquish(pairs);
-
-    // ___ Apply changes
-    items.forEach(function Item_pushAway_setBounds(item) {
-      var data = item.pushAwayData;
-      var bounds = data.bounds;
-      if (!bounds.equals(data.startBounds)) {
-        item.setBounds(bounds, immediately);
-      }
-    });
-  },
-
-  // ----------
-  // Function: setTrenches
-  // Sets up/moves the trenches for snapping to this item.
-  setTrenches: function Item_setTrenches(rect) {
-    if (this.parent !== null)
-      return;
-
-    if (!this.borderTrenches)
-      this.borderTrenches = Trenches.registerWithItem(this,"border");
-
-    var bT = this.borderTrenches;
-    Trenches.getById(bT.left).setWithRect(rect);
-    Trenches.getById(bT.right).setWithRect(rect);
-    Trenches.getById(bT.top).setWithRect(rect);
-    Trenches.getById(bT.bottom).setWithRect(rect);
-
-    if (!this.guideTrenches)
-      this.guideTrenches = Trenches.registerWithItem(this,"guide");
-
-    var gT = this.guideTrenches;
-    Trenches.getById(gT.left).setWithRect(rect);
-    Trenches.getById(gT.right).setWithRect(rect);
-    Trenches.getById(gT.top).setWithRect(rect);
-    Trenches.getById(gT.bottom).setWithRect(rect);
-
-  },
-
-  // ----------
-  // Function: removeTrenches
-  // Removes the trenches for snapping to this item.
-  removeTrenches: function Item_removeTrenches() {
-    for (var edge in this.borderTrenches) {
-      Trenches.unregister(this.borderTrenches[edge]); // unregister can take an array
-    }
-    this.borderTrenches = null;
-    for (var edge in this.guideTrenches) {
-      Trenches.unregister(this.guideTrenches[edge]); // unregister can take an array
-    }
-    this.guideTrenches = null;
-  },
-
-  // ----------
-  // Function: snap
-  // The snap function used during groupItem creation via drag-out
-  //
-  // Parameters:
-  //  immediately - bool for having the drag do the final positioning without animation
-  snap: function Item_snap(immediately) {
-    // make the snapping work with a wider range!
-    var defaultRadius = Trenches.defaultRadius;
-    Trenches.defaultRadius = 2 * defaultRadius; // bump up from 10 to 20!
-
-    var FauxDragInfo = new Drag(this, {});
-    FauxDragInfo.snap('none', false);
-    FauxDragInfo.stop(immediately);
-
-    Trenches.defaultRadius = defaultRadius;
-  },
-
-  // ----------
-  // Function: draggable
-  // Enables dragging on this item. Note: not to be called multiple times on the same item!
-  draggable: function Item_draggable() {
-    try {
-      Utils.assert(this.dragOptions, 'dragOptions');
-
-      var cancelClasses = [];
-      if (typeof this.dragOptions.cancelClass == 'string')
-        cancelClasses = this.dragOptions.cancelClass.split(' ');
-
-      var self = this;
-      var $container = iQ(this.container);
-      var startMouse;
-      var startPos;
-      var startSent;
-      var startEvent;
-      var droppables;
-      var dropTarget;
-
-      // determine the best drop target based on the current mouse coordinates
-      let determineBestDropTarget = function (e, box) {
-        // drop events
-        var best = {
-          dropTarget: null,
-          score: 0
-        };
-
-        droppables.forEach(function(droppable) {
-          var intersection = box.intersection(droppable.bounds);
-          if (intersection && intersection.area() > best.score) {
-            var possibleDropTarget = droppable.item;
-            var accept = true;
-            if (possibleDropTarget != dropTarget) {
-              var dropOptions = possibleDropTarget.dropOptions;
-              if (dropOptions && typeof dropOptions.accept == "function")
-                accept = dropOptions.accept.apply(possibleDropTarget, [self]);
-            }
-
-            if (accept) {
-              best.dropTarget = possibleDropTarget;
-              best.score = intersection.area();
-            }
-          }
-        });
-
-        return best.dropTarget;
-      }
-
-      // ___ mousemove
-      var handleMouseMove = function(e) {
-        // global drag tracking
-        drag.lastMoveTime = Date.now();
-
-        // positioning
-        var mouse = new Point(e.pageX, e.pageY);
-        if (!startSent) {
-          if(Math.abs(mouse.x - startMouse.x) > self.dragOptions.minDragDistance ||
-             Math.abs(mouse.y - startMouse.y) > self.dragOptions.minDragDistance) {
-            if (typeof self.dragOptions.start == "function")
-              self.dragOptions.start.apply(self,
-                  [startEvent, {position: {left: startPos.x, top: startPos.y}}]);
-            startSent = true;
-          }
-        }
-        if (startSent) {
-          // drag events
-          var box = self.getBounds();
-          box.left = startPos.x + (mouse.x - startMouse.x);
-          box.top = startPos.y + (mouse.y - startMouse.y);
-          self.setBounds(box, true);
-
-          if (typeof self.dragOptions.drag == "function")
-            self.dragOptions.drag.apply(self, [e]);
-
-          let bestDropTarget = determineBestDropTarget(e, box);
-
-          if (bestDropTarget != dropTarget) {
-            var dropOptions;
-            if (dropTarget) {
-              dropOptions = dropTarget.dropOptions;
-              if (dropOptions && typeof dropOptions.out == "function")
-                dropOptions.out.apply(dropTarget, [e]);
-            }
-
-            dropTarget = bestDropTarget;
-
-            if (dropTarget) {
-              dropOptions = dropTarget.dropOptions;
-              if (dropOptions && typeof dropOptions.over == "function")
-                dropOptions.over.apply(dropTarget, [e]);
-            }
-          }
-          if (dropTarget) {
-            dropOptions = dropTarget.dropOptions;
-            if (dropOptions && typeof dropOptions.move == "function")
-              dropOptions.move.apply(dropTarget, [e]);
-          }
-        }
-
-        e.preventDefault();
-      };
-
-      // ___ mouseup
-      var handleMouseUp = function(e) {
-        iQ(gWindow)
-          .unbind('mousemove', handleMouseMove)
-          .unbind('mouseup', handleMouseUp);
-
-        if (startSent && dropTarget) {
-          var dropOptions = dropTarget.dropOptions;
-          if (dropOptions && typeof dropOptions.drop == "function")
-            dropOptions.drop.apply(dropTarget, [e]);
-        }
-
-        if (startSent && typeof self.dragOptions.stop == "function")
-          self.dragOptions.stop.apply(self, [e]);
-
-        e.preventDefault();
-      };
-
-      // ___ mousedown
-      $container.mousedown(function(e) {
-        if (!Utils.isLeftClick(e))
-          return;
-
-        var cancel = false;
-        var $target = iQ(e.target);
-        cancelClasses.forEach(function(className) {
-          if ($target.hasClass(className))
-            cancel = true;
-        });
-
-        if (cancel) {
-          e.preventDefault();
-          return;
-        }
-
-        startMouse = new Point(e.pageX, e.pageY);
-        let bounds = self.getBounds();
-        startPos = bounds.position();
-        startEvent = e;
-        startSent = false;
-
-        droppables = [];
-        iQ('.iq-droppable').each(function(elem) {
-          if (elem != self.container) {
-            var item = Items.item(elem);
-            droppables.push({
-              item: item,
-              bounds: item.getBounds()
-            });
-          }
-        });
-
-        dropTarget = determineBestDropTarget(e, bounds);
-
-        iQ(gWindow)
-          .mousemove(handleMouseMove)
-          .mouseup(handleMouseUp);
-
-        e.preventDefault();
-      });
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
-  // Function: droppable
-  // Enables or disables dropping on this item.
-  droppable: function Item_droppable(value) {
-    try {
-      var $container = iQ(this.container);
-      if (value) {
-        Utils.assert(this.dropOptions, 'dropOptions');
-        $container.addClass('iq-droppable');
-      } else
-        $container.removeClass('iq-droppable');
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
-  // Function: resizable
-  // Enables or disables resizing of this item.
-  resizable: function Item_resizable(value) {
-    try {
-      var $container = iQ(this.container);
-      iQ('.iq-resizable-handle', $container).remove();
-
-      if (!value) {
-        $container.removeClass('iq-resizable');
-      } else {
-        Utils.assert(this.resizeOptions, 'resizeOptions');
-
-        $container.addClass('iq-resizable');
-
-        var self = this;
-        var startMouse;
-        var startSize;
-        var startAspect;
-
-        // ___ mousemove
-        var handleMouseMove = function(e) {
-          // global resize tracking
-          resize.lastMoveTime = Date.now();
-
-          var mouse = new Point(e.pageX, e.pageY);
-          var box = self.getBounds();
-          if (UI.rtl) {
-            var minWidth = (self.resizeOptions.minWidth || 0);
-            var oldWidth = box.width;
-            if (minWidth != oldWidth || mouse.x < startMouse.x) {
-              box.width = Math.max(minWidth, startSize.x - (mouse.x - startMouse.x));
-              box.left -= box.width - oldWidth;
-            }
-          } else {
-            box.width = Math.max(self.resizeOptions.minWidth || 0, startSize.x + (mouse.x - startMouse.x));
-          }
-          box.height = Math.max(self.resizeOptions.minHeight || 0, startSize.y + (mouse.y - startMouse.y));
-
-          if (self.resizeOptions.aspectRatio) {
-            if (startAspect < 1)
-              box.height = box.width * startAspect;
-            else
-              box.width = box.height / startAspect;
-          }
-
-          self.setBounds(box, true);
-
-          if (typeof self.resizeOptions.resize == "function")
-            self.resizeOptions.resize.apply(self, [e]);
-
-          e.preventDefault();
-          e.stopPropagation();
-        };
-
-        // ___ mouseup
-        var handleMouseUp = function(e) {
-          iQ(gWindow)
-            .unbind('mousemove', handleMouseMove)
-            .unbind('mouseup', handleMouseUp);
-
-          if (typeof self.resizeOptions.stop == "function")
-            self.resizeOptions.stop.apply(self, [e]);
-
-          e.preventDefault();
-          e.stopPropagation();
-        };
-
-        // ___ handle + mousedown
-        iQ('<div>')
-          .addClass('iq-resizable-handle iq-resizable-se')
-          .appendTo($container)
-          .mousedown(function(e) {
-            if (!Utils.isLeftClick(e))
-              return;
-
-            startMouse = new Point(e.pageX, e.pageY);
-            startSize = self.getBounds().size();
-            startAspect = startSize.y / startSize.x;
-
-            if (typeof self.resizeOptions.start == "function")
-              self.resizeOptions.start.apply(self, [e]);
-
-            iQ(gWindow)
-              .mousemove(handleMouseMove)
-              .mouseup(handleMouseUp);
-
-            e.preventDefault();
-            e.stopPropagation();
-          });
-        }
-    } catch(e) {
-      Utils.log(e);
-    }
-  }
-};
-
-// ##########
-// Class: Items
-// Keeps track of all Items.
-var Items = {
-  // ----------
-  // Function: toString
-  // Prints [Items] for debug use
-  toString: function Items_toString() {
-    return "[Items]";
-  },
-
-  // ----------
-  // Variable: defaultGutter
-  // How far apart Items should be from each other and from bounds
-  defaultGutter: 15,
-
-  // ----------
-  // Function: item
-  // Given a DOM element representing an Item, returns the Item.
-  item: function Items_item(el) {
-    return iQ(el).data('item');
-  },
-
-  // ----------
-  // Function: getTopLevelItems
-  // Returns an array of all Items not grouped into groupItems.
-  getTopLevelItems: function Items_getTopLevelItems() {
-    var items = [];
-
-    iQ('.tab, .groupItem').each(function(elem) {
-      var $this = iQ(elem);
-      var item = $this.data('item');
-      if (item && !item.parent && !$this.hasClass('phantom'))
-        items.push(item);
-    });
-
-    return items;
-  },
-
-  // ----------
-  // Function: getPageBounds
-  // Returns a <Rect> defining the area of the page <Item>s should stay within.
-  getPageBounds: function Items_getPageBounds() {
-    var width = Math.max(100, window.innerWidth);
-    var height = Math.max(100, window.innerHeight);
-    return new Rect(0, 0, width, height);
-  },
-
-  // ----------
-  // Function: getSafeWindowBounds
-  // Returns the bounds within which it is safe to place all non-stationary <Item>s.
-  getSafeWindowBounds: function Items_getSafeWindowBounds() {
-    // the safe bounds that would keep it "in the window"
-    var gutter = Items.defaultGutter;
-    // Here, I've set the top gutter separately, as the top of the window has its own
-    // extra chrome which makes a large top gutter unnecessary.
-    // TODO: set top gutter separately, elsewhere.
-    var topGutter = 5;
-    return new Rect(gutter, topGutter,
-        window.innerWidth - 2 * gutter, window.innerHeight - gutter - topGutter);
-
-  },
-
-  // ----------
-  // Function: arrange
-  // Arranges the given items in a grid within the given bounds,
-  // maximizing item size but maintaining standard tab aspect ratio for each
-  //
-  // Parameters:
-  //   items - an array of <Item>s. Can be null, in which case we won't
-  //     actually move anything.
-  //   bounds - a <Rect> defining the space to arrange within
-  //   options - an object with various properites (see below)
-  //
-  // Possible "options" properties:
-  //   animate - whether to animate; default: true.
-  //   z - the z index to set all the items; default: don't change z.
-  //   return - if set to 'widthAndColumns', it'll return an object with the
-  //     width of children and the columns.
-  //   count - overrides the item count for layout purposes;
-  //     default: the actual item count
-  //   columns - (int) a preset number of columns to use
-  //   dropPos - a <Point> which should have a one-tab space left open, used
-  //             when a tab is dragged over.
-  //
-  // Returns:
-  //   By default, an object with three properties: `rects`, the list of <Rect>s,
-  //   `dropIndex`, the index which a dragged tab should have if dropped
-  //   (null if no `dropPos` was specified), and the number of columns (`columns`).
-  //   If the `return` option is set to 'widthAndColumns', an object with the
-  //   width value of the child items (`childWidth`) and the number of columns
-  //   (`columns`) is returned.
-  arrange: function Items_arrange(items, bounds, options) {
-    if (!options)
-      options = {};
-    var animate = "animate" in options ? options.animate : true;
-    var immediately = !animate;
-
-    var rects = [];
-
-    var count = options.count || (items ? items.length : 0);
-    if (options.addTab)
-      count++;
-    if (!count) {
-      let dropIndex = (Utils.isPoint(options.dropPos)) ? 0 : null;
-      return {rects: rects, dropIndex: dropIndex};
-    }
-
-    var columns = options.columns || 1;
-    // We'll assume for the time being that all the items have the same styling
-    // and that the margin is the same width around.
-    var itemMargin = items && items.length ?
-                       parseInt(iQ(items[0].container).css('margin-left')) : 0;
-    var padding = itemMargin * 2;
-    var rows;
-    var tabWidth;
-    var tabHeight;
-    var totalHeight;
-
-    function figure() {
-      rows = Math.ceil(count / columns);
-      let validSize = TabItems.calcValidSize(
-        new Point((bounds.width - (padding * columns)) / columns, -1),
-        options);
-      tabWidth = validSize.x;
-      tabHeight = validSize.y;
-
-      totalHeight = (tabHeight * rows) + (padding * rows);    
-    }
-
-    figure();
-
-    while (rows > 1 && totalHeight > bounds.height) {
-      columns++;
-      figure();
-    }
-
-    if (rows == 1) {
-      let validSize = TabItems.calcValidSize(new Point(tabWidth,
-        bounds.height - 2 * itemMargin), options);
-      tabWidth = validSize.x;
-      tabHeight = validSize.y;
-    }
-    
-    if (options.return == 'widthAndColumns')
-      return {childWidth: tabWidth, columns: columns};
-
-    let initialOffset = 0;
-    if (UI.rtl) {
-      initialOffset = bounds.width - tabWidth - padding;
-    }
-    var box = new Rect(bounds.left + initialOffset, bounds.top, tabWidth, tabHeight);
-
-    var column = 0;
-
-    var dropIndex = false;
-    var dropRect = false;
-    if (Utils.isPoint(options.dropPos))
-      dropRect = new Rect(options.dropPos.x, options.dropPos.y, 1, 1);
-    for (let a = 0; a < count; a++) {
-      // If we had a dropPos, see if this is where we should place it
-      if (dropRect) {
-        let activeBox = new Rect(box);
-        activeBox.inset(-itemMargin - 1, -itemMargin - 1);
-        // if the designated position (dropRect) is within the active box,
-        // this is where, if we drop the tab being dragged, it should land!
-        if (activeBox.contains(dropRect))
-          dropIndex = a;
-      }
-      
-      // record the box.
-      rects.push(new Rect(box));
-
-      box.left += (UI.rtl ? -1 : 1) * (box.width + padding);
-      column++;
-      if (column == columns) {
-        box.left = bounds.left + initialOffset;
-        box.top += box.height + padding;
-        column = 0;
-      }
-    }
-
-    return {rects: rects, dropIndex: dropIndex, columns: columns};
-  },
-
-  // ----------
-  // Function: unsquish
-  // Checks to see which items can now be unsquished.
-  //
-  // Parameters:
-  //   pairs - an array of objects, each with two properties: item and bounds. The bounds are
-  //     modified as appropriate, but the items are not changed. If pairs is null, the
-  //     operation is performed directly on all of the top level items.
-  //   ignore - an <Item> to not include in calculations (because it's about to be closed, for instance)
-  unsquish: function Items_unsquish(pairs, ignore) {
-    var pairsProvided = (pairs ? true : false);
-    if (!pairsProvided) {
-      var items = Items.getTopLevelItems();
-      pairs = [];
-      items.forEach(function(item) {
-        pairs.push({
-          item: item,
-          bounds: item.getBounds()
-        });
-      });
-    }
-
-    var pageBounds = Items.getSafeWindowBounds();
-    pairs.forEach(function(pair) {
-      var item = pair.item;
-      if (item == ignore)
-        return;
-
-      var bounds = pair.bounds;
-      var newBounds = new Rect(bounds);
-
-      var newSize;
-      if (Utils.isPoint(item.userSize))
-        newSize = new Point(item.userSize);
-      else if (item.isAGroupItem)
-        newSize = GroupItems.calcValidSize(
-          new Point(GroupItems.minGroupWidth, -1));
-      else
-        newSize = TabItems.calcValidSize(
-          new Point(TabItems.tabWidth, -1));
-
-      if (item.isAGroupItem) {
-          newBounds.width = Math.max(newBounds.width, newSize.x);
-          newBounds.height = Math.max(newBounds.height, newSize.y);
-      } else {
-        if (bounds.width < newSize.x) {
-          newBounds.width = newSize.x;
-          newBounds.height = newSize.y;
-        }
-      }
-
-      newBounds.left -= (newBounds.width - bounds.width) / 2;
-      newBounds.top -= (newBounds.height - bounds.height) / 2;
-
-      var offset = new Point();
-      if (newBounds.left < pageBounds.left)
-        offset.x = pageBounds.left - newBounds.left;
-      else if (newBounds.right > pageBounds.right)
-        offset.x = pageBounds.right - newBounds.right;
-
-      if (newBounds.top < pageBounds.top)
-        offset.y = pageBounds.top - newBounds.top;
-      else if (newBounds.bottom > pageBounds.bottom)
-        offset.y = pageBounds.bottom - newBounds.bottom;
-
-      newBounds.offset(offset);
-
-      if (!bounds.equals(newBounds)) {
-        var blocked = false;
-        pairs.forEach(function(pair2) {
-          if (pair2 == pair || pair2.item == ignore)
-            return;
-
-          var bounds2 = pair2.bounds;
-          if (bounds2.intersects(newBounds))
-            blocked = true;
-          return;
-        });
-
-        if (!blocked) {
-          pair.bounds.copy(newBounds);
-        }
-      }
-      return;
-    });
-
-    if (!pairsProvided) {
-      pairs.forEach(function(pair) {
-        pair.item.setBounds(pair.bounds);
-      });
-    }
-  }
-};
deleted file mode 100644
--- a/browser/components/tabview/jar.mn
+++ /dev/null
@@ -1,9 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-browser.jar:
-        content/browser/tabview.css
-*       content/browser/tabview.js
-        content/browser/tabview.html
-        content/browser/tabview-content.js (content.js)
deleted file mode 100644
--- a/browser/components/tabview/modules/utils.jsm
+++ /dev/null
@@ -1,831 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-// **********
-// Title: utils.js
-
-this.EXPORTED_SYMBOLS = ["Point", "Rect", "Range", "Subscribable", "Utils", "MRUList"];
-
-// #########
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-// ##########
-// Class: Point
-// A simple point.
-//
-// Constructor: Point
-// If a is a Point, creates a copy of it. Otherwise, expects a to be x,
-// and creates a Point with it along with y. If either a or y are omitted,
-// 0 is used in their place.
-this.Point = function Point(a, y) {
-  if (Utils.isPoint(a)) {
-    this.x = a.x;
-    this.y = a.y;
-  } else {
-    this.x = (Utils.isNumber(a) ? a : 0);
-    this.y = (Utils.isNumber(y) ? y : 0);
-  }
-};
-
-Point.prototype = {
-  // ----------
-  // Function: toString
-  // Prints [Point (x,y)] for debug use
-  toString: function Point_toString() {
-    return "[Point (" + this.x + "," + this.y + ")]";
-  },
-
-  // ----------
-  // Function: distance
-  // Returns the distance from this point to the given <Point>.
-  distance: function Point_distance(point) {
-    var ax = this.x - point.x;
-    var ay = this.y - point.y;
-    return Math.sqrt((ax * ax) + (ay * ay));
-  }
-};
-
-// ##########
-// Class: Rect
-// A simple rectangle. Note that in addition to the left and width, it also has
-// a right property; changing one affects the others appropriately. Same for the
-// vertical properties.
-//
-// Constructor: Rect
-// If a is a Rect, creates a copy of it. Otherwise, expects a to be left,
-// and creates a Rect with it along with top, width, and height.
-this.Rect = function Rect(a, top, width, height) {
-  // Note: perhaps 'a' should really be called 'rectOrLeft'
-  if (Utils.isRect(a)) {
-    this.left = a.left;
-    this.top = a.top;
-    this.width = a.width;
-    this.height = a.height;
-  } else {
-    this.left = a;
-    this.top = top;
-    this.width = width;
-    this.height = height;
-  }
-};
-
-Rect.prototype = {
-  // ----------
-  // Function: toString
-  // Prints [Rect (left,top,width,height)] for debug use
-  toString: function Rect_toString() {
-    return "[Rect (" + this.left + "," + this.top + "," +
-            this.width + "," + this.height + ")]";
-  },
-
-  get right() {
-    return this.left + this.width;
-  },
-  set right(value) {
-    this.width = value - this.left;
-  },
-
-  get bottom() {
-    return this.top + this.height;
-  },
-  set bottom(value) {
-    this.height = value - this.top;
-  },
-
-  // ----------
-  // Variable: xRange
-  // Gives you a new <Range> for the horizontal dimension.
-  get xRange() {
-    return new Range(this.left, this.right);
-  },
-
-  // ----------
-  // Variable: yRange
-  // Gives you a new <Range> for the vertical dimension.
-  get yRange() {
-    return new Range(this.top, this.bottom);
-  },
-
-  // ----------
-  // Function: intersects
-  // Returns true if this rectangle intersects the given <Rect>.
-  intersects: function Rect_intersects(rect) {
-    return (rect.right > this.left &&
-            rect.left < this.right &&
-            rect.bottom > this.top &&
-            rect.top < this.bottom);
-  },
-
-  // ----------
-  // Function: intersection
-  // Returns a new <Rect> with the intersection of this rectangle and the give <Rect>,
-  // or null if they don't intersect.
-  intersection: function Rect_intersection(rect) {
-    var box = new Rect(Math.max(rect.left, this.left), Math.max(rect.top, this.top), 0, 0);
-    box.right = Math.min(rect.right, this.right);
-    box.bottom = Math.min(rect.bottom, this.bottom);
-    if (box.width > 0 && box.height > 0)
-      return box;
-
-    return null;
-  },
-
-  // ----------
-  // Function: contains
-  // Returns a boolean denoting if the <Rect> or <Point> is contained inside
-  // this rectangle.
-  //
-  // Parameters
-  //  - A <Rect> or a <Point>
-  contains: function Rect_contains(a) {
-    if (Utils.isPoint(a))
-      return (a.x > this.left &&
-              a.x < this.right &&
-              a.y > this.top &&
-              a.y < this.bottom);
-
-    return (a.left >= this.left &&
-            a.right <= this.right &&
-            a.top >= this.top &&
-            a.bottom <= this.bottom);
-  },
-
-  // ----------
-  // Function: center
-  // Returns a new <Point> with the center location of this rectangle.
-  center: function Rect_center() {
-    return new Point(this.left + (this.width / 2), this.top + (this.height / 2));
-  },
-
-  // ----------
-  // Function: size
-  // Returns a new <Point> with the dimensions of this rectangle.
-  size: function Rect_size() {
-    return new Point(this.width, this.height);
-  },
-
-  // ----------
-  // Function: position
-  // Returns a new <Point> with the top left of this rectangle.
-  position: function Rect_position() {
-    return new Point(this.left, this.top);
-  },
-
-  // ----------
-  // Function: area
-  // Returns the area of this rectangle.
-  area: function Rect_area() {
-    return this.width * this.height;
-  },
-
-  // ----------
-  // Function: inset
-  // Makes the rect smaller (if the arguments are positive) as if a margin is added all around
-  // the initial rect, with the margin widths (symmetric) being specified by the arguments.
-  //
-  // Paramaters
-  //  - A <Point> or two arguments: x and y
-  inset: function Rect_inset(a, b) {
-    if (Utils.isPoint(a)) {
-      b = a.y;
-      a = a.x;
-    }
-
-    this.left += a;
-    this.width -= a * 2;
-    this.top += b;
-    this.height -= b * 2;
-  },
-
-  // ----------
-  // Function: offset
-  // Moves (translates) the rect by the given vector.
-  //
-  // Paramaters
-  //  - A <Point> or two arguments: x and y
-  offset: function Rect_offset(a, b) {
-    if (Utils.isPoint(a)) {
-      this.left += a.x;
-      this.top += a.y;
-    } else {
-      this.left += a;
-      this.top += b;
-    }
-  },
-
-  // ----------
-  // Function: equals
-  // Returns true if this rectangle is identical to the given <Rect>.
-  equals: function Rect_equals(rect) {
-    return (rect.left == this.left &&
-            rect.top == this.top &&
-            rect.width == this.width &&
-            rect.height == this.height);
-  },
-
-  // ----------
-  // Function: union
-  // Returns a new <Rect> with the union of this rectangle and the given <Rect>.
-  union: function Rect_union(a) {
-    var newLeft = Math.min(a.left, this.left);
-    var newTop = Math.min(a.top, this.top);
-    var newWidth = Math.max(a.right, this.right) - newLeft;
-    var newHeight = Math.max(a.bottom, this.bottom) - newTop;
-    var newRect = new Rect(newLeft, newTop, newWidth, newHeight);
-
-    return newRect;
-  },
-
-  // ----------
-  // Function: copy
-  // Copies the values of the given <Rect> into this rectangle.
-  copy: function Rect_copy(a) {
-    this.left = a.left;
-    this.top = a.top;
-    this.width = a.width;
-    this.height = a.height;
-  }
-};
-
-// ##########
-// Class: Range
-// A physical interval, with a min and max.
-//
-// Constructor: Range
-// Creates a Range with the given min and max
-this.Range = function Range(min, max) {
-  if (Utils.isRange(min) && !max) { // if the one variable given is a range, copy it.
-    this.min = min.min;
-    this.max = min.max;
-  } else {
-    this.min = min || 0;
-    this.max = max || 0;
-  }
-};
-
-Range.prototype = {
-  // ----------
-  // Function: toString
-  // Prints [Range (min,max)] for debug use
-  toString: function Range_toString() {
-    return "[Range (" + this.min + "," + this.max + ")]";
-  },
-
-  // Variable: extent
-  // Equivalent to max-min
-  get extent() {
-    return (this.max - this.min);
-  },
-
-  set extent(extent) {
-    this.max = extent - this.min;
-  },
-
-  // ----------
-  // Function: contains
-  // Whether the <Range> contains the given <Range> or value or not.
-  //
-  // Parameters
-  //  - a number or <Range>
-  contains: function Range_contains(value) {
-    if (Utils.isNumber(value))
-      return value >= this.min && value <= this.max;
-    if (Utils.isRange(value))
-      return value.min >= this.min && value.max <= this.max;
-    return false;
-  },
-
-  // ----------
-  // Function: overlaps
-  // Whether the <Range> overlaps with the given <Range> value or not.
-  //
-  // Parameters
-  //  - a number or <Range>
-  overlaps: function Range_overlaps(value) {
-    if (Utils.isNumber(value))
-      return this.contains(value);
-    if (Utils.isRange(value))
-      return !(value.max < this.min || this.max < value.min);
-    return false;
-  },
-
-  // ----------
-  // Function: proportion
-  // Maps the given value to the range [0,1], so that it returns 0 if the value is <= the min,
-  // returns 1 if the value >= the max, and returns an interpolated "proportion" in (min, max).
-  //
-  // Parameters
-  //  - a number
-  //  - (bool) smooth? If true, a smooth tanh-based function will be used instead of the linear.
-  proportion: function Range_proportion(value, smooth) {
-    if (value <= this.min)
-      return 0;
-    if (this.max <= value)
-      return 1;
-
-    var proportion = (value - this.min) / this.extent;
-
-    if (smooth) {
-      // The ease function ".5+.5*Math.tanh(4*x-2)" is a pretty
-      // little graph. It goes from near 0 at x=0 to near 1 at x=1
-      // smoothly and beautifully.
-      // http://www.wolframalpha.com/input/?i=.5+%2B+.5+*+tanh%28%284+*+x%29+-+2%29
-      let tanh = function tanh(x) {
-        var e = Math.exp(x);
-        return (e - 1/e) / (e + 1/e);
-      };
-
-      return .5 - .5 * tanh(2 - 4 * proportion);
-    }
-
-    return proportion;
-  },
-
-  // ----------
-  // Function: scale
-  // Takes the given value in [0,1] and maps it to the associated value on the Range.
-  //
-  // Parameters
-  //  - a number in [0,1]
-  scale: function Range_scale(value) {
-    if (value > 1)
-      value = 1;
-    if (value < 0)
-      value = 0;
-    return this.min + this.extent * value;
-  }
-};
-
-// ##########
-// Class: Subscribable
-// A mix-in for allowing objects to collect subscribers for custom events.
-this.Subscribable = function Subscribable() {
-  this.subscribers = null;
-};
-
-Subscribable.prototype = {
-  // ----------
-  // Function: addSubscriber
-  // The given callback will be called when the Subscribable fires the given event.
-  addSubscriber: function Subscribable_addSubscriber(eventName, callback) {
-    try {
-      Utils.assertThrow(typeof callback == "function", "callback must be a function");
-      Utils.assertThrow(eventName && typeof eventName == "string",
-          "eventName must be a non-empty string");
-    } catch(e) {
-      Utils.log(e);
-      return;
-    }
-
-    if (!this.subscribers)
-      this.subscribers = {};
-
-    if (!this.subscribers[eventName])
-      this.subscribers[eventName] = [];
-
-    let subscribers = this.subscribers[eventName];
-    if (subscribers.indexOf(callback) == -1)
-      subscribers.push(callback);
-  },
-
-  // ----------
-  // Function: removeSubscriber
-  // Removes the subscriber associated with the event for the given callback.
-  removeSubscriber: function Subscribable_removeSubscriber(eventName, callback) {
-    try {
-      Utils.assertThrow(typeof callback == "function", "callback must be a function");
-      Utils.assertThrow(eventName && typeof eventName == "string",
-          "eventName must be a non-empty string");
-    } catch(e) {
-      Utils.log(e);
-      return;
-    }
-
-    if (!this.subscribers || !this.subscribers[eventName])
-      return;
-
-    let subscribers = this.subscribers[eventName];
-    let index = subscribers.indexOf(callback);
-
-    if (index > -1)
-      subscribers.splice(index, 1);
-  },
-
-  // ----------
-  // Function: _sendToSubscribers
-  // Internal routine. Used by the Subscribable to fire events.
-  _sendToSubscribers: function Subscribable__sendToSubscribers(eventName, eventInfo) {
-    try {
-      Utils.assertThrow(eventName && typeof eventName == "string",
-          "eventName must be a non-empty string");
-    } catch(e) {
-      Utils.log(e);
-      return;
-    }
-
-    if (!this.subscribers || !this.subscribers[eventName])
-      return;
-
-    let subsCopy = this.subscribers[eventName].concat();
-    subsCopy.forEach(function (callback) {
-      try {
-        callback(this, eventInfo);
-      } catch(e) {
-        Utils.log(e);
-      }
-    }, this);
-  }
-};
-
-// ##########
-// Class: Utils
-// Singelton with common utility functions.
-this.Utils = {
-  // ----------
-  // Function: toString
-  // Prints [Utils] for debug use
-  toString: function Utils_toString() {
-    return "[Utils]";
-  },
-
-  // ___ Logging
-  useConsole: true, // as opposed to dump
-  showTime: false,
-
-  // ----------
-  // Function: log
-  // Prints the given arguments to the JavaScript error console as a message.
-  // Pass as many arguments as you want, it'll print them all.
-  log: function Utils_log() {
-    var text = this.expandArgumentsForLog(arguments);
-    var prefix = this.showTime ? Date.now() + ': ' : '';
-    if (this.useConsole)    
-      Services.console.logStringMessage(prefix + text);
-    else
-      dump(prefix + text + '\n');
-  },
-
-  // ----------
-  // Function: error
-  // Prints the given arguments to the JavaScript error console as an error.
-  // Pass as many arguments as you want, it'll print them all.
-  error: function Utils_error() {
-    var text = this.expandArgumentsForLog(arguments);
-    var prefix = this.showTime ? Date.now() + ': ' : '';
-    if (this.useConsole)    
-      Cu.reportError(prefix + "tabview error: " + text);
-    else
-      dump(prefix + "TABVIEW ERROR: " + text + '\n');
-  },
-
-  // ----------
-  // Function: trace
-  // Prints the given arguments to the JavaScript error console as a message,
-  // along with a full stack trace.
-  // Pass as many arguments as you want, it'll print them all.
-  trace: function Utils_trace() {
-    var text = this.expandArgumentsForLog(arguments);
-
-    // cut off the first line of the stack trace, because that's just this function.
-    let stack = Error().stack.split("\n").slice(1);
-
-    // if the caller was assert, cut out the line for the assert function as well.
-    if (stack[0].indexOf("Utils_assert(") == 0)
-      stack.splice(0, 1);
-
-    this.log('trace: ' + text + '\n' + stack.join("\n"));
-  },
-
-  // ----------
-  // Function: assert
-  // Prints a stack trace along with label (as a console message) if condition is false.
-  assert: function Utils_assert(condition, label) {
-    if (!condition) {
-      let text;
-      if (typeof label != 'string')
-        text = 'badly formed assert';
-      else
-        text = "tabview assert: " + label;
-
-      this.trace(text);
-    }
-  },
-
-  // ----------
-  // Function: assertThrow
-  // Throws label as an exception if condition is false.
-  assertThrow: function Utils_assertThrow(condition, label) {
-    if (!condition) {
-      let text;
-      if (typeof label != 'string')
-        text = 'badly formed assert';
-      else
-        text = "tabview assert: " + label;
-
-      // cut off the first line of the stack trace, because that's just this function.
-      let stack = Error().stack.split("\n").slice(1);
-
-      throw text + "\n" + stack.join("\n");
-    }
-  },
-
-  // ----------
-  // Function: expandObject
-  // Prints the given object to a string, including all of its properties.
-  expandObject: function Utils_expandObject(obj) {
-    var s = obj + ' = {';
-    for (let prop in obj) {
-      let value;
-      try {
-        value = obj[prop];
-      } catch(e) {
-        value = '[!!error retrieving property]';
-      }
-
-      s += prop + ': ';
-      if (typeof value == 'string')
-        s += '\'' + value + '\'';
-      else if (typeof value == 'function')
-        s += 'function';
-      else
-        s += value;
-
-      s += ', ';
-    }
-    return s + '}';
-  },
-
-  // ----------
-  // Function: expandArgumentsForLog
-  // Expands all of the given args (an array) into a single string.
-  expandArgumentsForLog: function Utils_expandArgumentsForLog(args) {
-    var that = this;
-    return Array.map(args, function(arg) {
-      return typeof arg == 'object' ? that.expandObject(arg) : arg;
-    }).join('; ');
-  },
-
-  // ___ Misc
-
-  // ----------
-  // Function: isLeftClick
-  // Given a DOM mouse event, returns true if it was for the left mouse button.
-  isLeftClick: function Utils_isLeftClick(event) {
-    return event.button == 0;
-  },
-
-  // ----------
-  // Function: isMiddleClick
-  // Given a DOM mouse event, returns true if it was for the middle mouse button.
-  isMiddleClick: function Utils_isMiddleClick(event) {
-    return event.button == 1;
-  },
-
-  // ----------
-  // Function: isRightClick
-  // Given a DOM mouse event, returns true if it was for the right mouse button.
-  isRightClick: function Utils_isRightClick(event) {
-    return event.button == 2;
-  },
-
-  // ----------
-  // Function: isDOMElement
-  // Returns true if the given object is a DOM element.
-  isDOMElement: function Utils_isDOMElement(object) {
-    return object instanceof Ci.nsIDOMElement;
-  },
-
-  // ----------
-  // Function: isValidXULTab
-  // A xulTab is valid if it has not been closed,
-  // and it has not been removed from the DOM
-  // Returns true if the tab is valid.
-  isValidXULTab: function Utils_isValidXULTab(xulTab) {
-    return !xulTab.closing && xulTab.parentNode;
-  },
-
-  // ----------
-  // Function: isNumber
-  // Returns true if the argument is a valid number.
-  isNumber: function Utils_isNumber(n) {
-    return typeof n == 'number' && !isNaN(n);
-  },
-
-  // ----------
-  // Function: isRect
-  // Returns true if the given object (r) looks like a <Rect>.
-  isRect: function Utils_isRect(r) {
-    return (r &&
-            this.isNumber(r.left) &&
-            this.isNumber(r.top) &&
-            this.isNumber(r.width) &&
-            this.isNumber(r.height));
-  },
-
-  // ----------
-  // Function: isRange
-  // Returns true if the given object (r) looks like a <Range>.
-  isRange: function Utils_isRange(r) {
-    return (r &&
-            this.isNumber(r.min) &&
-            this.isNumber(r.max));
-  },
-
-  // ----------
-  // Function: isPoint
-  // Returns true if the given object (p) looks like a <Point>.
-  isPoint: function Utils_isPoint(p) {
-    return (p && this.isNumber(p.x) && this.isNumber(p.y));
-  },
-
-  // ----------
-  // Function: isPlainObject
-  // Check to see if an object is a plain object (created using "{}" or "new Object").
-  isPlainObject: function Utils_isPlainObject(obj) {
-    // Must be an Object.
-    // Make sure that DOM nodes and window objects don't pass through, as well
-    if (!obj || Object.prototype.toString.call(obj) !== "[object Object]" ||
-       obj.nodeType || obj.setInterval) {
-      return false;
-    }
-
-    // Not own constructor property must be Object
-    const hasOwnProperty = Object.prototype.hasOwnProperty;
-
-    if (obj.constructor &&
-       !hasOwnProperty.call(obj, "constructor") &&
-       !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf")) {
-      return false;
-    }
-
-    // Own properties are enumerated firstly, so to speed up,
-    // if last one is own, then all properties are own.
-
-    var key;
-    for (key in obj) {}
-
-    return key === undefined || hasOwnProperty.call(obj, key);
-  },
-
-  // ----------
-  // Function: isEmptyObject
-  // Returns true if the given object has no members.
-  isEmptyObject: function Utils_isEmptyObject(obj) {
-    for (let name in obj)
-      return false;
-    return true;
-  },
-
-  // ----------
-  // Function: copy
-  // Returns a copy of the argument. Note that this is a shallow copy; if the argument
-  // has properties that are themselves objects, those properties will be copied by reference.
-  copy: function Utils_copy(value) {
-    if (value && typeof value == 'object') {
-      if (Array.isArray(value))
-        return this.extend([], value);
-      return this.extend({}, value);
-    }
-    return value;
-  },
-
-  // ----------
-  // Function: merge
-  // Merge two array-like objects into the first and return it.
-  merge: function Utils_merge(first, second) {
-    Array.forEach(second, el => Array.push(first, el));
-    return first;
-  },
-
-  // ----------
-  // Function: extend
-  // Pass several objects in and it will combine them all into the first object and return it.
-  extend: function Utils_extend() {
-
-    // copy reference to target object
-    let target = arguments[0] || {};
-    // Deep copy is not supported
-    if (typeof target === "boolean") {
-      this.assert(false, "The first argument of extend cannot be a boolean." +
-          "Deep copy is not supported.");
-      return target;
-    }
-
-    // Back when this was in iQ + iQ.fn, so you could extend iQ objects with it.
-    // This is no longer supported.
-    let length = arguments.length;
-    if (length === 1) {
-      this.assert(false, "Extending the iQ prototype using extend is not supported.");
-      return target;
-    }
-
-    // Handle case when target is a string or something
-    if (typeof target != "object" && typeof target != "function") {
-      target = {};
-    }
-
-    for (let i = 1; i < length; i++) {
-      // Only deal with non-null/undefined values
-      let options = arguments[i];
-      if (options != null) {
-        // Extend the base object
-        for (let name in options) {
-          let copy = options[name];
-
-          // Prevent never-ending loop
-          if (target === copy)
-            continue;
-
-          if (copy !== undefined)
-            target[name] = copy;
-        }
-      }
-    }
-
-    // Return the modified object
-    return target;
-  },
-
-  // ----------
-  // Function: attempt
-  // Tries to execute a number of functions. Returns immediately the return
-  // value of the first non-failed function without executing successive
-  // functions, or null.
-  attempt: function Utils_attempt() {
-    let args = arguments;
-
-    for (let i = 0; i < args.length; i++) {
-      try {
-        return args[i]();
-      } catch (e) {}
-    }
-
-    return null;
-  }
-};
-
-// ##########
-// Class: MRUList
-// A most recently used list.
-//
-// Constructor: MRUList
-// If a is an array of entries, creates a copy of it.
-this.MRUList = function MRUList(a) {
-  if (Array.isArray(a))
-    this._list = a.concat();
-  else
-    this._list = [];
-};
-
-MRUList.prototype = {
-  // ----------
-  // Function: toString
-  // Prints [List (entry1, entry2, ...)] for debug use
-  toString: function MRUList_toString() {
-    return "[List (" + this._list.join(", ") + ")]";
-  },
-
-  // ----------
-  // Function: update
-  // Updates/inserts the given entry as the most recently used one in the list.
-  update: function MRUList_update(entry) {
-    this.remove(entry);
-    this._list.unshift(entry);
-  },
-
-  // ----------
-  // Function: remove
-  // Removes the given entry from the list.
-  remove: function MRUList_remove(entry) {
-    let index = this._list.indexOf(entry);
-    if (index > -1)
-      this._list.splice(index, 1);
-  },
-
-  // ----------
-  // Function: peek
-  // Returns the most recently used entry.  If a filter exists, gets the most 
-  // recently used entry which matches the filter.
-  peek: function MRUList_peek(filter) {
-    let match = null;
-    if (filter && typeof filter == "function")
-      this._list.some(function MRUList_peek_getEntry(entry) {
-        if (filter(entry)) {
-          match = entry
-          return true;
-        }
-        return false;
-      });
-    else 
-      match = this._list.length > 0 ? this._list[0] : null;
-
-    return match;
-  },
-};
-
deleted file mode 100644
--- a/browser/components/tabview/moz.build
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-EXTRA_JS_MODULES.tabview = ['modules/utils.jsm']
-BROWSER_CHROME_MANIFESTS += [
-    'test/browser.ini',
-]
-
-JAR_MANIFESTS += ['jar.mn']
-
-with Files('**'):
-    BUG_COMPONENT = ('Firefox', 'Panorama')
deleted file mode 100644
--- a/browser/components/tabview/search.js
+++ /dev/null
@@ -1,614 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* ******************************
- *
- * This file incorporates work from:
- * Quicksilver Score (qs_score):
- * http://rails-oceania.googlecode.com/svn/lachiecox/qs_score/trunk/qs_score.js
- * This incorporated work is covered by the following copyright and
- * permission notice:
- * Copyright 2008 Lachie Cox
- * Licensed under the MIT license.
- * http://jquery.org/license
- *
- *  ***************************** */
-
-// **********
-// Title: search.js
-// Implementation for the search functionality of Firefox Panorama.
-
-// ##########
-// Class: TabUtils
-//
-// A collection of helper functions for dealing with both <TabItem>s and
-// <xul:tab>s without having to worry which one is which.
-var TabUtils = {
-  // ----------
-  // Function: toString
-  // Prints [TabUtils] for debug use.
-  toString: function TabUtils_toString() {
-    return "[TabUtils]";
-  },
-
-  // ---------
-  // Function: nameOfTab
-  // Given a <TabItem> or a <xul:tab> returns the tab's name.
-  nameOf: function TabUtils_nameOf(tab) {
-    // We can have two types of tabs: A <TabItem> or a <xul:tab>
-    // because we have to deal with both tabs represented inside
-    // of active Panoramas as well as for windows in which
-    // Panorama has yet to be activated. We uses object sniffing to
-    // determine the type of tab and then returns its name.     
-    return tab.label != undefined ? tab.label : tab.$tabTitle[0].textContent;
-  },
-
-  // ---------
-  // Function: URLOf
-  // Given a <TabItem> or a <xul:tab> returns the URL of tab.
-  URLOf: function TabUtils_URLOf(tab) {
-    // Convert a <TabItem> to <xul:tab>
-    if ("tab" in tab)
-      tab = tab.tab;
-    return tab.linkedBrowser.currentURI.spec;
-  },
-
-  // ---------
-  // Function: faviconURLOf
-  // Given a <TabItem> or a <xul:tab> returns the URL of tab's favicon.
-  faviconURLOf: function TabUtils_faviconURLOf(tab) {
-    return tab.image != undefined ? tab.image : tab.$favImage[0].src;
-  },
-
-  // ---------
-  // Function: focus
-  // Given a <TabItem> or a <xul:tab>, focuses it and it's window.
-  focus: function TabUtils_focus(tab) {
-    // Convert a <TabItem> to a <xul:tab>
-    if ("tab" in tab)
-      tab = tab.tab;
-    tab.ownerDocument.defaultView.gBrowser.selectedTab = tab;
-    tab.ownerDocument.defaultView.focus();
-  }
-};
-
-// ##########
-// Class: TabMatcher
-//
-// A class that allows you to iterate over matching and not-matching tabs, 
-// given a case-insensitive search term.
-function TabMatcher(term) {
-  this.term = term;
-}
-
-TabMatcher.prototype = {
-  // ----------
-  // Function: toString
-  // Prints [TabMatcher (term)] for debug use.
-  toString: function TabMatcher_toString() {
-    return "[TabMatcher (" + this.term + ")]";
-  },
-
-  // ---------
-  // Function: _filterAndSortForMatches
-  // Given an array of <TabItem>s and <xul:tab>s returns a new array
-  // of tabs whose name matched the search term, sorted by lexical
-  // closeness.
-  _filterAndSortForMatches: function TabMatcher__filterAndSortForMatches(tabs) {
-    let self = this;
-    tabs = tabs.filter(function TabMatcher__filterAndSortForMatches_filter(tab) {
-      let name = TabUtils.nameOf(tab);
-      let url = TabUtils.URLOf(tab);
-      return name.match(new RegExp(self.term, "i")) || url.match(new RegExp(self.term, "i"));
-    });
-
-    tabs.sort(function TabMatcher__filterAndSortForMatches_sort(x, y) {
-      let yScore = self._scorePatternMatch(self.term, TabUtils.nameOf(y));
-      let xScore = self._scorePatternMatch(self.term, TabUtils.nameOf(x));
-      return yScore - xScore;
-    });
-
-    return tabs;
-  },
-
-  // ---------
-  // Function: _filterForUnmatches
-  // Given an array of <TabItem>s returns an unsorted array of tabs whose name
-  // does not match the the search term.
-  _filterForUnmatches: function TabMatcher__filterForUnmatches(tabs) {
-    let self = this;
-    return tabs.filter(function TabMatcher__filterForUnmatches_filter(tab) {
-      let name = tab.$tabTitle[0].textContent;
-      let url = TabUtils.URLOf(tab);
-      return !name.match(new RegExp(self.term, "i")) && !url.match(new RegExp(self.term, "i"));
-    });
-  },
-
-  // ---------
-  // Function: _getTabsForOtherWindows
-  // Returns an array of <TabItem>s and <xul:tabs>s representing tabs
-  // from all windows but the current window. <TabItem>s will be returned
-  // for windows in which Panorama has been activated at least once, while
-  // <xul:tab>s will be returned for windows in which Panorama has never
-  // been activated.
-  _getTabsForOtherWindows: function TabMatcher__getTabsForOtherWindows() {
-    let enumerator = Services.wm.getEnumerator("navigator:browser");
-    let allTabs = [];
-
-    while (enumerator.hasMoreElements()) {
-      let win = enumerator.getNext();
-      // This function gets tabs from other windows, not from the current window
-      if (win != gWindow)
-        allTabs.push.apply(allTabs, win.gBrowser.tabs);
-    }
-    return allTabs;
-  },
-
-  // ----------
-  // Function: matchedTabsFromOtherWindows
-  // Returns an array of <TabItem>s and <xul:tab>s that match the search term
-  // from all windows but the current window. <TabItem>s will be returned for
-  // windows in which Panorama has been activated at least once, while
-  // <xul:tab>s will be returned for windows in which Panorama has never
-  // been activated.
-  // (new TabMatcher("app")).matchedTabsFromOtherWindows();
-  matchedTabsFromOtherWindows: function TabMatcher_matchedTabsFromOtherWindows() {
-    if (this.term.length < 2)
-      return [];
-
-    let tabs = this._getTabsForOtherWindows();
-    return this._filterAndSortForMatches(tabs);
-  },
-
-  // ----------
-  // Function: matched
-  // Returns an array of <TabItem>s which match the current search term.
-  // If the term is less than 2 characters in length, it returns nothing.
-  matched: function TabMatcher_matched() {
-    if (this.term.length < 2)
-      return [];
-
-    let tabs = TabItems.getItems();
-    return this._filterAndSortForMatches(tabs);
-  },
-
-  // ----------
-  // Function: unmatched
-  // Returns all of <TabItem>s that .matched() doesn't return.
-  unmatched: function TabMatcher_unmatched() {
-    let tabs = TabItems.getItems();
-    if (this.term.length < 2)
-      return tabs;
-
-    return this._filterForUnmatches(tabs);
-  },
-
-  // ----------
-  // Function: doSearch
-  // Performs the search. Lets you provide three functions.
-  // The first is on all matched tabs in the window, the second on all unmatched
-  // tabs in the window, and the third on all matched tabs in other windows.
-  // The first two functions take two parameters: A <TabItem> and its integer index
-  // indicating the absolute rank of the <TabItem> in terms of match to
-  // the search term. The last function also takes two paramaters, but can be
-  // passed both <TabItem>s and <xul:tab>s and the index is offset by the
-  // number of matched tabs inside the window.
-  doSearch: function TabMatcher_doSearch(matchFunc, unmatchFunc, otherFunc) {
-    let matches = this.matched();
-    let unmatched = this.unmatched();
-    let otherMatches = this.matchedTabsFromOtherWindows();
-    
-    matches.forEach(function(tab, i) {
-      matchFunc(tab, i);
-    });
-
-    otherMatches.forEach(function(tab,i) {
-      otherFunc(tab, i+matches.length);
-    });
-
-    unmatched.forEach(function(tab, i) {
-      unmatchFunc(tab, i);
-    });
-  },
-
-  // ----------
-  // Function: _scorePatternMatch
-  // Given a pattern string, returns a score between 0 and 1 of how well
-  // that pattern matches the original string. It mimics the heuristics
-  // of the Mac application launcher Quicksilver.
-  _scorePatternMatch: function TabMatcher__scorePatternMatch(pattern, matched, offset) {
-    offset = offset || 0;
-    pattern = pattern.toLowerCase();
-    matched = matched.toLowerCase();
-
-    if (pattern.length == 0)
-      return 0.9;
-    if (pattern.length > matched.length)
-      return 0.0;
-
-    for (let i = pattern.length; i > 0; i--) {
-      let sub_pattern = pattern.substring(0,i);
-      let index = matched.indexOf(sub_pattern);
-
-      if (index < 0)
-        continue;
-      if (index + pattern.length > matched.length + offset)
-        continue;
-
-      let next_string = matched.substring(index+sub_pattern.length);
-      let next_pattern = null;
-
-      if (i >= pattern.length)
-        next_pattern = '';
-      else
-        next_pattern = pattern.substring(i);
-
-      let remaining_score = this._scorePatternMatch(next_pattern, next_string, offset + index);
-
-      if (remaining_score > 0) {
-        let score = matched.length-next_string.length;
-
-        if (index != 0) {
-          let c = matched.charCodeAt(index-1);
-          if (c == 32 || c == 9) {
-            for (let j = (index - 2); j >= 0; j--) {
-              c = matched.charCodeAt(j);
-              score -= ((c == 32 || c == 9) ? 1 : 0.15);
-            }
-          } else {
-            score -= index;
-          }
-        }
-
-        score += remaining_score * next_string.length;
-        score /= matched.length;
-        return score;
-      }
-    }
-    return 0.0;
-  }
-};
-
-// ##########
-// Class: TabHandlers
-// 
-// A object that handles all of the event handlers.
-var TabHandlers = {
-  _mouseDownLocation: null,
-
-  // ---------
-  // Function: onMatch
-  // Adds styles and event listeners to the matched tab items.
-  onMatch: function TabHandlers_onMatch(tab, index) {
-    tab.addClass("onTop");
-    index != 0 ? tab.addClass("notMainMatch") : tab.removeClass("notMainMatch");
-
-    // Remove any existing handlers before adding the new ones.
-    // If we don't do this, then we may add more handlers than
-    // we remove.
-    tab.$canvas
-      .unbind("mousedown", TabHandlers._hideHandler)
-      .unbind("mouseup", TabHandlers._showHandler);
-
-    tab.$canvas
-      .mousedown(TabHandlers._hideHandler)
-      .mouseup(TabHandlers._showHandler);
-  },
-
-  // ---------
-  // Function: onUnmatch
-  // Removes styles and event listeners from the unmatched tab items.
-  onUnmatch: function TabHandlers_onUnmatch(tab, index) {
-    tab.$container.removeClass("onTop");
-    tab.removeClass("notMainMatch");
-
-    tab.$canvas
-      .unbind("mousedown", TabHandlers._hideHandler)
-      .unbind("mouseup", TabHandlers._showHandler);
-  },
-
-  // ---------
-  // Function: onOther
-  // Removes styles and event listeners from the unmatched tabs.
-  onOther: function TabHandlers_onOther(tab, index) {
-    // Unlike the other on* functions, in this function tab can
-    // either be a <TabItem> or a <xul:tab>. In other functions
-    // it is always a <TabItem>. Also note that index is offset
-    // by the number of matches within the window.
-    let item = iQ("<div/>")
-      .addClass("inlineMatch")
-      .click(function TabHandlers_onOther_click(event) {
-        Search.hide(event);
-        TabUtils.focus(tab);
-      });
-
-    iQ("<img/>")
-      .attr("src", TabUtils.faviconURLOf(tab))
-      .appendTo(item);
-
-    iQ("<span/>")
-      .text(TabUtils.nameOf(tab))
-      .appendTo(item);
-
-    index != 0 ? item.addClass("notMainMatch") : item.removeClass("notMainMatch");
-    item.appendTo("#results");
-    iQ("#otherresults").show();
-  },
-
-  // ---------
-  // Function: _hideHandler
-  // Performs when mouse down on a canvas of tab item.
-  _hideHandler: function TabHandlers_hideHandler(event) {
-    iQ("#search").fadeOut();
-    iQ("#searchshade").fadeOut();
-    TabHandlers._mouseDownLocation = {x:event.clientX, y:event.clientY};
-  },
-
-  // ---------
-  // Function: _showHandler
-  // Performs when mouse up on a canvas of tab item.
-  _showHandler: function TabHandlers_showHandler(event) {
-    // If the user clicks on a tab without moving the mouse then
-    // they are zooming into the tab and we need to exit search
-    // mode.
-    if (TabHandlers._mouseDownLocation.x == event.clientX &&
-        TabHandlers._mouseDownLocation.y == event.clientY) {
-      Search.hide();
-      return;
-    }
-
-    iQ("#searchshade").show();
-    iQ("#search").show();
-    iQ("#searchbox")[0].focus();
-    // Marshal the search.
-    setTimeout(Search.perform, 0);
-  }
-};
-
-// ##########
-// Class: Search
-// 
-// A object that handles the search feature.
-var Search = {
-  _initiatedBy: "",
-  _blockClick: false,
-  _currentHandler: null,
-
-  // ----------
-  // Function: toString
-  // Prints [Search] for debug use.
-  toString: function Search_toString() {
-    return "[Search]";
-  },
-
-  // ----------
-  // Function: init
-  // Initializes the searchbox to be focused, and everything else to be hidden,
-  // and to have everything have the appropriate event handlers.
-  init: function Search_init() {
-    let self = this;
-
-    iQ("#search").hide();
-    iQ("#searchshade").hide().mousedown(function Search_init_shade_mousedown(event) {
-      if (event.target.id != "searchbox" && !self._blockClick)
-        self.hide();
-    });
-
-    iQ("#searchbox").keyup(function Search_init_box_keyup() {
-      self.perform();
-    })
-    .attr("title", tabviewString("button.searchTabs"));
-
-    iQ("#searchbutton").mousedown(function Search_init_button_mousedown() {
-      self._initiatedBy = "buttonclick";
-      self.ensureShown();
-      self.switchToInMode();
-    })
-    .attr("title", tabviewString("button.searchTabs"));
-
-    window.addEventListener("focus", function Search_init_window_focus() {
-      if (self.isEnabled()) {
-        self._blockClick = true;
-        setTimeout(function() {
-          self._blockClick = false;
-        }, 0);
-      }
-    }, false);
-
-    this.switchToBeforeMode();
-  },
-
-  // ----------
-  // Function: _beforeSearchKeyHandler
-  // Handles all keydown before the search interface is brought up.
-  _beforeSearchKeyHandler: function Search__beforeSearchKeyHandler(event) {
-    // Only match reasonable text-like characters for quick search.
-    if (event.altKey || event.ctrlKey || event.metaKey)
-      return;
-
-    if ((event.keyCode > 0 && event.keyCode <= event.DOM_VK_DELETE) ||
-        event.keyCode == event.DOM_VK_CONTEXT_MENU ||
-        event.keyCode == event.DOM_VK_SLEEP ||
-        (event.keyCode >= event.DOM_VK_F1 &&
-         event.keyCode <= event.DOM_VK_SCROLL_LOCK) ||
-        event.keyCode == event.DOM_VK_META ||
-        event.keyCode == 91 || // 91 = left windows key
-        event.keyCode == 92 || // 92 = right windows key
-        (!event.keyCode && !event.charCode)) {
-      return;
-    }
-
-    // If we are already in an input field, allow typing as normal.
-    if (event.target.nodeName == "INPUT")
-      return;
-
-    // / is used to activate the search feature so the key shouldn't be entered 
-    // into the search box.
-    if (event.keyCode == KeyEvent.DOM_VK_SLASH) {
-      event.stopPropagation();
-      event.preventDefault();
-    }
-
-    this.switchToInMode();
-    this._initiatedBy = "keydown";
-    this.ensureShown(true);
-  },
-
-  // ----------
-  // Function: _inSearchKeyHandler
-  // Handles all keydown while search mode.
-  _inSearchKeyHandler: function Search__inSearchKeyHandler(event) {
-    let term = iQ("#searchbox").val();
-    if ((event.keyCode == event.DOM_VK_ESCAPE) ||
-        (event.keyCode == event.DOM_VK_BACK_SPACE && term.length <= 1 &&
-         this._initiatedBy == "keydown")) {
-      this.hide(event);
-      return;
-    }
-
-    let matcher = this.createSearchTabMatcher();
-    let matches = matcher.matched();
-    let others =  matcher.matchedTabsFromOtherWindows();
-    if (event.keyCode == event.DOM_VK_RETURN &&
-        (matches.length > 0 || others.length > 0)) {
-      this.hide(event);
-      if (matches.length > 0) 
-        matches[0].zoomIn();
-      else
-        TabUtils.focus(others[0]);
-    }
-  },
-
-  // ----------
-  // Function: switchToBeforeMode
-  // Make sure the event handlers are appropriate for the before-search mode.
-  switchToBeforeMode: function Search_switchToBeforeMode() {
-    let self = this;
-    if (this._currentHandler)
-      iQ(window).unbind("keydown", this._currentHandler);
-    this._currentHandler = function Search_switchToBeforeMode_handler(event) {
-      self._beforeSearchKeyHandler(event);
-    }
-    iQ(window).keydown(this._currentHandler);
-  },
-
-  // ----------
-  // Function: switchToInMode
-  // Make sure the event handlers are appropriate for the in-search mode.
-  switchToInMode: function Search_switchToInMode() {
-    let self = this;
-    if (this._currentHandler)
-      iQ(window).unbind("keydown", this._currentHandler);
-    this._currentHandler = function Search_switchToInMode_handler(event) {
-      self._inSearchKeyHandler(event);
-    }
-    iQ(window).keydown(this._currentHandler);
-  },
-
-  createSearchTabMatcher: function Search_createSearchTabMatcher() {
-    return new TabMatcher(iQ("#searchbox").val());
-  },
-
-  // ----------
-  // Function: isEnabled
-  // Checks whether search mode is enabled or not.
-  isEnabled: function Search_isEnabled() {
-    return iQ("#search").css("display") != "none";
-  },
-
-  // ----------
-  // Function: hide
-  // Hides search mode.
-  hide: function Search_hide(event) {
-    if (!this.isEnabled())
-      return;
-
-    iQ("#searchbox").val("");
-    iQ("#searchshade").hide();
-    iQ("#search").hide();
-
-    iQ("#searchbutton").css({ opacity:.8 });
-
-    if (AppConstants.platform == "macosx")
-      UI.setTitlebarColors(true);
-
-    this.perform();
-    this.switchToBeforeMode();
-
-    if (event) {
-      // when hiding the search mode, we need to prevent the keypress handler
-      // in UI__setTabViewFrameKeyHandlers to handle the key press again. e.g. Esc
-      // which is already handled by the key down in this class.
-      if (event.type == "keydown")
-        UI.ignoreKeypressForSearch = true;
-      event.preventDefault();
-      event.stopPropagation();
-    }
-
-    // Return focus to the tab window
-    UI.blurAll();
-    gTabViewFrame.contentWindow.focus();
-
-    let newEvent = document.createEvent("Events");
-    newEvent.initEvent("tabviewsearchdisabled", false, false);
-    dispatchEvent(newEvent);
-  },
-
-  // ----------
-  // Function: perform
-  // Performs a search.
-  perform: function Search_perform() {
-    let matcher =  this.createSearchTabMatcher();
-
-    // Remove any previous other-window search results and
-    // hide the display area.
-    iQ("#results").empty();
-    iQ("#otherresults").hide();
-    iQ("#otherresults>.label").text(tabviewString("search.otherWindowTabs"));
-
-    matcher.doSearch(TabHandlers.onMatch, TabHandlers.onUnmatch, TabHandlers.onOther);
-  },
-
-  // ----------
-  // Function: ensureShown
-  // Ensures the search feature is displayed.  If not, display it.
-  // Parameters:
-  //  - a boolean indicates whether this is triggered by a keypress or not
-  ensureShown: function Search_ensureShown(activatedByKeypress) {
-    let $search = iQ("#search");
-    let $searchShade = iQ("#searchshade");
-    let $searchbox = iQ("#searchbox");
-    iQ("#searchbutton").css({ opacity: 1 });
-
-    // NOTE: when this function is called by keydown handler, next keypress
-    // event or composition events of IME will be fired on the focused editor.
-    function dispatchTabViewSearchEnabledEvent() {
-      let newEvent = document.createEvent("Events");
-      newEvent.initEvent("tabviewsearchenabled", false, false);
-      dispatchEvent(newEvent);
-    };
-
-    if (!this.isEnabled()) {
-      $searchShade.show();
-      $search.show();
-
-      if (AppConstants.platform == "macosx")
-        UI.setTitlebarColors({active: "#717171", inactive: "#EDEDED"});
-
-      if (activatedByKeypress) {
-        // set the focus so key strokes are entered into the textbox.
-        $searchbox[0].focus();
-        dispatchTabViewSearchEnabledEvent();
-      } else {
-        // marshal the focusing, otherwise it ends up with searchbox[0].focus gets
-        // called before the search button gets the focus after being pressed.
-        setTimeout(function setFocusAndDispatchSearchEnabledEvent() {
-          $searchbox[0].focus();
-          dispatchTabViewSearchEnabledEvent();
-        }, 0);
-      }
-    }
-  }
-};
-
deleted file mode 100644
--- a/browser/components/tabview/storage.js
+++ /dev/null
@@ -1,201 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// **********
-// Title: storage.js
-
-// ##########
-// Class: Storage
-// Singleton for permanent storage of TabView data.
-var Storage = {
-  GROUP_DATA_IDENTIFIER: "tabview-group",
-  GROUPS_DATA_IDENTIFIER: "tabview-groups",
-  TAB_DATA_IDENTIFIER: "tabview-tab",
-  UI_DATA_IDENTIFIER: "tabview-ui",
-
-  // ----------
-  // Function: toString
-  // Prints [Storage] for debug use
-  toString: function Storage_toString() {
-    return "[Storage]";
-  },
-
-  // ----------
-  // Function: init
-  // Sets up the object.
-  init: function Storage_init() {
-    this._sessionStore =
-      Cc["@mozilla.org/browser/sessionstore;1"].
-        getService(Ci.nsISessionStore);
-  },
-
-  // ----------
-  // Function: uninit
-  uninit: function Storage_uninit () {
-    this._sessionStore = null;
-  },
-
-  // ----------
-  // Function: saveTab
-  // Saves the data for a single tab.
-  saveTab: function Storage_saveTab(tab, data) {
-    Utils.assert(tab, "tab");
-
-    this._sessionStore.setTabValue(tab, this.TAB_DATA_IDENTIFIER,
-      JSON.stringify(data));
-  },
-
-  // ----------
-  // Function: getTabData
-  // Load tab data from session store and return it.
-  getTabData: function Storage_getTabData(tab) {
-    Utils.assert(tab, "tab");
-
-    let existingData = null;
-
-    try {
-      let tabData = this._sessionStore.getTabValue(tab, this.TAB_DATA_IDENTIFIER);
-      if (tabData != "")
-        existingData = JSON.parse(tabData);
-    } catch (e) {
-      // getTabValue will fail if the property doesn't exist.
-      Utils.log(e);
-    }
-
-    return existingData;
-  },
-
-  // ----------
-  // Function: getTabState
-  // Returns the current state of the given tab.
-  getTabState: function Storage_getTabState(tab) {
-    Utils.assert(tab, "tab");
-    let tabState;
-
-    try {
-      tabState = JSON.parse(this._sessionStore.getTabState(tab));
-    } catch (e) {}
-
-    return tabState;
-  },
-
-  // ----------
-  // Function: saveGroupItem
-  // Saves the data for a single groupItem, associated with a specific window.
-  saveGroupItem: function Storage_saveGroupItem(win, data) {
-    var id = data.id;
-    var existingData = this.readGroupItemData(win);
-    existingData[id] = data;
-    this._sessionStore.setWindowValue(win, this.GROUP_DATA_IDENTIFIER,
-      JSON.stringify(existingData));
-  },
-
-  // ----------
-  // Function: deleteGroupItem
-  // Deletes the data for a single groupItem from the given window.
-  deleteGroupItem: function Storage_deleteGroupItem(win, id) {
-    var existingData = this.readGroupItemData(win);
-    delete existingData[id];
-    this._sessionStore.setWindowValue(win, this.GROUP_DATA_IDENTIFIER,
-      JSON.stringify(existingData));
-  },
-
-  // ----------
-  // Function: readGroupItemData
-  // Returns the data for all groupItems associated with the given window.
-  readGroupItemData: function Storage_readGroupItemData(win) {
-    var existingData = {};
-    let data;
-    try {
-      data = this._sessionStore.getWindowValue(win, this.GROUP_DATA_IDENTIFIER);
-      if (data)
-        existingData = JSON.parse(data);
-    } catch (e) {
-      // getWindowValue will fail if the property doesn't exist
-      Utils.log("Error in readGroupItemData: "+e, data);
-    }
-    return existingData;
-  },
-
-  // ----------
-  // Function: readWindowBusyState
-  // Returns the current busyState for the given window.
-  readWindowBusyState: function Storage_readWindowBusyState(win) {
-    let state;
-
-    try {
-      let data = this._sessionStore.getWindowState(win);
-      if (data)
-        state = JSON.parse(data);
-    } catch (e) {
-      Utils.log("Error while parsing window state");
-    }
-
-    return (state && state.windows[0].busy);
-  },
-
-  // ----------
-  // Function: saveGroupItemsData
-  // Saves the global data for the <GroupItems> singleton for the given window.
-  saveGroupItemsData: function Storage_saveGroupItemsData(win, data) {
-    this.saveData(win, this.GROUPS_DATA_IDENTIFIER, data);
-  },
-
-  // ----------
-  // Function: readGroupItemsData
-  // Reads the global data for the <GroupItems> singleton for the given window.
-  readGroupItemsData: function Storage_readGroupItemsData(win) {
-    return this.readData(win, this.GROUPS_DATA_IDENTIFIER);
-  },
-
-  // ----------
-  // Function: saveUIData
-  // Saves the global data for the <UIManager> singleton for the given window.
-  saveUIData: function Storage_saveUIData(win, data) {
-    this.saveData(win, this.UI_DATA_IDENTIFIER, data);
-  },
-
-  // ----------
-  // Function: readUIData
-  // Reads the global data for the <UIManager> singleton for the given window.
-  readUIData: function Storage_readUIData(win) {
-    return this.readData(win, this.UI_DATA_IDENTIFIER);
-  },
-
-  // ----------
-  // Function: saveVisibilityData
-  // Saves visibility for the given window.
-  saveVisibilityData: function Storage_saveVisibilityData(win, data) {
-    this._sessionStore.setWindowValue(
-      win, win.TabView.VISIBILITY_IDENTIFIER, data);
-  },
-
-  // ----------
-  // Function: saveData
-  // Generic routine for saving data to a window.
-  saveData: function Storage_saveData(win, id, data) {
-    try {
-      this._sessionStore.setWindowValue(win, id, JSON.stringify(data));
-    } catch (e) {
-      Utils.log("Error in saveData: "+e);
-    }
-  },
-
-  // ----------
-  // Function: readData
-  // Generic routine for reading data from a window.
-  readData: function Storage_readData(win, id) {
-    var existingData = {};
-    try {
-      var data = this._sessionStore.getWindowValue(win, id);
-      if (data)
-        existingData = JSON.parse(data);
-    } catch (e) {
-      Utils.log("Error in readData: "+e);
-    }
-
-    return existingData;
-  }
-};
-
deleted file mode 100644
--- a/browser/components/tabview/tabitems.js
+++ /dev/null
@@ -1,1423 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// **********
-// Title: tabitems.js
-
-// ##########
-// Class: TabItem
-// An <Item> that represents a tab. Also implements the <Subscribable> interface.
-//
-// Parameters:
-//   tab - a xul:tab
-function TabItem(tab, options) {
-  Utils.assert(tab, "tab");
-
-  this.tab = tab;
-  // register this as the tab's tabItem
-  this.tab._tabViewTabItem = this;
-
-  if (!options)
-    options = {};
-
-  // ___ set up div
-  document.body.appendChild(TabItems.fragment().cloneNode(true));
-  
-  // The document fragment contains just one Node
-  // As per DOM3 appendChild: it will then be the last child
-  let div = document.body.lastChild;
-  let $div = iQ(div);
-
-  this._showsCachedData = false;
-  this.canvasSizeForced = false;
-  this.$thumb = iQ('.thumb', $div);
-  this.$fav   = iQ('.favicon', $div);
-  this.$tabTitle = iQ('.tab-title', $div);
-  this.$canvas = iQ('.thumb canvas', $div);
-  this.$cachedThumb = iQ('img.cached-thumb', $div);
-  this.$favImage = iQ('.favicon>img', $div);
-  this.$close = iQ('.close', $div);
-
-  this.tabCanvas = new TabCanvas(this.tab, this.$canvas[0]);
-
-  this._hidden = false;
-  this.isATabItem = true;
-  this.keepProportional = true;
-  this._hasBeenDrawn = false;
-  this._reconnected = false;
-  this.isDragging = false;
-  this.isStacked = false;
-
-  // Read off the total vertical and horizontal padding on the tab container
-  // and cache this value, as it must be the same for every TabItem.
-  if (Utils.isEmptyObject(TabItems.tabItemPadding)) {
-    TabItems.tabItemPadding.x = parseInt($div.css('padding-left'))
-        + parseInt($div.css('padding-right'));
-
-    TabItems.tabItemPadding.y = parseInt($div.css('padding-top'))
-        + parseInt($div.css('padding-bottom'));
-  }
-  
-  this.bounds = new Rect(0,0,1,1);
-
-  this._lastTabUpdateTime = Date.now();
-
-  // ___ superclass setup
-  this._init(div);
-
-  // ___ drag/drop
-  // override dropOptions with custom tabitem methods
-  this.dropOptions.drop = function(e) {
-    let groupItem = drag.info.item.parent;
-    groupItem.add(drag.info.$el);
-  };
-
-  this.draggable();
-
-  let self = this;
-
-  // ___ more div setup
-  $div.mousedown(function(e) {
-    if (!Utils.isRightClick(e))
-      self.lastMouseDownTarget = e.target;
-  });
-
-  $div.mouseup(function(e) {
-    var same = (e.target == self.lastMouseDownTarget);
-    self.lastMouseDownTarget = null;
-    if (!same)
-      return;
-
-    // press close button or middle mouse click
-    if (iQ(e.target).hasClass("close") || Utils.isMiddleClick(e)) {
-      self.closedManually = true;
-      self.close();
-    } else {
-      if (!Items.item(this).isDragging)
-        self.zoomIn();
-    }
-  });
-
-  this.droppable(true);
-
-  this.$close.attr("title", tabbrowserString("tabs.closeTab"));
-
-  TabItems.register(this);
-
-  // ___ reconnect to data from Storage
-  if (!TabItems.reconnectingPaused())
-    this._reconnect(options);
-};
-
-TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
-  // ----------
-  // Function: toString
-  // Prints [TabItem (tab)] for debug use
-  toString: function TabItem_toString() {
-    return "[TabItem (" + this.tab + ")]";
-  },
-
-  // ----------
-  // Function: forceCanvasSize
-  // Repaints the thumbnail with the given resolution, and forces it
-  // to stay that resolution until unforceCanvasSize is called.
-  forceCanvasSize: function TabItem_forceCanvasSize(w, h) {
-    this.canvasSizeForced = true;
-    this.$canvas[0].width = w;
-    this.$canvas[0].height = h;
-    this.tabCanvas.paint();
-  },
-
-  // ----------
-  // Function: unforceCanvasSize
-  // Stops holding the thumbnail resolution; allows it to shift to the
-  // size of thumbnail on screen. Note that this call does not nest, unlike
-  // <TabItems.resumePainting>; if you call forceCanvasSize multiple
-  // times, you just need a single unforce to clear them all.
-  unforceCanvasSize: function TabItem_unforceCanvasSize() {
-    this.canvasSizeForced = false;
-  },
-
-  // ----------
-  // Function: isShowingCachedData
-  // Returns a boolean indicates whether the cached data is being displayed or
-  // not. 
-  isShowingCachedData: function TabItem_isShowingCachedData() {
-    return this._showsCachedData;
-  },
-
-  // ----------
-  // Function: showCachedData
-  // Shows the cached data i.e. image and title.  Note: this method should only
-  // be called at browser startup with the cached data avaliable.
-  showCachedData: function TabItem_showCachedData() {
-    let {title, url} = this.getTabState();
-    let thumbnailURL = gPageThumbnails.getThumbnailURL(url);
-
-    this.$cachedThumb.attr("src", thumbnailURL).show();
-    this.$canvas.css({opacity: 0});
-
-    let tooltip = (title && title != url ? title + "\n" + url : url);
-    this.$tabTitle.text(title).attr("title", tooltip);
-    this._showsCachedData = true;
-  },
-
-  // ----------
-  // Function: hideCachedData
-  // Hides the cached data i.e. image and title and show the canvas.
-  hideCachedData: function TabItem_hideCachedData() {
-    this.$cachedThumb.attr("src", "").hide();
-    this.$canvas.css({opacity: 1.0});
-    this._showsCachedData = false;
-  },
-
-  // ----------
-  // Function: getStorageData
-  // Get data to be used for persistent storage of this object.
-  getStorageData: function TabItem_getStorageData() {
-    let data = {
-      groupID: (this.parent ? this.parent.id : 0)
-    };
-    if (this.parent && this.parent.getActiveTab() == this)
-      data.active = true;
-
-    return data;
-  },
-
-  // ----------
-  // Function: save
-  // Store persistent for this object.
-  save: function TabItem_save() {
-    try {
-      if (!this.tab || !Utils.isValidXULTab(this.tab) || !this._reconnected) // too soon/late to save
-        return;
-
-      let data = this.getStorageData();
-      if (TabItems.storageSanity(data))
-        Storage.saveTab(this.tab, data);
-    } catch(e) {
-      Utils.log("Error in saving tab value: "+e);
-    }
-  },
-
-  // ----------
-  // Function: _getCurrentTabStateEntry
-  // Returns the current tab state's active history entry.
-  _getCurrentTabStateEntry: function TabItem__getCurrentTabStateEntry() {
-    let tabState = Storage.getTabState(this.tab);
-
-    if (tabState) {
-      let index = (tabState.index || tabState.entries.length) - 1;
-      if (index in tabState.entries)
-        return tabState.entries[index];
-    }
-
-    return null;
-  },
-
-  // ----------
-  // Function: getTabState
-  // Returns the current tab state, i.e. the title and URL of the active
-  // history entry.
-  getTabState: function TabItem_getTabState() {
-    let entry = this._getCurrentTabStateEntry();
-    let title = "";
-    let url = "";
-
-    if (entry) {
-      if (entry.title)
-        title = entry.title;
-
-      url = entry.url;
-    } else {
-      url = this.tab.linkedBrowser.currentURI.spec;
-    }
-
-    return {title: title, url: url};
-  },
-
-  // ----------
-  // Function: _reconnect
-  // Load the reciever's persistent data from storage. If there is none, 
-  // treats it as a new tab. 
-  //
-  // Parameters:
-  //   options - an object with additional parameters, see below
-  //
-  // Possible options:
-  //   groupItemId - if the tab doesn't have any data associated with it and
-  //                 groupItemId is available, add the tab to that group.
-  _reconnect: function TabItem__reconnect(options) {
-    Utils.assertThrow(!this._reconnected, "shouldn't already be reconnected");
-    Utils.assertThrow(this.tab, "should have a xul:tab");
-
-    let tabData = Storage.getTabData(this.tab);
-    let groupItem;
-
-    if (tabData && TabItems.storageSanity(tabData)) {
-      // Show the cached data while we're waiting for the tabItem to be updated.
-      // If the tab isn't restored yet this acts as a placeholder until it is.
-      this.showCachedData();
-
-      if (this.parent)
-        this.parent.remove(this, {immediately: true});
-
-      if (tabData.groupID)
-        groupItem = GroupItems.groupItem(tabData.groupID);
-      else
-        groupItem = new GroupItem([], {immediately: true, bounds: tabData.bounds});
-
-      if (groupItem) {
-        groupItem.add(this, {immediately: true});
-
-        // restore the active tab for each group between browser sessions
-        if (tabData.active)
-          groupItem.setActiveTab(this);
-
-        // if it matches the selected tab or no active tab and the browser
-        // tab is hidden, the active group item would be set.
-        if (this.tab.selected ||
-            (!GroupItems.getActiveGroupItem() && !this.tab.hidden))
-          UI.setActive(this.parent);
-      }
-    } else {
-      if (options && options.groupItemId)
-        groupItem = GroupItems.groupItem(options.groupItemId);
-
-      if (groupItem) {
-        groupItem.add(this, {immediately: true});
-      } else {
-        // create tab group by double click is handled in UI_init().
-        GroupItems.newTab(this, {immediately: true});
-      }
-    }
-
-    this._reconnected = true;
-    this.save();
-    this._sendToSubscribers("reconnected");
-  },
-
-  // ----------
-  // Function: setHidden
-  // Hide/unhide this item
-  setHidden: function TabItem_setHidden(val) {
-    if (val)
-      this.addClass("tabHidden");
-    else
-      this.removeClass("tabHidden");
-    this._hidden = val;
-  },
-
-  // ----------
-  // Function: getHidden
-  // Return hide state of item
-  getHidden: function TabItem_getHidden() {
-    return this._hidden;
-  },
-
-  // ----------
-  // Function: setBounds
-  // Moves this item to the specified location and size.
-  //
-  // Parameters:
-  //   rect - a <Rect> giving the new bounds
-  //   immediately - true if it should not animate; default false
-  //   options - an object with additional parameters, see below
-  //
-  // Possible options:
-  //   force - true to always update the DOM even if the bounds haven't changed; default false
-  setBounds: function TabItem_setBounds(inRect, immediately, options) {
-    Utils.assert(Utils.isRect(inRect), 'TabItem.setBounds: rect is not a real rectangle!');
-
-    if (!options)
-      options = {};
-
-    // force the input size to be valid
-    let validSize = TabItems.calcValidSize(
-      new Point(inRect.width, inRect.height), 
-      {hideTitle: (this.isStacked || options.hideTitle === true)});
-    let rect = new Rect(inRect.left, inRect.top, 
-      validSize.x, validSize.y);
-
-    var css = {};
-
-    if (rect.left != this.bounds.left || options.force)
-      css.left = rect.left;
-
-    if (rect.top != this.bounds.top || options.force)
-      css.top = rect.top;
-
-    if (rect.width != this.bounds.width || options.force) {
-      css.width = rect.width - TabItems.tabItemPadding.x;
-      css.fontSize = TabItems.getFontSizeFromWidth(rect.width);
-      css.fontSize += 'px';
-    }
-
-    if (rect.height != this.bounds.height || options.force) {
-      css.height = rect.height - TabItems.tabItemPadding.y;
-      if (!this.isStacked)
-        css.height -= TabItems.fontSizeRange.max;
-    }
-
-    if (Utils.isEmptyObject(css))
-      return;
-
-    this.bounds.copy(rect);
-
-    // If this is a brand new tab don't animate it in from
-    // a random location (i.e., from [0,0]). Instead, just
-    // have it appear where it should be.
-    if (immediately || (!this._hasBeenDrawn)) {
-      this.$container.css(css);
-    } else {
-      TabItems.pausePainting();
-      this.$container.animate(css, {
-          duration: 200,
-        easing: "tabviewBounce",
-        complete: function() {
-          TabItems.resumePainting();
-        }
-      });
-    }
-
-    if (css.fontSize && !(this.parent && this.parent.isStacked())) {
-      if (css.fontSize < TabItems.fontSizeRange.min)
-        immediately ? this.$tabTitle.hide() : this.$tabTitle.fadeOut();
-      else
-        immediately ? this.$tabTitle.show() : this.$tabTitle.fadeIn();
-    }
-
-    if (css.width) {
-      TabItems.update(this.tab);
-
-      let widthRange, proportion;
-
-      if (this.parent && this.parent.isStacked()) {
-        if (UI.rtl) {
-          this.$fav.css({top:0, right:0});
-        } else {
-          this.$fav.css({top:0, left:0});
-        }
-        widthRange = new Range(70, 90);
-        proportion = widthRange.proportion(css.width); // between 0 and 1
-      } else {
-        if (UI.rtl) {
-          this.$fav.css({top:4, right:2});
-        } else {
-          this.$fav.css({top:4, left:4});
-        }
-        widthRange = new Range(40, 45);
-        proportion = widthRange.proportion(css.width); // between 0 and 1
-      }
-
-      if (proportion <= .1)
-        this.$close.hide();
-      else
-        this.$close.show().css({opacity:proportion});
-
-      var pad = 1 + 5 * proportion;
-      var alphaRange = new Range(0.1,0.2);
-      this.$fav.css({
-       "-moz-padding-start": pad + "px",
-       "-moz-padding-end": pad + 2 + "px",
-       "padding-top": pad + "px",
-       "padding-bottom": pad + "px",
-       "border-color": "rgba(0,0,0,"+ alphaRange.scale(proportion) +")",
-      });
-    }
-
-    this._hasBeenDrawn = true;
-
-    UI.clearShouldResizeItems();
-
-    rect = this.getBounds(); // ensure that it's a <Rect>
-
-    Utils.assert(Utils.isRect(this.bounds), 'TabItem.setBounds: this.bounds is not a real rectangle!');
-
-    if (!this.parent && Utils.isValidXULTab(this.tab))
-      this.setTrenches(rect);
-
-    this.save();
-  },
-
-  // ----------
-  // Function: setZ
-  // Sets the z-index for this item.
-  setZ: function TabItem_setZ(value) {
-    this.zIndex = value;
-    this.$container.css({zIndex: value});
-  },
-
-  // ----------
-  // Function: close
-  // Closes this item (actually closes the tab associated with it, which automatically
-  // closes the item.
-  // Parameters:
-  //   groupClose - true if this method is called by group close action.
-  // Returns true if this tab is removed.
-  close: function TabItem_close(groupClose) {
-    // When the last tab is closed, put a new tab into closing tab's group. If
-    // closing tab doesn't belong to a group and no empty group, create a new 
-    // one for the new tab.
-    if (!groupClose && gBrowser.tabs.length == 1) {
-      let group = this.tab._tabViewTabItem.parent;
-      group.newTab(null, { closedLastTab: true });
-    }
-
-    // when "TabClose" event is fired, the browser tab is about to close and our 
-    // item "close" is fired before the browser tab actually get closed. 
-    // Therefore, we need "tabRemoved" event below.
-    gBrowser.removeTab(this.tab);
-    let tabClosed = !this.tab;
-
-    if (tabClosed)
-      this._sendToSubscribers("tabRemoved");
-
-    // No need to explicitly delete the tab data, becasue sessionstore data
-    // associated with the tab will automatically go away
-    return tabClosed;
-  },
-
-  // ----------
-  // Function: addClass
-  // Adds the specified CSS class to this item's container DOM element.
-  addClass: function TabItem_addClass(className) {
-    this.$container.addClass(className);
-  },
-
-  // ----------
-  // Function: removeClass
-  // Removes the specified CSS class from this item's container DOM element.
-  removeClass: function TabItem_removeClass(className) {
-    this.$container.removeClass(className);
-  },
-
-  // ----------
-  // Function: makeActive
-  // Updates this item to visually indicate that it's active.
-  makeActive: function TabItem_makeActive() {
-    this.$container.addClass("focus");
-
-    if (this.parent)
-      this.parent.setActiveTab(this);
-  },
-
-  // ----------
-  // Function: makeDeactive
-  // Updates this item to visually indicate that it's not active.
-  makeDeactive: function TabItem_makeDeactive() {
-    this.$container.removeClass("focus");
-  },
-
-  // ----------
-  // Function: zoomIn
-  // Allows you to select the tab and zoom in on it, thereby bringing you
-  // to the tab in Firefox to interact with.
-  // Parameters:
-  //   isNewBlankTab - boolean indicates whether it is a newly opened blank tab.
-  zoomIn: function TabItem_zoomIn(isNewBlankTab) {
-    // don't allow zoom in if its group is hidden
-    if (this.parent && this.parent.hidden)
-      return;
-
-    let self = this;
-    let $tabEl = this.$container;
-    let $canvas = this.$canvas;
-
-    Search.hide();
-
-    UI.setActive(this);
-    TabItems._update(this.tab, {force: true});
-
-    // Zoom in!
-    let tab = this.tab;
-
-    function onZoomDone() {
-      $canvas.css({ 'transform': null });
-      $tabEl.removeClass("front");
-
-      UI.goToTab(tab);
-
-      // tab might not be selected because hideTabView() is invoked after
-      // UI.goToTab() so we need to setup everything for the gBrowser.selectedTab
-      if (!tab.selected) {
-        UI.onTabSelect(gBrowser.selectedTab);
-      } else {
-        if (isNewBlankTab)
-          gWindow.gURLBar.focus();
-      }
-      if (self.parent && self.parent.expanded)
-        self.parent.collapse();
-
-      self._sendToSubscribers("zoomedIn");
-    }
-
-    let animateZoom = gPrefBranch.getBoolPref("animate_zoom");
-    if (animateZoom) {
-      let transform = this.getZoomTransform();
-      TabItems.pausePainting();
-
-      if (this.parent && this.parent.expanded)
-        $tabEl.removeClass("stack-trayed");
-      $tabEl.addClass("front");
-      $canvas
-        .css({ 'transform-origin': transform.transformOrigin })
-        .animate({ 'transform': transform.transform }, {
-          duration: 230,
-          easing: 'fast',
-          complete: function() {
-            onZoomDone();
-
-            setTimeout(function() {
-              TabItems.resumePainting();
-            }, 0);
-          }
-        });
-    } else {
-      setTimeout(onZoomDone, 0);
-    }
-  },
-
-  // ----------
-  // Function: zoomOut
-  // Handles the zoom down animation after returning to TabView.
-  // It is expected that this routine will be called from the chrome thread
-  //
-  // Parameters:
-  //   complete - a function to call after the zoom down animation
-  zoomOut: function TabItem_zoomOut(complete) {
-    let $tab = this.$container, $canvas = this.$canvas;
-    var self = this;
-    
-    let onZoomDone = function onZoomDone() {
-      $tab.removeClass("front");
-      $canvas.css("transform", null);
-
-      if (typeof complete == "function")
-        complete();
-    };
-
-    UI.setActive(this);
-    TabItems._update(this.tab, {force: true});
-
-    $tab.addClass("front");
-
-    let animateZoom = gPrefBranch.getBoolPref("animate_zoom");
-    if (animateZoom) {
-      // The scaleCheat of 2 here is a clever way to speed up the zoom-out
-      // code. See getZoomTransform() below.
-      let transform = this.getZoomTransform(2);
-      TabItems.pausePainting();
-
-      $canvas.css({
-        'transform': transform.transform,
-        'transform-origin': transform.transformOrigin
-      });
-
-      $canvas.animate({ "transform": "scale(1.0)" }, {
-        duration: 300,
-        easing: 'cubic-bezier', // note that this is legal easing, even without parameters
-        complete: function() {
-          TabItems.resumePainting();
-          onZoomDone();
-        }
-      });
-    } else {
-      onZoomDone();
-    }
-  },
-
-  // ----------
-  // Function: getZoomTransform
-  // Returns the transform function which represents the maximum bounds of the
-  // tab thumbnail in the zoom animation.
-  getZoomTransform: function TabItem_getZoomTransform(scaleCheat) {
-    // Taking the bounds of the container (as opposed to the canvas) makes us
-    // immune to any transformations applied to the canvas.
-    let { left, top, width, height, right, bottom } = this.$container.bounds();
-
-    let { innerWidth: windowWidth, innerHeight: windowHeight } = window;
-
-    // The scaleCheat is a clever way to speed up the zoom-in code.
-    // Because image scaling is slowest on big images, we cheat and stop
-    // the image at scaled-down size and placed accordingly. Because the
-    // animation is fast, you can't see the difference but it feels a lot
-    // zippier. The only trick is choosing the right animation function so
-    // that you don't see a change in percieved animation speed from frame #1
-    // (the tab) to frame #2 (the half-size image) to frame #3 (the first frame
-    // of real animation). Choosing an animation that starts fast is key.
-
-    if (!scaleCheat)
-      scaleCheat = 1.7;
-
-    let zoomWidth = width + (window.innerWidth - width) / scaleCheat;
-    let zoomScaleFactor = zoomWidth / width;
-
-    let zoomHeight = height * zoomScaleFactor;
-    let zoomTop = top * (1 - 1/scaleCheat);
-    let zoomLeft = left * (1 - 1/scaleCheat);
-
-    let xOrigin = (left - zoomLeft) / ((left - zoomLeft) + (zoomLeft + zoomWidth - right)) * 100;
-    let yOrigin = (top - zoomTop) / ((top - zoomTop) + (zoomTop + zoomHeight - bottom)) * 100;
-
-    return {
-      transformOrigin: xOrigin + "% " + yOrigin + "%",
-      transform: "scale(" + zoomScaleFactor + ")"
-    };
-  },
-
-  // ----------
-  // Function: updateCanvas
-  // Updates the tabitem's canvas.
-  updateCanvas: function TabItem_updateCanvas() {
-    // ___ thumbnail
-    let $canvas = this.$canvas;
-    let w = $canvas.width();
-    let h = $canvas.height();
-    let dimsChanged = !this.canvasSizeForced &&
-      (w != $canvas[0].width || h != $canvas[0].height);
-
-    TabItems._lastUpdateTime = Date.now();
-    this._lastTabUpdateTime = TabItems._lastUpdateTime;
-
-    if (this.tabCanvas) {
-      if (dimsChanged) {
-        // more tasking as it involves the creation of a temp canvas.
-        this.tabCanvas.update(w, h);
-      } else {
-        this.tabCanvas.paint();
-      }
-    }
-
-    // ___ cache
-    if (this.isShowingCachedData())
-      this.hideCachedData();
-  }
-});
-
-// ##########
-// Class: TabItems
-// Singleton for managing <TabItem>s
-var TabItems = {
-  minTabWidth: 40,
-  tabWidth: 160,
-  tabHeight: 120,
-  tabAspect: 0, // set in init
-  invTabAspect: 0, // set in init  
-  fontSize: 9,
-  fontSizeRange: new Range(8,15),
-  _fragment: null,
-  items: [],
-  paintingPaused: 0,
-  _tabsWaitingForUpdate: null,
-  _heartbeat: null, // see explanation at startHeartbeat() below
-  _heartbeatTiming: 200, // milliseconds between calls
-  _maxTimeForUpdating: 200, // milliseconds that consecutive updates can take
-  _lastUpdateTime: Date.now(),
-  _eventListeners: [],
-  _pauseUpdateForTest: false,
-  _reconnectingPaused: false,
-  tabItemPadding: {},
-  _mozAfterPaintHandler: null,
-
-  // ----------
-  // Function: toString
-  // Prints [TabItems count=count] for debug use
-  toString: function TabItems_toString() {
-    return "[TabItems count=" + this.items.length + "]";
-  },
-
-  // ----------
-  // Function: init
-  // Set up the necessary tracking to maintain the <TabItems>s.
-  init: function TabItems_init() {
-    Utils.assert(window.AllTabs, "AllTabs must be initialized first");
-    let self = this;
-    
-    // Set up tab priority queue
-    this._tabsWaitingForUpdate = new TabPriorityQueue();
-    this.minTabHeight = this.minTabWidth * this.tabHeight / this.tabWidth;
-    this.tabAspect = this.tabHeight / this.tabWidth;
-    this.invTabAspect = 1 / this.tabAspect;
-
-    let $canvas = iQ("<canvas>")
-      .attr('moz-opaque', '');
-    $canvas.appendTo(iQ("body"));
-    $canvas.hide();
-
-    let mm = gWindow.messageManager;
-    this._mozAfterPaintHandler = this.onMozAfterPaint.bind(this);
-    mm.addMessageListener("Panorama:MozAfterPaint", this._mozAfterPaintHandler);
-
-    // When a tab is opened, create the TabItem
-    this._eventListeners.open = function (event) {
-      let tab = event.target;
-
-      if (!tab.pinned)
-        self.link(tab);
-    }
-    // When a tab's content is loaded, show the canvas and hide the cached data
-    // if necessary.
-    this._eventListeners.attrModified = function (event) {
-      let tab = event.target;
-
-      if (!tab.pinned)
-        self.update(tab);
-    }
-    // When a tab is closed, unlink.
-    this._eventListeners.close = function (event) {
-      let tab = event.target;
-
-      // XXX bug #635975 - don't unlink the tab if the dom window is closing.
-      if (!tab.pinned && !UI.isDOMWindowClosing)
-        self.unlink(tab);
-    }
-    for (let name in this._eventListeners) {
-      AllTabs.register(name, this._eventListeners[name]);
-    }
-
-    let activeGroupItem = GroupItems.getActiveGroupItem();
-    let activeGroupItemId = activeGroupItem ? activeGroupItem.id : null;
-    // For each tab, create the link.
-    AllTabs.tabs.forEach(function (tab) {
-      if (tab.pinned)
-        return;
-
-      let options = {immediately: true};
-      // if tab is visible in the tabstrip and doesn't have any data stored in 
-      // the session store (see TabItem__reconnect), it implies that it is a 
-      // new tab which is created before Panorama is initialized. Therefore, 
-      // passing the active group id to the link() method for setting it up.
-      if (!tab.hidden && activeGroupItemId)
-         options.groupItemId = activeGroupItemId;
-      self.link(tab, options);
-      self.update(tab);
-    });
-  },
-
-  // ----------
-  // Function: uninit
-  uninit: function TabItems_uninit() {
-    let mm = gWindow.messageManager;
-    mm.removeMessageListener("Panorama:MozAfterPaint", this._mozAfterPaintHandler);
-
-    for (let name in this._eventListeners) {
-      AllTabs.unregister(name, this._eventListeners[name]);
-    }
-    this.items.forEach(function(tabItem) {
-      delete tabItem.tab._tabViewTabItem;
-
-      for (let x in tabItem) {
-        if (typeof tabItem[x] == "object")
-          tabItem[x] = null;
-      }
-    });
-
-    this.items = null;
-    this._eventListeners = null;
-    this._lastUpdateTime = null;
-    this._tabsWaitingForUpdate.clear();
-  },
-
-  // ----------
-  // Function: fragment
-  // Return a DocumentFragment which has a single <div> child. This child node
-  // will act as a template for all TabItem containers.
-  // The first call of this function caches the DocumentFragment in _fragment.
-  fragment: function TabItems_fragment() {
-    if (this._fragment)
-      return this._fragment;
-
-    let div = document.createElement("div");
-    div.classList.add("tab");
-    div.innerHTML = "<div class='thumb'>" +
-            "<img class='cached-thumb' style='display:none'/><canvas moz-opaque/></div>" +
-            "<div class='favicon'><img/></div>" +
-            "<span class='tab-title'>&nbsp;</span>" +
-            "<div class='close'></div>";
-    this._fragment = document.createDocumentFragment();
-    this._fragment.appendChild(div);
-
-    return this._fragment;
-  },
-
-  // Function: _isComplete
-  // Checks whether the xul:tab has fully loaded and calls a callback with a 
-  // boolean indicates whether the tab is loaded or not.
-  _isComplete: function TabItems__isComplete(tab, callback) {
-    Utils.assertThrow(tab, "tab");
-
-    // A pending tab can't be complete, yet.
-    if (tab.hasAttribute("pending")) {
-      setTimeout(() => callback(false));
-      return;
-    }
-
-    let mm = tab.linkedBrowser.messageManager;
-    let message = "Panorama:isDocumentLoaded";
-
-    mm.addMessageListener(message, function onMessage(cx) {
-      mm.removeMessageListener(cx.name, onMessage);
-      callback(cx.json.isLoaded);
-    });
-    mm.sendAsyncMessage(message);
-  },
-
-  // ----------
-  // Function: onMozAfterPaint
-  // Called when a web page is painted.
-  onMozAfterPaint: function TabItems_onMozAfterPaint(cx) {
-    let index = gBrowser.browsers.indexOf(cx.target);
-    if (index == -1)
-      return;
-
-    let tab = gBrowser.tabs[index];
-    if (!tab.pinned)
-      this.update(tab);
-  },
-
-  // ----------
-  // Function: update
-  // Takes in a xul:tab.
-  update: function TabItems_update(tab) {
-    try {
-      Utils.assertThrow(tab, "tab");
-      Utils.assertThrow(!tab.pinned, "shouldn't be an app tab");
-      Utils.assertThrow(tab._tabViewTabItem, "should already be linked");
-
-      let shouldDefer = (
-        this.isPaintingPaused() ||
-        this._tabsWaitingForUpdate.hasItems() ||
-        Date.now() - this._lastUpdateTime < this._heartbeatTiming
-      );
-
-      if (shouldDefer) {
-        this._tabsWaitingForUpdate.push(tab);
-        this.startHeartbeat();
-      } else
-        this._update(tab);
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
-  // Function: _update
-  // Takes in a xul:tab.
-  //
-  // Parameters:
-  //   tab - a xul tab to update
-  //   options - an object with additional parameters, see below
-  //
-  // Possible options:
-  //   force - true to always update the tab item even if it's incomplete
-  _update: function TabItems__update(tab, options) {
-    try {
-      if (this._pauseUpdateForTest)
-        return;
-
-      Utils.assertThrow(tab, "tab");
-
-      // ___ get the TabItem
-      Utils.assertThrow(tab._tabViewTabItem, "must already be linked");
-      let tabItem = tab._tabViewTabItem;
-
-      // Even if the page hasn't loaded, display the favicon and title
-      // ___ icon
-      FavIcons.getFavIconUrlForTab(tab, function TabItems__update_getFavIconUrlCallback(iconUrl) {
-        let favImage = tabItem.$favImage[0];
-        let fav = tabItem.$fav;
-        if (iconUrl) {
-          if (favImage.src != iconUrl)
-            favImage.src = iconUrl;
-          fav.show();
-        } else {
-          if (favImage.hasAttribute("src"))
-            favImage.removeAttribute("src");
-          fav.hide();
-        }
-        tabItem._sendToSubscribers("iconUpdated");
-      });
-
-      // ___ label
-      let label = tab.label;
-      let $name = tabItem.$tabTitle;
-      if ($name.text() != label)
-        $name.text(label);
-
-      // ___ remove from waiting list now that we have no other
-      // early returns
-      this._tabsWaitingForUpdate.remove(tab);
-
-      // ___ URL
-      let tabUrl = tab.linkedBrowser.currentURI.spec;
-      let tooltip = (label == tabUrl ? label : label + "\n" + tabUrl);
-      tabItem.$container.attr("title", tooltip);
-
-      // ___ Make sure the tab is complete and ready for updating.
-      if (options && options.force) {
-        tabItem.updateCanvas();
-        tabItem._sendToSubscribers("updated");
-      } else {
-        this._isComplete(tab, function TabItems__update_isComplete(isComplete) {
-          if (!Utils.isValidXULTab(tab) || tab.pinned)
-            return;
-
-          if (isComplete) {
-            tabItem.updateCanvas();
-            tabItem._sendToSubscribers("updated");
-          } else {
-            this._tabsWaitingForUpdate.push(tab);
-          }
-        }.bind(this));
-      }
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
-  // Function: link
-  // Takes in a xul:tab, creates a TabItem for it and adds it to the scene. 
-  link: function TabItems_link(tab, options) {
-    try {
-      Utils.assertThrow(tab, "tab");
-      Utils.assertThrow(!tab.pinned, "shouldn't be an app tab");
-      Utils.assertThrow(!tab._tabViewTabItem, "shouldn't already be linked");
-      new TabItem(tab, options); // sets tab._tabViewTabItem to itself
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
-  // Function: unlink
-  // Takes in a xul:tab and destroys the TabItem associated with it. 
-  unlink: function TabItems_unlink(tab) {
-    try {
-      Utils.assertThrow(tab, "tab");
-      Utils.assertThrow(tab._tabViewTabItem, "should already be linked");
-      // note that it's ok to unlink an app tab; see .handleTabUnpin
-
-      this.unregister(tab._tabViewTabItem);
-      tab._tabViewTabItem._sendToSubscribers("close");
-      tab._tabViewTabItem.$container.remove();
-      tab._tabViewTabItem.removeTrenches();
-      Items.unsquish(null, tab._tabViewTabItem);
-
-      tab._tabViewTabItem.tab = null;
-      tab._tabViewTabItem.tabCanvas.tab = null;
-      tab._tabViewTabItem.tabCanvas = null;
-      tab._tabViewTabItem = null;
-      Storage.saveTab(tab, null);
-
-      this._tabsWaitingForUpdate.remove(tab);
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
-  // when a tab becomes pinned, destroy its TabItem
-  handleTabPin: function TabItems_handleTabPin(xulTab) {
-    this.unlink(xulTab);
-  },
-
-  // ----------
-  // when a tab becomes unpinned, create a TabItem for it
-  handleTabUnpin: function TabItems_handleTabUnpin(xulTab) {
-    this.link(xulTab);
-    this.update(xulTab);
-  },
-
-  // ----------
-  // Function: startHeartbeat
-  // Start a new heartbeat if there isn't one already started.
-  // The heartbeat is a chain of setTimeout calls that allows us to spread
-  // out update calls over a period of time.
-  // _heartbeat is used to make sure that we don't add multiple 
-  // setTimeout chains.
-  startHeartbeat: function TabItems_startHeartbeat() {
-    if (!this._heartbeat) {
-      let self = this;
-      this._heartbeat = setTimeout(function() {
-        self._checkHeartbeat();
-      }, this._heartbeatTiming);
-    }
-  },
-
-  // ----------
-  // Function: _checkHeartbeat
-  // This periodically checks for tabs waiting to be updated, and calls
-  // _update on them.
-  // Should only be called by startHeartbeat and resumePainting.
-  _checkHeartbeat: function TabItems__checkHeartbeat() {
-    this._heartbeat = null;
-
-    if (this.isPaintingPaused())
-      return;
-
-    // restart the heartbeat to update all waiting tabs once the UI becomes idle
-    if (!UI.isIdle()) {
-      this.startHeartbeat();
-      return;
-    }
-
-    let accumTime = 0;
-    let items = this._tabsWaitingForUpdate.getItems();
-    // Do as many updates as we can fit into a "perceived" amount
-    // of time, which is tunable.
-    while (accumTime < this._maxTimeForUpdating && items.length) {
-      let updateBegin = Date.now();
-      this._update(items.pop());
-      let updateEnd = Date.now();
-
-      // Maintain a simple average of time for each tabitem update
-      // We can use this as a base by which to delay things like
-      // tab zooming, so there aren't any hitches.
-      let deltaTime = updateEnd - updateBegin;
-      accumTime += deltaTime;
-    }
-
-    if (this._tabsWaitingForUpdate.hasItems())
-      this.startHeartbeat();
-  },
-
-  // ----------
-  // Function: pausePainting
-  // Tells TabItems to stop updating thumbnails (so you can do
-  // animations without thumbnail paints causing stutters).
-  // pausePainting can be called multiple times, but every call to
-  // pausePainting needs to be mirrored with a call to <resumePainting>.
-  pausePainting: function TabItems_pausePainting() {
-    this.paintingPaused++;
-    if (this._heartbeat) {
-      clearTimeout(this._heartbeat);
-      this._heartbeat = null;
-    }
-  },
-
-  // ----------
-  // Function: resumePainting
-  // Undoes a call to <pausePainting>. For instance, if you called
-  // pausePainting three times in a row, you'll need to call resumePainting
-  // three times before TabItems will start updating thumbnails again.
-  resumePainting: function TabItems_resumePainting() {
-    this.paintingPaused--;
-    Utils.assert(this.paintingPaused > -1, "paintingPaused should not go below zero");
-    if (!this.isPaintingPaused())
-      this.startHeartbeat();
-  },
-
-  // ----------
-  // Function: isPaintingPaused
-  // Returns a boolean indicating whether painting
-  // is paused or not.
-  isPaintingPaused: function TabItems_isPaintingPaused() {
-    return this.paintingPaused > 0;
-  },
-
-  // ----------
-  // Function: pauseReconnecting
-  // Don't reconnect any new tabs until resume is called.
-  pauseReconnecting: function TabItems_pauseReconnecting() {
-    Utils.assertThrow(!this._reconnectingPaused, "shouldn't already be paused");
-
-    this._reconnectingPaused = true;
-  },
-  
-  // ----------
-  // Function: resumeReconnecting
-  // Reconnect all of the tabs that were created since we paused.
-  resumeReconnecting: function TabItems_resumeReconnecting() {
-    Utils.assertThrow(this._reconnectingPaused, "should already be paused");
-
-    this._reconnectingPaused = false;
-    this.items.forEach(function(item) {
-      if (!item._reconnected)
-        item._reconnect();
-    });
-  },
-  
-  // ----------
-  // Function: reconnectingPaused
-  // Returns true if reconnecting is paused.
-  reconnectingPaused: function TabItems_reconnectingPaused() {
-    return this._reconnectingPaused;
-  },
-  
-  // ----------
-  // Function: register
-  // Adds the given <TabItem> to the master list.
-  register: function TabItems_register(item) {
-    Utils.assert(item && item.isAnItem, 'item must be a TabItem');
-    Utils.assert(this.items.indexOf(item) == -1, 'only register once per item');
-    this.items.push(item);
-  },
-
-  // ----------
-  // Function: unregister
-  // Removes the given <TabItem> from the master list.
-  unregister: function TabItems_unregister(item) {
-    var index = this.items.indexOf(item);
-    if (index != -1)
-      this.items.splice(index, 1);
-  },
-
-  // ----------
-  // Function: getItems
-  // Returns a copy of the master array of <TabItem>s.
-  getItems: function TabItems_getItems() {
-    return Utils.copy(this.items);
-  },
-
-  // ----------
-  // Function: saveAll
-  // Saves all open <TabItem>s.
-  saveAll: function TabItems_saveAll() {
-    let tabItems = this.getItems();
-
-    tabItems.forEach(function TabItems_saveAll_forEach(tabItem) {
-      tabItem.save();
-    });
-  },
-
-  // ----------
-  // Function: storageSanity
-  // Checks the specified data (as returned by TabItem.getStorageData or loaded from storage)
-  // and returns true if it looks valid.
-  // TODO: this is a stub, please implement
-  storageSanity: function TabItems_storageSanity(data) {
-    return true;
-  },
-
-  // ----------
-  // Function: getFontSizeFromWidth
-  // Private method that returns the fontsize to use given the tab's width
-  getFontSizeFromWidth: function TabItem_getFontSizeFromWidth(width) {
-    let widthRange = new Range(0, TabItems.tabWidth);
-    let proportion = widthRange.proportion(width - TabItems.tabItemPadding.x, true);
-    // proportion is in [0,1]
-    return TabItems.fontSizeRange.scale(proportion);
-  },
-
-  // ----------
-  // Function: _getWidthForHeight
-  // Private method that returns the tabitem width given a height.
-  _getWidthForHeight: function TabItems__getWidthForHeight(height) {
-    return height * TabItems.invTabAspect;
-  },
-
-  // ----------
-  // Function: _getHeightForWidth
-  // Private method that returns the tabitem height given a width.
-  _getHeightForWidth: function TabItems__getHeightForWidth(width) {
-    return width * TabItems.tabAspect;
-  },
-
-  // ----------
-  // Function: calcValidSize
-  // Pass in a desired size, and receive a size based on proper title
-  // size and aspect ratio.
-  calcValidSize: function TabItems_calcValidSize(size, options) {
-    Utils.assert(Utils.isPoint(size), 'input is a Point');
-
-    let width = Math.max(TabItems.minTabWidth, size.x);
-    let showTitle = !options || !options.hideTitle;
-    let titleSize = showTitle ? TabItems.fontSizeRange.max : 0;
-    let height = Math.max(TabItems.minTabHeight, size.y - titleSize);
-    let retSize = new Point(width, height);
-
-    if (size.x > -1)
-      retSize.y = this._getHeightForWidth(width);
-    if (size.y > -1)
-      retSize.x = this._getWidthForHeight(height);
-
-    if (size.x > -1 && size.y > -1) {
-      if (retSize.x < size.x)
-        retSize.y = this._getHeightForWidth(retSize.x);
-      else
-        retSize.x = this._getWidthForHeight(retSize.y);
-    }
-
-    if (showTitle)
-      retSize.y += titleSize;
-
-    return retSize;
-  }
-};
-
-// ##########
-// Class: TabPriorityQueue
-// Container that returns tab items in a priority order
-// Current implementation assigns tab to either a high priority
-// or low priority queue, and toggles which queue items are popped
-// from. This guarantees that high priority items which are constantly
-// being added will not eclipse changes for lower priority items.
-function TabPriorityQueue() {
-};
-
-TabPriorityQueue.prototype = {
-  _low: [], // low priority queue
-  _high: [], // high priority queue
-
-  // ----------
-  // Function: toString
-  // Prints [TabPriorityQueue count=count] for debug use
-  toString: function TabPriorityQueue_toString() {
-    return "[TabPriorityQueue count=" + (this._low.length + this._high.length) + "]";
-  },
-
-  // ----------
-  // Function: clear
-  // Empty the update queue
-  clear: function TabPriorityQueue_clear() {
-    this._low = [];
-    this._high = [];
-  },
-
-  // ----------
-  // Function: hasItems
-  // Return whether pending items exist
-  hasItems: function TabPriorityQueue_hasItems() {
-    return (this._low.length > 0) || (this._high.length > 0);
-  },
-
-  // ----------
-  // Function: getItems
-  // Returns all queued items, ordered from low to high priority
-  getItems: function TabPriorityQueue_getItems() {
-    return this._low.concat(this._high);
-  },
-
-  // ----------
-  // Function: push
-  // Add an item to be prioritized
-  push: function TabPriorityQueue_push(tab) {
-    // Push onto correct priority queue.
-    // It's only low priority if it's in a stack, and isn't the top,
-    // and the stack isn't expanded.
-    // If it already exists in the destination queue,
-    // leave it. If it exists in a different queue, remove it first and push
-    // onto new queue.
-    let item = tab._tabViewTabItem;
-    if (item.parent && (item.parent.isStacked() &&
-      !item.parent.isTopOfStack(item) &&
-      !item.parent.expanded)) {
-      let idx = this._high.indexOf(tab);
-      if (idx != -1) {
-        this._high.splice(idx, 1);
-        this._low.unshift(tab);
-      } else if (this._low.indexOf(tab) == -1)
-        this._low.unshift(tab);
-    } else {
-      let idx = this._low.indexOf(tab);
-      if (idx != -1) {
-        this._low.splice(idx, 1);
-        this._high.unshift(tab);
-      } else if (this._high.indexOf(tab) == -1)
-        this._high.unshift(tab);
-    }
-  },
-
-  // ----------
-  // Function: pop
-  // Remove and return the next item in priority order
-  pop: function TabPriorityQueue_pop() {
-    let ret = null;
-    if (this._high.length)
-      ret = this._high.pop();
-    else if (this._low.length)
-      ret = this._low.pop();
-    return ret;
-  },
-
-  // ----------
-  // Function: peek
-  // Return the next item in priority order, without removing it
-  peek: function TabPriorityQueue_peek() {
-    let ret = null;
-    if (this._high.length)
-      ret = this._high[this._high.length-1];
-    else if (this._low.length)
-      ret = this._low[this._low.length-1];
-    return ret;
-  },
-
-  // ----------
-  // Function: remove
-  // Remove the passed item
-  remove: function TabPriorityQueue_remove(tab) {
-    let index = this._high.indexOf(tab);
-    if (index != -1)
-      this._high.splice(index, 1);
-    else {
-      index = this._low.indexOf(tab);
-      if (index != -1)
-        this._low.splice(index, 1);
-    }
-  }
-};
-
-// ##########
-// Class: TabCanvas
-// Takes care of the actual canvas for the tab thumbnail
-// Does not need to be accessed from outside of tabitems.js
-function TabCanvas(tab, canvas) {
-  this.tab = tab;
-  this.canvas = canvas;
-};
-
-TabCanvas.prototype = Utils.extend(new Subscribable(), {
-  // ----------
-  // Function: toString
-  // Prints [TabCanvas (tab)] for debug use
-  toString: function TabCanvas_toString() {
-    return "[TabCanvas (" + this.tab + ")]";
-  },
-
-  // ----------
-  // Function: paint
-  paint: function TabCanvas_paint(evt) {
-    var w = this.canvas.width;
-    var h = this.canvas.height;
-    if (!w || !h)
-      return;
-
-    gPageThumbnails.captureToCanvas(this.tab.linkedBrowser, this.canvas, () => {
-      this._sendToSubscribers("painted");
-    });
-  },
-
-  // ----------
-  // Function: update
-  // Changing the dims of a canvas will clear it, so we don't want to do
-  // do this to a canvas we're currently displaying. This method grabs
-  // a new thumbnail at the new dims and then copies it over to the
-  // displayed canvas.
-  update: function TabCanvas_update(aWidth, aHeight) {
-    let temp = gPageThumbnails.createCanvas(window);
-    temp.width = aWidth;
-    temp.height = aHeight;
-    gPageThumbnails.captureToCanvas(this.tab.linkedBrowser, temp, () => {
-      let ctx = this.canvas.getContext('2d');
-      this.canvas.width = aWidth;
-      this.canvas.height = aHeight;
-      try {
-        ctx.drawImage(temp, 0, 0);
-      } catch (ex if ex.name == "InvalidStateError") {
-        // Can't draw if the canvas created by page thumbs isn't valid. This
-        // can happen during shutdown.
-        return;
-      }
-      this._sendToSubscribers("painted");
-    });
-  },
-
-  // ----------
-  // Function: toImageData
-  toImageData: function TabCanvas_toImageData() {
-    return this.canvas.toDataURL("image/png");
-  }
-});
deleted file mode 100644
--- a/browser/components/tabview/tabview.css
+++ /dev/null
@@ -1,294 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* Platform-independent structural styling for
- * <strike>Tab Candy</strike> Panorama
-----------------------------------*/
-
-html {
-  overflow: hidden;
-/*   image-rendering: -moz-crisp-edges; */
-}
-
-body {
-  padding: 0px;
-  margin: 0 auto;
-}
-
-#content {
-  overflow: -moz-hidden-unscrollable;
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-}
-
-#bg {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  z-index: -999999;
-}
-
-/* Tabs
-----------------------------------*/
-
-.tab {
-  position: absolute;
-  overflow: visible !important;
-}
-
-.tab canvas,
-.cached-thumb {
-  width: 100%;
-  height: 100%;
-  position: absolute;
-  top: 0px;
-  left: 0px;
-}
-
-.tabHidden {
-  display: none;
-}
-
-.thumb {
-  position: relative;
-  width: 100%;
-  height: 100%;
-}
-
-.favicon {
-  position: absolute;
-}
-
-/* Apply crisp rendering for favicons at exactly 2dppx resolution */
-@media (resolution: 2dppx) {
-  .favicon > img {
-    image-rendering: -moz-crisp-edges;
-  }
-}
-
-.close {
-  position: absolute;
-  cursor: pointer;
-}
-
-.expander {
-  position: absolute;
-}
-
-.tab-title {
-  position: absolute;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-.stacked .tab-title {
-  display: none;
-}
-
-.stack-trayed .tab-title {
-  display: block !important;
-}
-
-/* Tab: Zooming
-----------------------------------*/
-
-.front {
-  z-index: 999999 !important;
-  image-rendering: -moz-crisp-edges;
-}
-
-.front canvas {
-  border: none !important;
-  padding: 1px !important;
-}
-
-/* Groups
-----------------------------------*/
-
-.groupItem {
-  position: absolute;
-}
-
-.appTabTrayContainer {
-  position: absolute;
-}
-
-.title-container {
-  /* We want the title container to leave out width, position of the .close
-     button and space between input and .close button. Keep an eye on LTR and
-     RTL differences in .close. */
-  width: calc(100% - 16px - 6px - 6px);
-}
-
-input.name {
-  text-overflow: ellipsis;
-  width: -moz-available;
-}
-
-input.name:focus {
-  text-overflow: clip;
-}
-
-/* Other Items
-----------------------------------*/
-
-.undo {
-  position: absolute;
-}
-
-/* Trenches
-----------------------------------*/
-
-.guideTrench, 
-.visibleTrench, 
-.activeVisibleTrench {
-  position: absolute;
-}
-
-.guideTrench {
-  z-index: -101;
-}
-
-.visibleTrench {
-  z-index: -103;
-}
-
-.activeVisibleTrench {
-  z-index: -102;
-}
-
-/* Other
-----------------------------------*/
-
-.titlebar {
-  position: absolute;
-}
-
-.title-shield {
-  position: absolute;
-  left: 0;
-  top: 0;
-  width: 100%;
-  height: 100%;
-  z-index: 10;
-}
-
-.transparentBorder {
-  border: 1px solid transparent !important;
-}
-
-.stackExpander {
-  position: absolute;
-}
-
-.shield {
-  left: 0;
-  top: 0;
-  width: 100%;
-  height: 100%;
-  position: absolute;
-}
-
-.banner {
-  left: 0;
-  bottom: 0;
-  right: 0;
-  padding: 10px 0;
-  position: absolute;
-  z-index: 1000060;
-  background: #000;
-  color: #fff;
-  opacity: 0;
-  text-align: center;
-  font-weight: 700;
-}
-
-/* Resizable
-----------------------------------*/
-.resizer {
-  position: absolute;
-}
-
-.iq-resizable-handle {
-  position: absolute;
-  z-index: 99999;
-  display: block;
-}
-
-.iq-resizable-disabled .iq-resizable-handle, 
-.iq-resizable-autohide .iq-resizable-handle {
-  display: none;
-}
-
-/* Search
-----------------------------------*/
-#searchshade{
-  position: absolute;
-  top: 0px;
-  left: 0px;
-  z-index: 1000001;
-}
-
-#search{
-  position: absolute;
-  top: 0px;
-  left: 0px;
-  pointer-events: none;
-  z-index: 1000050;
-}
-
-html[dir=rtl] #search {
-  left: auto;
-  right: 0;
-}
-
-#searchbox{
-  position: absolute;
-  right: 20px;
-  top: 20px;
-  pointer-events: auto;
-}
-
-html[dir=rtl] #searchbox {
-  right: auto;
-  left: 20px;
-}
-
-#actions{
-  position: absolute;
-  top: 0px;
-  right: -3px;
-  z-index: 1000000;
-}
-
-html[dir=rtl] #actions {
-  right: auto;
-  left: -3px;
-}
-
-#otherresults{
-  position: absolute;
-  opacity: 0;
-  overflow: hidden;
-}
-
-.onTop{
-  z-index: 1000010 !important;
-}
-
-.inlineMatch{
-  display: inline-block;
-  pointer-events: auto;
-}
-
-.inlineMatch>span{
-  display: inline-block;
-  overflow: hidden;
-}
deleted file mode 100644
--- a/browser/components/tabview/tabview.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<!DOCTYPE html>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
-<head>
-  <title>&nbsp;</title>
-  <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
-  <link rel="stylesheet" href="tabview.css" type="text/css"/>
-  <link rel="stylesheet" href="chrome://browser/skin/tabview/tabview.css" type="text/css"/>
-</head>
-
-<body transparent="true">
-  <div id="content">
-    <div id="bg">
-    </div>
-    <div id="actions">
-      <input id="exit-button" type="button" alt="" groups="0" />
-      <input id="searchbutton" type="button"/>
-    </div>
-  </div>  
-
-  <div id="searchshade"></div>
-  <div id="search">
-    <input id="searchbox" type="text"/>
-    <div id="otherresults">
-      <span class="label"></span>
-      <span id="results"></span>
-    </div>
-  </div>
-
-  <script type="text/javascript;version=1.8" src="tabview.js"></script>
-</body>
-</html>
deleted file mode 100644
--- a/browser/components/tabview/tabview.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-var Cr = Components.results;
-
-Cu.import("resource:///modules/tabview/utils.jsm");
-Cu.import("resource://gre/modules/AppConstants.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "tabviewBundle", function() {
-  return Services.strings.
-    createBundle("chrome://browser/locale/tabview.properties");
-});
-XPCOMUtils.defineLazyGetter(this, "tabbrowserBundle", function() {
-  return Services.strings.
-    createBundle("chrome://browser/locale/tabbrowser.properties");
-});
-
-function tabviewString(name) {
-  return tabviewBundle.GetStringFromName('tabview.' + name);
-}
-function tabbrowserString(name) {
-  return tabbrowserBundle.GetStringFromName(name);
-}
-
-XPCOMUtils.defineLazyGetter(this, "gPrefBranch", function() {
-  return Services.prefs.getBranch("browser.panorama.");
-});
-
-XPCOMUtils.defineLazyModuleGetter(this, "gPageThumbnails",
-  "resource://gre/modules/PageThumbs.jsm", "PageThumbs");
-
-var gWindow = window.parent;
-var gBrowser = gWindow.gBrowser;
-var gTabView = gWindow.TabView;
-var gTabViewDeck = gWindow.document.getElementById("tab-view-deck");
-var gBrowserPanel = gWindow.document.getElementById("browser-panel");
-var gTabViewFrame = gWindow.document.getElementById("tab-view");
-
-var AllTabs = {
-  _events: {
-    attrModified: "TabAttrModified",
-    close:        "TabClose",
-    move:         "TabMove",
-    open:         "TabOpen",
-    select:       "TabSelect",
-    pinned:       "TabPinned",
-    unpinned:     "TabUnpinned"
-  },
-
-  get tabs() {
-    return Array.filter(gBrowser.tabs, tab => Utils.isValidXULTab(tab));
-  },
-
-  register: function AllTabs_register(eventName, callback) {
-    gBrowser.tabContainer.addEventListener(this._events[eventName], callback, false);
-  },
-
-  unregister: function AllTabs_unregister(eventName, callback) {
-    gBrowser.tabContainer.removeEventListener(this._events[eventName], callback, false);
-  }
-};
-
-# NB: Certain files need to evaluate before others
-
-#include iq.js
-#include storage.js
-#include items.js
-#include groupitems.js
-#include tabitems.js
-#include favicons.js
-#include drag.js
-#include trench.js
-#include search.js
-#include telemetry.js
-#include ui.js
deleted file mode 100644
--- a/browser/components/tabview/telemetry.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Collects telemetry data for Tabview.
- */
-var Telemetry = {
-  TOPIC_GATHER_TELEMETRY: "gather-telemetry",
-
-  /**
-   * Initializes the object.
-   */
-  init: function Telemetry_init() {
-    Services.obs.addObserver(this, this.TOPIC_GATHER_TELEMETRY, false);
-  }, 
-
-  /**
-   * Uninitializes the object.
-   */
-  uninit: function Telemetry_uninit() {
-    Services.obs.removeObserver(this, this.TOPIC_GATHER_TELEMETRY);
-  },
-
-  /**
-   * Adds telemetry values to gather usage statistics.
-   */
-  _collect: function Telemetry_collect() {
-    let stackedGroupsCount = 0;
-    let childCounts = [];
-
-    GroupItems.groupItems.forEach(function (groupItem) {
-      if (!groupItem.isEmpty()) {
-        childCounts.push(groupItem.getChildren().length);
-
-        if (groupItem.isStacked())
-          stackedGroupsCount++;
-      }
-    });
-
-    function addTelemetryValue(aId, aValue) {
-      Services.telemetry.getHistogramById("PANORAMA_" + aId).add(aValue);
-    }
-    function median(aChildCounts) {
-      aChildCounts.sort(function(x, y) { return x - y; });
-      let middle = Math.floor(aChildCounts.length / 2);
-      return aChildCounts[middle];
-    }
-
-    addTelemetryValue("GROUPS_COUNT", GroupItems.groupItems.length);
-    addTelemetryValue("STACKED_GROUPS_COUNT", stackedGroupsCount);
-    addTelemetryValue("MEDIAN_TABS_IN_GROUPS_COUNT", median(childCounts));
-  },
-
-  /**
-   * Observes for gather telemetry topic.
-   */
-  observe: function Telemetry_observe(aSubject, aTopic, aData) {
-    if (!gWindow.PrivateBrowsingUtils.isWindowPrivate(gWindow))
-      this._collect();
-  }
-}
-
deleted file mode 100644
--- a/browser/components/tabview/test/browser.ini
+++ /dev/null
@@ -1,196 +0,0 @@
-[DEFAULT]
-skip-if = e10s # Bug 1092281
-
-support-files =
-  dummy_page.html
-  head.js
-  search1.html
-  search2.html
-  test_bug600645.html
-  test_bug644097.html
-  test_bug678374.html
-  test_bug678374_icon16.png
-
-[browser_tabview_alltabs.js]
-[browser_tabview_apptabs.js]
-[browser_tabview_bug580412.js]
-[browser_tabview_bug586553.js]
-[browser_tabview_bug587043.js]
-[browser_tabview_bug587231.js]
-skip-if = buildapp == 'mulet'
-[browser_tabview_bug587276.js]
-skip-if = e10s || true # Bug 1091200, bug 1096285
-[browser_tabview_bug587351.js]
-[browser_tabview_bug587503.js]
-[browser_tabview_bug587990.js]
-[browser_tabview_bug588265.js]
-[browser_tabview_bug589324.js]
-skip-if = e10s # Bug 1086190
-[browser_tabview_bug590606.js]
-[browser_tabview_bug591706.js]
-[browser_tabview_bug593283.js]
-[browser_tabview_bug595191.js]
-[browser_tabview_bug595436.js]
-[browser_tabview_bug595518.js]
-[browser_tabview_bug595521.js]
-[browser_tabview_bug595560.js]
-[browser_tabview_bug595601.js]
-[browser_tabview_bug595804.js]
-[browser_tabview_bug595930.js]
-[browser_tabview_bug595943.js]
-[browser_tabview_bug595965.js]
-skip-if = e10s # Bug 1086190
-[browser_tabview_bug596781.js]
-[browser_tabview_bug597360.js]
-[browser_tabview_bug597399.js]
-[browser_tabview_bug597980.js]
-skip-if = true # Bug 711907
-[browser_tabview_bug598375.js]
-[browser_tabview_bug598600.js]
-[browser_tabview_bug599048.js]
-[browser_tabview_bug599626.js]
-skip-if = os == 'linux' || e10s # Disabled on Linux:  Bug 939620, much fail, so amaze; Disabled for e10s: Bug ??????
-[browser_tabview_bug600645.js]
-[browser_tabview_bug600812.js]
-skip-if = e10s # Bug 1086190
-[browser_tabview_bug602432.js]
-skip-if = true # Bug 704417
-[browser_tabview_bug604098.js]
-[browser_tabview_bug606657.js]
-[browser_tabview_bug606905.js]
-[browser_tabview_bug607108.js]
-skip-if = os == 'linux' # Bug 947521
-[browser_tabview_bug608037.js]
-skip-if = e10s # Bug 1086190
-[browser_tabview_bug608153.js]
-[browser_tabview_bug608158.js]
-[browser_tabview_bug608184.js]
-[browser_tabview_bug608405.js]
-[browser_tabview_bug610208.js]
-[browser_tabview_bug610242.js]
-skip-if = true # Bug 736036
-[browser_tabview_bug612470.js]
-[browser_tabview_bug613541.js]
-skip-if = os == "win" # Bug 951477
-[browser_tabview_bug616729.js]
-skip-if = e10s # Bug 1086190
-[browser_tabview_bug616967.js]
-[browser_tabview_bug618816.js]
-[browser_tabview_bug618828.js]
-skip-if = buildapp == 'mulet'
-[browser_tabview_bug619937.js]
-[browser_tabview_bug622835.js]
-[browser_tabview_bug623768.js]
-skip-if = e10s # Bug 1086190
-[browser_tabview_bug624265_perwindowpb.js]
-skip-if = true # Bug 921984, hopefully fixed by bug 930202
-[browser_tabview_bug624692.js]
-[browser_tabview_bug624727_perwindowpb.js]
-skip-if = buildapp == 'mulet'
-[browser_tabview_bug624847.js]
-skip-if = e10s # Bug 1086190
-[browser_tabview_bug624931.js]
-[browser_tabview_bug624953.js]
-[browser_tabview_bug625195.js]
-[browser_tabview_bug625269.js]
-[browser_tabview_bug625424.js]
-[browser_tabview_bug625955.js]
-[browser_tabview_bug626368.js]
-skip-if = e10s # Bug 1086190
-[browser_tabview_bug626455.js]
-skip-if = e10s # Bug 1086190
-[browser_tabview_bug626525.js]
-[browser_tabview_bug626791.js]
-skip-if = buildapp == 'mulet'
-[browser_tabview_bug627736.js]
-[browser_tabview_bug628061.js]
-[browser_tabview_bug628165.js]
-[browser_tabview_bug628270.js]
-[browser_tabview_bug628887.js]
-[browser_tabview_bug629189.js]
-[browser_tabview_bug629195.js]
-skip-if = os == 'linux'&&debug # bug 981703
-[browser_tabview_bug630102.js]
-[browser_tabview_bug630157.js]
-skip-if = true # Bug 922422
-[browser_tabview_bug631662.js]
-skip-if = true # Bug 922422
-[browser_tabview_bug631752.js]
-[browser_tabview_bug633788.js]
-[browser_tabview_bug634077.js]
-[browser_tabview_bug634085.js]
-[browser_tabview_bug634672.js]
-[browser_tabview_bug635696.js]
-[browser_tabview_bug637840.js]
-skip-if = buildapp == 'mulet'
-[browser_tabview_bug640765.js]
-[browser_tabview_bug641802.js]
-[browser_tabview_bug642793.js]
-[browser_tabview_bug643392.js]
-[browser_tabview_bug644097.js]
-[browser_tabview_bug648882.js]
-skip-if = true # Bug 752862
-[browser_tabview_bug649006.js]
-[browser_tabview_bug649307.js]
-[browser_tabview_bug649319.js]
-[browser_tabview_bug650280_perwindowpb.js]
-[browser_tabview_bug650573.js]
-[browser_tabview_bug651311.js]
-[browser_tabview_bug654295.js]
-[browser_tabview_bug654721.js]
-[browser_tabview_bug654941.js]
-skip-if = true # Bug 754222
-[browser_tabview_bug655269.js]
-[browser_tabview_bug656778.js]
-skip-if = os == "mac" # Bug 946918
-[browser_tabview_bug656913.js]
-skip-if = e10s # Bug 1086190
-[browser_tabview_bug659594.js]
-skip-if = os == "mac" || e10s # mac: Bug 939617; e10s - Bug ?????? - "leaked until shutdown [nsGlobalWindow #82 about:blank]"
-[browser_tabview_bug662266.js]
-[browser_tabview_bug663421.js]
-[browser_tabview_bug665502.js]
-skip-if = buildapp == 'mulet'
-[browser_tabview_bug669694.js]
-[browser_tabview_bug673196.js]
-[browser_tabview_bug673729.js]
-skip-if = true # Bug 749980
-[browser_tabview_bug678374.js]
-skip-if = true # Bug 795265
-[browser_tabview_bug681599.js]
-[browser_tabview_bug685476.js]
-[browser_tabview_bug685692.js]
-[browser_tabview_bug686654.js]
-[browser_tabview_bug696602.js]
-skip-if = true # Bug 736425
-[browser_tabview_bug697390.js]
-[browser_tabview_bug705621.js]
-[browser_tabview_bug706430.js]
-[browser_tabview_bug706736.js]
-skip-if = buildapp == 'mulet'
-[browser_tabview_bug707466.js]
-[browser_tabview_bug712203.js]
-[browser_tabview_bug715454.js]
-[browser_tabview_bug716880.js]
-[browser_tabview_bug728887.js]
-[browser_tabview_bug733115.js]
-[browser_tabview_bug749658.js]
-[browser_tabview_bug766597.js]
-[browser_tabview_click_group.js]
-[browser_tabview_dragdrop.js]
-[browser_tabview_exit_button.js]
-[browser_tabview_expander.js]
-[browser_tabview_firstrun_pref.js]
-[browser_tabview_group.js]
-skip-if = os == "mac" || os == "win" # Bug 945687
-[browser_tabview_launch.js]
-[browser_tabview_multiwindow_search.js]
-skip-if = e10s # Bug 1086190
-[browser_tabview_pending_tabs.js]
-[browser_tabview_privatebrowsing_perwindowpb.js]
-skip-if = os == 'linux' || e10s # linux: Bug 944300; e10s: bug ?????? - "leaked until shutdown [nsGlobalWindow #82 about:blank]"
-[browser_tabview_rtl.js]
-[browser_tabview_search.js]
-[browser_tabview_snapping.js]
-[browser_tabview_startup_transitions.js]
-[browser_tabview_undo_group.js]
deleted file mode 100644
--- a/browser/components/tabview/test/browser_tabview_alltabs.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-function test() {
-  waitForExplicitFinish();
-
-  let AllTabs;
-  let newTab = gBrowser.addTab();
-
-  // TabPinned
-  let pinned = function (event) {
-    let tab = event.target;
-
-    is(tab, newTab, "The tabs are the same after the tab is pinned");
-    ok(tab.pinned, "The tab gets pinned");
-
-    gBrowser.unpinTab(tab);
-  };
-
-  // TabUnpinned
-  let unpinned = function (event) {
-    let tab = event.target;
-
-    AllTabs.unregister("pinned", pinned);
-    AllTabs.unregister("unpinned", unpinned);
-
-    is(tab, newTab, "The tabs are the same after the tab is unpinned");
-    ok(!tab.pinned, "The tab gets unpinned");
-
-    // clean up and finish
-    gBrowser.removeTab(tab);
-    hideTabView(finish);
-  };
-
-  showTabView(function () {
-    AllTabs = TabView.getContentWindow().AllTabs;
-
-    AllTabs.register("pinned", pinned);
-    AllTabs.register("unpinned", unpinned);
-
-    ok(!newTab.pinned, "The tab is not pinned");
-    gBrowser.pinTab(newTab);
-  });
-}
-
deleted file mode 100644
--- a/browser/components/tabview/test/browser_tabview_apptabs.js
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-function test() {
-  waitForExplicitFinish();
-
-  showTabView(onTab