Bug 528884 - Remove places' menu and toolbar bindings. r=mak
authorAsaf Romano <mano@mozilla.com>
Wed, 05 May 2010 15:28:04 +0200
changeset 41915 d7393e28fb2d
parent 41914 11a25fc022ba
child 41916 a8ba788cac18
push id13136
push usermak77@bonardo.net
push dateWed, 05 May 2010 13:30:42 +0000
treeherdermozilla-central@d7393e28fb2d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak
bugs528884
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 528884 - Remove places' menu and toolbar bindings. r=mak
browser/base/content/browser-menubar.inc
browser/base/content/browser-places.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/global-scripts.inc
browser/base/content/test/browser_customize.js
browser/components/places/content/browserPlacesViews.js
browser/components/places/content/controller.js
browser/components/places/content/menu.xml
browser/components/places/content/places.css
browser/components/places/content/places.js
browser/components/places/content/toolbar.xml
browser/components/places/content/tree.xml
browser/components/places/jar.mn
browser/components/places/src/PlacesUIUtils.jsm
browser/components/places/tests/browser/browser_drag_bookmarks_on_toolbar.js
browser/components/places/tests/browser/browser_library_search.js
browser/components/places/tests/browser/browser_sort_in_library.js
browser/components/places/tests/browser/browser_views_liveupdate.js
browser/components/places/tests/chrome/test_0_bug510634.xul
browser/themes/gnomestripe/browser/browser.css
browser/themes/pinstripe/browser/browser.css
browser/themes/winstripe/browser/browser.css
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -450,26 +450,28 @@
                           hidden="true"
                           label="&bidiSwitchPageDirectionItem.label;"
                           accesskey="&bidiSwitchPageDirectionItem.accesskey;"
                           oncommand="SwitchDocumentDirection(window.content)"/>
               </menupopup>
             </menu>
 
             <menu id="history-menu"
-                  oncommand="var node = event.target.node; if (node) { PlacesUIUtils.markPageAsTyped(node.uri); openUILink(node.uri, event, false, true); }"
+                  oncommand="this._placesView._onCommand(event);"
                   onclick="checkForMiddleClick(this, event);"
                   label="&historyMenu.label;"
                   accesskey="&historyMenu.accesskey;">
               <menupopup id="goPopup"
-                         type="places"
-                         onpopupshowing="HistoryMenu.onPopupShowing(event);"
-                         onpopuphidden="HistoryMenu.onPopupHidden(event);"
-                         place="place:redirectsMode=2&amp;sort=4&amp;maxResults=10"
-                         tooltip="bhTooltip" popupsinherittooltip="true">
+#ifndef XP_MACOSX
+                         placespopup="true"
+#endif
+                         onpopupshowing="if (!document.getElementById('history-menu')._placesView)
+                                           new HistoryMenu(event);"
+                         tooltip="bhTooltip"
+                         popupsinherittooltip="true">
                 <menuitem id="historyMenuBack"
                           label="&backCmd.label;"
 #ifdef XP_MACOSX
                           key="goBackKb2"
 #else
                           key="goBackKb"
 #endif
                           command="Browser:BackOrBackDuplicate"
@@ -494,42 +496,50 @@
                           key="showAllHistoryKb"
 #endif
                           command="Browser:ShowAllHistory"/>
                 <menuseparator id="startHistorySeparator"/>
                 <menuseparator id="endHistorySeparator" builder="end"/>
                 <menu id="historyUndoMenu"
                       label="&historyUndoMenu.label;"
                       disabled="true">
-                  <menupopup id="historyUndoPopup" placespopup="true"
-                             onpopupshowing="HistoryMenu.populateUndoSubmenu();"/>
+                  <menupopup id="historyUndoPopup"
+#ifndef XP_MACOSX
+                             placespopup="true"
+#endif
+                             onpopupshowing="document.getElementById('history-menu')._placesView.populateUndoSubmenu();"/>
                 </menu>
                 <menu id="historyUndoWindowMenu"
                       label="&historyUndoWindowMenu.label;"
                       disabled="true">
-                  <menupopup id="historyUndoWindowPopup" placespopup="true"
-                             onpopupshowing="HistoryMenu.populateUndoWindowSubmenu();"/>
+                  <menupopup id="historyUndoWindowPopup"
+#ifndef XP_MACOSX
+                             placespopup="true"
+#endif
+                             onpopupshowing="document.getElementById('history-menu')._placesView.populateUndoWindowSubmenu();"/>
                 </menu>
               </menupopup>
             </menu>
 
   <menu id="bookmarksMenu"
         label="&bookmarksMenu.label;"
         accesskey="&bookmarksMenu.accesskey;"
         ondragenter="PlacesMenuDNDController.onBookmarksMenuDragEnter(event);"
         ondragover="BookmarksMenuDropHandler.onDragOver(event);"
         ondrop="BookmarksMenuDropHandler.onDrop(event);">
     <menupopup id="bookmarksMenuPopup"
-               type="places"
-               place="place:folder=BOOKMARKS_MENU"
+#ifndef XP_MACOSX
+               placespopup="true"
+#endif
                context="placesContext"
                openInTabs="children"
                oncommand="BookmarksEventHandler.onCommand(event);"
                onclick="BookmarksEventHandler.onClick(event);"
-               onpopupshowing="BookmarksEventHandler.onPopupShowing(event);"
+               onpopupshowing="if (!document.getElementById('bookmarksMenu')._placesView)
+                                 new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
                tooltip="bhTooltip" popupsinherittooltip="true">
       <menuitem id="menu_bookmarkThisPage"
                 label="&bookmarkThisPageCmd.label;"
                 command="Browser:AddBookmarkAs"
                 key="addBookmarkAsKb"/>
       <menuitem id="subscribeToPageMenuitem"
                 label="&subscribeToPageMenuitem.label;"
                 oncommand="return FeedHandler.subscribeToFeed(null, event);"
@@ -551,21 +561,23 @@
                 label="&organizeBookmarks.label;"
                 command="Browser:ShowAllBookmarks"
                 key="manBookmarkKb"/>
       <menuseparator id="organizeBookmarksSeparator"/>
       <menu id="bookmarksToolbarFolderMenu"
             class="menu-iconic bookmark-item"
             label="&personalbarCmd.label;"
             container="true">
-        <menupopup id="bookmarksToolbarFolderPopup"
-                   type="places"
-                   place="place:folder=TOOLBAR"
+        <menupopup id="bookmarksToolbarFolderPopup"  
+#ifndef XP_MACOSX
+                   placespopup="true"
+#endif
                    context="placesContext"
-                   onpopupshowing="BookmarksEventHandler.onPopupShowing(event);"/>
+                   onpopupshowing="if (!this.parentNode._placesView)
+                                     new PlacesMenu(event, 'place:folder=TOOLBAR');"/>
       </menu>
       <menuseparator/>
     </menupopup>
   </menu>
 
             <menu id="tools-menu"
                   label="&toolsMenu.label;"
                   accesskey="&toolsMenu.accesskey;">
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -563,25 +563,29 @@ var PlacesCommandHook = {
 
     // remove all tags for the associated url
     PlacesUtils.tagging.untagURI(gEditItemOverlay._uri, null);
 
     this.panel.hidePopup();
   }
 };
 
-// Helper object for the history menu.
-var HistoryMenu = {
-  get _ss() {
-    delete this._ss;
-    return this._ss = Cc["@mozilla.org/browser/sessionstore;1"].
-                      getService(Ci.nsISessionStore);
-  },
+// View for the history menu.
+function HistoryMenu(aPopupShowingEvent) {
+  XPCOMUtils.defineLazyServiceGetter(this, "_ss",
+                                     "@mozilla.org/browser/sessionstore;1",
+                                     "nsISessionStore");
+  PlacesMenu.call(this, aPopupShowingEvent,
+                  "place:redirectsMode=2&sort=4&maxResults=10");
+}
 
-  toggleRecentlyClosedTabs: function PHM_toggleRecentlyClosedTabs() {
+HistoryMenu.prototype = {
+  __proto__: PlacesMenu.prototype,
+
+  toggleRecentlyClosedTabs: function HM_toggleRecentlyClosedTabs() {
     // enable/disable the Recently Closed Tabs sub menu
     var undoPopup = document.getElementById("historyUndoPopup");
 
     // no restorable tabs, so disable menu
     if (this._ss.getClosedTabCount(window) == 0)
       undoPopup.parentNode.setAttribute("disabled", true);
     else
       undoPopup.parentNode.removeAttribute("disabled");
@@ -733,50 +737,38 @@ var HistoryMenu = {
     let m = undoPopup.appendChild(document.createElement("menuitem"));
     m.id = "menu_restoreAllWindows";
     m.setAttribute("label", gNavigatorBundle.getString("menuRestoreAllWindows.label"));
     m.setAttribute("accesskey", gNavigatorBundle.getString("menuRestoreAllWindows.accesskey"));
     m.setAttribute("oncommand",
       "for (var i = 0; i < " + undoItems.length + "; i++) undoCloseWindow();");
   },
 
-  /**
-   * popupshowing handler for the history menu.
-   * @param aEvent
-   *        The popupshowing event.
-   */
-  onPopupShowing: function PHM_onPopupShowing(aEvent) {
+  _onPopupShowing: function HM__onPopupShowing(aEvent) {
+    PlacesMenu.prototype._onPopupShowing.apply(this, arguments);
+
     // Don't handle events for submenus.
     if (aEvent.target != aEvent.currentTarget)
       return;
 
-    var menuPopup = aEvent.target;
-    var resultNode = menuPopup.getResultNode();
+    let resultNode = this.result.root;
     resultNode.containerOpen = true;
     document.getElementById("endHistorySeparator").hidden =
       resultNode.childCount == 0;
 
     this.toggleRecentlyClosedTabs();
     this.toggleRecentlyClosedWindows();
   },
 
-  /**
-   * popuphidden handler for the history menu.
-   * @param aEvent
-   *        The popuphidden event.
-   */
-  onPopupHidden: function PHM_onPopupHidden(aEvent) {
-    // Don't handle events for submenus.
-    if (aEvent.target != aEvent.currentTarget)
-      return;
-
-    var menuPopup = aEvent.target;
-    var resultNode = menuPopup.getResultNode();
-    if (resultNode.containerOpen)
-      resultNode.containerOpen = false;
+  _onCommand: function HM__onCommand(aEvent) {
+    let placesNode = aEvent.target._placesNode;
+    if (placesNode) {
+      PlacesUIUtils.markPageAsTyped(placesNode.uri);
+      openUILink(placesNode.uri, aEvent, false, true);
+    }
   }
 };
 
 /**
  * Functions for handling events in the Bookmarks Toolbar and menu.
  */
 var BookmarksEventHandler = {  
   /**
@@ -805,136 +797,40 @@ var BookmarksEventHandler = {
       for (node = target.parentNode; node; node = node.parentNode) {
         if (node.localName == "menupopup")
           node.hidePopup();
         else if (node.localName != "menu")
           break;
       }
     }
 
-    if (target.node && PlacesUtils.nodeIsContainer(target.node)) {
+    if (target._placesNode && PlacesUtils.nodeIsContainer(target._placesNode)) {
       // Don't open the root folder in tabs when the empty area on the toolbar
       // is middle-clicked or when a non-bookmark item except for Open in Tabs)
       // in a bookmarks menupopup is middle-clicked.
       if (target.localName == "menu" || target.localName == "toolbarbutton")
-        PlacesUIUtils.openContainerNodeInTabs(target.node, aEvent);
+        PlacesUIUtils.openContainerNodeInTabs(target._placesNode, aEvent);
     }
     else if (aEvent.button == 1) {
       // left-clicks with modifier are already served by onCommand
       this.onCommand(aEvent);
     }
   },
 
   /**
    * Handler for command event for an item in the bookmarks toolbar.
    * Menus and submenus from the folder buttons bubble up to this handler.
    * Opens the item.
    * @param aEvent 
    *        DOMEvent for the command
    */
   onCommand: function BM_onCommand(aEvent) {
     var target = aEvent.originalTarget;
-    if (target.node)
-      PlacesUIUtils.openNodeWithEvent(target.node, aEvent);
-  },
-
-  /**
-   * Handler for popupshowing event for an item in bookmarks toolbar or menu.
-   * If the item isn't the main bookmarks menu, add an "Open All in Tabs"
-   * menuitem to the bottom of the popup.
-   * @param event 
-   *        DOMEvent for popupshowing
-   */
-  onPopupShowing: function BM_onPopupShowing(event) {
-    var target = event.originalTarget;
-    if (!target.hasAttribute("placespopup"))
-      return;
-
-    // Check if the popup contains at least 2 menuitems with places nodes
-    var numNodes = 0;
-    var hasMultipleURIs = false;
-    var currentChild = target.firstChild;
-    while (currentChild) {
-      if (currentChild.localName == "menuitem" && currentChild.node) {
-        if (++numNodes == 2) {
-          hasMultipleURIs = true;
-          break;
-        }
-      }
-      currentChild = currentChild.nextSibling;
-    }
-
-    var itemId = target._resultNode.itemId;
-    var siteURIString = "";
-    if (itemId != -1 && PlacesUtils.itemIsLivemark(itemId)) {
-      var siteURI = PlacesUtils.livemarks.getSiteURI(itemId);
-      if (siteURI)
-        siteURIString = siteURI.spec;
-    }
-
-    if (!siteURIString && target._endOptOpenSiteURI) {
-        target.removeChild(target._endOptOpenSiteURI);
-        target._endOptOpenSiteURI = null;
-    }
-
-    if (!hasMultipleURIs && target._endOptOpenAllInTabs) {
-      target.removeChild(target._endOptOpenAllInTabs);
-      target._endOptOpenAllInTabs = null;
-    }
-
-    if (!(hasMultipleURIs || siteURIString)) {
-      // we don't have to show any option
-      if (target._endOptSeparator) {
-        target.removeChild(target._endOptSeparator);
-        target._endOptSeparator = null;
-        target._endMarker = -1;
-      }
-      return;
-    }
-
-    if (!target._endOptSeparator) {
-      // create a separator before options
-      target._endOptSeparator = document.createElement("menuseparator");
-      target._endOptSeparator.className = "bookmarks-actions-menuseparator";
-      target._endMarker = target.childNodes.length;
-      target.appendChild(target._endOptSeparator);
-    }
-
-    if (siteURIString && !target._endOptOpenSiteURI) {
-      // Add "Open (Feed Name)" menuitem if it's a livemark with a siteURI
-      target._endOptOpenSiteURI = document.createElement("menuitem");
-      target._endOptOpenSiteURI.className = "openlivemarksite-menuitem";
-      target._endOptOpenSiteURI.setAttribute("targetURI", siteURIString);
-      target._endOptOpenSiteURI.setAttribute("oncommand",
-          "openUILink(this.getAttribute('targetURI'), event);");
-      // If a user middle-clicks this item we serve the oncommand event
-      // We are using checkForMiddleClick because of Bug 246720
-      // Note: stopPropagation is needed to avoid serving middle-click
-      // with BT_onClick that would open all items in tabs
-      target._endOptOpenSiteURI.setAttribute("onclick",
-          "checkForMiddleClick(this, event); event.stopPropagation();");
-      target._endOptOpenSiteURI.setAttribute("label",
-          PlacesUIUtils.getFormattedString("menuOpenLivemarkOrigin.label",
-          [target.parentNode.getAttribute("label")]));
-      target.appendChild(target._endOptOpenSiteURI);
-    }
-
-    if (hasMultipleURIs && !target._endOptOpenAllInTabs) {
-        // Add the "Open All in Tabs" menuitem if there are
-        // at least two menuitems with places result nodes.
-        target._endOptOpenAllInTabs = document.createElement("menuitem");
-        target._endOptOpenAllInTabs.className = "openintabs-menuitem";
-        target._endOptOpenAllInTabs.setAttribute("oncommand",
-            "PlacesUIUtils.openContainerNodeInTabs(this.parentNode._resultNode, event);");
-        target._endOptOpenAllInTabs.setAttribute("onclick",
-            "checkForMiddleClick(this, event); event.stopPropagation();");
-        target._endOptOpenAllInTabs.setAttribute("label",
-            gNavigatorBundle.getString("menuOpenAllInTabs.label"));
-        target.appendChild(target._endOptOpenAllInTabs);
-    }
+    if (target._placesNode)
+      PlacesUIUtils.openNodeWithEvent(target._placesNode, aEvent);
   },
 
   fillInBHTooltip: function(aDocument, aEvent) {
     var node;
     var cropped = false;
     var targetURI;
 
     if (aDocument.tooltipNode.localName == "treechildren") {
@@ -946,18 +842,18 @@ var BookmarksEventHandler = {
         return false;
       node = tree.view.nodeForTreeIndex(row.value);
       cropped = tbo.isCellCropped(row.value, column.value);
     }
     else {
       // Check whether the tooltipNode is a Places node.
       // In such a case use it, otherwise check for targetURI attribute.
       var tooltipNode = aDocument.tooltipNode;
-      if (tooltipNode.node)
-        node = tooltipNode.node;
+      if (tooltipNode._placesNode)
+        node = tooltipNode._placesNode;
       else {
         // This is a static non-Places node.
         targetURI = tooltipNode.getAttribute("targetURI");
       }
     }
 
     if (!node && !targetURI)
       return false;
@@ -1193,8 +1089,40 @@ var PlacesStarButton = {
                                             aLastModified, aItemType) {
     if (!this._batching && aProperty == "uri")
       this.updateState();
   },
 
   onItemVisited: function() { },
   onItemMoved: function() { }
 };
+
+// This object handles the initlization and uninitlization of the bookmarks
+// toolbar.  updateState is called when the browser window is opened and
+// after closing the toolbar customization dialog.
+let PlacesToolbarHelper = {
+  _place: "place:folder=TOOLBAR",
+  _cachedElt: null,
+
+  onBrowserWindowClose: function PTH_onBrowserWindowClose() {
+    if (this._cachedElt)
+      this._cachedElt._placesView.uninit();
+  },
+
+  updateState: function PTH_updateState() {
+    let currentElt = document.getElementById("PlacesToolbar");
+
+    // Bail out if the state has not changed.
+    if (currentElt == this._cachedElt)
+      return;
+
+    if (!this._cachedElt) {
+      // The toolbar has been added.
+      new PlacesToolbar(this._place);
+      this._cachedElt = currentElt;
+    }
+    else {
+      // The toolbar has been removed.
+      this._cachedElt._placesView.uninit();
+      this._cachedElt = null;
+    }
+  }
+};
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1296,16 +1296,18 @@ function delayedStartup(isLoadingBlank, 
   try {
     Cc["@mozilla.org/browser/sessionstore;1"]
       .getService(Ci.nsISessionStore)
       .init(window);
   } catch (ex) {
     dump("nsSessionStore could not be initialized: " + ex + "\n");
   }
 
+  PlacesToolbarHelper.updateState();
+
   // bookmark-all-tabs command
   gBookmarkAllTabsHandler.init();
 
   // Attach a listener to watch for "command" events bubbling up from error
   // pages.  This lets us fix bugs like 401575 which require error page UI to
   // do privileged things, without letting error pages have any privilege
   // themselves.
   gBrowser.addEventListener("command", BrowserOnCommand, false);
@@ -3346,16 +3348,18 @@ function BrowserToolboxCustomizeDone(aTo
         document.getElementById('Browser:Back').hasAttribute('disabled') &&
         document.getElementById('Browser:Forward').hasAttribute('disabled');
 
 #ifndef XP_MACOSX
     updateEditUIVisibility();
 #endif
   }
 
+  PlacesToolbarHelper.updateState();
+
   UpdateUrlbarSearchSplitterState();
 
   CombinedStopReload.init();
 
   // Update the urlbar
   if (gURLBar) {
     URLBarSetURI();
     XULBrowserWindow.asyncUpdateUI();
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -545,24 +545,50 @@
              defaultset="personal-bookmarks"
              toolbarname="&personalbarCmd.label;" accesskey="&personalbarCmd.accesskey;"
 #ifdef WINCE
              collapsed="true"
 #endif
              customizable="true">
       <toolbaritem flex="1" id="personal-bookmarks" title="&bookmarksItem.title;"
                    removable="true">
-         <hbox id="bookmarksBarContent" flex="1"
-               type="places"
-               place="place:folder=TOOLBAR"
-               context="placesContext"
-               onclick="BookmarksEventHandler.onClick(event);"
-               oncommand="BookmarksEventHandler.onCommand(event);"
-               onpopupshowing="BookmarksEventHandler.onPopupShowing(event);"
-               tooltip="bhTooltip" popupsinherittooltip="true"/>
+        <hbox flex="1"
+              id="PlacesToolbar"
+              context="placesContext"
+              onclick="BookmarksEventHandler.onClick(event);"
+              oncommand="BookmarksEventHandler.onCommand(event);"
+              tooltip="bhTooltip"
+              popupsinherittooltip="true">
+          <toolbarbutton class="bookmark-item bookmarks-toolbar-customize"
+                         mousethrough="never"
+                         label="&bookmarksToolbarItem.label;"/>
+          <hbox flex="1">
+            <hbox align="center">
+              <image id="PlacesToolbarDropIndicator"
+                     mousethrough="always"
+                     collapsed="true"/>
+            </hbox>
+            <scrollbox orient="horizontal"
+                       id="PlacesToolbarItems"
+                       flex="1"/>
+            <toolbarbutton type="menu"
+                           id="PlacesChevron"
+                           class="chevron"
+                           mousethrough="never"
+                           collapsed="true"
+                           tooltiptext="&bookmarksToolbarChevron.tooltip;"
+                           onpopupshowing="document.getElementById('PlacesToolbar')
+                                                   ._placesView._onChevronPopupShowing(event);">
+              <menupopup id="PlacesChevronPopup"
+                         placespopup="true"
+                         popupsinherittooltip="true"
+                         context="placesContext"/>
+            </toolbarbutton>
+          </hbox>
+        </hbox>
       </toolbaritem>
     </toolbar>
 
     <toolbar id="TabsToolbar"
              fullscreentoolbar="true"
              customizable="true"
              mode="icons" lockmode="true"
              iconsize="small" defaulticonsize="small" lockiconsize="true"
--- a/browser/base/content/global-scripts.inc
+++ b/browser/base/content/global-scripts.inc
@@ -34,11 +34,12 @@
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
 <script type="application/javascript" src="chrome://global/content/printUtils.js"/>
 <script type="application/javascript" src="chrome://global/content/viewZoomOverlay.js"/>
+<script type="application/javascript" src="chrome://browser/content/places/browserPlacesViews.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser.js"/>
 <script type="application/javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
 <script type="application/javascript" src="chrome://global/content/viewSourceUtils.js"/>
--- a/browser/base/content/test/browser_customize.js
+++ b/browser/base/content/test/browser_customize.js
@@ -18,18 +18,20 @@ function testCustomizeFrameLoadedPre(){
 function testCustomizeFrameLoaded()
 {
   var panel = document.getElementById("customizeToolbarSheetPopup");
   panel.addEventListener("popuphidden", testCustomizePopupHidden, false);
 
   var frame = document.getElementById("customizeToolbarSheetIFrame");
   frame.removeEventListener("load", testCustomizeFrameLoadedPre, true);
 
-  var menu = document.getElementById("bookmarksMenuPopup");
-  ok("getResult" in menu, "menu has binding");
+  if (navigator.platform.indexOf("Mac") == -1) {
+    var menu = document.getElementById("bookmarksMenuPopup");
+    ok("result" in menu, "menu has binding");
+  }
 
   var framedoc = document.getElementById("customizeToolbarSheetIFrame").contentDocument;
   var b = framedoc.getElementById("donebutton");
 
   b.focus();
   framedoc.getElementById("donebutton").doCommand();
 }
   
new file mode 100644
--- /dev/null
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -0,0 +1,1700 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Places Frontend Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Google Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Annie Sullivan <annie.sullivan@gmail.com>
+ *   Ben Goodger <beng@google.com>
+ *   Myk Melez <myk@mozilla.org>
+ *   Marco Bonardo <mak77@bonardo.net>
+ *   Asaf Romano <mano@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+/**
+ * The base view implements everything that's common to the toolbar and
+ * menu views.
+ */
+function PlacesViewBase(aPlace) {
+  this.place = aPlace;
+  this._controller = new PlacesController(this);
+  this._viewElt.controllers.appendController(this._controller);
+}
+
+PlacesViewBase.prototype = {
+  // The xul element that holds the entire view.
+  _viewElt: null,
+  get viewElt() this._viewElt,
+
+  // The xul element that represents the root container.
+  _rootElt: null,
+
+  // Set to true for views that are represented by native widgets (i.e.
+  // the native mac menu).
+  _nativeView: false,
+
+  QueryInterface: XPCOMUtils.generateQI(
+    [Components.interfaces.nsINavHistoryResultObserver,
+     Components.interfaces.nsISupportsWeakReference]),
+
+  _place: "",
+  get place() this._place,
+  set place(val) {
+    this._place = val;
+
+    let history = PlacesUtils.history;
+    let queries = { }, options = { };
+    history.queryStringToQueries(val, queries, { }, options);
+    if (!queries.value.length)
+      queries.value = [history.getNewQuery()];
+
+    let result = history.executeQueries(queries.value, queries.value.length,
+                                        options.value);
+    result.addObserver(this, false);
+    return val;
+  },
+
+  _result: null,
+  get result() this._result,
+  set result(val) {
+    if (this._result == val)
+      return;
+
+    if (this._result) {
+      this._result.removeObserver(this);
+      this._resultNode.containerOpen = false;
+    }
+
+    if (this._rootElt.localName == "menupopup")
+      this._rootElt._built = false;
+
+    this._result = val;
+    if (val) {
+      this._resultNode = val.root;
+      this._rootElt._placesNode = this._resultNode;
+      this._resultNode._DOMElement = this._rootElt;
+
+      // This calls _rebuild through invalidateContainer.
+      this._resultNode.containerOpen = true;
+    }
+    else {
+      this._resultNode = null;
+    }
+
+    return val;
+  },
+
+  get controller() this._controller,
+
+  get selType() "single",
+  selectItems: function() { },
+  selectAll: function() { },
+
+  get selectedNode() {
+    if (this._contextMenuShown) {
+      let popup = document.popupNode;
+      return popup._placesNode || popup.parentNode._placesNode || null;
+    }
+    return null;
+  },
+
+  get hasSelection() this.selectedNode != null,
+
+  get selectedNodes() {
+    let selectedNode = this.selectedNode;
+    return selectedNode ? [selectedNode] : [];
+  },
+
+  get removableSelectionRanges() {
+    // On static content the current selectedNode would be the selection's
+    // parent node. We don't want to allow removing a node when the
+    // selection is not explicit.
+    if (document.popupNode &&
+        (document.popupNode == "menupopup" || !document.popupNode._placesNode))
+      return [];
+
+    return [this.selectedNodes];
+  },
+
+  get draggableSelection() [this._draggedElt],
+
+  get insertionPoint() {
+    // There is no insertion point for history queries, so bail out now and
+    // save a lot of work when updating commands.
+    let resultNode = this._resultNode;
+    if (PlacesUtils.nodeIsQuery(resultNode) &&
+        PlacesUtils.asQuery(resultNode).queryOptions.queryType ==
+          Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY)
+      return null;
+
+    // By default, the insertion point is at the top level, at the end.
+    let index = PlacesUtils.bookmarks.DEFAULT_INDEX;
+    let container = this._resultNode;
+    let orientation = Ci.nsITreeView.DROP_BEFORE;
+    let isTag = false;
+
+    let selectedNode = this.selectedNode;
+    if (selectedNode) {
+      let popup = document.popupNode;
+      if (!popup._placesNode || popup._placesNode == this._resultNode) {
+        // If a static menuitem is selected, or if the root node is selected,
+        // the insertion point is inside the folder, at the end.
+        container = selectedNode;
+        orientation = Ci.nsITreeView.DROP_ON;
+      }
+      else {
+        // In all other cases the insertion point is before that node.
+        container = selectedNode.parent;
+        index = container.getChildIndex(selectedNode);
+        isTag = PlacesUtils.nodeIsTagQuery(container);
+      }
+    }
+
+    if (PlacesControllerDragHelper.disallowInsertion(container))
+      return null;
+
+    return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
+                              index, orientation, isTag);
+  },
+
+  buildContextMenu: function PVB_buildContextMenu(aPopup) {
+    this._contextMenuShown = true;
+    window.updateCommands("places");
+    return this.controller.buildContextMenu(aPopup);
+  },
+
+  destroyContextMenu: function PVB_destroyContextMenu(aPopup) {
+    this._contextMenuShown = false;
+    if (window.content)
+      window.content.focus();
+  },
+
+  _cleanPopup: function PVB_cleanPopup(aPopup) {
+    // Remove places popup children and update markers to keep track of
+    // their indices.
+    let start = aPopup._startMarker != -1 ? aPopup._startMarker + 1 : 0;
+    let end = aPopup._endMarker != -1 ? aPopup._endMarker :
+                                        aPopup.childNodes.length;
+    let items = [];
+    let placesNodeFound = false;
+    for (let i = start; i < end; ++i) {
+      let item = aPopup.childNodes[i];
+      if (item.getAttribute("builder") == "end") {
+        // we need to do this for menus that have static content at the end but
+        // are initially empty, eg. the history menu, we need to know where to
+        // start inserting new items.
+        aPopup._endMarker = i;
+        break;
+      }
+      if (item._placesNode) {
+        items.push(item);
+        placesNodeFound = true;
+      }
+      else {
+        // This is static content...
+        if (!placesNodeFound)
+          // ...at the start of the popup
+          // Initialized in menu.xml, in the base binding
+          aPopup._startMarker++;
+        else {
+          // ...after places nodes
+          aPopup._endMarker = i;
+          break;
+        }
+      }
+    }
+
+    for (let i = 0; i < items.length; ++i) {
+      aPopup.removeChild(items[i]);
+      if (aPopup._endMarker != -1)
+        aPopup._endMarker--;
+    }
+  },
+
+  _rebuildPopup: function PVB__rebuildPopup(aPopup) {
+    this._cleanPopup(aPopup);
+
+    // If this is a livemark container check if the status menuitem has
+    // to be added or removed.
+    if (PlacesUtils.nodeIsLivemarkContainer(aPopup._placesNode))
+      this._ensureLivemarkStatusMenuItem(aPopup);
+
+    let resultNode = aPopup._placesNode;
+    if (!resultNode.containerOpen)
+      return;
+
+    let cc = resultNode.childCount;
+    if (cc > 0) {
+      if (aPopup._emptyMenuItem)
+        aPopup._emptyMenuItem.hidden = true;
+
+      for (let i = 0; i < cc; ++i) {
+        let child = resultNode.getChild(i);
+        this._insertNewItemToPopup(child, aPopup, null);
+      }
+    }
+    else {
+      // This menu is empty.  If there is no static content, add
+      // an element to show it is empty.
+      if (aPopup._startMarker == -1 && aPopup._endMarker == -1)
+        this._showEmptyMenuItem(aPopup);
+    }
+    aPopup._built = true;
+  },
+
+  _removeChild: function PVB__removeChild(aChild) {
+    // If document.popupNode pointed to this child, null it out,
+    // otherwise controller's command-updating may rely on the removed
+    // item still being "selected".
+    if (document.popupNode == aChild)
+      document.popupNode = null;
+
+    aChild.parentNode.removeChild(aChild);
+  },
+
+  _showEmptyMenuItem: function PVB__showEmptyMenuItem(aPopup) {
+    if (aPopup._emptyMenuItem) {
+      aPopup._emptyMenuItem.hidden = false;
+      return;
+    }
+
+    let label = PlacesUIUtils.getString("bookmarksMenuEmptyFolder");
+    aPopup._emptyMenuItem = document.createElement("menuitem");
+    aPopup._emptyMenuItem.setAttribute("label", label);
+    aPopup._emptyMenuItem.setAttribute("disabled", true);
+    aPopup.appendChild(aPopup._emptyMenuItem);
+  },
+
+  _createMenuItemForPlacesNode:
+  function PVB__createMenuItemForPlacesNode(aPlacesNode) {
+    let element;
+    let type = aPlacesNode.type;
+    if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR)
+      element = document.createElement("menuseparator");
+    else {
+      if (PlacesUtils.uriTypes.indexOf(type) != -1) {
+        element = document.createElement("menuitem");
+        element.className = "menuitem-iconic bookmark-item menuitem-with-favicon";
+        element.setAttribute("scheme",
+                             PlacesUIUtils.guessUrlSchemeForUI(aPlacesNode.uri));
+      }
+      else if (PlacesUtils.containerTypes.indexOf(type) != -1) {
+        element = document.createElement("menu");
+        element.setAttribute("container", "true");
+
+        if (aPlacesNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY) {
+          element.setAttribute("query", "true");
+          if (PlacesUtils.nodeIsTagQuery(aPlacesNode))
+            element.setAttribute("tagContainer", "true");
+          else if (PlacesUtils.nodeIsDay(aPlacesNode))
+            element.setAttribute("dayContainer", "true");
+          else if (PlacesUtils.nodeIsHost(aPlacesNode))
+            element.setAttribute("hostContainer", "true");
+        }
+        else if (aPlacesNode.itemId != -1) {
+          if (PlacesUtils.nodeIsLivemarkContainer(aPlacesNode))
+            element.setAttribute("livemark", "true");
+        }
+
+        let popup = document.createElement("menupopup");
+        popup._placesNode = PlacesUtils.asContainer(aPlacesNode);
+        if (this._nativeView) {
+          popup._startMarker = -1;
+          popup._endMarker = -1;
+        }
+        else
+          popup.setAttribute("placespopup", "true");
+#ifdef XP_MACOSX
+        // No context menu on mac.
+        popup.setAttribute("context", "placesContext");
+#endif
+        element.appendChild(popup);
+        element.className = "menu-iconic bookmark-item";
+
+        aPlacesNode._DOMElement = popup;
+      }
+      else
+        throw "Unexpected node";
+
+      element.setAttribute("label", PlacesUIUtils.getBestTitle(aPlacesNode));
+
+      let icon = aPlacesNode.icon;
+      if (icon)
+        element.setAttribute("image", icon);
+    }
+
+    element._placesNode = aPlacesNode;
+    if (!aPlacesNode._DOMElement)
+      aPlacesNode._DOMElement = element;
+
+    return element;
+  },
+
+  _insertNewItemToPopup:
+  function PVB__insertNewItemToPopup(aNewChild, aPopup, aBefore) {
+    let element = this._createMenuItemForPlacesNode(aNewChild);
+
+    if (aBefore) {
+      aPopup.insertBefore(element, aBefore);
+    }
+    else {
+      // Add the new element to the menu.  If there is static content at
+      // the end of the menu, add the element before that.  Otherwise,
+      // just add to the end.
+      if (aPopup._endMarker != -1) {
+        let lastElt = aPopup.childNodes[aPopup._endMarker];
+        aPopup.insertBefore(element, lastElt);
+      }
+      else {
+        aPopup.appendChild(element);
+      }
+    }
+
+    if (aPopup._endMarker != -1)
+      aPopup._endMarker++;
+
+    return element;
+  },
+
+  /**
+   * Add, update or remove the livemark status menuitem.
+   * @param aPopup
+   *        The livemark container popup
+   */
+  _ensureLivemarkStatusMenuItem:
+  function PVB_ensureLivemarkStatusMenuItem(aPopup) {
+    let itemId = aPopup._placesNode.itemId;
+    let as = PlacesUtils.annotations;
+
+    let lmStatus = null;
+    if (as.itemHasAnnotation(itemId, "livemark/loadfailed"))
+      lmStatus = "bookmarksLivemarkFailed";
+    else if (as.itemHasAnnotation(itemId, "livemark/loading"))
+      lmStatus = "bookmarksLivemarkLoading";
+
+    let lmStatusElt = aPopup._lmStatusMenuItem;
+    if (lmStatus && !lmStatusElt) {
+      // Create the status menuitem and cache it in the popup object.
+      lmStatusElt = document.createElement("menuitem");
+      lmStatusElt.setAttribute("lmStatus", lmStatus);
+      lmStatusElt.setAttribute("label", PlacesUIUtils.getString(lmStatus));
+      lmStatusElt.setAttribute("disabled", true);
+      aPopup.insertBefore(lmStatusElt,
+                          aPopup.childNodes.item(aPopup._startMarker + 1));
+      aPopup._startMarker++;
+    }
+    else if (lmStatus && lmStatusElt.getAttribute("lmStatus") != lmStatus) {
+      // Status has changed, update the cached status menuitem.
+      lmStatusElt.setAttribute("label", this.getString(lmStatus));
+    }
+    else if (!lmStatus && lmStatusElt) {
+      // No status, remove the cached menuitem.
+      aPopup.removeChild(aPopup._lmStatusMenuItem);
+      aPopup._lmStatusMenuItem = null;
+      aPopup._startMarker--;
+    }
+  },
+
+  nodeURIChanged: function PVB_nodeURIChanged(aPlacesNode, aURIString) {
+    let elt = aPlacesNode._DOMElement;
+    if (!elt)
+      throw "aPlacesNode must have _DOMElement set";
+
+    // Here we need the <menu>.
+    if (elt.localName == "menupopup")
+      elt = elt.parentNode;
+
+    elt.setAttribute("scheme", PlacesUIUtils.guessUrlSchemeForUI(aURIString));
+  },
+
+  nodeIconChanged: function PT_nodeIconChanged(aPlacesNode) {
+    let elt = aPlacesNode._DOMElement;
+    if (!elt)
+      throw "aPlacesNode must have _DOMElement set";
+
+    // There's no UI representation for the root node, thus there's nothing to
+    // be done when the icon changes.
+    if (elt == this._rootElt)
+      return;
+
+    // Here we need the <menu>.
+    if (elt.localName == "menupopup")
+      elt = elt.parentNode;
+
+    let icon = aPlacesNode.icon;
+    if (!icon)
+      elt.removeAttribute("image");
+    else if (icon != elt.getAttribute("image"))
+      elt.setAttribute("image", icon);
+  },
+
+  nodeAnnotationChanged:
+  function PVB_nodeAnnotationChanged(aPlacesNode, aAnno) {
+    // Ensure the changed annotation is a livemark one.
+    if (/^livemark\//.test(aAnno) &&
+        PlacesUtils.nodeIsLivemarkContainer(aPlacesNode)) {
+      let elt = aPlacesNode._DOMElement;
+      if (!elt)
+        throw "aPlacesNode must have _DOMElement set";
+
+      let menu = elt.parentNode;
+      if (!menu.hasAttribute("livemark"))
+        menu.setAttribute("livemark", "true");
+
+      // Add or remove the livemark status menuitem.
+      this._ensureLivemarkStatusMenuItem(elt);
+    }
+  },
+
+  nodeRemoved:
+  function PVB_nodeRemoved(aParentPlacesNode, aPlacesNode, aIndex) {
+    let parentElt = aParentPlacesNode._DOMElement;
+    let elt = aPlacesNode._DOMElement;
+
+    if (!parentElt)
+      throw "aParentPlacesNode must have _DOMElement set";
+    if (!elt)
+      throw "aPlacesNode must have _DOMElement set";
+
+    // Here we need the <menu>.
+    if (elt.localName == "menupopup")
+      elt = elt.parentNode;
+
+    if (parentElt._built) {
+      parentElt.removeChild(elt);
+
+      // Figure out if we need to show the "<Empty>" menu-item.
+      // TODO Bug 517701: This doesn't seem to handle the case of an empty
+      // root.
+      if (!parentElt.hasChildNodes() ||
+          (parentElt.childNodes.length == 1 &&
+          parentElt.firstChild == parentElt._emptyMenuItem))
+        this._showEmptyMenuItem(parentElt);
+
+      if (parentElt._endMarker != -1)
+        parentElt._endMarker--;
+    }
+  },
+
+  nodeReplaced:
+  function PBV_nodeReplaced(aParentPlacesNode, aOldPlacesNode, aNewPlacesNode, aIndex) {
+    let parentElt = aParentPlacesNode._DOMElement;
+    if (!parentElt)
+      throw "aParentPlacesNode node must have _DOMElement set";
+
+    if (parentElt._built) {
+      let elt = aOldPlacesNode._DOMElement;
+      if (!elt)
+        throw "aOldPlacesNode must have _DOMElement set";
+
+      // Here we need the <menu>.
+      if (elt.localName == "menupopup")
+        elt = elt.parentNode;
+
+      parentElt.removeChild(elt);
+
+      // No worries: If elt is the last item (i.e. no nextSibling),
+      // _insertNewItem/_insertNewItemToPopup will insert the new element as
+      // the last item.
+      let nextElt = elt.nextSibling;
+      this._insertNewItemToPopup(aNewPlacesNode, parentElt, nextElt);
+    }
+  },
+
+  nodeHistoryDetailsChanged: function() { },
+  nodeTagsChanged: function() { },
+  nodeDateAddedChanged: function() { },
+  nodeLastModifiedChanged: function() { },
+  nodeKeywordChanged: function() { },
+  sortingChanged: function() { },
+  // Replaced by containerStateChanged.
+  containerOpened: function() { },
+  containerClosed: function() { },
+
+  nodeInserted:
+  function PVB_nodeInserted(aParentPlacesNode, aPlacesNode, aIndex) {
+    let parentElt = aParentPlacesNode._DOMElement;
+    if (!parentElt)
+      throw "aParentPlacesNode node must have _DOMElement set";
+
+    if (!parentElt._built)
+      return;
+
+    let index = parentElt._startMarker + 1 + aIndex;
+    this._insertNewItemToPopup(aPlacesNode, parentElt,
+                               parentElt.childNodes[index]);
+    if (parentElt._emptyMenuItem)
+      parentElt._emptyMenuItem.hidden = true;
+  },
+
+  nodeMoved:
+  function PBV_nodeMoved(aPlacesNode,
+                         aOldParentPlacesNode, aOldIndex,
+                         aNewParentPlacesNode, aNewIndex) {
+    // Note: the current implementation of moveItem does not actually
+    // use this notification when the item in question is moved from one
+    // folder to another.  Instead, it calls nodeRemoved and nodeInserted
+    // for the two folders.  Thus, we can assume old-parent == new-parent.
+    let elt = aPlacesNode._DOMElement;
+    if (!elt)
+      throw "aPlacesNode must have _DOMElement set";
+
+    // Here we need the <menu>.
+    if (elt.localName == "menupopup")
+      elt = elt.parentNode;
+
+    // If our root node is a folder, it might be moved. There's nothing
+    // we need to do in that case.
+    if (elt == this._rootElt)
+      return;
+
+    let parentElt = aNewParentPlacesNode._DOMElement;
+    if (!parentElt)
+      throw "aNewParentPlacesNode node must have _DOMElement set";
+
+    if (parentElt._built) {
+      // Move the node.
+      parentElt.removeChild(elt);
+      let index = parentElt._startMarker + 1 + aNewIndex;
+      parentElt.insertBefore(elt, parentElt.childNodes[index]);
+    }
+  },
+
+  containerStateChanged:
+  function PVB_containerStateChanged(aPlacesNode, aOldState, aNewState) {
+    if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED ||
+        aNewState == Ci.nsINavHistoryContainerResultNode.STATE_CLOSED) {
+      this.invalidateContainer(aPlacesNode);
+    }
+    else {
+      throw "Unexpected state passed to containerStateChanged";
+    }
+  },
+
+  invalidateContainer: function PVB_invalidateContainer(aPlacesNode) {
+    let elt = aPlacesNode._DOMElement;
+    if (!elt)
+      throw "aPlacesNode must have _DOMElement set";
+
+    elt._built = false;
+
+    // If the menupopup is open we should live-update it.
+    if (elt.parentNode.open)
+      this._rebuildPopup(elt);
+  },
+
+  uninit: function PVB_uninit() {
+    if (this._result) {
+      this._result.removeObserver(this);
+      this._resultNode.containerOpen = false;
+      this._resultNode = null;
+      this._result = null;
+    }
+
+    delete this._viewElt._placesView;
+  },
+
+  get isRTL() {
+    if ("_isRTL" in this)
+      return this._isRTL;
+
+    return this._isRTL = document.defaultView.getComputedStyle(this, "")
+                                 .direction == "rtl"
+  },
+
+  /**
+   * Adds an "Open All in Tabs" menuitem to the bottom of the popup.
+   * @param aPopup
+   *        a Places popup.
+   */
+  _mayAddCommandsItems: function PVB__mayAddCommandsItems(aPopup) {
+    // The command items are never added to the root popup.
+    if (aPopup == this._rootElt)
+      return;
+
+    // Check if the popup contains at least 2 menuitems with places nodes
+    let numURINodes = 0;
+    let currentChild = aPopup.firstChild;
+    while (currentChild) {
+      if (currentChild.localName == "menuitem" && currentChild._placesNode) {
+        if (++numURINodes == 2)
+          break;
+      }
+      currentChild = currentChild.nextSibling;
+    }
+
+    let hasMultipleURIs = numURINodes > 1;
+    let itemId = aPopup._placesNode.itemId;
+    let siteURIString = "";
+    if (itemId != -1 && PlacesUtils.itemIsLivemark(itemId)) {
+      let siteURI = PlacesUtils.livemarks.getSiteURI(itemId);
+      if (siteURI)
+        siteURIString = siteURI.spec;
+    }
+
+    if (!siteURIString && aPopup._endOptOpenSiteURI) {
+      aPopup.removeChild(aPopup._endOptOpenSiteURI);
+      aPopup._endOptOpenSiteURI = null;
+    }
+
+    if (!hasMultipleURIs && aPopup._endOptOpenAllInTabs) {
+      aPopup.removeChild(aPopup._endOptOpenAllInTabs);
+      aPopup._endOptOpenAllInTabs = null;
+    }
+
+    if (!(hasMultipleURIs || siteURIString)) {
+      // We don't have to show any option.
+      if (aPopup._endOptSeparator) {
+        aPopup.removeChild(aPopup._endOptSeparator);
+        aPopup._endOptSeparator = null;
+        aPopup._endMarker = -1;
+      }
+      return;
+    }
+
+    if (!aPopup._endOptSeparator) {
+      // Create a separator before options.
+      aPopup._endOptSeparator = document.createElement("menuseparator");
+      aPopup._endOptSeparator.className = "bookmarks-actions-menuseparator";
+      aPopup._endMarker = aPopup.childNodes.length;
+      aPopup.appendChild(aPopup._endOptSeparator);
+    }
+
+    if (siteURIString && !aPopup._endOptOpenSiteURI) {
+      // Add "Open (Feed Name)" menuitem if it's a livemark with a siteURI.
+      aPopup._endOptOpenSiteURI = document.createElement("menuitem");
+      aPopup._endOptOpenSiteURI.className = "openlivemarksite-menuitem";
+      aPopup._endOptOpenSiteURI.setAttribute("targetURI", siteURIString);
+      aPopup._endOptOpenSiteURI.setAttribute("oncommand",
+          "openUILink(this.getAttribute('targetURI'), event);");
+
+      // If a user middle-clicks this item we serve the oncommand event
+      // We are using checkForMiddleClick because of Bug 246720
+      // Note: stopPropagation is needed to avoid serving middle-click
+      // with BT_onClick that would open all items in tabs.
+      aPopup._endOptOpenSiteURI.setAttribute("onclick",
+          "checkForMiddleClick(this, event); event.stopPropagation();");
+      aPopup._endOptOpenSiteURI.setAttribute("label",
+          PlacesUIUtils.getFormattedString("menuOpenLivemarkOrigin.label",
+          [aPopup.parentNode.getAttribute("label")]));
+      aPopup.appendChild(aPopup._endOptOpenSiteURI);
+    }
+
+    if (hasMultipleURIs && !aPopup._endOptOpenAllInTabs) {
+      // Add the "Open All in Tabs" menuitem if there are
+      // at least two menuitems with places result nodes.
+      aPopup._endOptOpenAllInTabs = document.createElement("menuitem");
+      aPopup._endOptOpenAllInTabs.className = "openintabs-menuitem";
+      aPopup._endOptOpenAllInTabs.setAttribute("oncommand",
+        "PlacesUIUtils.openContainerNodeInTabs(this.parentNode._placesNode, event);");
+      aPopup._endOptOpenAllInTabs.setAttribute("onclick",
+        "checkForMiddleClick(this, event); event.stopPropagation();");
+      aPopup._endOptOpenAllInTabs.setAttribute("label",
+        gNavigatorBundle.getString("menuOpenAllInTabs.label"));
+      aPopup.appendChild(aPopup._endOptOpenAllInTabs);
+    }
+  },
+
+  _onPopupShowing: function PVB__onPopupShowing(aEvent) {
+    // Avoid handling popupshowing of inner views.
+    let popup = aEvent.originalTarget;
+    if (popup._placesNode && PlacesUIUtils.getViewForNode(popup) == this) {
+      if (!popup._placesNode.containerOpen)
+        popup._placesNode.containerOpen = true;
+      if (!popup._built)
+        this._rebuildPopup(popup);
+
+      this._mayAddCommandsItems(popup);
+    }
+  },
+
+  _addEventListeners:
+  function PVB__addEventListeners(aObject, aEventNames, aCapturing) {
+    for (let i = 0; i < aEventNames.length; i++) {
+      aObject.addEventListener(aEventNames[i], this, aCapturing);
+    }
+  },
+
+  _removeEventListeners:
+  function PVB__removeEventListeners(aObject, aEventNames, aCapturing) {
+    for (let i = 0; i < aEventNames.length; i++) {
+      aObject.removeEventListener(aEventNames[i], this, aCapturing);
+    }
+  },
+};
+
+function PlacesToolbar(aPlace) {
+  // Add some smart getters for our elements.
+  let thisView = this;
+  [
+    ["_viewElt",              "PlacesToolbar"],
+    ["_rootElt",              "PlacesToolbarItems"],
+    ["_dropIndicator",        "PlacesToolbarDropIndicator"],
+    ["_chevron",              "PlacesChevron"],
+    ["_chevronPopup",         "PlacesChevronPopup"]
+  ].forEach(function (elementGlobal) {
+    let [name, id] = elementGlobal;
+    thisView.__defineGetter__(name, function () {
+      let element = document.getElementById(id);
+      if (!element)
+        return null;
+
+      delete thisView[name];
+      return thisView[name] = element;
+    });
+  });
+
+  this._viewElt._placesView = this;
+
+  this._addEventListeners(this._viewElt, this._cbEvents, false);
+  this._addEventListeners(this._rootElt, ["popupshowing", "popuphidden"], true);
+  this._addEventListeners(this._rootElt, ["overflow", "underflow"], true);
+  this._addEventListeners(window, ["resize", "unload"], false);
+
+  PlacesViewBase.call(this, aPlace);
+}
+
+PlacesToolbar.prototype = {
+  __proto__: PlacesViewBase.prototype,
+
+  _cbEvents: ["dragstart", "dragover", "dragleave", "dragend", "drop",
+#ifdef XP_UNIX
+#ifndef XP_MACOSX
+              "mousedown",
+#endif
+#endif
+              "mousemove", "mouseover", "mouseout"],
+
+  QueryInterface: function PT_QueryInterface(aIID) {
+    if (aIID.equals(Ci.nsIDOMEventListener) ||
+        aIID.equals(Ci.nsITimerCallback))
+      return this;
+
+    return PlacesViewBase.prototype.QueryInterface.apply(this, arguments);
+  },
+
+  uninit: function PT_uninit() {
+    this._removeEventListeners(this._viewElt, this._cbEvents, false);
+    this._removeEventListeners(this._rootElt, ["popupshowing", "popuphidden"],
+                               true);
+    this._removeEventListeners(this._rootElt, ["overflow", "underflow"], true);
+    this._removeEventListeners(window, ["resize", "unload"], false);
+
+    PlacesViewBase.prototype.uninit.apply(this, arguments);
+  },
+
+  _openedMenuButton: null,
+  _allowPopupShowing: true,
+
+  _rebuild: function PT__rebuild() {
+    // Clear out references to existing nodes, since they will be removed
+    // and re-added.
+    if (this._overFolder.elt)
+      this._clearOverFolder();
+
+    this._openedMenuButton = null;
+    while (this._rootElt.hasChildNodes()) {
+      this._rootElt.removeChild(this._rootElt.firstChild);
+    }
+
+    let cc = this._resultNode.childCount;
+    for (let i = 0; i < cc; ++i) {
+      this._insertNewItem(this._resultNode.getChild(i), null);
+    }
+
+    if (this._chevronPopup.hasAttribute("type")) {
+      // Chevron has already been initialized, but since we are forcing
+      // a rebuild of the toolbar, it has to be rebuilt.
+      // Otherwise, it will be initialized when the toolbar overflows.
+      this._chevronPopup.place = this.place;
+    }
+  },
+
+  _insertNewItem:
+  function PT__insertNewItem(aChild, aBefore) {
+    let type = aChild.type;
+    let button;
+    if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) {
+      button = document.createElement("toolbarseparator");
+    }
+    else {
+      button = document.createElement("toolbarbutton");
+      button.className = "bookmark-item";
+      button.setAttribute("label", aChild.title);
+      let icon = aChild.icon;
+      if (icon)
+        button.setAttribute("image", icon);
+
+      if (PlacesUtils.containerTypes.indexOf(type) != -1) {
+        button.setAttribute("type", "menu");
+        button.setAttribute("container", "true");
+
+        if (PlacesUtils.nodeIsQuery(aChild)) {
+          button.setAttribute("query", "true");
+          if (PlacesUtils.nodeIsTagQuery(aChild))
+            button.setAttribute("tagContainer", "true");
+        }
+        else if (PlacesUtils.nodeIsLivemarkContainer(aChild)) {
+          button.setAttribute("livemark", "true");
+        }
+
+        let popup = document.createElement("menupopup");
+        popup.setAttribute("placespopup", "true");
+        button.appendChild(popup);
+        popup._placesNode = PlacesUtils.asContainer(aChild);
+#ifndef XP_MACOSX
+        popup.setAttribute("context", "placesContext");
+#endif
+
+        aChild._DOMElement = popup;
+      }
+      else if (PlacesUtils.nodeIsURI(aChild)) {
+        button.setAttribute("scheme",
+                            PlacesUIUtils.guessUrlSchemeForUI(aChild.uri));
+      }
+    }
+
+    button._placesNode = aChild;
+    if (!aChild._DOMElement)
+      aChild._DOMElement = button;
+
+    if (aBefore)
+      this._rootElt.insertBefore(button, aBefore);
+    else
+      this._rootElt.appendChild(button);
+  },
+
+  _updateChevronPopupNodesVisibility:
+  function PT__updateChevronPopupNodesVisibility() {
+    for (let i = 0; i < this._chevronPopup.childNodes.length; i++) {
+      this._chevronPopup.childNodes[i].hidden =
+        this._rootElt.childNodes[i].style.visibility != "hidden";
+    }
+  },
+
+  _onChevronPopupShowing:
+  function PT__onChevronPopupShowing(aEvent) {
+    // Handle popupshowing only for the chevron popup, not for nested ones.
+    if (aEvent.target != this._chevronPopup)
+      return;
+
+    if (!this._chevron._placesView)
+      this._chevron._placesView = new PlacesMenu(aEvent, this.place);
+
+    this._updateChevronPopupNodesVisibility();
+  },
+
+  handleEvent: function PT_handleEvent(aEvent) {
+    switch (aEvent.type) {
+      case "unload":
+        this.uninit();
+        break;
+      case "resize":
+        // This handler updates nodes visibility in both the toolbar
+        // and the chevron popup when a window resize does not change
+        // the overflow status of the toolbar.
+        this.updateChevron();
+        break;
+      case "overflow":
+        if (aEvent.target != aEvent.currentTarget)
+          return;
+
+        // Ignore purely vertical overflows.
+        if (aEvent.detail == 0)
+          return;
+
+        // Attach the popup binding to the chevron popup if it has not yet
+        // been initialized.
+        if (!this._chevronPopup.hasAttribute("type")) {
+          this._chevronPopup.setAttribute("place", this.place);
+          this._chevronPopup.setAttribute("type", "places");
+        }
+        this._chevron.collapsed = false;
+        this.updateChevron();
+        break;
+      case "underflow":
+        if (aEvent.target != aEvent.currentTarget)
+          return;
+
+        // Ignore purely vertical underflows.
+        if (aEvent.detail == 0)
+          return;
+
+        this._chevron.collapsed = true;
+        this.updateChevron();
+        break;
+      case "dragstart":
+        this._onDragStart(aEvent);
+        break;
+      case "dragover":
+        this._onDragOver(aEvent);
+        break;
+      case "dragleave":
+        this._onDragLeave(aEvent);
+        break;
+      case "dragend":
+        this._onDragEnd(aEvent);
+        break;
+      case "drop":
+        this._onDrop(aEvent);
+        break;
+      case "mouseover":
+        this._onMouseOver(aEvent);
+        break;
+      case "mousemove":
+        this._onMouseMove(aEvent);
+        break;
+      case "mouseout":
+        this._onMouseOut(aEvent);
+        break;
+      case "mousedown":
+        this._onMouseDown(aEvent);
+        break;
+      case "popupshowing":
+        this._onPopupShowing(aEvent);
+        break;
+      case "popuphidden":
+        this._onPopupHidden(aEvent);
+        break;
+    }
+  },
+
+  updateChevron: function PT_updateChevron() {
+    // If the chevron is collapsed there's nothing to update.
+    if (this._chevron.collapsed)
+      return;
+
+    // XXX (bug 508816) Scrollbox does not handle correctly RTL mode.
+    // This workarounds the issue scrolling the box to the right.
+    if (this._isRTL)
+      this._rootElt.scrollLeft = this._rootElt.scrollWidth;
+
+    // Update the chevron on a timer.  This will avoid repeated work when
+    // lot of changes happen in a small timeframe.
+    if (this._updateChevronTimer)
+      this._updateChevronTimer.cancel();
+
+    this._updateChevronTimer = this._setTimer(100);
+  },
+
+  _updateChevronTimerCallback: function PT__updateChevronTimerCallback() {
+    let scrollRect = this._rootElt.getBoundingClientRect();
+    let childOverflowed = false;
+    for (let i = 0; i < this._rootElt.childNodes.length; i++) {
+      let child = this._rootElt.childNodes[i];
+      // Once a child overflows, all the next ones will.
+      if (!childOverflowed) {
+        let childRect = child.getBoundingClientRect();
+        childOverflowed = this._isRTL ? (childRect.left < scrollRect.left)
+                                      : (childRect.right > scrollRect.right);
+      }
+      child.style.visibility = childOverflowed ? "hidden" : "visible";
+    }
+
+    // We rebuild the chevron on popupShowing, so if it is open
+    // we must update it.
+    if (this._chevron.open)
+      this._updateChevronPopupNodesVisibility();
+  },
+
+  nodeInserted:
+  function PT_nodeInserted(aParentPlacesNode, aPlacesNode, aIndex) {
+    let parentElt = aParentPlacesNode._DOMElement;
+    if (!parentElt) 
+      throw "aParentPlacesNode node must have _DOMElement set";
+
+    if (parentElt == this._rootElt) {
+      let children = this._rootElt.childNodes;
+      this._insertNewItem(aPlacesNode,
+        aIndex < children.length ? children[aIndex] : null);
+      this.updateChevron();
+      return;
+    }
+
+    PlacesViewBase.prototype.nodeInserted.apply(this, arguments);
+  },
+
+  nodeRemoved:
+  function PT_nodeRemoved(aParentPlacesNode, aPlacesNode, aIndex) {
+    let parentElt = aParentPlacesNode._DOMElement;
+    let elt = aPlacesNode._DOMElement;
+
+    if (!parentElt)
+      throw "aParentPlacesNode node must have _DOMElement set";
+    if (!elt)
+      throw "aPlacesNode must have _DOMElement set";
+
+    // Here we need the <menu>.
+    if (elt.localName == "menupopup")
+      elt = elt.parentNode;
+
+    if (parentElt == this._rootElt) {
+      this._removeChild(elt);
+      this.updateChevron();
+      return;
+    }
+
+    PlacesViewBase.prototype.nodeRemoved.apply(this, arguments);
+  },
+
+  nodeMoved:
+  function PT_nodeMoved(aPlacesNode,
+                        aOldParentPlacesNode, aOldIndex,
+                        aNewParentPlacesNode, aNewIndex) {
+    let parentElt = aNewParentPlacesNode._DOMElement;
+    if (!parentElt) 
+      throw "aNewParentPlacesNode node must have _DOMElement set";
+
+    if (parentElt == this._rootElt) {
+      // Container is on the toolbar.
+
+      // Move the element.
+      let elt = aPlacesNode._DOMElement;
+      if (!elt)
+        throw "aPlacesNode must have _DOMElement set";
+
+      // Here we need the <menu>.
+      if (elt.localName == "menupopup")
+        elt = elt.parentNode;
+
+      this._removeChild(elt);
+      this._rootElt.insertBefore(elt, this._rootElt.childNodes[aNewIndex]);
+
+      // If the chevron popup is open, keep it in sync.
+      if (this._chevron.open) {
+        let chevronPopup = this._chevronPopup;
+        let menuitem = chevronPopup.childNodes[aOldIndex];
+        chevronPopup.removeChild(menuitem);
+        chevronPopup.insertBefore(menuitem,
+                                  chevronPopup.childNodes[aNewIndex]);
+      }
+      this.updateChevron();
+      return;
+    }
+
+    PlacesViewBase.prototype.nodeMoved.apply(this, arguments);
+  },
+
+  nodeTitleChanged: function PT_nodeTitleChanged(aPlacesNode, aNewTitle) {
+    let elt = aPlacesNode._DOMElement;
+    if (!elt)
+      throw "aPlacesNode must have _DOMElement set";
+
+    // There's no UI representation for the root node, thus there's
+    // nothing to be done when the title changes.
+    if (elt == this._rootElt)
+      return;
+
+    // Here we need the <menu>.
+    if (elt.localName == "menupopup")
+      elt = elt.parentNode;
+
+    if (elt.parentNode == this._rootElt) {
+      // Node is on the toolbar
+      elt.label = aNewTitle;
+      this.updateChevron();
+    }
+    else {
+      // Node is within a built menu.
+      elt.label = aNewTitle || PlacesUIUtils.getBestTitle(aPlacesNode);
+    }
+  },
+
+  nodeReplaced:
+  function PT_nodeReplaced(aParentPlacesNode,
+                           aOldPlacesNode, aNewPlacesNode, aIndex) {
+    let parentElt = aParentPlacesNode._DOMElement;
+    if (!parentElt) 
+      throw "aParentPlacesNode node must have _DOMElement set";
+
+    if (parentElt == this._rootElt) {
+      let elt = aOldPlacesNode._DOMElement;
+      if (!elt)
+        throw "aOldPlacesNode must have _DOMElement set";
+
+      // Here we need the <menu>.
+      if (elt.localName == "menupopup")
+        elt = elt.parentNode;
+
+      this._removeChild(elt);
+
+      // No worries: If elt is the last item (i.e. no nextSibling),
+      // _insertNewItem/_insertNewItemToPopup will insert the new element as
+      // the last item.
+      let next = elt.nextSibling;
+      this._insertNewItem(aNewPlacesNode, next);
+      this.updateChevron();
+      return;
+    }
+
+    PlacesViewBase.prototype.nodeReplaced.apply(this, arguments);
+  },
+
+  invalidateContainer: function PT_invalidateContainer(aPlacesNode) {
+    let elt = aPlacesNode._DOMElement;
+    if (!elt)
+      throw "aPlacesNode must have _DOMElement set";
+
+    if (elt == this._rootElt) {
+      // Container is the toolbar itself.
+      this._rebuild();
+      return;
+    }
+
+    PlacesViewBase.prototype.invalidateContainer.apply(this, arguments);
+  },
+
+  _overFolder: { elt: null,
+                 openTimer: null,
+                 hoverTime: 350,
+                 closeTimer: null },
+
+  _clearOverFolder: function PT__clearOverFolder() {
+    // The mouse is no longer dragging over the stored menubutton.
+    // Close the menubutton, clear out drag styles, and clear all
+    // timers for opening/closing it.
+    if (this._overFolder.elt && this._overFolder.elt.lastChild) {
+      if (!this._overFolder.elt.lastChild.hasAttribute("dragover")) {
+        this._overFolder.elt.lastChild.hidePopup();
+      }
+      this._overFolder.elt.removeAttribute("dragover");
+      this._overFolder.elt = null;
+    }
+    if (this._overFolder.openTimer) {
+      this._overFolder.openTimer.cancel();
+      this._overFolder.openTimer = null;
+    }
+    if (this._overFolder.closeTimer) {
+      this._overFolder.closeTimer.cancel();
+      this._overFolder.closeTimer = null;
+    }
+  },
+
+  /**
+   * This function returns information about where to drop when dragging over
+   * the toolbar.  The returned object has the following properties:
+   * - ip: the insertion point for the bookmarks service.
+   * - beforeIndex: child index to drop before, for the drop indicator.
+   * - folderElt: the folder to drop into, if applicable.
+   */
+  _getDropPoint: function PT__getDropPoint(aEvent) {
+    let result = this.result;
+    if (!PlacesUtils.nodeIsFolder(this._resultNode))
+      return null;
+
+    let dropPoint = { ip: null, beforeIndex: null, folderElt: null };
+    let elt = aEvent.target;
+    if (elt._placesNode && elt != this._rootElt &&
+        elt.localName != "menupopup") {
+      let eltRect = elt.getBoundingClientRect();
+      let eltIndex = Array.indexOf(this._rootElt.childNodes, elt);
+      if (PlacesUtils.nodeIsFolder(elt._placesNode) &&
+          !PlacesUtils.nodeIsReadOnly(elt._placesNode)) {
+        // This is a folder.
+        // If we are in the middle of it, drop inside it.
+        // Otherwise, drop before it, with regards to RTL mode.
+        let threshold = eltRect.width * 0.25;
+        if (this._isRTL ? (aEvent.clientX > eltRect.right - threshold)
+                        : (aEvent.clientX < eltRect.left + threshold)) {
+          // Drop before this folder.
+          dropPoint.ip =
+            new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
+                               eltIndex, Ci.nsITreeView.DROP_BEFORE);
+          dropPoint.beforeIndex = eltIndex;
+        }
+        else if (this._isRTL ? (aEvent.clientX > eltRect.left + threshold)
+                             : (aEvent.clientX < eltRect.right - threshold)) {
+          // Drop inside this folder.
+          dropPoint.ip =
+            new InsertionPoint(PlacesUtils.getConcreteItemId(elt._placesNode),
+                               -1, Ci.nsITreeView.DROP_ON,
+                               PlacesUtils.nodeIsTagQuery(elt._placesNode));
+          dropPoint.beforeIndex = eltIndex;
+          dropPoint.folderElt = elt;
+        }
+        else {
+          // Drop after this folder.
+          let beforeIndex =
+            (eltIndex == this._rootElt.childNodes.length - 1) ?
+            -1 : eltIndex + 1;
+
+          dropPoint.ip =
+            new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
+                               beforeIndex, Ci.nsITreeView.DROP_BEFORE);
+          dropPoint.beforeIndex = beforeIndex;
+        }
+      }
+      else {
+        // This is a non-folder node or a read-only folder.
+        // Drop before it with regards to RTL mode.
+        let threshold = eltRect.width * 0.5;
+        if (this._isRTL ? (aEvent.clientX > eltRect.left + threshold)
+                        : (aEvent.clientX < eltRect.left + threshold)) {
+          // Drop before this bookmark.
+          dropPoint.ip =
+            new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
+                               eltIndex, Ci.nsITreeView.DROP_BEFORE);
+          dropPoint.beforeIndex = eltIndex;
+        }
+        else {
+          // Drop after this bookmark.
+          let beforeIndex =
+            eltIndex == this._rootElt.childNodes.length - 1 ?
+            -1 : eltIndex + 1;
+          dropPoint.ip =
+            new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
+                               beforeIndex, Ci.nsITreeView.DROP_BEFORE);
+          dropPoint.beforeIndex = beforeIndex;
+        }
+      }
+    }
+    else {
+      // We are most likely dragging on the empty area of the
+      // toolbar, we should drop after the last node.
+      dropPoint.ip =
+        new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
+                           -1, Ci.nsITreeView.DROP_BEFORE);
+      dropPoint.beforeIndex = -1;
+    }
+
+    return dropPoint;
+  },
+
+  _setTimer: function PT_setTimer(aTime) {
+    let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    timer.initWithCallback(this, aTime, timer.TYPE_ONE_SHOT);
+    return timer;
+  },
+
+  notify: function PT_notify(aTimer) {
+    if (aTimer == this._updateChevronTimer) {
+      this._updateChevronTimer = null;
+      this._updateChevronTimerCallback();
+    }
+
+    // * Timer to turn off indicator bar.
+    else if (aTimer == this._ibTimer) {
+      this._dropIndicator.collapsed = true;
+      this._ibTimer = null;
+    }
+
+    // * Timer to open a menubutton that's being dragged over.
+    else if (aTimer == this._overFolder.openTimer) {
+      // Set the autoopen attribute on the folder's menupopup so that
+      // the menu will automatically close when the mouse drags off of it.
+      this._overFolder.elt.lastChild.setAttribute("autoopened", "true");
+      this._overFolder.elt.open = true;
+      this._overFolder.openTimer = null;
+    }
+
+    // * Timer to close a menubutton that's been dragged off of.
+    else if (aTimer == this._overFolder.closeTimer) {
+      // Close the menubutton if we are not dragging over it or one of
+      // its children.  The autoopened attribute will let the menu know to
+      // close later if the menu is still being dragged over.
+      let currentPlacesNode = PlacesControllerDragHelper.currentDropTarget;
+      let inHierarchy = false;
+      while (currentPlacesNode) {
+        if (currentPlacesNode == this._rootElt) {
+          inHierarchy = true;
+          break;
+        }
+        currentPlacesNode = currentPlacesNode.parentNode;
+      }
+      // The _clearOverFolder() function will close the menu for
+      // _overFolder.elt.  So null it out if we don't want to close it.
+      if (inHierarchy)
+        this._overFolder.elt = null;
+
+      // Clear out the folder and all associated timers.
+      this._clearOverFolder();
+    }
+  },
+
+  _onMouseOver: function PT__onMouseOver(aEvent) {
+    let button = aEvent.target;
+    if (button.parentNode == this._rootElt && button._placesNode &&
+        PlacesUtils.nodeIsURI(button._placesNode))
+      window.XULBrowserWindow.setOverLink(aEvent.target._placesNode.uri, null);
+  },
+
+  _onMouseOut: function PT__onMouseOut(aEvent) {
+    window.XULBrowserWindow.setOverLink("", null);
+  },
+
+  _cleanupDragDetails: function PT__cleanupDragDetails() {
+    // Called on dragend and drop.
+    PlacesControllerDragHelper.currentDropTarget = null;
+    this._draggedElt = null;
+    if (this._ibTimer)
+      this._ibTimer.cancel();
+
+    this._dropIndicator.collapsed = true;
+  },
+
+  _onDragStart: function PT__onDragStart(aEvent) {
+    // Sub menus have their own d&d handlers.
+    let draggedElt = aEvent.target;
+    if (draggedElt.parentNode != this._rootElt || !draggedElt._placesNode)
+      return;
+
+    if (draggedElt.localName == "toolbarbutton" &&
+        draggedElt.getAttribute("type") == "menu") {
+      // If the drag gesture on a container is toward down we open instead
+      // of dragging.
+      if (this._mouseDownTimer) {
+        this._mouseDownTimer.cancel();
+        this._mouseDownTimer = null;
+      }
+      let translateY = this._cachedMouseMoveEvent.clientY - aEvent.clientY;
+      let translateX = this._cachedMouseMoveEvent.clientX - aEvent.clientX;
+      if ((translateY) >= Math.abs(translateX/2)) {
+        // Don't start the drag.
+        aEvent.preventDefault();
+        // Open the menu.
+        draggedElt.open = true;
+        return;
+      }
+
+      // If the menu is open, close it.
+      if (draggedElt.open) {
+        draggedElt.firstChild.hidePopup();
+        draggedElt.open = false;
+      }
+    }
+
+    // Activate the view and cache the dragged element.
+    this._draggedElt = draggedElt._placesNode;
+    this._rootElt.focus();
+
+    this._controller.setDataTransfer(aEvent);
+    aEvent.stopPropagation();
+  },
+
+  _onDragOver: function PT__onDragOver(aEvent) {
+    // Cache the dataTransfer
+    PlacesControllerDragHelper.currentDropTarget = aEvent.target;
+    let dt = aEvent.dataTransfer;
+
+    let dropPoint = this._getDropPoint(aEvent);
+    if (!dropPoint || !dropPoint.ip ||
+        !PlacesControllerDragHelper.canDrop(dropPoint.ip, dt)) {
+      this._dropIndicator.collapsed = true;
+      aEvent.stopPropagation();
+      return;
+    }
+
+    if (this._ibTimer) {
+      this._ibTimer.cancel();
+      this._ibTimer = null;
+    }
+
+    if (dropPoint.folderElt || aEvent.originalTarget == this._chevron) {
+      // Dropping over a menubutton or chevron button.
+      // Set styles and timer to open relative menupopup.
+      let overElt = dropPoint.folderElt || this._chevron;
+      if (this._overFolder.elt != overElt) {
+        this._clearOverFolder();
+        this._overFolder.elt = overElt;
+        this._overFolder.openTimer = this._setTimer(this._overFolder.hoverTime);
+      }
+      if (!this._overFolder.elt.hasAttribute("dragover"))
+        this._overFolder.elt.setAttribute("dragover", "true");
+
+      this._dropIndicator.collapsed = true;
+    }
+    else {
+      // Dragging over a normal toolbarbutton,
+      // show indicator bar and move it to the appropriate drop point.
+      let ind = this._dropIndicator;
+      let halfInd = ind.clientWidth / 2;
+      let translateX;
+      if (this._isRTL) {
+        halfInd = Math.ceil(halfInd);
+        translateX = 0 - this._rootElt.getBoundingClientRect().right - halfInd;
+        if (this._rootElt.firstChild) {
+          if (dropPoint.beforeIndex == -1)
+            translateX += this._rootElt.lastChild.getBoundingClientRect().left;
+          else {
+            translateX += this._rootElt.childNodes[dropPoint.beforeIndex]
+                              .getBoundingClientRect().right;
+          }
+        }
+      }
+      else {
+        halfInd = Math.floor(halfInd);
+        translateX = 0 - this._rootElt.getBoundingClientRect().left +
+                     halfInd;
+        if (this._rootElt.firstChild) {
+          if (dropPoint.beforeIndex == -1)
+            translateX += this._rootElt.lastChild.getBoundingClientRect().right;
+          else {
+            translateX += this._rootElt.childNodes[dropPoint.beforeIndex]
+                              .getBoundingClientRect().left;
+          }
+        }
+      }
+
+      ind.style.MozTransform = "translate(" + Math.round(translateX) + "px)";
+      ind.style.MozMarginStart = (-ind.clientWidth) + "px";
+      ind.collapsed = false;
+
+      // Clear out old folder information.
+      this._clearOverFolder();
+    }
+
+    aEvent.preventDefault();
+    aEvent.stopPropagation();
+  },
+
+  _onDrop: function PT__onDrop(aEvent) {
+    PlacesControllerDragHelper.currentDropTarget = aEvent.target;
+
+    let dropPoint = this._getDropPoint(aEvent);
+    if (dropPoint && dropPoint.ip) {
+      PlacesControllerDragHelper.onDrop(dropPoint.ip, aEvent.dataTransfer)
+      aEvent.preventDefault();
+    }
+
+    this._cleanupDragDetails();
+    aEvent.stopPropagation();
+  },
+
+  _onDragLeave: function PT__onDragLeave(aEvent) {
+    PlacesControllerDragHelper.currentDropTarget = null;
+
+    // Set timer to turn off indicator bar (if we turn it off
+    // here, dragenter might be called immediately after, creating
+    // flicker).
+    if (this._ibTimer)
+      this._ibTimer.cancel();
+    this._ibTimer = this._setTimer(10);
+
+    // If we hovered over a folder, close it now.
+    if (this._overFolder.elt)
+        this._overFolder.closeTimer = this._setTimer(this._overFolder.hoverTime);
+  },
+
+  _onDragEnd: function PT_onDragEnd(aEvent) {
+    this._cleanupDragDetails();
+  },
+
+  _onPopupShowing: function PT__onPopupShowing(aEvent) {
+    if (!this._allowPopupShowing) {
+      this._allowPopupShowing = true;
+      aEvent.preventDefault();
+      return;
+    }
+
+    let parent = aEvent.target.parentNode;
+    if (parent.localName == "toolbarbutton")
+      this._openedMenuButton = parent;
+
+    return PlacesViewBase.prototype._onPopupShowing.apply(this, arguments);
+  },
+
+  _onPopupHidden: function PT__onPopupHidden(aEvent) {
+    let popup = aEvent.target;
+
+    // Avoid handling popuphidden of inner views
+    if (popup._placesNode && PlacesUIUtils.getViewForNode(popup) == this) {
+      // UI performance: folder queries are cheap, keep the resultnode open
+      // so we don't rebuild its contents whenever the popup is reopened.
+      if (!PlacesUtils.nodeIsFolder(popup._placesNode))
+        popup._placesNode.containerOpen = false;
+    }
+
+    let parent = popup.parentNode;
+    if (parent.localName == "toolbarbutton") {
+      this._openedMenuButton = null;
+      // Clear the dragover attribute if present, if we are dragging into a
+      // folder in the hierachy of current opened popup we don't clear
+      // this attribute on clearOverFolder.  See Notify for closeTimer.
+      if (parent.hasAttribute("dragover"))
+        parent.removeAttribute("dragover");
+    }
+  },
+
+  _onMouseDown: function PT__onMouseDown(aEvent) {
+#ifdef XP_UNIX
+#ifndef XP_MACOSX
+    let target = aEvent.target;
+    if (aEvent.button == 0 &&
+        target.localName == "toolbarbutton" &&
+        target.getAttribute("type") == "menu") {
+      this._allowPopupShowing = false;
+      // On Linux we can open the popup only after a delay.
+      // Indeed as soon as the menupopup opens we are unable to start a
+      // drag aEvent.  See bug 500081 for details.
+      this._mouseDownTimer = Cc["@mozilla.org/timer;1"].
+                             createInstance(Ci.nsITimer);
+      let callback = {
+        _self: this,
+        _target: target,
+        notify: function(timer) {
+          this._target.open = true;
+          this._mouseDownTimer = null;
+        }
+      };
+
+      this._mouseDownTimer.initWithCallback(callback, 300,
+                                            Ci.nsITimer.TYPE_ONE_SHOT);
+    }
+#endif
+#endif
+  },
+
+  _onMouseUp: function PT__onMouseUp(aEvent) {
+    if (aEvent.button != 0)
+      return;
+
+    if (this._mouseDownTimer) {
+      // On a click (down/up), we should open the menu popup.
+      this._mouseDownTimer.cancel();
+      this._mouseDownTimer = null;
+      aEvent.target.open = true;
+    }
+  },
+
+  _onMouseMove: function PT__onMouseMove(aEvent) {
+    // Used in dragStart to prevent dragging folders when dragging down.
+    this._cachedMouseMoveEvent = aEvent;
+
+    if (this._openedMenuButton == null ||
+        PlacesControllerDragHelper.getSession())
+      return;
+
+    let target = aEvent.originalTarget;
+    if (this._openedMenuButton != target &&
+        target.localName == "toolbarbutton" &&
+        target.type == "menu") {
+      this._openedMenuButton.open = false;
+      target.open = true;
+    }
+  }
+};
+
+/**
+ * View for Places menus.  This object should be created during the first
+ * popupshowing that's dispatched on the menu.
+ */
+function PlacesMenu(aPopupShowingEvent, aPlace) {
+  this._rootElt = aPopupShowingEvent.target; // <menupopup>
+  this._viewElt = this._rootElt.parentNode;   // <menu>
+  this._viewElt._placesView = this;
+  this._addEventListeners(this._rootElt, ["popupshowing", "popuphidden"], true);
+  this._addEventListeners(window, ["unload"], false);
+
+#ifdef XP_MACOSX
+  if (this._viewElt.parentNode.localName == "menubar") {
+    this._nativeView = true;
+    this._rootElt._startMarker = -1;
+    this._rootElt._endMarker = -1;
+  }
+#endif
+
+  PlacesViewBase.call(this, aPlace);
+  this._onPopupShowing(aPopupShowingEvent);
+}
+
+PlacesMenu.prototype = {
+  __proto__: PlacesViewBase.prototype,
+
+  QueryInterface: function PM_QueryInterface(aIID) {
+    if (aIID.equals(Ci.nsIDOMEventListener))
+      return this;
+
+    return PlacesViewBase.prototype.QueryInterface.apply(this, arguments);
+  },
+
+  _removeChild: function PM_removeChild(aChild) {
+    PlacesViewBase.prototype._removeChild.apply(this, arguments);
+    if (this._endMarker != -1)
+      this._endMarker--;
+  },
+
+  nodeTitleChanged: function PM_nodeTitleChanged(aPlacesNode, aNewTitle) {
+    let elt = aPlacesNode._DOMElement;
+    if (!elt)
+      throw "aPlacesNode must have _DOMElement set";
+
+    // There's no UI representation for the root node, thus there's
+    // nothing to be done when the title changes.
+    if (elt == this._rootElt)
+      return;
+
+    elt.label = aNewTitle || PlacesUIUtils.getBestTitle(aPlacesNode);
+  },
+
+  uninit: function PM_uninit() {
+    this._removeEventListeners(this._rootElt, ["popupshowing", "popuphidden"],
+                               true);
+    this._removeEventListeners(window, ["unload"], false);
+
+    PlacesViewBase.prototype.uninit.apply(this, arguments);
+  },
+
+  handleEvent: function PM_handleEvent(aEvent) {
+    switch (aEvent.type) {
+      case "unload":
+        this.uninit();
+        break;
+      case "popupshowing":
+        this._onPopupShowing(aEvent);
+        break;
+      case "popuphidden":
+        this._onPopupHidden(aEvent);
+        break;
+    }
+  },
+
+  _onPopupHidden: function PM__onPopupHidden(aEvent) {
+    // Avoid handling popuphidden of inner views.
+    let popup = aEvent.originalTarget;
+    if (!popup._placesNode || PlacesUIUtils.getViewForNode(popup) != this)
+      return;
+
+    // UI performance: folder queries are cheap, keep the resultnode open
+    // so we don't rebuild its contents whenever the popup is reopened.
+    if (!PlacesUtils.nodeIsFolder(popup._placesNode))
+      popup._placesNode.containerOpen = false;
+
+    // The autoopened attribute is set for folders which have been
+    // automatically opened when dragged over.  Turn off this attribute
+    // when the folder closes because it is no longer applicable.
+    popup.removeAttribute("autoopened");
+    popup.removeAttribute("dragstart");
+  }
+};
+
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -128,17 +128,17 @@ PlacesController.prototype = {
   isCommandEnabled: function PC_isCommandEnabled(aCommand) {
     switch (aCommand) {
     case "cmd_undo":
       return PlacesUIUtils.ptm.numberOfUndoItems > 0;
     case "cmd_redo":
       return PlacesUIUtils.ptm.numberOfRedoItems > 0;
     case "cmd_cut":
     case "placesCmd_cut":
-      var nodes = this._view.getSelectionNodes();
+      var nodes = this._view.selectedNodes;
       // If selection includes history nodes there's no reason to allow cut.
       for (var i = 0; i < nodes.length; i++) {
         if (nodes[i].itemId == -1)
           return false;
       }
       // Otherwise fallback to cmd_delete check.
     case "cmd_delete":
     case "placesCmd_delete":
@@ -151,35 +151,35 @@ PlacesController.prototype = {
     case "cmd_copy":
     case "placesCmd_copy":
       return this._view.hasSelection;
     case "cmd_paste":
     case "placesCmd_paste":
       return this._canInsert(true) && this._isClipboardDataPasteable();
     case "cmd_selectAll":
       if (this._view.selType != "single") {
-        var rootNode = this._view.getResultNode();
+        let rootNode = this._view.result.root;
         if (rootNode.containerOpen && rootNode.childCount > 0)
             return true;
       }
       return false;
     case "placesCmd_open":
     case "placesCmd_open:window":
     case "placesCmd_open:tab":
       var selectedNode = this._view.selectedNode;
       return selectedNode && PlacesUtils.nodeIsURI(selectedNode);
     case "placesCmd_new:folder":
     case "placesCmd_new:livemark":
       return this._canInsert();
     case "placesCmd_new:bookmark":
       return this._canInsert();
     case "placesCmd_new:separator":
       return this._canInsert() &&
-             !PlacesUtils.asQuery(this._view.getResultNode()).queryOptions.excludeItems &&
-             this._view.getResult().sortingMode ==
+             !PlacesUtils.asQuery(this._view.result.root).queryOptions.excludeItems &&
+             this._view.result.sortingMode ==
                  Ci.nsINavHistoryQueryOptions.SORT_BY_NONE;
     case "placesCmd_show:info":
       var selectedNode = this._view.selectedNode;
       if (selectedNode &&
           PlacesUtils.getConcreteItemId(selectedNode) != -1  &&
           !PlacesUtils.nodeIsLivemarkItem(selectedNode))
         return true;
       return false;
@@ -191,17 +191,17 @@ PlacesController.prototype = {
       // Livemark containers
       var selectedNode = this._view.selectedNode;
       return selectedNode && PlacesUtils.nodeIsLivemarkContainer(selectedNode);
     case "placesCmd_sortBy:name":
       var selectedNode = this._view.selectedNode;
       return selectedNode &&
              PlacesUtils.nodeIsFolder(selectedNode) &&
              !PlacesUtils.nodeIsReadOnly(selectedNode) &&
-             this._view.getResult().sortingMode ==
+             this._view.result.sortingMode ==
                  Ci.nsINavHistoryQueryOptions.SORT_BY_NONE;
     case "placesCmd_createBookmark":
       var node = this._view.selectedNode;
       return node && PlacesUtils.nodeIsURI(node) && node.itemId == -1;
     default:
       return false;
     }
   },
@@ -317,21 +317,21 @@ PlacesController.prototype = {
    * removable item.
    * @param aIsMoveCommand
    *        True if the command for which this method is called only moves the
    *        selected items to another container, false otherwise.
    * @returns true if all nodes in the selection can be removed,
    *          false otherwise.
    */
   _hasRemovableSelection: function PC__hasRemovableSelection(aIsMoveCommand) {
-    var ranges = this._view.getRemovableSelectionRanges();
+    var ranges = this._view.removableSelectionRanges;
     if (!ranges.length)
       return false;
 
-    var root = this._view.getResultNode();
+    var root = this._view.result.root;
 
     for (var j = 0; j < ranges.length; j++) {
       var nodes = ranges[j];
       for (var i = 0; i < nodes.length; ++i) {
         // Disallow removing the view's root node
         if (nodes[i] == root)
           return false;
 
@@ -364,18 +364,18 @@ PlacesController.prototype = {
     var ip = this._view.insertionPoint;
     return ip != null && (isPaste || ip.isTag != true);
   },
 
   /**
    * Determines whether or not the root node for the view is selected
    */
   rootNodeIsSelected: function PC_rootNodeIsSelected() {
-    var nodes = this._view.getSelectionNodes();
-    var root = this._view.getResultNode();
+    var nodes = this._view.selectedNodes;
+    var root = this._view.result.root;
     for (var i = 0; i < nodes.length; ++i) {
       if (nodes[i] == root)
         return true;      
     }
 
     return false;
   },
 
@@ -446,18 +446,18 @@ PlacesController.prototype = {
    *          node are set on its corresponding object as properties.
    * Notes:
    *   1) This can be slow, so don't call it anywhere performance critical!
    *   2) A single-object array corresponding the root node is returned if
    *      there's no selection.
    */
   _buildSelectionMetadata: function PC__buildSelectionMetadata() {
     var metadata = [];
-    var root = this._view.getResultNode();
-    var nodes = this._view.getSelectionNodes();
+    var root = this._view.result.root;
+    var nodes = this._view.selectedNodes;
     if (nodes.length == 0)
       nodes.push(root); // See the second note above
 
     for (var i=0; i < nodes.length; i++) {
       var nodeData = {};
       var node = nodes[i];
       var nodeType = node.type;
       var uri = null;
@@ -790,17 +790,17 @@ PlacesController.prototype = {
   /**
    * Opens the links in the selected folder, or the selected links in new tabs. 
    */
   openSelectionInTabs: function PC_openLinksInTabs(aEvent) {
     var node = this._view.selectedNode;
     if (node && PlacesUtils.nodeIsContainer(node))
       PlacesUIUtils.openContainerNodeInTabs(this._view.selectedNode, aEvent);
     else
-      PlacesUIUtils.openURINodesInTabs(this._view.getSelectionNodes(), aEvent);
+      PlacesUIUtils.openURINodesInTabs(this._view.selectedNodes, aEvent);
   },
 
   /**
    * Shows the Add Bookmark UI for the current insertion point.
    *
    * @param aType
    *        the type of the new item (bookmark/livemark/folder)
    */
@@ -861,17 +861,17 @@ PlacesController.prototype = {
   },
 
   /**
    * Opens a dialog for moving the selected nodes.
    */
   moveSelectedBookmarks: function PC_moveBookmarks() {
     window.openDialog("chrome://browser/content/places/moveBookmarks.xul",
                       "", "chrome, modal",
-                      this._view.getSelectionNodes());
+                      this._view.selectedNodes);
   },
 
   /**
    * Sort the selected folder by name
    */
   sortFolderByName: function PC_sortFolderByName() {
     var itemId = PlacesUtils.getConcreteItemId(this._view.selectedNode);
     var txn = PlacesUIUtils.ptm.sortFolderByName(itemId);
@@ -986,17 +986,17 @@ PlacesController.prototype = {
   },
 
   /**
    * Removes the set of selected ranges from bookmarks.
    * @param   txnName
    *          See |remove|.
    */
   _removeRowsFromBookmarks: function PC__removeRowsFromBookmarks(txnName) {
-    var ranges = this._view.getRemovableSelectionRanges();
+    var ranges = this._view.removableSelectionRanges;
     var transactions = [];
     var removedFolders = [];
 
     for (var i = 0; i < ranges.length; i++)
       this._removeRange(ranges[i], transactions, removedFolders);
 
     if (transactions.length > 0) {
       var txn = PlacesUIUtils.ptm.aggregateTransactions(txnName, transactions);
@@ -1005,20 +1005,20 @@ PlacesController.prototype = {
   },
 
   /**
    * Removes the set of selected ranges from history.
    */
   _removeRowsFromHistory: function PC__removeRowsFromHistory() {
     // Other containers are history queries, just delete from history
     // history deletes are not undoable.
-    var nodes = this._view.getSelectionNodes();
+    var nodes = this._view.selectedNodes;
     var URIs = [];
     var bhist = PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory);
-    var root = this._view.getResultNode();
+    var root = this._view.result.root;
 
     for (var i = 0; i < nodes.length; ++i) {
       var node = nodes[i];
       if (PlacesUtils.nodeIsURI(node)) {
         var uri = PlacesUtils._uri(node.uri);
         // avoid trying to delete the same url twice
         if (URIs.indexOf(uri) < 0) {
           URIs.push(uri);
@@ -1083,17 +1083,17 @@ PlacesController.prototype = {
    *          as part of another operation.
    */
   remove: function PC_remove(aTxnName) {
     if (!this._hasRemovableSelection(false))
       return;
 
     NS_ASSERT(aTxnName !== undefined, "Must supply Transaction Name");
 
-    var root = this._view.getResultNode();
+    var root = this._view.result.root;
 
     if (PlacesUtils.nodeIsFolder(root)) 
       this._removeRowsFromBookmarks(aTxnName);
     else if (PlacesUtils.nodeIsQuery(root)) {
       var queryType = PlacesUtils.asQuery(root).queryOptions.queryType;
       if (queryType == Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS)
         this._removeRowsFromBookmarks(aTxnName);
       else if (queryType == Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY)
@@ -1110,23 +1110,23 @@ PlacesController.prototype = {
    * dropped elsewhere.
    * @param   aEvent
    *          The dragstart event.
    */
   setDataTransfer: function PC_setDataTransfer(aEvent) {
     let dt = aEvent.dataTransfer;
     let doCopy = ["copyLink", "copy", "link"].indexOf(dt.effectAllowed) != -1;
 
-    let result = this._view.getResult();
+    let result = this._view.result;
     let didSuppressNotifications = result.suppressNotifications;
     if (!didSuppressNotifications)
       result.suppressNotifications = true;
 
     try {
-      let nodes = this._view.getDraggableSelection();
+      let nodes = this._view.draggableSelection;
       for (let i = 0; i < nodes.length; ++i) {
         var node = nodes[i];
 
         function addData(type, index, overrideURI) {
           let wrapNode = PlacesUtils.wrapNode(node, type, overrideURI, doCopy);
           dt.mozSetDataAt(type, wrapNode, index);
         }
 
@@ -1152,24 +1152,24 @@ PlacesController.prototype = {
         result.suppressNotifications = false;
     }
   },
 
   /**
    * Copy Bookmarks and Folders to the clipboard
    */
   copy: function PC_copy() {
-    let result = this._view.getResult();
+    let result = this._view.result;
 
     let didSuppressNotifications = result.suppressNotifications;
     if (!didSuppressNotifications)
       result.suppressNotifications = true;
 
     try {
-      let nodes = this._view.getSelectionNodes();
+      let nodes = this._view.selectedNodes;
 
       let xferable =  Cc["@mozilla.org/widget/transferable;1"].
                       createInstance(Ci.nsITransferable);
       let foundFolder = false, foundLink = false;
       let copiedFolders = [];
       let placeString, mozURLString, htmlString, unicodeString;
       placeString = mozURLString = htmlString = unicodeString = "";
 
@@ -1626,36 +1626,32 @@ function goUpdatePlacesCommands() {
   updatePlacesCommand("placesCmd_cut");
   updatePlacesCommand("placesCmd_copy");
   updatePlacesCommand("placesCmd_paste");
   updatePlacesCommand("placesCmd_delete");
 }
 
 function doGetPlacesControllerForCommand(aCommand)
 {
-  var placesController = top.document.commandDispatcher
-                            .getControllerForCommand(aCommand);
-  if (!placesController) {
-    // If building commands for a context menu, look for an element in the
-    // current popup.
-    var element = document.popupNode;
-    while (element) {
-      var isContextMenuShown = ("_contextMenuShown" in element) && element._contextMenuShown;
-      // Check for the parent menupopup or the hbox used for toolbars
-      if ((element.localName == "menupopup" || element.localName == "hbox") &&
-          isContextMenuShown) {
-        placesController = element.controllers.getControllerForCommand(aCommand);
-        break;
-      }
-      element = element.parentNode;
-    }
+  let controller = top.document.commandDispatcher
+                      .getControllerForCommand(aCommand);
+  if (controller)
+    return controller;
+
+  // If building commands for a context menu, look for an element in the
+  // current popup.
+  let element = document.popupNode;
+  if (element) {
+    let view = PlacesUIUtils.getViewForNode(element);
+    if (view && view._contextMenuShown)
+      return view.viewElt.controllers.getControllerForCommand(aCommand);
   }
 
-  return placesController;
+  return null;
 }
 
 function goDoPlacesCommand(aCommand)
 {
-  var controller = doGetPlacesControllerForCommand(aCommand);
+  let controller = doGetPlacesControllerForCommand(aCommand);
   if (controller && controller.isCommandEnabled(aCommand))
     controller.doCommand(aCommand);
 }
 
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -91,118 +91,118 @@
           if (this._startMarker != -1 &&
               target.boxObject.y <= this.childNodes[this._startMarker].boxObject.y)
             betweenMarkers = false;
           if (this._endMarker != -1 &&
               target.boxObject.y >= this.childNodes[this._endMarker].boxObject.y)
             betweenMarkers = false;
 
           // Hide the dropmarker if current node is not a Places node.
-          return !(target && target.node && betweenMarkers);
+          return !(target && target._placesNode && betweenMarkers);
         ]]></body>
       </method>
 
       <!-- This function returns information about where to drop when
            dragging over this popup insertion point -->
       <method name="_getDropPoint">
         <parameter name="aEvent"/>
           <body><![CDATA[
             // Can't drop if the menu isn't a folder
-            var resultNode = this._resultNode;
+            let resultNode = this._placesNode;
 
             if (!PlacesUtils.nodeIsFolder(resultNode) ||
                 PlacesControllerDragHelper.disallowInsertion(resultNode)) {
               return null;
             }
 
-            var dropPoint = { ip: null, folderNode: null };
+            var dropPoint = { ip: null, folderElt: null };
 
-            // The node we are dragging over
-            var xulNode = aEvent.target;
+            // The element we are dragging over
+            let elt = aEvent.target;
 
             // Calculate positions taking care of arrowscrollbox
-            var eventY = aEvent.layerY;
-            var scrollbox = this._scrollBox;
-            var scrollboxOffset = scrollbox.scrollBoxObject.y -
+            let eventY = aEvent.layerY;
+            let scrollbox = this._scrollBox;
+            let scrollboxOffset = scrollbox.scrollBoxObject.y -
                                   (scrollbox.boxObject.y - this.boxObject.y);
-            var nodeY = xulNode.boxObject.y - scrollboxOffset;
-            var nodeHeight = xulNode.boxObject.height;
+            let eltY = elt.boxObject.y - scrollboxOffset;
+            let eltHeight = elt.boxObject.height;
 
-            if (!xulNode.node) {
-              // if we are dragging over a non places node drop at the end
+            if (!elt._placesNode) {
+              // If we are dragging over a non places node drop at the end.
               dropPoint.ip = new InsertionPoint(
                                   PlacesUtils.getConcreteItemId(resultNode),
                                   -1,
                                   Ci.nsITreeView.DROP_ON);
               return dropPoint;
             }
-            else if ((PlacesUtils.nodeIsFolder(xulNode.node) ||
-                      PlacesUtils.nodeIsTagQuery(xulNode.node)) &&
-                     !PlacesUtils.nodeIsReadOnly(xulNode.node)) {
+            else if ((PlacesUtils.nodeIsFolder(elt._placesNode) ||
+                      PlacesUtils.nodeIsTagQuery(elt._placesNode)) &&
+                     !PlacesUtils.nodeIsReadOnly(elt._placesNode)) {
               // This is a folder or a tag container.
-              if (eventY - nodeY < nodeHeight * 0.20) {
-                // If mouse is in the top part of the node, drop above folder.
+              if (eventY - eltY < eltHeight * 0.20) {
+                // If mouse is in the top part of the element, drop above folder.
                 dropPoint.ip = new InsertionPoint(
                                     PlacesUtils.getConcreteItemId(resultNode),
                                     -1,
                                     Ci.nsITreeView.DROP_BEFORE,
-                                    PlacesUtils.nodeIsTagQuery(xulNode.node),
-                                    xulNode.node.itemId);
+                                    PlacesUtils.nodeIsTagQuery(elt._placesNode),
+                                    elt._placesNode.itemId);
                 return dropPoint;
               }
-              else if (eventY - nodeY < nodeHeight * 0.80) {
-                // If mouse is in the middle of the node, drop inside folder.
+              else if (eventY - eltY < eltHeight * 0.80) {
+                // If mouse is in the middle of the element, drop inside folder.
                 dropPoint.ip = new InsertionPoint(
-                                    PlacesUtils.getConcreteItemId(xulNode.node),
+                                    PlacesUtils.getConcreteItemId(elt._placesNode),
                                     -1,
                                     Ci.nsITreeView.DROP_ON,
-                                    PlacesUtils.nodeIsTagQuery(xulNode.node));
-                dropPoint.folderNode = xulNode;
+                                    PlacesUtils.nodeIsTagQuery(elt._placesNode));
+                dropPoint.folderElt = elt;
                 return dropPoint;
               }
             }
-            else if (eventY - nodeY <= nodeHeight / 2) {
+            else if (eventY - eltY <= eltHeight / 2) {
               // This is a non-folder node or a readonly folder.
               // If the mouse is above the middle, drop above this item.
               dropPoint.ip = new InsertionPoint(
                                   PlacesUtils.getConcreteItemId(resultNode),
                                   -1,
                                   Ci.nsITreeView.DROP_BEFORE,
-                                  PlacesUtils.nodeIsTagQuery(xulNode.node),
-                                  xulNode.node.itemId);
+                                  PlacesUtils.nodeIsTagQuery(elt._placesNode),
+                                  elt._placesNode.itemId);
               return dropPoint;
             }
 
             // Drop below the item.
             dropPoint.ip = new InsertionPoint(
                                 PlacesUtils.getConcreteItemId(resultNode),
                                 -1,
                                 Ci.nsITreeView.DROP_AFTER,
-                                PlacesUtils.nodeIsTagQuery(xulNode.node),
-                                xulNode.node.itemId);
+                                PlacesUtils.nodeIsTagQuery(elt._placesNode),
+                                elt._placesNode.itemId);
             return dropPoint;
         ]]></body>
       </method>
 
       <!-- Sub-menus should be opened when the mouse drags over them, and closed
            when the mouse drags off.  The overFolder object manages opening and
            closing of folders when the mouse hovers. -->
       <field name="_overFolder"><![CDATA[({
         _self: this,
-        _folder: {node: null,
+        _folder: {elt: null,
                   openTimer: null,
                   hoverTime: 350,
                   closeTimer: null},
         _closeMenuTimer: null,
 
-        get node() {
-          return this._folder.node;
+        get elt() {
+          return this._folder.elt;
         },
-        set node(val) {
-          return this._folder.node = val;
+        set elt(val) {
+          return this._folder.elt = val;
         },
 
         get openTimer() {
           return this._folder.openTimer;
         },
         set openTimer(val) {
           return this._folder.openTimer = val;
         },
@@ -234,29 +234,29 @@
           return timer;
         },
 
         notify: function OF__notify(aTimer) {
           // Function to process all timer notifications.
 
           if (aTimer == this._folder.openTimer) {
             // Timer to open a submenu that's being dragged over.
-            this._folder.node.lastChild.setAttribute("autoopened", "true");
-            this._folder.node.lastChild.showPopup(this._folder.node);
+            this._folder.elt.lastChild.setAttribute("autoopened", "true");
+            this._folder.elt.lastChild.showPopup(this._folder.elt);
             this._folder.openTimer = null;
           }
 
           else if (aTimer == this._folder.closeTimer) {
             // Timer to close a submenu that's been dragged off of.
             // Only close the submenu if the mouse isn't being dragged over any
             // of its child menus.
             var draggingOverChild = PlacesControllerDragHelper
-                                    .draggingOverChildNode(this._folder.node);
+                                    .draggingOverChildNode(this._folder.elt);
             if (draggingOverChild)
-              this._folder.node = null;
+              this._folder.elt = null;
             this.clear();
 
             // Close any parent folders which aren't being dragged over.
             // (This is necessary because of the above code that keeps a folder
             // open while its children are being dragged over.)
             if (!draggingOverChild)
               this.closeParentMenus();
           }
@@ -280,117 +280,117 @@
 
         //  Helper function to close all parent menus of this menu,
         //  as long as none of the parent's children are currently being
         //  dragged over.
         closeParentMenus: function OF__closeParentMenus() {
           var popup = this._self;
           var parent = popup.parentNode;
           while (parent) {
-            if (parent.nodeName == "menupopup" && parent._resultNode) {
+            if (parent.localName == "menupopup" && parent._placesNode) {
               if (PlacesControllerDragHelper.draggingOverChildNode(parent.parentNode))
                 break;
               parent.hidePopup();
             }
             parent = parent.parentNode;
           }
         },
 
         //  The mouse is no longer dragging over the stored menubutton.
         //  Close the menubutton, clear out drag styles, and clear all
         //  timers for opening/closing it.
         clear: function OF__clear() {
-          if (this._folder.node && this._folder.node.lastChild) {
-            if (!this._folder.node.lastChild.hasAttribute("dragover"))
-              this._folder.node.lastChild.hidePopup();
+          if (this._folder.elt && this._folder.elt.lastChild) {
+            if (!this._folder.elt.lastChild.hasAttribute("dragover"))
+              this._folder.elt.lastChild.hidePopup();
             // remove menuactive style
-            this._folder.node.removeAttribute("_moz-menuactive");
-            this._folder.node = null;
+            this._folder.elt.removeAttribute("_moz-menuactive");
+            this._folder.elt = null;
           }
           if (this._folder.openTimer) {
             this._folder.openTimer.cancel();
             this._folder.openTimer = null;
           }
           if (this._folder.closeTimer) {
             this._folder.closeTimer.cancel();
             this._folder.closeTimer = null;
           }
         }
       })]]></field>
 
       <method name="_cleanupDragDetails">
         <body><![CDATA[
           // Called on dragend and drop.
           PlacesControllerDragHelper.currentDropTarget = null;
-          this._rootView._draggedNode = null;
+          this._rootView._draggedElt = null;
           this.removeAttribute("dragover");
           this.removeAttribute("dragstart");
           this._indicatorBar.hidden = true;
         ]]></body>
       </method>
 
     </implementation>
 
     <handlers>
       <handler event="DOMMenuItemActive"><![CDATA[
-        var node = event.target;
-        if (node.parentNode != this)
+        let elt = event.target;
+        if (elt.parentNode != this)
           return;
 
 #ifdef XP_MACOSX
-        // XXXschonfeld: The following check is a temporary hack
-        // until bug 420033 is resolved.
-        while (node) {
-          if (node.id == "bookmarksMenuPopup" || node.id == "goPopup")
+        // XXX: The following check is a temporary hack until bug 420033 is
+        // resolved.
+        let parentElt = elt.parent;
+        while (parentElt) {
+          if (parentElt.id == "bookmarksMenuPopup" ||
+              parentElt.id == "goPopup")
             return;
 
-          node = node.parentNode;
+          parentElt = parentElt.parentNode;
         }
 #endif
 
         if (window.XULBrowserWindow) {
-          var nodeItem = event.target.node;
+          let elt = event.target;
+          let placesNode = elt._placesNode;
 
           var linkURI;
-          if (nodeItem && PlacesUtils.nodeIsURI(nodeItem))
-            linkURI = nodeItem.uri;
-          else if (node.hasAttribute("targetURI"))
-            linkURI = node.getAttribute("targetURI");
+          if (placesNode && PlacesUtils.nodeIsURI(placesNode))
+            linkURI = placesNode.uri;
+          else if (elt.hasAttribute("targetURI"))
+            linkURI = elt.getAttribute("targetURI");
 
           if (linkURI)
             window.XULBrowserWindow.setOverLink(linkURI, null);
         }
       ]]></handler>
 
       <handler event="DOMMenuItemInactive"><![CDATA[
-        var node = event.target;
-        if (node.parentNode != this)
+        let elt = event.target;
+        if (elt.parentNode != this)
           return;
 
         if (window.XULBrowserWindow)
           window.XULBrowserWindow.setOverLink("", null);
       ]]></handler>
 
       <handler event="dragstart"><![CDATA[
-        if (!event.target.node)
+        if (!event.target._placesNode)
           return;
 
-        let draggedNode = event.target.node;
+        let draggedElt = event.target._placesNode;
 
         // Force a copy action if parent node is a query or we are dragging a
         // not-removable node.
-        if (!PlacesControllerDragHelper.canMoveNode(draggedNode))
+        if (!PlacesControllerDragHelper.canMoveNode(draggedElt))
           event.dataTransfer.effectAllowed = "copyLink";
 
-        // Activate the view and cache the dragged node.
-        this._rootView._draggedNode = draggedNode;
-        this._rootView.focus();
-
-        this._rootView._controller.setDataTransfer(event);
-
+        // Activate the view and cache the dragged element.
+        this._rootView._draggedElt = draggedElt;
+        this._rootView.controller.setDataTransfer(event);
         this.setAttribute("dragstart", "true");
         event.stopPropagation();
       ]]></handler>
 
       <handler event="drop"><![CDATA[
         PlacesControllerDragHelper.currentDropTarget = event.target;
 
         let dropPoint = this._getDropPoint(event);
@@ -413,65 +413,65 @@
           this._indicatorBar.hidden = true;
           event.stopPropagation();
           return;
         }
 
         // Mark this popup as being dragged over.
         this.setAttribute("dragover", "true");
 
-        if (dropPoint.folderNode) {
+        if (dropPoint.folderElt) {
           // We are dragging over a folder.
           // _overFolder should take the care of opening it on a timer.
-          if (this._overFolder.node &&
-              this._overFolder.node != dropPoint.folderNode) {
+          if (this._overFolder.elt &&
+              this._overFolder.elt != dropPoint.folderElt) {
             // We are dragging over a new folder, let's clear old values
             this._overFolder.clear();
           }
-          if (!this._overFolder.node) {
-            this._overFolder.node = dropPoint.folderNode;
+          if (!this._overFolder.elt) {
+            this._overFolder.elt = dropPoint.folderElt;
             // Create the timer to open this folder.
             this._overFolder.openTimer = this._overFolder
                                              .setTimer(this._overFolder.hoverTime);
           }
           // Since we are dropping into a folder set the corresponding style.
-          dropPoint.folderNode.setAttribute("_moz-menuactive", true);
+          dropPoint.folderElt.setAttribute("_moz-menuactive", true);
         }
         else {
           // We are not dragging over a folder.
           // Clear out old _overFolder information.
           this._overFolder.clear();
         }
 
         // Autoscroll the popup strip if we drag over the scroll buttons.
         let anonid = event.originalTarget.getAttribute('anonid');
         let scrollDir = anonid == "scrollbutton-up" ? -1 :
                         anonid == "scrollbutton-down" ? 1 : 0;
         if (scrollDir != 0) {
           this._scrollBox.scrollByIndex(scrollDir, false);
         }
 
         // Check if we should hide the drop indicator for this target.
-        if (dropPoint.folderNode || this._hideDropIndicator(event)) {
+        if (dropPoint.folderElt || this._hideDropIndicator(event)) {
           this._indicatorBar.hidden = true;
           event.preventDefault();
           event.stopPropagation();
           return;
         }
 
         // We should display the drop indicator relative to the arrowscrollbox.
         let sbo = this._scrollBox.scrollBoxObject;
         let newMarginTop = 0;
         if (scrollDir == 0) {
-          let node = this.firstChild;
-          while (node && event.screenY > node.boxObject.screenY +
-                                         node.boxObject.height / 2)
-            node = node.nextSibling;
-          newMarginTop = node ? node.boxObject.screenY - sbo.screenY :
-                                sbo.height;
+          let elt = this.firstChild;
+          while (elt && event.screenY > elt.boxObject.screenY +
+                                        elt.boxObject.height / 2)
+            elt = elt.nextSibling;
+          newMarginTop = elt ? elt.boxObject.screenY - sbo.screenY :
+                               sbo.height;
         }
         else if (scrollDir == 1)
           newMarginTop = sbo.height;
 
         // Set the new marginTop based on arrowscrollbox.
         newMarginTop += sbo.y - this._scrollBox.boxObject.y;
         this._indicatorBar.firstChild.style.marginTop = newMarginTop + "px";
         this._indicatorBar.hidden = false;
@@ -486,17 +486,17 @@
 
         // If we have not moved to a valid new target clear the drop indicator
         // this happens when moving out of the popup.
         let target = event.relatedTarget;
         if (!target)
           this._indicatorBar.hidden = true;
 
         // Close any folder being hovered over
-        if (this._overFolder.node) {
+        if (this._overFolder.elt) {
           this._overFolder.closeTimer = this._overFolder
                                             .setTimer(this._overFolder.hoverTime);
         }
 
         // The autoopened attribute is set when this folder was automatically
         // opened after the user dragged over it.  If this attribute is set,
         // auto-close the folder on drag exit.
         // We should also try to close this popup if the drag has started
@@ -511,578 +511,9 @@
       ]]></handler>
 
       <handler event="dragend"><![CDATA[
         this._cleanupDragDetails();
       ]]></handler>
 
     </handlers>
   </binding>
-
-
-  <binding id="places-menupopup"
-           extends="chrome://browser/content/places/menu.xml#places-popup-base">
-    <implementation>
-      <destructor><![CDATA[
-        if (this._result) {
-          this._result.removeObserver(this._resultObserver);
-          this._resultNode.containerOpen = false;
-          this._resultNode = null;
-          this._result = null;
-        }
-      ]]></destructor>
-
-      <field name="_initialized">false</field>
-      <method name="_ensureInitialized">
-        <body><![CDATA[
-          if (this._initialized)
-            return;
-
-          this._controller = new PlacesController(this);
-          this.controllers.appendController(this._controller);
-
-          // This function should only be called for top-level menus like the bookmarks menu.
-          // Submenus get their _result and _resultNode from their parents.
-          if (this.hasAttribute("place")) {
-            // Do the initial build.
-            this.place = this.place;
-          }
-          this._initialized = true;
-        ]]></body>
-      </method>
-
-      <property name="controller"
-                readonly="true"
-                onget="return this._controller;"/>
-
-      <method name="onPopupShowing">
-        <parameter name="aEvent"/>
-        <body><![CDATA[
-          var popup = aEvent.target;
-          var resultNode = popup._resultNode;
-          if (!resultNode.containerOpen)
-            resultNode.containerOpen = true;
-          if (!popup.parentNode._built)
-            this._rebuild(popup);
-        ]]></body>
-      </method>
-
-      <field name="_result">null</field>
-      <field name="_resultNode">null</field>
-
-      <!-- nsIPlacesView -->
-      <method name="getResult">
-        <body><![CDATA[
-          return this._result;
-        ]]></body>
-      </method>
-
-      <!-- nsIPlacesView -->
-      <method name="getResultNode">
-        <body><![CDATA[
-          this._ensureInitialized();
-          return this._resultNode;
-        ]]></body>
-      </method>
-
-      <method name="removeItem">
-        <parameter name="child"/>
-        <body><![CDATA[
-          // if document.popupNode pointed to this child, null it out,
-          // otherwise controller's command-updating may rely on the removed
-          // item still being "selected".
-          if (document.popupNode == child)
-            document.popupNode = null;
-
-          child.parentNode.removeChild(child);
-
-          if (this._endMarker != -1)
-            this._endMarker--;
-        ]]></body>
-      </method>
-
-      <method name="insertNewItem">
-        <parameter name="aChild"/>
-        <parameter name="aParentPopup"/>
-        <parameter name="aBefore"/>
-        <body><![CDATA[
-          let element = PlacesUIUtils.createMenuItemForNode(aChild,
-                                                            aParentPopup.ownerDocument);
-          if (aBefore)
-            aParentPopup.insertBefore(element, aBefore);
-          else {
-            // Add the new element to the menu.  If there is static content at
-            // the end of the menu, add the element before that.  Otherwise,
-            // just add to the end.
-            if (aParentPopup._endMarker != -1) {
-              aParentPopup.insertBefore(element,
-                                        aParentPopup.childNodes[aParentPopup._endMarker]);
-            }
-            else
-              aParentPopup.appendChild(element);
-          }
-
-          if (aParentPopup._endMarker != -1)
-            aParentPopup._endMarker++;
-
-#ifdef XP_MACOSX
-          // Bug 529062:
-          // We rely on the menu* bindings, but those aren't never applied
-          // in native mac menus, for elements which are added to the document
-          // through appendChild / insertBefore.
-          if (this.parentNode.parentNode.localName != "menubar")
-            return;
-
-          function applyBinding(elm) {
-            // getPropertyCSSValue is semi-deprecared, but there's no
-            // alternative for parsing css_uri values reliably.
-            let elmBindingURI = window.getComputedStyle(element, "")
-                                      .getPropertyCSSValue("-moz-binding");
-            if (elmBindingURI.primitiveType == CSSPrimitiveValue.CSS_URI)
-              document.addBinding(elm, elmBindingURI.getStringValue());
-          }
-
-          applyBinding(element);
-          if (element.localName == "menu")
-            applyBinding(element.firstChild);
-#endif
-        ]]></body>
-      </method>
-
-      <method name="_showEmptyMenuItem">
-        <parameter name="aPopup"/>
-        <body><![CDATA[
-          if (aPopup._emptyMenuItem) {
-            aPopup._emptyMenuItem.hidden = false;
-            return;
-          }
-
-          var label = PlacesUIUtils.getString("bookmarksMenuEmptyFolder");
-          aPopup._emptyMenuItem = document.createElement("menuitem");
-          aPopup._emptyMenuItem.setAttribute("label", label);
-          aPopup._emptyMenuItem.setAttribute("disabled", true);
-          aPopup.appendChild(aPopup._emptyMenuItem);
-        ]]></body>
-      </method>
-
-      <method name="_rebuild">
-        <parameter name="aPopup"/>
-        <body><![CDATA[
-          PlacesUIUtils.cleanPlacesPopup(aPopup);
-
-          // If this is a livemark container check if the status menuitem has
-          // to be added or removed.
-          if (PlacesUtils.nodeIsLivemarkContainer(aPopup._resultNode))
-            PlacesUIUtils.ensureLivemarkStatusMenuItem(aPopup);
-
-          var cc = aPopup._resultNode.childCount;
-          if (cc > 0) {
-            if (aPopup._emptyMenuItem)
-              aPopup._emptyMenuItem.hidden = true;
-
-            for (var i = 0; i < cc; ++i) {
-              var child = aPopup._resultNode.getChild(i);
-              this.insertNewItem(child, aPopup, null);
-            }
-          }
-          else {
-            // This menu is empty.  If there is no static content, add
-            // an element to show it is empty.
-            if (aPopup._startMarker == -1 && aPopup._endMarker == -1)
-              this._showEmptyMenuItem(aPopup);
-          }
-          aPopup.parentNode._built = true;
-        ]]></body>
-      </method>
-
-      <!-- nsINavHistoryResultObserver -->
-      <field name="_resultObserver"><![CDATA[({
-        _self: this,
-
-        get result() {
-          return this._self._result;
-        },
-
-        set result(val) {
-          if (this._self._result) {
-            this._self._result.removeObserver(this);
-            this._self._resultNode.containerOpen = false;
-          }
-
-          this._self.parentNode._built = false;
-          this._self._result = val;
-          if (val) {
-            this._self._resultNode = val.root;
-            this._self._resultNode._DOMElement = this._self.parentNode;
-          }
-          else {
-            this._self._resultNode = null;
-          }
-
-          return val;
-        },
-
-        nodeInserted: function PMV_nodeInserted(aParentNode, aNode, aIndex) {
-          let parentElt = aParentNode._DOMElement;
-          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
-
-          if (!parentElt._built)
-            return;
-
-          // parentElt is the <menu> element for the container,
-          // we need the <menupopup>
-          let popup = parentElt.firstChild;
-
-          let index = popup._startMarker + 1 + aIndex;
-          this._self.insertNewItem(aNode, popup, popup.childNodes[index]);
-          if (popup._emptyMenuItem)
-            popup._emptyMenuItem.hidden = true;
-        },
-
-        nodeRemoved: function PMV_nodeRemoved(aParentNode, aNode, aIndex) {
-          let parentElt = aParentNode._DOMElement;
-          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
-
-          if (!parentElt._built)
-            return;
-
-          // parentElt is the <menu> element for the container,
-          // we need the <menupopup>
-          let popup = parentElt.firstChild;
-
-          let nodeElt = aNode._DOMElement;
-          NS_ASSERT(nodeElt, "node must have _DOMElement set");
-          popup.removeChild(nodeElt);
-
-          // Figure out if we need to show the "<Empty>" menu-item.
-          // TODO Bug 517701: This doesn't seem to handle the case of an empty
-          // root (parentElt == this._self.parentNode).
-          if (!popup.hasChildNodes() ||
-              (popup.childNodes.length == 1 &&
-              popup.firstChild == popup._emptyMenuItem))
-            this._self._showEmptyMenuItem(popup);
-
-          if (popup._endMarker != -1)
-            popup._endMarker--;
-        },
-
-        nodeMoved:
-        function PMV_nodeMoved(aNode,
-                               aOldParent, aOldIndex,
-                               aNewParent, aNewIndex) {
-          // Note: the current implementation of moveItem does not actually
-          // use this notification when the item in question is moved from one
-          // folder to another.  Instead, it calls nodeRemoved and nodeInserted
-          // for the two folders.  Thus, we can assume aOldParent == aNewParent.
-
-          let nodeElt = aNode._DOMElement;
-          NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-          // If our root node is a folder, it might be moved. There's nothing
-          // we need to do in that case.
-          if (nodeElt == this._self.parentNode)
-            return;
-
-          // Move the node.
-          let popup = nodeElt.parentNode;
-          let index = popup._startMarker + 1 + aNewIndex;
-          popup.removeChild(nodeElt);
-          popup.insertBefore(nodeElt, popup.childNodes[index]);
-        },
-
-        nodeTitleChanged: function PMV__nodeTitleChanged(aNode, aNewTitle) {
-          let nodeElt = aNode._DOMElement;
-          NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-          // There's no UI representation for the root node, thus there's
-          // nothing to be done when the title changes.
-          if (nodeElt == this._self.parentNode)
-            return;
-
-          nodeElt.label = aNewTitle || PlacesUIUtils.getBestTitle(aNode);
-        },
-
-        nodeURIChanged: function PMV_nodeURIChanged(aNode, aURIString) {
-          let nodeElt = aNode._DOMElement;
-          NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-          nodeElt.setAttribute("scheme",
-                               PlacesUIUtils.guessUrlSchemeForUI(aURIString));
-        },
-
-        nodeIconChanged: function PMV_nodeIconChanged(aNode) {
-          let nodeElt = aNode._DOMElement;
-          NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-          // There's no UI representation for the root node, thus there's
-          // nothing to be done when the icon changes.
-          if (nodeElt == this._self.parentNode)
-            return;
-
-          var icon = aNode.icon;
-          if (icon) {
-            if (nodeElt.getAttribute("image") != icon)
-              nodeElt.setAttribute("image", icon);
-          }
-          else
-            nodeElt.removeAttribute("image");
-        },
-
-        nodeAnnotationChanged:
-        function PMV_nodeAnnotationChanged(aNode, aAnno) {
-          // Ensure the changed annotation is a livemark one.
-          if (/^livemark\//.test(aAnno) &&
-              PlacesUtils.nodeIsLivemarkContainer(aNode)) {
-            let nodeElt = aNode._DOMElement;
-            NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-            if (!nodeElt.hasAttribute("livemark"))
-              nodeElt.setAttribute("livemark", "true");
-
-            // Add or remove the livemark status menuitem.
-            PlacesUIUtils.ensureLivemarkStatusMenuItem(nodeElt.firstChild);
-          }
-        },
-
-        nodeHistoryDetailsChanged: function() { },
-        nodeTagsChanged: function() { },
-        nodeDateAddedChanged: function() { },
-        nodeLastModifiedChanged: function() { },
-        nodeKeywordChanged: function() { },
-
-        nodeReplaced:
-        function PMV_nodeReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
-          let parentElt = aParentNode._DOMElement;
-          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
-
-          if (!parentElt._built)
-            return;
-
-          // parentElt is the <menu> element for the container,
-          // we need the <menupopup>.
-          let popup = parentElt.firstChild;
-
-          let nodeElt = aOldNode._DOMElement;
-          NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-          // No worries: If nodeElt is the last item (i.e. no nextSibling),
-          // insertNewItem will insert the new element as the last item.
-          let next = nodeElt.nextSibling;
-          this._self.removeItem(nodeElt);
-          this._self.insertNewItem(aNewNode, popup, next);
-        },
-
-        containerOpened: function PMV_containerOpened(aNode) {
-          this.invalidateContainer(aNode);
-        },
-
-        containerClosed: function PMV_containerClosed(aNode) {
-          this.invalidateContainer(aNode);
-        },
-
-        containerStateChanged:
-        function PMV_containerStateChanged(aNode, aOldState, aNewState) {},
-
-        invalidateContainer: function PMV_invalidateContainer(aContainer) {
-          // Do nothing if the entire view is already marked un-built.
-          if (!this._self.parentNode._built)
-            return;
-
-          let containerNodeElt = aContainer._DOMElement;
-          NS_ASSERT(containerNodeElt, "node must have _DOMElement set");
-          containerNodeElt._built = false;
-
-          // If the menupopup is open we should live-update it.
-          if (containerNodeElt.open)
-            this._self._rebuild(containerNodeElt.firstChild);
-        },
-
-        sortingChanged: function PMV_sortingChanged(aSortingMode) {
-        },
-        
-        QueryInterface: function PTV_QueryInterface(aIID) {
-          if (aIID.equals(Ci.nsINavHistoryResultObserver) ||
-              aIID.equals(Ci.nsISupportsWeakReference) ||
-              aIID.equals(Ci.nsISupports))
-            return this;
-          throw Cr.NS_ERROR_NO_INTERFACE;
-        }
-      })]]></field>
-
-      <!-- nsIPlacesView -->
-      <property name="place">
-        <getter><![CDATA[
-          return this.getAttribute("place");
-        ]]></getter>
-        <setter><![CDATA[
-          this.setAttribute("place", val);
-          var queries = { }, options = { };
-          PlacesUtils.history.queryStringToQueries(val, queries, { }, options);
-          if (!queries.value.length)
-            queries.value = [PlacesUtils.history.getNewQuery()];
-          var result =
-            PlacesUtils.history.executeQueries(queries.value,
-                                               queries.value.length,
-                                               options.value);
-
-          result.addObserver(this._resultObserver, false);
-          return val;
-        ]]></setter>
-      </property>
-
-      <!-- nsIPlacesView -->
-      <property name="hasSelection">
-        <getter><![CDATA[
-          return this.selectedNode != null;
-        ]]></getter>
-      </property>
-
-      <!-- nsIPlacesView -->
-      <method name="getSelectionNodes">
-        <body><![CDATA[
-          var selectedNode = this.selectedNode;
-          return selectedNode ? [selectedNode] : [];
-        ]]></body>
-      </method>
-
-      <!-- nsIPlacesView -->
-      <method name="getRemovableSelectionRanges">
-        <body><![CDATA[
-          // On static content the current selectedNode would be the selection's
-          // parent node. We don't want to allow removing a node when the
-          // selection is not explicit.
-          if (document.popupNode &&
-              (document.popupNode == "menupopup" || !document.popupNode.node))
-            return [];
-
-          return [this.getSelectionNodes()];
-        ]]></body>
-      </method>
-
-      <!-- nsIPlacesView -->
-      <method name="getDraggableSelection">
-        <body><![CDATA[
-          return [this._draggedNode];
-        ]]></body>
-      </method>
-
-      <!-- nsIPlacesView -->
-      <property name="selectedNode">
-        <getter><![CDATA[
-          if (this._contextMenuShown) {
-            var popupNode = document.popupNode;
-            return popupNode.node || popupNode.parentNode._resultNode || null;
-          }
-          return null;
-        ]]></getter>
-      </property>
-
-      <!-- nsIPlacesView -->
-      <property name="insertionPoint">
-        <getter><![CDATA[
-          // there is no insertion point for history queries
-          // so bail out now and save a lot of work when updating commands
-          var resultNode = this._resultNode;
-          if (PlacesUtils.nodeIsQuery(resultNode) &&
-              PlacesUtils.asQuery(resultNode).queryOptions.queryType ==
-                Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY)
-              return null;
-
-          // By default, the insertion point is at the top level, at the end.
-          var index = PlacesUtils.bookmarks.DEFAULT_INDEX;
-          var container = null;
-          var orientation = Ci.nsITreeView.DROP_BEFORE;
-          var isTag = false;
-
-          if (PlacesUtils.nodeIsFolder(resultNode)) {
-            container = resultNode;
-            isTag = PlacesUtils.nodeIsTagQuery(resultNode);
-          }
-
-          var selectedNode = this.selectedNode;
-          if (selectedNode) {
-            var popupNode = document.popupNode;
-            if (!popupNode.node) {
-              // If a static menuitem is selected the insertion point
-              // is inside the folder, at the end.
-              container = selectedNode;
-              orientation = Ci.nsITreeView.DROP_ON;
-            }
-            else {
-              // In all other cases the insertion point is before that node.
-              container = selectedNode.parent;
-              index = container.getChildIndex(selectedNode);
-              isTag = PlacesUtils.nodeIsTagQuery(container);
-            }
-          }
-
-          if (PlacesControllerDragHelper.disallowInsertion(container))
-            return null;
-
-          return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
-                                    index, orientation, isTag);
-        ]]></getter>
-      </property>
-
-      <!-- nsIPlacesView -->
-      <method name="selectAll">
-        <body/>
-      </method>
-
-      <method name="selectItems">
-        <body/>
-      </method>
-
-      <property name="selType" readonly="true" onget="return 'single';"/>
-
-      <method name="buildContextMenu">
-        <parameter name="aPopup"/>
-        <body><![CDATA[
-          this._ensureInitialized();
-          this._contextMenuShown = true;
-          window.updateCommands("places");
-          return this.controller.buildContextMenu(aPopup);
-        ]]></body>
-      </method>
-
-      <method name="destroyContextMenu">
-        <parameter name="aPopup"/>
-        <body>
-          <![CDATA[
-            this._contextMenuShown = false;
-            if (window.content)
-              window.content.focus();
-          ]]>
-        </body>
-      </method>
-    </implementation>
-    <handlers>
-      <handler event="popupshowing" phase="capturing"><![CDATA[
-        this._ensureInitialized();
-        var popup = event.target;
-        // Avoid handling popupshowing of inner views
-        if (!popup._resultNode || PlacesUIUtils.getViewForNode(popup) != this)
-          return;
-
-        this.onPopupShowing(event);
-      ]]></handler>
-
-      <handler event="popuphidden"><![CDATA[
-        var popup = event.target;
-        // We should avoid to handle events of inner views
-        if (!popup._resultNode || PlacesUIUtils.getViewForNode(popup) != this)
-          return;
-
-        // UI performance: folder queries are cheap, keep the resultnode open
-        // so we don't rebuild its contents whenever the popup is reopened.
-        if (!PlacesUtils.nodeIsFolder(popup._resultNode))
-          popup._resultNode.containerOpen = false;
-
-        // The autoopened attribute is set for folders which have been
-        // automatically opened when dragged over.  Turn off this attribute
-        // when the folder closes because it is no longer applicable.
-        popup.removeAttribute("autoopened");
-        popup.removeAttribute("dragstart");
-      ]]></handler>
-    </handlers>
-  </binding>
-
 </bindings>
--- a/browser/components/places/content/places.css
+++ b/browser/components/places/content/places.css
@@ -1,29 +1,21 @@
 tree[type="places"] {
   -moz-binding: url("chrome://browser/content/places/tree.xml#places-tree");
 }
 
-hbox[type="places"] {
-  -moz-binding: url("chrome://browser/content/places/toolbar.xml#places-bar");
-}
-
 .bookmarks-toolbar-customize,
-toolbarpaletteitem .bookmarks-toolbar-items {
+toolbarpaletteitem #PlacesToolbarItems {
   display: none;
 }
 
 toolbarpaletteitem .bookmarks-toolbar-customize {
   display: -moz-box;
 }
 
 .toolbar-drop-indicator {
   position: relative;
   z-index: 1;
 }
 
-menupopup[type="places"] {
-  -moz-binding: url("chrome://browser/content/places/menu.xml#places-menupopup");
-}
-
 menupopup[placespopup="true"] {
   -moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-base");
 }
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -326,17 +326,17 @@ var PlacesOrganizer = {
    * Handle focus changes on the trees.
    * When moving focus between panes we should update the details pane contents.
    * @param   aEvent
    *          The mouse event.
    */
   onTreeFocus: function PO_onTreeFocus(aEvent) {
     var currentView = aEvent.currentTarget;
     var selectedNodes = currentView.selectedNode ? [currentView.selectedNode] :
-                        this._content.getSelectionNodes();
+                        this._content.selectedNodes;
     this._fillDetailsPane(selectedNodes);
   },
 
   openFlatContainer: function PO_openFlatContainerFlatContainer(aContainer) {
     if (aContainer.itemId != -1)
       this._places.selectItems([aContainer.itemId]);
     else if (PlacesUtils.nodeIsQuery(aContainer))
       this._places.selectPlaceURI(aContainer.uri);
@@ -346,25 +346,25 @@ var PlacesOrganizer = {
     PlacesUIUtils.openNodeWithEvent(this._content.selectedNode, aEvent);
   },
 
   /**
    * Returns the options associated with the query currently loaded in the
    * main places pane.
    */
   getCurrentOptions: function PO_getCurrentOptions() {
-    return PlacesUtils.asQuery(this._content.getResult().root).queryOptions;
+    return PlacesUtils.asQuery(this._content.result.root).queryOptions;
   },
 
   /**
    * Returns the queries associated with the query currently loaded in the
    * main places pane.
    */
   getCurrentQueries: function PO_getCurrentQueries() {
-    return PlacesUtils.asQuery(this._content.getResult().root).getQueries();
+    return PlacesUtils.asQuery(this._content.result.root).getQueries();
   },
 
   /**
    * Show the migration wizard for importing from a file.
    */
   importBookmarks: function PO_import() {
     // XXX: ifdef it to be non-modal (non-"sheet") on mac (see bug 259039)
     var features = "modal,centerscreen,chrome,resizable=no";
@@ -604,17 +604,17 @@ var PlacesOrganizer = {
     var height = previewBox.boxObject.height;
     var width = height * (screen.width / screen.height);
     canvas.width = width;
     canvas.height = height;
   },
 
   onContentTreeSelect: function PO_onContentTreeSelect() {
     if (this._content.treeBoxObject.focused)
-      this._fillDetailsPane(this._content.getSelectionNodes());
+      this._fillDetailsPane(this._content.selectedNodes);
   },
 
   _fillDetailsPane: function PO__fillDetailsPane(aNodeList) {
     var infoBox = document.getElementById("infoBox");
     var detailsDeck = document.getElementById("detailsDeck");
 
     // Make sure the infoBox UI is visible if we need to use it, we hide it
     // below when we don't.
@@ -1281,17 +1281,17 @@ var ViewMenu = {
    *          current sort column or the title column will be used.
    * @param   aDirection
    *          The direction to sort - "ascending" or "descending".
    *          Can be null - the last direction or descending will be used.
    *
    * If both aColumnID and aDirection are null, the view will be unsorted.
    */
   setSortColumn: function VM_setSortColumn(aColumn, aDirection) {
-    var result = document.getElementById("placeContent").getResult();
+    var result = document.getElementById("placeContent").result;
     if (!aColumn && !aDirection) {
       result.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_NONE;
       return;
     }
 
     var columnId;
     if (aColumn) {
       columnId = aColumn.getAttribute("anonid");
deleted file mode 100644
--- a/browser/components/places/content/toolbar.xml
+++ /dev/null
@@ -1,1326 +0,0 @@
-<?xml version="1.0"?>
-
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is the Places Toolbar View.
-#
-# The Initial Developer of the Original Code is Google Inc.
-# Portions created by the Initial Developer are Copyright (C) 2005-2006
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#   Annie Sullivan <annie.sullivan@gmail.com>
-#   Ben Goodger <beng@google.com>
-#   Myk Melez <myk@mozilla.org>
-#   Marco Bonardo <mak77@bonardo.net>
-#   Asaf Romano <mano@mozilla.com>
-#
-# Alternatively, the contents of this file may be used under the terms of
-# either the GNU General Public License Version 2 or later (the "GPL"), or
-# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-# in which case the provisions of the GPL or the LGPL are applicable instead
-# of those above. If you wish to allow use of your version of this file only
-# under the terms of either the GPL or the LGPL, and not to allow others to
-# use your version of this file under the terms of the MPL, indicate your
-# decision by deleting the provisions above and replace them with the notice
-# and other provisions required by the GPL or the LGPL. If you do not delete
-# the provisions above, a recipient may use your version of this file under
-# the terms of any one of the MPL, the GPL or the LGPL.
-#
-# ***** END LICENSE BLOCK *****
-
-
-<!DOCTYPE bindings [
-<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd" >
-%browserDTD;
-]>
-
-<bindings id="placesToolbarBindings"
-          xmlns="http://www.mozilla.org/xbl"
-          xmlns:xbl="http://www.mozilla.org/xbl"
-          xmlns:html="http://www.w3.org/1999/xhtml"
-          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
-  <binding id="places-bar">
-    <resources>
-      <stylesheet src="chrome://browser/skin/places/places.css"/>
-    </resources>
-
-    <content>
-        <xul:toolbarbutton class="bookmark-item bookmarks-toolbar-customize"
-                           mousethrough="never"
-                           label="&bookmarksToolbarItem.label;"/>
-        <xul:hbox flex="1">
-          <xul:hbox align="center">
-            <xul:image class="toolbar-drop-indicator"
-                       mousethrough="always"
-                       collapsed="true"/>
-          </xul:hbox>
-          <xul:scrollbox orient="horizontal"
-                         class="bookmarks-toolbar-items"
-                         flex="1">
-            <children/>
-          </xul:scrollbox>
-          <xul:toolbarbutton type="menu"
-                             class="chevron"
-                             mousethrough="never"
-                             collapsed="true"
-                             tooltiptext="&bookmarksToolbarChevron.tooltip;"
-                             onpopupshowing="_onChevronPopupShowing(event);">
-            <xul:menupopup anonid="chevronPopup"
-                           popupsinherittooltip="true"
-                           xbl:inherits="tooltip"
-#ifndef XP_MACOSX
-                           context="placesContext"
-#endif
-            />
-          </xul:toolbarbutton>
-        </xul:hbox>
-    </content>
-
-    <implementation implements="nsIAccessibleProvider, nsITimerCallback, nsIDOMEventListener">
-      <constructor><![CDATA[
-        this._init();
-      ]]></constructor>
-
-      <destructor><![CDATA[
-        this._scrollbox.removeEventListener("overflow", this, false);
-        this._scrollbox.removeEventListener("underflow", this, false);
-        window.removeEventListener("resize", this, false);
-
-        if (this._result) {
-          this._result.removeObserver(this._resultObserver);
-          this._resultNode.containerOpen = false;
-          this._resultNode = null;
-          this._result = null;
-        }
-      ]]></destructor>
-
-      <property name="controller"
-                readonly="true"
-                onget="return this._controller;"/>
-
-      <method name="_init">
-        <body><![CDATA[
-          // XBL bug is in the middle...
-          // When toolbar customization is opened, this binding is attached
-          // again, as a result of adding the item under the wrapper.  However,
-          // the binding isn't detached from the "original" hbox element due
-          // to bug 83635.
-          //
-          // Then, when the customization dialog is closed, the binding is
-          // attached the third time, as a result of adding our element back to
-          // the toolbar.
-          //
-          // So, We'll just continue using the original binding, which was
-          // never removed, and avoid using the new bindings.  This means that
-          // this workaround will work just until bug 83635 is fixed.
-          //
-          // However, when the binding is "reconstructed", we do need to add
-          // back the event listeners and the places controller.
-          //
-          // Note: we could avoid part of this mess by moving the "Bookmark
-          // Toolbar Items" placeholder out of this binding.
-
-          // We also need to avoid initializing _result and _resultNode and
-          // _controller as XBL fields.  Otherwise, they'll be unset when the
-          // "extra" bindings are applied.
-
-          this._scrollbox.addEventListener("overflow", this, false);
-          this._scrollbox.addEventListener("underflow", this, false);
-          window.addEventListener("resize", this, false);
-
-          if (this._result === undefined) {
-            this._result = null;
-            this._resultNode = null;
-            if (this.hasAttribute("place")) {
-              // Do the initial build.
-              this.place = this.place;
-            }
-          }
-
-          // Attach the places controller.
-          if (!this._controller) 
-            this._controller = new PlacesController(this);
-
-          this.controllers.appendController(this._controller);
-        ]]></body>
-      </method>
-
-      <field name="_scrollbox">
-        document.getAnonymousElementByAttribute(this, "class",
-                                                "bookmarks-toolbar-items")
-      </field>
-      <field name="_dropIndicator">
-        document.getAnonymousElementByAttribute(this, "class",
-                                                "toolbar-drop-indicator")
-      </field>
-      <field name="_chevron">
-        document.getAnonymousElementByAttribute(this, "class", "chevron")
-      </field>
-      <field name="_chevronPopup">
-        document.getAnonymousElementByAttribute(this, "anonid", "chevronPopup")
-      </field>
-
-      <field name="_openedMenuButton">null</field>
-      <field name="_allowPopupShowing">true</field>
-
-      <field name="_isRTL">
-        document.defaultView.getComputedStyle(this.parentNode, "")
-                            .direction == "rtl"
-      </field>
-
-      <!-- nsIPlacesView -->
-      <method name="getResult">
-        <body><![CDATA[
-          return this._result;
-        ]]></body>
-      </method>
-
-      <!-- nsIPlacesView -->
-      <method name="getResultNode">
-        <body><![CDATA[
-          return this._resultNode;
-        ]]></body>
-      </method>
-
-      <method name="_rebuild">
-        <body><![CDATA[
-          // Clear out references to existing nodes, since they will be removed
-          // and re-added.
-          if (this._overFolder.node)
-            this._clearOverFolder();
-          this._openedMenuButton = null;
-
-          while (this.hasChildNodes())
-            this.removeChild(this.firstChild);
-
-          let cc = this._resultNode.childCount;
-          for (let i = 0; i < cc; ++i)
-            this.insertNewItem(this._resultNode.getChild(i), null);
-
-          if (this._chevronPopup.hasAttribute("type")) {
-            // Chevron has already been initialized, but since we are forcing
-            // a rebuild of the toolbar, it has to be rebuilt.
-            // Otherwise, it will be initialized when the toolbar overflows.
-            this._chevronPopup.place = this.place;
-          }
-        ]]></body>
-      </method>
-
-      <method name="insertNewItem">
-        <parameter name="aChild"/>
-        <parameter name="aBefore"/>
-        <body><![CDATA[
-          var type = aChild.type;
-          var button;
-          if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR)
-            button = document.createElement("toolbarseparator");
-          else {
-            button = document.createElement("toolbarbutton");
-            button.className = "bookmark-item";
-            button.setAttribute("label", aChild.title);
-            var icon = aChild.icon;
-            if (icon)
-              button.setAttribute("image", icon);
-
-            if (PlacesUtils.containerTypes.indexOf(type) != -1) {
-              button.setAttribute("type", "menu");
-              button.setAttribute("container", "true");
-
-              if (PlacesUtils.nodeIsQuery(aChild)) {
-                button.setAttribute("query", "true");
-                if (PlacesUtils.nodeIsTagQuery(aChild))
-                  button.setAttribute("tagContainer", "true");
-              }
-              else if (PlacesUtils.nodeIsLivemarkContainer(aChild))
-                button.setAttribute("livemark", "true");
-
-              var popup = document.createElement("menupopup");
-              popup.setAttribute("placespopup", "true");
-              button.appendChild(popup);
-              popup._resultNode = PlacesUtils.asContainer(aChild);
-#ifndef XP_MACOSX
-              popup.setAttribute("context", "placesContext");
-#endif
-            }
-            else if (PlacesUtils.nodeIsURI(aChild))
-              button.setAttribute("scheme", PlacesUIUtils.guessUrlSchemeForUI(aChild.uri));
-          }
-
-          button.node = aChild;
-          aChild._DOMElement = button;
-          if (aBefore)
-            this.insertBefore(button, aBefore);
-          else
-            this.appendChild(button);
-        ]]></body>
-      </method>
-
-      <method name="removeItem">
-        <parameter name="child"/>
-        <body><![CDATA[
-          // if document.popupNode pointed to this child, null it out,
-          // otherwise controller's command-updating may rely on the removed
-          // item still being "selected".
-          if (document.popupNode == child)
-            document.popupNode = null;
-
-          child.parentNode.removeChild(child);
-        ]]></body>
-      </method>
-
-      <method name="_updateChevronPopupNodesVisibility">
-        <body><![CDATA[
-          for (let i = 0; i < this._chevronPopup.childNodes.length; i++) {
-            this._chevronPopup.childNodes[i].hidden =
-              this.childNodes[i].style.visibility != "hidden";
-          }
-        ]]></body>
-      </method>
-
-      <method name="_onChevronPopupShowing">
-        <parameter name="aEvent"/>
-        <body><![CDATA[
-          // Handle popupshowing only for the chevron popup, not for
-          // nested ones.
-          if (aEvent.target != this._chevronPopup)
-            return;
-
-          this._updateChevronPopupNodesVisibility();
-        ]]></body>
-      </method>
-
-      <method name="handleEvent">
-        <parameter name="aEvent"/>
-        <body><![CDATA[
-          // Both overflow/underflow and resize events should not be handled
-          // for descendant nodes.
-          if (aEvent.target != aEvent.currentTarget)
-            return;
-
-          switch (aEvent.type) {
-            case "resize":
-              // This handler updates nodes visibility in both the toolbar
-              // and the chevron popup when a window resize does not change
-              // the overflow status of the toolbar.
-              break;
-
-            case "overflow":
-              // Ignore purely vertical overflows.
-              if (aEvent.detail == 0)
-                return;
-
-              // Attach the popup binding to the chevron popup if it has not yet
-              // been initialized.
-              if (!this._chevronPopup.hasAttribute("type")) {
-                this._chevronPopup.setAttribute("place", this.place);
-                this._chevronPopup.setAttribute("type", "places");
-              }
-              this._chevron.collapsed = false;
-              break;
-
-            case "underflow":
-              // Ignore purely vertical underflows.
-              if (aEvent.detail == 0)
-                return;
-
-              this._chevron.collapsed = true;
-              break;
-          }
-
-          this.updateChevron();
-        ]]></body>
-      </method>
-
-      <method name="updateChevron">
-        <body><![CDATA[
-          // If the chevron is collapsed there's nothing to update.
-          if (this._chevron.collapsed)
-            return;
-
-          // XXX (bug 508816) Scrollbox does not handle correctly RTL mode.
-          // This workarounds the issue scrolling the box to the right.
-          if (this._isRTL)
-            this._scrollbox.scrollLeft = this._scrollbox.scrollWidth;
-
-          // Update the chevron on a timer.  This will avoid repeated work when
-          // lot of changes happen in a small timeframe.
-          if (this._updateChevronTimer)
-            this._updateChevronTimer.cancel();
-          this._updateChevronTimer = this._setTimer(100);
-        ]]></body>
-      </method>
-
-      <method name="_updateChevronTimerCallback">
-        <body><![CDATA[
-          var scrollRect = this._scrollbox.getBoundingClientRect();
-          var childOverflowed = false;
-          for (let i = 0; i < this.childNodes.length; i++) {
-            let child = this.childNodes[i];
-            // Once a child overflows, all the next ones will.
-            if (!childOverflowed) {
-              let childRect = child.getBoundingClientRect();
-              childOverflowed = this._isRTL ? (childRect.left < scrollRect.left)
-                                            : (childRect.right > scrollRect.right);
-            }
-            child.style.visibility = childOverflowed ? "hidden" : "visible";
-          }
-
-          // We rebuild the chevron on popupShowing, so if it is open
-          // we must update it.
-          if (this._chevron.open)
-            this._updateChevronPopupNodesVisibility();
-        ]]></body>
-      </method>
-
-      <!-- nsIPlacesView -->
-      <property name="place">
-        <getter><![CDATA[
-          return this.getAttribute("place");
-        ]]></getter>
-        <setter><![CDATA[
-          this.setAttribute("place", val);
-
-          var history = PlacesUtils.history;
-          var queries = { }, options = { };
-          history.queryStringToQueries(val, queries, { }, options);
-          if (!queries.value.length)
-            queries.value = [history.getNewQuery()];
-          try {
-            var result =
-              history.executeQueries(queries.value, queries.value.length,
-                                     options.value);
-            result.addObserver(this._resultObserver, false);
-          }
-          catch(ex) {
-            // Invalid query, or had no results.
-            // This is valid, eg: user deletes his bookmarks toolbar folder.
-          }
-          return val;
-        ]]></setter>
-      </property>
-
-      <!-- nsIPlacesView -->
-      <property name="hasSelection">
-        <getter><![CDATA[
-          return this.selectedNode != null;
-        ]]></getter>
-      </property>
-
-      <!-- nsIPlacesView -->
-      <method name="getSelectionNodes">
-        <body><![CDATA[
-          var selectedNode = this.selectedNode;
-          return selectedNode ? [selectedNode] : [];
-        ]]></body>
-      </method>
-
-      <!-- nsIPlacesView -->
-      <method name="getRemovableSelectionRanges">
-        <body><![CDATA[
-          // On static content the current selectedNode would be the selection's
-          // parent node. We don't want to allow removing a node when the
-          // selection is not explicit.
-          if (document.popupNode &&
-              (document.popupNode == "menupopup" || !document.popupNode.node))
-            return [];
-
-          return [this.getSelectionNodes()];
-        ]]></body>
-      </method>
-
-      <!-- nsIPlacesView -->
-      <method name="getDraggableSelection">
-        <body><![CDATA[
-          return [this._draggedNode];
-        ]]></body>
-      </method>
-
-      <!-- nsIPlacesView -->
-      <property name="selectedNode">
-        <getter><![CDATA[
-          if (this._contextMenuShown) {
-            var popupNode = document.popupNode;
-            if (popupNode == this)
-              return this.getResultNode();
-
-            return popupNode.node || popupNode.parentNode._resultNode || null;
-          }
-          return null;
-        ]]></getter>
-      </property>
-
-      <!-- nsIPlacesView -->
-      <property name="insertionPoint">
-        <getter><![CDATA[
-          // By default, the insertion point is at the top level, at the end.
-          var index = PlacesUtils.bookmarks.DEFAULT_INDEX;
-          var container = this._resultNode;
-          var orientation = Ci.nsITreeView.DROP_BEFORE;
-          var isTag = false;
-
-          var selectedNode = this.selectedNode;
-          if (selectedNode) {
-            var popupNode = document.popupNode;
-            if (!popupNode.node) {
-              // If a static menuitem is selected the insertion point
-              // is inside the folder, at the end.
-              container = selectedNode;
-              orientation = Ci.nsITreeView.DROP_ON;
-            }
-            else {
-              // In all other cases the insertion point is before that node.
-              container = selectedNode.parent;
-              index = container.getChildIndex(selectedNode);
-              isTag = PlacesUtils.nodeIsTagQuery(container);
-            }
-          }
-
-          if (PlacesControllerDragHelper.disallowInsertion(container))
-            return null;
-
-          return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
-                                    index, orientation, isTag);
-        ]]></getter>
-      </property>
-
-      <!-- nsIPlacesView -->
-      <method name="selectAll">
-        <body><![CDATA[
-          // Nothing
-        ]]></body>
-      </method>
-
-      <method name="selectItems">
-        <body><![CDATA[
-          // Nothing
-        ]]></body>
-      </method>
-
-      <!-- nsINavHistoryResultObserver -->
-      <field name="_resultObserver"><![CDATA[({
-        _self: this,
-
-        get result() {
-          return this._self._result;
-        },
-
-        set result(val) {
-          if (this._self._result) {
-            this._self._result.removeObserver(this);
-            this._self._resultNode.containerOpen = false;
-          }
-
-          this._self._result = val;
-          if (val) {
-            this._self._resultNode = val.root;
-            this._self._resultNode._DOMElement = this._self;
-            // This calls _rebuild through invalidateContainer.
-            this._self._resultNode.containerOpen = true;
-          }
-          else {
-            this._self._resultNode = null;
-          }
-
-          return val;
-        },
-
-        nodeInserted: function TV_V_nodeInserted(aParentNode, aNode, aIndex) {
-          let parentElt = aParentNode._DOMElement;
-          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
-
-          if (parentElt == this._self) {
-            // Node is on the toolbar.
-            let children = this._self.childNodes;
-            this._self.insertNewItem(aNode,
-              aIndex < children.length ? children[aIndex] : null);
-            this._self.updateChevron();
-          }
-          else if (parentElt._built) {
-            // Node is within a built menu.
-            let popup = parentElt.firstChild;
-            let before = popup.childNodes[aIndex] || null;
-            this._self.insertNewItemToPopup(aNode, popup, before);
-            if (popup._emptyMenuItem)
-              popup._emptyMenuItem.hidden = true;
-          }
-        },
-
-        nodeRemoved: function TV_V_nodeRemoved(aParentNode, aNode, aIndex) {
-          let parentElt = aParentNode._DOMElement;
-          let nodeElt = aNode._DOMElement;
-
-          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
-          NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-          if (parentElt == this._self) {
-            // Node is on the toolbar.
-            this._self.removeChild(nodeElt);
-            this._self.updateChevron();
-          }
-          else if (parentElt._built) {
-            // Node is within a built menu.
-            var popup = parentElt.firstChild;
-            popup.removeChild(nodeElt);
-            if (!popup.hasChildNodes() ||
-                (popup.childNodes.length == 1 &&
-                popup.firstChild == popup._emptyMenuItem))
-              this._self._showEmptyMenuItem(popup);
-
-            if (popup._endMarker != -1)
-              popup._endMarker--;
-          }
-        },
-
-        nodeMoved:
-        function TV_V_nodeMoved(aNode,
-                                aOldParent, aOldIndex,
-                                aNewParent, aNewIndex) {
-          // Note: the current implementation of moveItem does not actually
-          // use this notification when the item in question is moved from one
-          // folder to another.  Instead, it calls nodeRemoved and nodeInserted
-          // for the two folders.  Thus, we can assume aOldParent == aNewParent.
-
-          let nodeElt = aNode._DOMElement;
-          NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-          // If our root node is a folder, it might be moved. There's nothing
-          // we need to do in that case.
-          if (nodeElt == this._self)
-            return;
-
-          let parentElt = aNewParent._DOMElement;
-          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
-
-          if (parentElt == this._self) {
-            // Container is on the toolbar.
-
-            // Move the node.
-            this._self.removeChild(nodeElt);
-            this._self.insertBefore(nodeElt, this._self.childNodes[aNewIndex]);
-
-            // If the chevron popup is open, keep it in sync.
-            if (this._self._chevron.open) {
-              let chevronPopup = this._self._chevronPopup;
-              let menuitem = chevronPopup.childNodes[aOldIndex];
-              chevronPopup.removeChild(menuitem);
-              chevronPopup.insertBefore(menuitem,
-                                        chevronPopup.childNodes[aNewIndex]);
-            }
-            this._self.updateChevron();
-          }
-          else if (parentElt._built) {
-            // Container is within a built menu.
-
-            // parentElt is the <menu> element for the container,
-            // we need the <menupopup>.
-            var popup = parentElt.firstChild;
-
-            // Move the node.
-            popup.removeChild(nodeElt);
-            popup.insertBefore(nodeElt, popup.childNodes[aNewIndex]);
-          }
-        },
-
-        nodeTitleChanged: function TV_V_nodeTitleChanged(aNode, aNewTitle) {
-          let nodeElt = aNode._DOMElement;
-          NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-          // There's no UI representation for the root node, thus there's
-          // nothing to be done when the title changes.
-          if (nodeElt == this._self)
-            return;
-
-          if (nodeElt.parentNode == this._self) {
-            // Node is on the toolbar
-            nodeElt.label = aNewTitle;
-            this._self.updateChevron();
-          }
-          else {
-            // Node is within a built menu.
-            nodeElt.label = aNewTitle || PlacesUIUtils.getBestTitle(aNode);
-          }
-        },
-
-        nodeURIChanged: function TV_V_nodeURIChanged(aNode, aURIString) {
-          let nodeElt = aNode._DOMElement;
-          NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-          nodeElt.setAttribute("scheme",
-                               PlacesUIUtils.guessUrlSchemeForUI(aURIString));
-        },
-
-        nodeIconChanged: function TV_V_nodeIconChanged(aNode) {
-          let nodeElt = aNode._DOMElement;
-          NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-          // There's no UI representation for the root node, thus there's
-          // nothing to be done when the icon changes.
-          if (nodeElt == this._self)
-            return;
-
-          let icon = aNode.icon;
-          if (icon) {
-            if (nodeElt.getAttribute("image") != icon)
-              nodeElt.setAttribute("image", icon);
-          }
-          else
-            nodeElt.removeAttribute("image");
-        },
-
-        nodeAnnotationChanged:
-        function TV_V_nodeAnnotationChanged(aNode, aAnno) {
-          // Ensure the changed annotation is a livemark one.
-          if (/^livemark\//.test(aAnno) &&
-              PlacesUtils.nodeIsLivemarkContainer(aNode)) {
-            let nodeElt = aNode._DOMElement;
-            NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-            if (!nodeElt.hasAttribute("livemark"))
-              nodeElt.setAttribute("livemark", "true");
-
-            // Add or remove the livemark status menuitem.
-            PlacesUIUtils.ensureLivemarkStatusMenuItem(nodeElt.firstChild);
-          }
-        },
-
-        nodeHistoryDetailsChanged: function() { },
-        nodeTagsChanged: function() { },
-        nodeDateAddedChanged: function() { },
-        nodeLastModifiedChanged: function() { },
-        nodeKeywordChanged: function() { },
-
-        nodeReplaced:
-        function TV_V_nodeReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
-          let nodeElt = aOldNode._DOMElement;
-          NS_ASSERT(nodeElt, "node must have _DOMElement set");
-
-          // No worries: If nodeElt is the last item (i.e. no nextSibling),
-          // insertNewItem/insertNewItemToPopup will insert the new element as
-          // the last item.
-          let next = nodeElt.nextSibling;
-
-          let parentElt = aParentNode._DOMElement;
-          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
-          if (parentElt == this._self) {
-            // Node is on the toolbar.
-            this._self.removeItem(nodeElt);
-            this._self.insertNewItem(aNewNode, next);
-            this._self.updateChevron();
-          }
-          else if (parentElt._built) {
-            // Node is within a built menu.
-            let popup = parentElt.firstChild;
-            popup.removeItem(nodeElt);
-            this._self.insertNewItemToPopup(aNewNode, popup, next);
-          }
-        },
-
-        containerOpened: function TV_V_containerOpened(aContainer) {
-          this.invalidateContainer(aContainer);
-        },
-
-        containerClosed: function TV_V_containerClosed(aContainer) {
-          this.invalidateContainer(aContainer);
-        },
-
-        containerStateChanged:
-        function TV_V_containerStateChanged(aNode, aOldState, aNewState) {},
-
-        invalidateContainer: function TV_V_invalidateContainer(aContainer) {
-          let containerNodeElt = aContainer._DOMElement;
-          NS_ASSERT(containerNodeElt, "node must have _DOMElement set");
-
-          if (containerNodeElt == this._self) {
-            // Container is the toolbar itself.
-            this._self._rebuild();
-          }
-          else if (containerNodeElt._built) {
-            // Container is a built menu.
-            containerNodeElt._built = false;
-            // If the menupopup is open we should live-update it.
-            if (containerNodeElt.open)
-              this._self._rebuildPopup(containerNodeElt.firstChild);
-          }
-        },
-
-        sortingChanged: function TV_V_sortingChanged(aSortingMode) {
-        },
-
-        QueryInterface: function PTV_QueryInterface(aIID) {
-          if (aIID.equals(Ci.nsINavHistoryResultObserver) ||
-              aIID.equals(Ci.nsISupportsWeakReference) ||
-              aIID.equals(Ci.nsISupports))
-            return this;
-          throw Cr.NS_ERROR_NO_INTERFACE;
-        }
-      })]]></field>
-
-      <property name="selType" onget="return 'single';"/>
-
-      <method name="buildContextMenu">
-        <parameter name="aPopup"/>
-        <body><![CDATA[
-          this._contextMenuShown = true;
-          window.updateCommands("places");
-          return this.controller.buildContextMenu(aPopup);
-        ]]></body>
-      </method>
-
-      <method name="destroyContextMenu">
-        <parameter name="aPopup"/>
-        <body><![CDATA[
-          this._contextMenuShown = false;
-          if (window.content)
-            window.content.focus();
-        ]]></body>
-      </method>
-
-      <method name="_showEmptyMenuItem">
-        <parameter name="aPopup"/>
-        <body><![CDATA[
-          if (aPopup._emptyMenuItem) {
-            aPopup._emptyMenuItem.hidden = false;
-            return;
-          }
-
-          var label = PlacesUIUtils.getString("bookmarksMenuEmptyFolder");
-          aPopup._emptyMenuItem = document.createElement("menuitem");
-          aPopup._emptyMenuItem.setAttribute("label", label);
-          aPopup._emptyMenuItem.setAttribute("disabled", true);
-          aPopup.appendChild(aPopup._emptyMenuItem);
-        ]]></body>
-      </method>
-
-      <method name="insertNewItemToPopup">
-        <parameter name="aChild"/>
-        <parameter name="aParentPopup"/>
-        <parameter name="aBefore"/>
-        <body><![CDATA[
-          var element = PlacesUIUtils.createMenuItemForNode(aChild,
-                                                            aParentPopup.ownerDocument);
-
-          if (aBefore)
-            aParentPopup.insertBefore(element, aBefore);
-          else {
-            // Add the new element to the menu.  If there is static content at
-            // the end of the menu, add the element before that.  Otherwise,
-            // just add to the end.
-            if (aParentPopup._endMarker != -1) {
-              let lastNode = aParentPopup.childNodes[aParentPopup._endMarker];
-              aParentPopup.insertBefore(element, lastNode);
-            }
-            else
-              aParentPopup.appendChild(element);
-          }
-
-          if (aParentPopup._endMarker != -1)
-            aParentPopup._endMarker++;
-        ]]></body>
-      </method>
-
-      <method name="_containerPopupShowing">
-        <parameter name="aPopup"/>
-        <body><![CDATA[
-          if (!aPopup.parentNode._built)
-            this._rebuildPopup(aPopup);
-        ]]></body>
-      </method>
-
-      <method name="_rebuildPopup">
-        <parameter name="aPopup"/>
-        <body><![CDATA[
-          PlacesUIUtils.cleanPlacesPopup(aPopup);
-
-          // If this is a livemark container check if the status menuitem has
-          // to be added or removed.
-          if (PlacesUtils.nodeIsLivemarkContainer(aPopup._resultNode))
-            PlacesUIUtils.ensureLivemarkStatusMenuItem(aPopup);
-
-          var resultNode = aPopup._resultNode;
-          if (!resultNode.containerOpen)
-            resultNode.containerOpen = true;
-
-          var cc = resultNode.childCount;
-          if (cc > 0) {
-            if (aPopup._emptyMenuItem)
-              aPopup._emptyMenuItem.hidden = true;
-
-            for (let i = 0; i < cc; ++i) {
-              var child = resultNode.getChild(i);
-              this.insertNewItemToPopup(child, aPopup, null);
-            }
-          }
-          else {
-            // This menu is empty.  If there is no static content, add
-            // an element to show it is empty.
-            if (aPopup._startMarker == -1 && aPopup._endMarker == -1)
-              this._showEmptyMenuItem(aPopup);
-          }
-          aPopup.parentNode._built = true;
-        ]]></body>
-      </method>
-
-      <field name="_overFolder"><![CDATA[
-       (
-         // Menu buttons should be opened when the mouse drags over them, and
-         // closed when the mouse drags off. This object manages opening and
-         // closing of folders when the mouse hovers.
-         { node: null, openTimer: null, hoverTime: 350, closeTimer: null }
-       );
-      ]]></field>
-
-      <method name="_clearOverFolder">
-        <body><![CDATA[
-          // The mouse is no longer dragging over the stored menubutton.
-          // Close the menubutton, clear out drag styles, and clear all
-          // timers for opening/closing it.
-          if (this._overFolder.node && this._overFolder.node.lastChild) {
-            if (!this._overFolder.node.lastChild.hasAttribute("dragover")) {
-              this._overFolder.node.lastChild.hidePopup();
-            }
-            this._overFolder.node.removeAttribute("dragover");
-            this._overFolder.node = null;
-          }
-          if (this._overFolder.openTimer) {
-            this._overFolder.openTimer.cancel();
-            this._overFolder.openTimer = null;
-          }
-          if (this._overFolder.closeTimer) {
-            this._overFolder.closeTimer.cancel();
-            this._overFolder.closeTimer = null;
-          }
-        ]]></body>
-      </method>
-
-      <method name="_getDropPoint">
-        <parameter name="aEvent"/>
-        <body><![CDATA[
-          // This function returns information about where to drop when
-          // dragging over the toolbar.
-          // The returned object has 3 properties:
-          // - ip: the insertion point for the bookmarks service.
-          // - beforeIndex: child index to drop before, for the drop indicator.
-          // - folderNode: the folder to drop into, if applicable.
-          var result = this.getResult();
-          if (!PlacesUtils.nodeIsFolder(this._resultNode))
-            return null;
-
-          var dropPoint = { ip: null, beforeIndex: null, folderNode: null };
-          var xulNode = aEvent.target;
-          if (xulNode.node) {
-            let nodeRect = xulNode.getBoundingClientRect();
-            let nodeIndex = Array.indexOf(this.childNodes, xulNode);
-            if (PlacesUtils.nodeIsFolder(xulNode.node) &&
-                !PlacesUtils.nodeIsReadOnly(xulNode.node)) {
-              // This is a folder.
-              // If we are in the middle of it, drop inside it.
-              // Otherwise, drop before it, with regards to RTL mode.
-              let threshold = nodeRect.width * 0.25;
-              if (this._isRTL ? (aEvent.clientX > nodeRect.right - threshold)
-                              : (aEvent.clientX < nodeRect.left + threshold)) {
-                // Drop before this folder.
-                dropPoint.ip =
-                  new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
-                                     nodeIndex, Ci.nsITreeView.DROP_BEFORE);
-                dropPoint.beforeIndex = nodeIndex;
-              }
-              else if (this._isRTL ? (aEvent.clientX > nodeRect.left + threshold)
-                                   : (aEvent.clientX < nodeRect.right - threshold)) {
-                // Drop inside this folder.
-                dropPoint.ip =
-                  new InsertionPoint(PlacesUtils.getConcreteItemId(xulNode.node),
-                                     -1, Ci.nsITreeView.DROP_ON,
-                                     PlacesUtils.nodeIsTagQuery(xulNode.node));
-                dropPoint.beforeIndex = nodeIndex;
-                dropPoint.folderNode = xulNode;
-              }
-              else {
-                // Drop after this folder.
-                let beforeIndex =
-                  (nodeIndex == this.childNodes.length - 1) ? -1 : nodeIndex + 1;
-                dropPoint.ip =
-                  new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
-                                     beforeIndex, Ci.nsITreeView.DROP_BEFORE);
-                dropPoint.beforeIndex = beforeIndex;
-              }
-            }
-            else {
-              // This is a non-folder node or a read-only folder.
-              // Drop before it with regards to RTL mode.
-              let threshold = nodeRect.width * 0.5;
-              if (this._isRTL ? (aEvent.clientX > nodeRect.left + threshold)
-                              : (aEvent.clientX < nodeRect.left + threshold)) {
-                // Drop before this bookmark.
-                dropPoint.ip =
-	                new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
-	                                   nodeIndex, Ci.nsITreeView.DROP_BEFORE);
-                dropPoint.beforeIndex = nodeIndex;
-              }
-              else {
-                // Drop after this bookmark.
-                let beforeIndex =
-                  nodeIndex == this.childNodes.length - 1 ? -1 : nodeIndex + 1;
-                dropPoint.ip =
-                  new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
-                                     beforeIndex, Ci.nsITreeView.DROP_BEFORE);
-                dropPoint.beforeIndex = beforeIndex;
-              }
-            }
-          }
-          else {
-            // We are most likely dragging on the empty area of the
-            // toolbar, we should drop after the last node.
-            dropPoint.ip =
-              new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
-                                 -1, Ci.nsITreeView.DROP_BEFORE);
-            dropPoint.beforeIndex = -1;
-          }
-
-          return dropPoint;
-        ]]></body>
-      </method>
-
-      <method name="_setTimer">
-        <parameter name="aTime"/>
-        <body><![CDATA[
-          var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-          timer.initWithCallback(this, aTime, timer.TYPE_ONE_SHOT);
-          return timer;
-        ]]></body>
-      </method>
-
-      <!-- nsITimerCallback -->
-      <method name="notify">
-        <parameter name="aTimer"/>
-        <body><![CDATA[
-          // Function to process all timer notifications.
-
-          if (aTimer == this._updateChevronTimer) {
-            this._updateChevronTimer = null;
-            this._updateChevronTimerCallback();
-          }
-
-          // * Timer to turn off indicator bar.
-          else if (aTimer == this._ibTimer) {
-            this._dropIndicator.collapsed = true;
-            this._ibTimer = null;
-          }
-
-          // * Timer to open a menubutton that's being dragged over.
-          else if (aTimer == this._overFolder.openTimer) {
-            // Set the autoopen attribute on the folder's menupopup so that
-            // the menu will automatically close when the mouse drags off of it.
-            this._overFolder.node.lastChild.setAttribute("autoopened", "true");
-            this._overFolder.node.open = true;
-            this._overFolder.openTimer = null;
-          }
-
-          // * Timer to close a menubutton that's been dragged off of.
-          else if (aTimer == this._overFolder.closeTimer) {
-            // Close the menubutton if we are not dragging over it or one of
-            // its children.  The autoopened attribute will let the menu know to
-            // close later if the menu is still being dragged over.
-            var currentNode = PlacesControllerDragHelper.currentDropTarget;
-            var inHierarchy = false;
-            while (currentNode) {
-              if (currentNode == this) {
-                inHierarchy = true;
-                break;
-              }
-              currentNode = currentNode.parentNode;
-            }
-            // The _clearOverFolder() function will close the menu for _overFolder.node.
-            // So null it out if we don't want to close it.
-            if (inHierarchy)
-              this._overFolder.node = null;
-
-            // Clear out the folder and all associated timers.
-            this._clearOverFolder();
-          }
-        ]]></body>
-      </method>
-
-      <method name="_cleanupDragDetails">
-        <body><![CDATA[
-          // Called on dragend and drop.
-          PlacesControllerDragHelper.currentDropTarget = null;
-          this._draggedNode = null;
-          if (this._ibTimer)
-            this._ibTimer.cancel();
-          this._dropIndicator.collapsed = true;
-        ]]></body>
-      </method>
-
-    </implementation>
-
-    <handlers>
-      <handler event="mouseover"><![CDATA[
-        var button = event.target;
-        if (button.parentNode == this && button.node &&
-            PlacesUtils.nodeIsURI(button.node))
-          window.XULBrowserWindow.setOverLink(event.target.node.uri, null);
-      ]]></handler>
-
-      <handler event="mouseout"><![CDATA[
-        window.XULBrowserWindow.setOverLink("", null);
-      ]]></handler>
-
-      <handler event="dragstart"><![CDATA[
-        // Sub menus have their own d&d handlers.
-        let draggedDOMNode = event.target;
-        if (draggedDOMNode.parentNode != this || !draggedDOMNode.node)
-          return;
-
-        if (draggedDOMNode.localName == "toolbarbutton" &&
-            draggedDOMNode.getAttribute("type") == "menu") {
-          // If the drag gesture on a container is toward down we open instead
-          // of dragging.
-          if (this._mouseDownTimer) {
-            this._mouseDownTimer.cancel();
-            this._mouseDownTimer = null;
-          }
-          let translateY = this._cachedMouseMoveEvent.clientY - event.clientY;
-          let translateX = this._cachedMouseMoveEvent.clientX - event.clientX;
-          if ((translateY) >= Math.abs(translateX/2)) {
-            // Don't start the drag.
-            event.preventDefault();
-            // Open the menu
-            draggedDOMNode.open = true;
-            return;
-          }
-          // If the menu is open, close it.
-          if (draggedDOMNode.open) {
-            draggedDOMNode.firstChild.hidePopup();
-            draggedDOMNode.open = false;
-          }
-        }
-
-        // Activate the view and cache the dragged node.
-        this._draggedNode = draggedDOMNode.node;
-        this.focus();
-
-        this._controller.setDataTransfer(event);
-        event.stopPropagation();
-      ]]></handler>
-
-      <handler event="dragover"><![CDATA[
-        PlacesControllerDragHelper.currentDropTarget = event.target;
-        let dt = event.dataTransfer;
-
-        let dropPoint = this._getDropPoint(event);
-        if (!dropPoint || !dropPoint.ip ||
-            !PlacesControllerDragHelper.canDrop(dropPoint.ip, dt)) {
-          this._dropIndicator.collapsed = true;
-          event.stopPropagation();
-          return;
-        }
-
-        if (this._ibTimer) {
-          this._ibTimer.cancel();
-          this._ibTimer = null;
-        }
-
-        if (dropPoint.folderNode || event.originalTarget == this._chevron) {
-          // Dropping over a menubutton or chevron button.
-          // Set styles and timer to open relative menupopup.
-          let overNode = dropPoint.folderNode || this._chevron;
-          if (this._overFolder.node != overNode) {
-            this._clearOverFolder();
-            this._overFolder.node = overNode;
-            this._overFolder.openTimer = this._setTimer(this._overFolder.hoverTime);
-          }
-          if (!this._overFolder.node.hasAttribute("dragover"))
-            this._overFolder.node.setAttribute("dragover", "true");
-
-          this._dropIndicator.collapsed = true;
-        }
-        else {
-          // Dragging over a normal toolbarbutton.
-          // Show indicator bar and move it to the appropriate drop point.
-          let ind = this._dropIndicator;
-          let halfInd = ind.clientWidth / 2;
-          let translateX;
-          if (this._isRTL) {
-            halfInd = Math.ceil(halfInd);
-            translateX = 0 - this._scrollbox.getBoundingClientRect().right -
-                             halfInd;
-            if (this.firstChild) {
-              if (dropPoint.beforeIndex == -1)
-                translateX += this.lastChild.getBoundingClientRect().left;
-              else {
-                translateX += this.childNodes[dropPoint.beforeIndex]
-                                .getBoundingClientRect().right;
-              }
-            }
-          }
-          else {
-            halfInd = Math.floor(halfInd);
-            translateX = 0 - this._scrollbox.getBoundingClientRect().left +
-                         halfInd;
-            if (this.firstChild) {
-              if (dropPoint.beforeIndex == -1)
-                translateX += this.lastChild.getBoundingClientRect().right;
-              else {
-                translateX += this.childNodes[dropPoint.beforeIndex]
-                                  .getBoundingClientRect().left;
-              }
-            }
-          }
-
-          ind.style.MozTransform = "translate(" + Math.round(translateX) + "px)";
-          ind.style.MozMarginStart = (-ind.clientWidth) + "px";
-          ind.collapsed = false;
-
-          // Clear out old folder information.
-          this._clearOverFolder();
-        }
-
-        event.preventDefault();
-        event.stopPropagation();
-      ]]></handler>
-
-      <handler event="drop"><![CDATA[
-        PlacesControllerDragHelper.currentDropTarget = event.target;
-
-        let dropPoint = this._getDropPoint(event);
-        if (dropPoint && dropPoint.ip) {
-          PlacesControllerDragHelper.onDrop(dropPoint.ip, event.dataTransfer);
-          event.preventDefault();
-        }
-
-        this._cleanupDragDetails();
-        event.stopPropagation();
-      ]]></handler>
-
-      <handler event="dragleave"><![CDATA[
-        PlacesControllerDragHelper.currentDropTarget = null;
-
-        // Set timer to turn off indicator bar (if we turn it off
-        // here, dragenter might be called immediately after, creating
-        // flicker).
-        if (this._ibTimer)
-          this._ibTimer.cancel();
-        this._ibTimer = this._setTimer(10);
-
-        // If we hovered over a folder, close it now.
-        if (this._overFolder.node)
-            this._overFolder.closeTimer = this._setTimer(this._overFolder.hoverTime);
-      ]]></handler>
-
-      <handler event="dragend"><![CDATA[
-        this._cleanupDragDetails();
-      ]]></handler>
-
-      <handler event="popupshowing" phase="capturing"><![CDATA[
-        if (!this._allowPopupShowing) {
-          this._allowPopupShowing = true;
-          event.preventDefault();
-          return;
-        }
-
-        var popup = event.originalTarget;
-
-        // Avoid handling popupshowing of inner views
-        if (popup._resultNode && PlacesUIUtils.getViewForNode(popup) == this)
-          this._containerPopupShowing(popup);
-
-        var parent = popup.parentNode;
-        if (parent.localName == "toolbarbutton")
-          this._openedMenuButton = parent;
-      ]]></handler>
-
-      <handler event="popuphidden"><![CDATA[
-        var popup = event.originalTarget;
-
-        // Avoid handling popuphidden of inner views
-        if (popup._resultNode && PlacesUIUtils.getViewForNode(popup) == this) {
-          // UI performance: folder queries are cheap, keep the resultnode open
-          // so we don't rebuild its contents whenever the popup is reopened.
-          if (!PlacesUtils.nodeIsFolder(popup._resultNode))
-            popup._resultNode.containerOpen = false;
-        }
-
-        var parent = popup.parentNode;
-        if (parent.localName == "toolbarbutton") {
-          this._openedMenuButton = null;
-          // Clear the dragover attribute if present, if we are dragging into a
-          // folder in the hierachy of current opened popup we don't clear
-          // this attribute on clearOverFolder.  See Notify for closeTimer.
-          if (parent.hasAttribute("dragover"))
-            parent.removeAttribute("dragover");
-        }
-      ]]></handler>
-
-#ifdef XP_UNIX
-#ifndef XP_MACOSX
-      <handler event="mousedown"><![CDATA[
-        var target = event.target;
-        if (event.button == 0 &&
-            target.localName == "toolbarbutton" &&
-            target.getAttribute("type") == "menu") {
-          this._allowPopupShowing = false;
-          // On Linux we can open the popup only after a delay.
-          // Indeed as soon as the menupopup opens we are unable to start a
-          // drag event.  See bug 500081 for details.
-          this._mouseDownTimer = Cc["@mozilla.org/timer;1"]
-                                   .createInstance(Ci.nsITimer);
-          var callback = {
-            _self: this,
-		        _target: target,
-		        notify: function(timer) {
-              this._target.open = true;
-              this._self._mouseDownTimer = null;
-            }
-          };
-
-          this._mouseDownTimer.initWithCallback(callback, 300,
-                                                Ci.nsITimer.TYPE_ONE_SHOT);
-        }
-      ]]></handler>
-#endif
-#endif
-      <handler event="mouseup"><![CDATA[
-        if (event.button != 0)
-          return;
-
-        if (this._mouseDownTimer) {
-          // On a click (down/up) we should open the menu popup
-          this._mouseDownTimer.cancel();
-          this._mouseDownTimer = null;
-          event.target.open = true;
-        }
-      ]]></handler>
-
-      <handler event="mousemove"><![CDATA[
-        // Used in dragStart to prevent dragging folders when dragging down
-        this._cachedMouseMoveEvent = event;
-
-        if (this._openedMenuButton == null ||
-            PlacesControllerDragHelper.getSession())
-          return;
-
-        var target = event.originalTarget;
-        if (this._openedMenuButton != target &&
-            target.localName == "toolbarbutton" &&
-            target.type == "menu") {
-          this._openedMenuButton.open = false;
-          target.open = true;
-        }
-      ]]></handler>
-    </handlers>
-  </binding>
-
-</bindings>
--- a/browser/components/places/content/tree.xml
+++ b/browser/components/places/content/tree.xml
@@ -31,79 +31,68 @@
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
-# ***** END LICENSE BLOCK ***** 
+# ***** END LICENSE BLOCK *****
 
 <bindings id="placesTreeBindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:xbl="http://www.mozilla.org/xbl"
           xmlns:html="http://www.w3.org/1999/xhtml"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  
+
   <binding id="places-tree" extends="chrome://global/content/bindings/tree.xml#tree">
     <implementation>
       <constructor><![CDATA[
         // Force an initial build.
         if (this.place)
           this.place = this.place;
       ]]></constructor>
 
       <destructor><![CDATA[
         // Break the treeviewer->result->treeviewer cycle.
         // Note: unsetting the result's viewer also unsets
         // the viewer's reference to our treeBoxObject.
-        var result = this.getResult();
+        var result = this.result;
         if (result) {
           result.root.containerOpen = false;
         }
         this.view = null;
       ]]></destructor>
 
       <property name="controller"
                 readonly="true"
-                onget="return this._controller;"/>
+                onget="return this._controller"/>
 
       <!-- overriding -->
       <property name="view">
         <getter><![CDATA[
           try {
             return this.treeBoxObject.view.QueryInterface(Ci.nsINavHistoryResultTreeViewer);
           }
           catch(e) {
             return null;
           }
         ]]></getter>
-        <setter><![CDATA[ 
+        <setter><![CDATA[
           return this.treeBoxObject.view = val;
         ]]></setter>
       </property>
 
-      <method name="getBestOptions">
-        <body><![CDATA[
-          // Get the best set of grouping options to use, either reuse the 
-          // existing ones or create new ones. 
-          var options = this.getResult().queryOptions;
-          if (!options)
-            options = PlacesUtils.history.getNewQueryOptions();
-          return options;
-        ]]></body>
-      </method>
-
       <method name="applyFilter">
         <parameter name="filterString"/>
         <parameter name="folderRestrict"/>
         <body><![CDATA[
           // preserve grouping
-          var queryNode = PlacesUtils.asQuery(this.getResultNode());
+          var queryNode = PlacesUtils.asQuery(this.result.root);
           var options = queryNode.queryOptions.clone();
 
           // Make sure we're getting uri results.
           // We do not yet support searching into grouped queries or into
           // tag containers, so we must fall to the default case.
           if (PlacesUtils.nodeIsHistoryContainer(queryNode) ||
               options.resultType == options.RESULTS_AS_TAG_QUERY ||
               options.resultType == options.RESULTS_AS_TAG_CONTENTS)
@@ -115,23 +104,23 @@
           if (folderRestrict) {
             query.setFolders(folderRestrict, folderRestrict.length);
             options.queryType = options.QUERY_TYPE_BOOKMARKS;
           }
 
           this.load([query], options);
         ]]></body>
       </method>
-      
+
       <method name="load">
         <parameter name="queries"/>
         <parameter name="options"/>
         <body><![CDATA[
           // Cleanup old result if exists.
-          let oldResult = this.getResult();
+          let oldResult = this.result;
           if (oldResult) {
             oldResult.removeObserver(this.view);
             oldResult.root.containerOpen = false;
           }
 
           let result = PlacesUtils.history
                                   .executeQueries(queries, queries.length,
                                                   options);
@@ -178,20 +167,20 @@
             // reload with the last place set
             if (this.place)
               this.place = this.place;
           }
           return val;
         ]]></setter>
       </property>
 
-      <!-- 
+      <!--
         Causes a particular node represented by the specified placeURI to be
         selected in the tree. All containers above the node in the hierarchy
-        will be opened, so that the node is visible. 
+        will be opened, so that the node is visible.
         -->
       <method name="selectPlaceURI">
         <parameter name="placeURI"/>
         <body><![CDATA[
           // Do nothing if a node matching the given uri is already selected
           if (this.hasSelection && this.selectedNode.uri == placeURI)
             return;
 
@@ -221,48 +210,48 @@
             }
 
             if (!wasOpen)
               container.containerOpen = false;
 
             return null;
           }
 
-          var container = this.getResultNode();
+          var container = this.result.root;
           NS_ASSERT(container, "No result, cannot select place URI!");
           if (!container)
             return;
 
           var child = findNode(container, placeURI, []);
           if (child)
             this.selectNode(child);
           else {
             // If the specified child could not be located, clear the selection
             var selection = this.view.selection;
             selection.clearSelection();
           }
         ]]></body>
       </method>
 
-      <!-- 
-        Causes a particular node to be selected in the tree, resulting in all 
+      <!--
+        Causes a particular node to be selected in the tree, resulting in all
         containers above the node in the hierarchy to be opened, so that the
-        node is visible. 
+        node is visible.
         -->
       <method name="selectNode">
         <parameter name="node"/>
-        <body><![CDATA[ 
+        <body><![CDATA[
           var view = this.view;
 
           var parent = node.parent;
           if (parent && !parent.containerOpen) {
-            // Build a list of all of the nodes that are the parent of this one 
-            // in the result. 
+            // Build a list of all of the nodes that are the parent of this one
+            // in the result.
             var parents = [];
-            var root = this.getResultNode();
+            var root = this.result.root;
             while (parent && parent != root) {
               parents.push(parent);
               parent = parent.parent;
             }
 
             // Walk the list backwards (opening from the root of the hierarchy)
             // opening each folder as we go.
             for (var i = parents.length - 1; i >= 0; --i) {
@@ -274,39 +263,32 @@
             // Select the specified node...
           }
 
           var index = view.treeIndexForNode(node);
           if (index == Ci.nsINavHistoryResultTreeViewer.INDEX_INVISIBLE)
             return;
 
           view.selection.select(index);
-          // ... and ensure it's visible, not scrolled off somewhere. 
+          // ... and ensure it's visible, not scrolled off somewhere.
           this.treeBoxObject.ensureRowIsVisible(index);
         ]]></body>
       </method>
 
       <!-- nsIPlacesView -->
-      <method name="getResult">
-        <body><![CDATA[
+      <property name="result">
+        <getter><![CDATA[
           try {
             return this.view.QueryInterface(Ci.nsINavHistoryResultObserver).result;
           }
           catch (e) {
             return null;
           }
-        ]]></body>
-      </method>
-
-      <!-- nsIPlacesView -->
-      <method name="getResultNode">
-        <body><![CDATA[
-          return this.getResult().root;
-        ]]></body>
-      </method>
+        ]]></getter>
+      </property>
 
       <!-- nsIPlacesView -->
       <property name="place">
         <getter><![CDATA[
           return this.getAttribute("place");
         ]]></getter>
         <setter><![CDATA[
           this.setAttribute("place", val);
@@ -327,63 +309,63 @@
       </property>
 
       <!-- nsIPlacesView -->
       <property name="hasSelection">
         <getter><![CDATA[
           return this.view && this.view.selection.count >= 1;
         ]]></getter>
       </property>
-      
+
       <!-- nsIPlacesView -->
-      <method name="getSelectionNodes">
-        <body><![CDATA[ 
+      <property name="selectedNodes">
+        <getter><![CDATA[
           let nodes = [];
           if (!this.hasSelection)
             return nodes;
 
           let selection = this.view.selection;
           let rc = selection.getRangeCount();
           let resultview = this.view;
           for (let i = 0; i < rc; ++i) {
             let min = { }, max = { };
             selection.getRangeAt(i, min, max);
 
             for (let j = min.value; j <= max.value; ++j)
               nodes.push(resultview.nodeForTreeIndex(j));
           }
           return nodes;
-        ]]></body>
-      </method>
+        ]]></getter>
+      </property>
 
       <!-- nsIPlacesView -->
-      <method name="getRemovableSelectionRanges">
-        <body><![CDATA[ 
-          // This function exists in addition to getSelectionNodes because it
+      <property name="removableSelectionRanges">
+        <getter><![CDATA[
+          // This property exists in addition to selectedNodes because it
           // encodes selection ranges (which only occur in list views) into
           // the return value. For each removed range, the index at which items
           // will be re-inserted upon the remove transaction being performed is
-          // the first index of the range, so that the view updates correctly. 
+          // the first index of the range, so that the view updates correctly.
           //
           // For example, if we remove rows 2,3,4 and 7,8 from a list, when we
           // undo that operation, if we insert what was at row 3 at row 3 again,
-          // it will show up _after_ the item that was at row 5. So we need to 
-          // insert all items at row 2, and the tree view will update correctly. 
+          // it will show up _after_ the item that was at row 5. So we need to
+          // insert all items at row 2, and the tree view will update correctly.
           //
           // Also, this function collapses the selection to remove redundant
           // data, e.g. when deleting this selection:
           //
           //      http://www.foo.com/
           //  (-) Some Folder
           //        http://www.bar.com/
           //
-          // ... returning http://www.bar.com/ as part of the selection is 
-          // redundant because it is implied by removing "Some Folder". We 
+          // ... returning http://www.bar.com/ as part of the selection is
+          // redundant because it is implied by removing "Some Folder". We
           // filter out all such redundancies since some partial amount of
-          // the folder's children may be selected.          
+          // the folder's children may be selected.
           //
           let nodes = [];
           if (!this.hasSelection)
             return nodes;
 
           var selection = this.view.selection;
           var rc = selection.getRangeCount();
           var resultview = this.view;
@@ -391,36 +373,33 @@
           // the for loop) since the row index of a container is unique for the
           // entire view, and we could have some really wacky selection and we
           // don't want to blow up.
           var containers = { };
           for (var i = 0; i < rc; ++i) {
             var range = [];
             var min = { }, max = { };
             selection.getRangeAt(i, min, max);
-            
+
             for (var j = min.value; j <= max.value; ++j) {
               if (this.view.isContainer(j))
                 containers[j] = true;
               if (!(this.view.getParentIndex(j) in containers))
                 range.push(resultview.nodeForTreeIndex(j));
             }
             nodes.push(range);
           }
           return nodes;
-        ]]></body>
-      </method>
-      
+        ]]></getter>
+      </property>
+
       <!-- nsIPlacesView -->
-      <method name="getDraggableSelection">
-        <body><![CDATA[
-          return this.getSelectionNodes();
-        ]]></body>
-      </method>
-      
+      <property name="draggableSelection"
+                onget="return this.selectedNodes"/>
+
       <!-- nsIPlacesView -->
       <property name="selectedNode">
         <getter><![CDATA[
           var view = this.view;
           if (!view || view.selection.count != 1)
             return null;
 
           var selection = view.selection;
@@ -435,50 +414,50 @@
       <property name="insertionPoint">
         <getter><![CDATA[
           // invalidated on selection and focus changes
           if (this._cachedInsertionPoint !== undefined)
             return this._cachedInsertionPoint;
 
           // there is no insertion point for history queries
           // so bail out now and save a lot of work when updating commands
-          var resultNode = this.getResultNode();
+          var resultNode = this.result.root;
           if (PlacesUtils.nodeIsQuery(resultNode) &&
               PlacesUtils.asQuery(resultNode).queryOptions.queryType ==
                 Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY)
               return this._cachedInsertionPoint = null;
 
           var orientation = Ci.nsITreeView.DROP_BEFORE;
-          // If there is no selection, insert at the end of the container. 
+          // If there is no selection, insert at the end of the container.
           if (!this.hasSelection) {
             var index = this.view.rowCount - 1;
             this._cachedInsertionPoint =
               this._getInsertionPoint(index, orientation);
             return this._cachedInsertionPoint;
           }
 
           // This is a two-part process. The first part is determining the drop
           // orientation.
           // * The default orientation is to drop _before_ the selected item.
           // * If the selected item is a container, the default orientation
           //   is to drop _into_ that container.
           //
           // Warning: It may be tempting to use tree indexes in this code, but
-          //          you must not, since the tree is nested and as your tree 
+          //          you must not, since the tree is nested and as your tree
           //          index may change when folders before you are opened and
           //          closed. You must convert your tree index to a node, and
           //          then use getChildIndex to find your absolute index in
-          //          the parent container instead. 
+          //          the parent container instead.
           //
           var resultView = this.view;
           var selection = resultView.selection;
           var rc = selection.getRangeCount();
           var min = { }, max = { };
           selection.getRangeAt(rc - 1, min, max);
-          
+
           // If the sole selection is a container, and we are not in
           // a flatlist, insert into it.
           // Note that this only applies to _single_ selections,
           // if the last element within a multi-selection is a
           // container, insert _adjacent_ to the selection.
           //
           // If the sole selection is the bookmarks toolbar folder, we insert
           // into it even if it is not opened
@@ -493,28 +472,28 @@
           return this._cachedInsertionPoint;
         ]]></getter>
       </property>
 
       <method name="_getInsertionPoint">
         <parameter name="index"/>
         <parameter name="orientation"/>
         <body><![CDATA[
-          var result = this.getResult();
+          var result = this.result;
           var resultview = this.view;
           var container = result.root;
           var dropNearItemId = -1;
           NS_ASSERT(container, "null container");
           // When there's no selection, assume the container is the container
           // the view is populated from (i.e. the result's itemId).
           if (index != -1) {
             var lastSelected = resultview.nodeForTreeIndex(index);
             if (resultview.isContainer(index) && orientation == Ci.nsITreeView.DROP_ON) {
               // If the last selected item is an open container, append _into_
-              // it, rather than insert adjacent to it. 
+              // it, rather than insert adjacent to it.
               container = lastSelected;
               index = -1;
             }
             else if (lastSelected.containerOpen &&
                      orientation == Ci.nsITreeView.DROP_AFTER &&
                      lastSelected.hasChildren) {
              // If the last selected item is an open container and the user is
              // trying to drag into it as a first item, really insert into it.
@@ -564,17 +543,17 @@
                                     index, orientation,
                                     PlacesUtils.nodeIsTagQuery(container),
                                     dropNearItemId);
         ]]></body>
       </method>
 
       <!-- nsIPlacesView -->
       <method name="selectAll">
-        <body><![CDATA[ 
+        <body><![CDATA[
           this.view.selection.selectAll();
         ]]></body>
       </method>
 
       <!-- This method will select the first node in the tree that matches
            each given item id. It will open any parent nodes that it needs
            to in order to show the selected items.
       -->
@@ -652,22 +631,22 @@
             // subtree, revert the node to its previous openness.
             if (foundOne)
               nodesToOpen.unshift(node);
             node.containerOpen = previousOpenness;
             return foundOne;
           }
 
           // Disable notifications while looking for nodes.
-          let result = this.getResult();
+          let result = this.result;
           let didSuppressNotifications = result.suppressNotifications;
           if (!didSuppressNotifications)
             result.suppressNotifications = true
           try {
-            findNodes(this.getResultNode());
+            findNodes(this.result.root);
           }
           finally {
             if (!didSuppressNotifications)
               result.suppressNotifications = false;
           }
 
           // For all the nodes we've found, highlight the corresponding
           // index in the tree.
@@ -722,17 +701,17 @@
           win = win.parent;
         }
       ]]></handler>
 
       <handler event="dragstart"><![CDATA[
         if (event.target.localName != "treechildren")
           return;
 
-        let nodes = this.getSelectionNodes();
+        let nodes = this.selectedNodes;
         for (let i = 0; i < nodes.length; i++) {
           let node = nodes[i];
 
           // Disallow dragging the root node of a tree.
           if (!node.parent) {
             event.preventDefault();
             event.stopPropagation();
             return;
@@ -754,17 +733,17 @@
         if (event.target.localName != "treechildren")
           return;
 
         let row = { }, col = { }, child = { };
         this.treeBoxObject.getCellAt(event.clientX, event.clientY,
                                      row, col, child);
         let node = row.value != -1 ?
                    this.view.nodeForTreeIndex(row.value) :
-                   this.getResultNode();
+                   this.result.root;
         // cache the dropTarget for the view
         PlacesControllerDragHelper.currentDropTarget = node;
 
         // We have to calculate the orientation since view.canDrop will use
         // it and we want to be consistent with the dropfeedback.
         let tbo = this.treeBoxObject;
         let rowHeight = tbo.rowHeight;
         let eventY = event.clientY - tbo.treeBody.boxObject.y -
--- a/browser/components/places/jar.mn
+++ b/browser/components/places/jar.mn
@@ -4,21 +4,21 @@ browser.jar:
 *   content/browser/places/bookmarkProperties2.xul       (content/bookmarkProperties.xul)
 *   content/browser/places/places.xul                    (content/places.xul) 
 *   content/browser/places/places.js                     (content/places.js)
     content/browser/places/places.css                    (content/places.css)
     content/browser/places/organizer.css                 (content/organizer.css)
 *   content/browser/places/bookmarkProperties.xul        (content/bookmarkProperties.xul)
 *   content/browser/places/bookmarkProperties.js         (content/bookmarkProperties.js)
 *   content/browser/places/placesOverlay.xul             (content/placesOverlay.xul)
-*   content/browser/places/toolbar.xml                   (content/toolbar.xml)
 *   content/browser/places/menu.xml                      (content/menu.xml)
 *   content/browser/places/tree.xml                      (content/tree.xml)
 *   content/browser/places/controller.js                 (content/controller.js)
 *   content/browser/places/treeView.js                   (content/treeView.js)
+*   content/browser/places/browserPlacesViews.js         (content/browserPlacesViews.js)
 # keep the Places version of the history sidebar at history/history-panel.xul 
 # to prevent having to worry about between versions of the browser
 *   content/browser/history/history-panel.xul            (content/history-panel.xul) 
 *   content/browser/places/history-panel.js              (content/history-panel.js)
 # ditto for the bookmarks sidebar
 *   content/browser/bookmarks/bookmarksPanel.xul         (content/bookmarksPanel.xul)
 *   content/browser/bookmarks/bookmarksPanel.js          (content/bookmarksPanel.js)
 *   content/browser/bookmarks/sidebarUtils.js            (content/sidebarUtils.js)
--- a/browser/components/places/src/PlacesUIUtils.jsm
+++ b/browser/components/places/src/PlacesUIUtils.jsm
@@ -669,27 +669,29 @@ var PlacesUIUtils = {
 
   /**
    * Returns the closet ancestor places view for the given DOM node
    * @param aNode
    *        a DOM node
    * @return the closet ancestor places view if exists, null otherwsie.
    */
   getViewForNode: function PUIU_getViewForNode(aNode) {
-    var node = aNode;
+    let node = aNode;
 
-    // the view for a <menu> of which its associated menupopup is a places view,
-    // is the menupopup
-    if (node.localName == "menu" && !node.node &&
-        node.firstChild.getAttribute("type") == "places")
-      return node.firstChild;
+    // The view for a <menu> of which its associated menupopup is a places
+    // view, is the menupopup.
+    if (node.localName == "menu" && !node._placesNode &&
+        node.firstChild._placesView)
+      return node.firstChild._placesView;
 
-    while (node) {
-      // XXXmano: Use QueryInterface(nsIPlacesView) once we implement it...
-      if (node.getAttribute("type") == "places")
+    // XXXmano: somehow we reach the xul document here!
+    while (node instanceof Ci.nsIDOMElement) {
+      if (node._placesView)
+        return node._placesView;
+      if (node.localName == "tree" && node.getAttribute("type") == "places")
         return node;
 
       node = node.parentNode;
     }
 
     return null;
   },
 
@@ -935,134 +937,16 @@ var PlacesUIUtils = {
    * @return guessed scheme for this url string.
    *
    * @note this is not supposed be perfect, so use it only for UI purposes.
    */
   guessUrlSchemeForUI: function PUU_guessUrlSchemeForUI(aUrlString) {
     return aUrlString.substr(0, aUrlString.indexOf(":"));
   },
 
-  /**
-   * Creates a menu item ready to be added to a popup.
-   * Helper for the toolbar and menu views.
-   * @param aNode
-   *        Places node used as source for DOM node.
-   * @param aDocument
-   *        The node will be created in this document.
-   * @return a DOM menuitem node.
-   */
-  createMenuItemForNode:
-  function PUU_createMenuItemForNode(aNode, aDocument) {
-    var element;
-    // For add-ons backwards compatibility, if the caller does not provide
-    // a document, we guess one.
-    var document = aDocument || this._getTopBrowserWin().document;
-    var type = aNode.type;
-    if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) {
-      element = document.createElement("menuseparator");
-    }
-    else {
-      if (PlacesUtils.uriTypes.indexOf(type) != -1) {
-        element = document.createElement("menuitem");
-        element.className = "menuitem-iconic bookmark-item menuitem-with-favicon";
-        element.setAttribute("scheme", this.guessUrlSchemeForUI(aNode.uri));
-      }
-      else if (PlacesUtils.containerTypes.indexOf(type) != -1) {
-        element = document.createElement("menu");
-        element.setAttribute("container", "true");
-
-        if (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY) {
-          element.setAttribute("query", "true");
-          if (PlacesUtils.nodeIsTagQuery(aNode))
-            element.setAttribute("tagContainer", "true");
-          else if (PlacesUtils.nodeIsDay(aNode))
-            element.setAttribute("dayContainer", "true");
-          else if (PlacesUtils.nodeIsHost(aNode))
-            element.setAttribute("hostContainer", "true");
-        }
-        else if (aNode.itemId != -1) {
-          if (PlacesUtils.nodeIsLivemarkContainer(aNode))
-            element.setAttribute("livemark", "true");
-        }
-
-        var popup = document.createElement("menupopup");
-        popup.setAttribute("placespopup", "true");
-        popup._resultNode = PlacesUtils.asContainer(aNode);
-#ifdef XP_MACOSX
-        // Binding on Mac native menus is lazy attached, so onPopupShowing,
-        // in the capturing phase, fields are not yet initialized.
-        // In that phase we have to ensure markers are not undefined to build
-        // the popup correctly.
-        popup._startMarker = -1;
-        popup._endMarker = -1;
-#else
-        // no context menu on mac
-        popup.setAttribute("context", "placesContext");
-#endif
-        element.appendChild(popup);
-        element.className = "menu-iconic bookmark-item";
-      }
-      else
-        throw "Unexpected node";
-
-      element.setAttribute("label", this.getBestTitle(aNode));
-
-      var icon = aNode.icon;
-      if (icon)
-        element.setAttribute("image", icon);
-    }
-    element.node = aNode;
-    element.node._DOMElement = element;
-
-    return element;
-  },
-
-  cleanPlacesPopup: function PUIU_cleanPlacesPopup(aPopup) {
-    // Remove places popup children and update markers to keep track of
-    // their indices.
-    var start = aPopup._startMarker != -1 ? aPopup._startMarker + 1 : 0;
-    var end = aPopup._endMarker != -1 ? aPopup._endMarker :
-                                        aPopup.childNodes.length;
-    var items = [];
-    var placesNodeFound = false;
-    for (var i = start; i < end; ++i) {
-      var item = aPopup.childNodes[i];
-      if (item.getAttribute("builder") == "end") {
-        // we need to do this for menus that have static content at the end but
-        // are initially empty, eg. the history menu, we need to know where to
-        // start inserting new items.
-        aPopup._endMarker = i;
-        break;
-      }
-      if (item.node) {
-        items.push(item);
-        placesNodeFound = true;
-      }
-      else {
-        // This is static content...
-        if (!placesNodeFound) {
-          // ...at the start of the popup
-          // Initialized in menu.xml, in the base binding
-          aPopup._startMarker++;
-        }
-        else {
-          // ...after places nodes
-          aPopup._endMarker = i;
-          break;
-        }
-      }
-    }
-
-    for (var i = 0; i < items.length; ++i) {
-      aPopup.removeChild(items[i]);
-      if (aPopup._endMarker != -1)
-        aPopup._endMarker--;
-    }
-  },
-
   getBestTitle: function PUIU_getBestTitle(aNode) {
     var title;
     if (!aNode.title && PlacesUtils.uriTypes.indexOf(aNode.type) != -1) {
       // if node title is empty, try to set the label using host and filename
       // PlacesUtils._uri() will throw if aNode.uri is not a valid URI
       try {
         var uri = PlacesUtils._uri(aNode.uri);
         var host = uri.host;
--- a/browser/components/places/tests/browser/browser_drag_bookmarks_on_toolbar.js
+++ b/browser/components/places/tests/browser/browser_drag_bookmarks_on_toolbar.js
@@ -33,17 +33,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 const TEST_URL = "http://www.mozilla.org";
 const TEST_TITLE = "example_title";
 
-var gBookmarksToolbar = window.document.getElementById("bookmarksBarContent");
+var gBookmarksToolbar = window.document.getElementById("PlacesToolbar");
 var dragDirections = { LEFT: 0, UP: 1, RIGHT: 2, DOWN: 3 };
 
 /**
  * Tests dragging on toolbar.
  *
  * We must test these 2 cases:
  *   - Dragging toward left, top, right should start a drag.
  *   - Dragging toward down should should open the container if the item is a
@@ -140,20 +140,20 @@ function synthesizeDragWithDirection(aEl
   aElement.removeEventListener("click", prevent, false);
 
   // Cleanup eventually opened menus.
   if (aElement.localName == "menu" && aElement.open)
     aElement.open = false;
 }
 
 function getToolbarNodeForItemId(aItemId) {
-  var children = gBookmarksToolbar.childNodes;
+  var children = document.getElementById("PlacesToolbarItems").childNodes;
   var node = null;
   for (var i = 0; i < children.length; i++) {
-    if (aItemId == children[i].node.itemId) {
+    if (aItemId == children[i]._placesNode.itemId) {
       node = children[i];
       break;
     }
   }
   return node;
 }
 
 function getExpectedDataForPlacesNode(aNode) {
@@ -182,18 +182,18 @@ var gTests = [
       // Create a test folder to be dragged.
       var folderId = PlacesUtils.bookmarks
                                 .createFolder(PlacesUtils.toolbarFolderId,
                                               TEST_TITLE,
                                               PlacesUtils.bookmarks.DEFAULT_INDEX);
       var element = getToolbarNodeForItemId(folderId);
       isnot(element, null, "Found node on toolbar");
 
-      isnot(element.node, null, "Toolbar node has an associated Places node.");
-      var expectedData = getExpectedDataForPlacesNode(element.node);
+      isnot(element._placesNode, null, "Toolbar node has an associated Places node.");
+      var expectedData = getExpectedDataForPlacesNode(element._placesNode);
 
       ok(true, "Dragging left");
       synthesizeDragWithDirection(element, expectedData, dragDirections.LEFT);
       ok(true, "Dragging right");
       synthesizeDragWithDirection(element, expectedData, dragDirections.RIGHT);
       ok(true, "Dragging up");
       synthesizeDragWithDirection(element, expectedData, dragDirections.UP);
       ok(true, "Dragging down");
@@ -213,18 +213,18 @@ var gTests = [
       var itemId = PlacesUtils.bookmarks
                               .insertBookmark(PlacesUtils.toolbarFolderId,
                                               PlacesUtils._uri(TEST_URL),
                                               PlacesUtils.bookmarks.DEFAULT_INDEX,
                                               TEST_TITLE);
       var element = getToolbarNodeForItemId(itemId);
       isnot(element, null, "Found node on toolbar");
 
-      isnot(element.node, null, "Toolbar node has an associated Places node.");
-      var expectedData = getExpectedDataForPlacesNode(element.node);
+      isnot(element._placesNode, null, "Toolbar node has an associated Places node.");
+      var expectedData = getExpectedDataForPlacesNode(element._placesNode);
 
       ok(true, "Dragging left");
       synthesizeDragWithDirection(element, expectedData, dragDirections.LEFT);
       ok(true, "Dragging right");
       synthesizeDragWithDirection(element, expectedData, dragDirections.RIGHT);
       ok(true, "Dragging up");
       synthesizeDragWithDirection(element, expectedData, dragDirections.UP);
       ok(true, "Dragging down");
--- a/browser/components/places/tests/browser/browser_library_search.js
+++ b/browser/components/places/tests/browser/browser_library_search.js
@@ -197,30 +197,30 @@ function search(aFolderId, aSearchStr, a
   if (aFolderId) {
     folderTree.selectItems([aFolderId]);
     isnot(folderTree.selectedNode, null,
        "Sanity check: left pane tree should have selection after selecting!");
 
     // getFolders() on a History query returns an empty array, so no use
     // comparing against aFolderId in that case.
     if (aFolderId !== PlacesUIUtils.leftPaneQueries["History"]) {
-      // contentTree.place should be equal to contentTree.getResult().root.uri,
+      // contentTree.place should be equal to contentTree.result.root.uri,
       // but it's not until bug 476952 is fixed.
-      var query = queryStringToQuery(contentTree.getResult().root.uri);
+      var query = queryStringToQuery(contentTree.result.root.uri);
       is(query.getFolders()[0], aFolderId,
          "Content tree's folder should be what was selected in the left pane");
     }
   }
 
   // Second, ensure that searching updates the content tree and search UI
   // properly.
   var searchBox = doc.getElementById("searchFilter");
   searchBox.value = aSearchStr;
   libraryWin.PlacesSearchBox.search(searchBox.value);
-  query = queryStringToQuery(contentTree.getResult().root.uri);
+  query = queryStringToQuery(contentTree.result.root.uri);
   if (aSearchStr) {
     is(query.searchTerms, aSearchStr,
        "Content tree's searchTerms should be text in search box");
     is(doc.getElementById("searchModifiers").hidden, false,
        "Scope bar should not be hidden after searching");
     if (getSelectedScopeButtonId() == "scopeBarHistory" ||
         getSelectedScopeButtonId() == "scopeBarAll" ||
         aFolderId == PlacesUtils.bookmarks.unfiledBookmarksFolder) {
--- a/browser/components/places/tests/browser/browser_sort_in_library.js
+++ b/browser/components/places/tests/browser/browser_sort_in_library.js
@@ -42,17 +42,17 @@
  * Bug 443745 - View>Sort>of "alpha" sort items is default to Z>A instead of A>Z
  * https://bugzilla.mozilla.org/show_bug.cgi?id=443745
  *
  * Bug 444179 - Library>Views>Sort>Sort by Tags does nothing
  * https://bugzilla.mozilla.org/show_bug.cgi?id=444179
  *
  * Basically, fully tests sorting the placeContent tree in the Places Library
  * window.  Sorting is verified by comparing the nsINavHistoryResult returned by
- * placeContent.getResult to the expected sort values.
+ * placeContent.result to the expected sort values.
  */
 
 // Two properties of nsINavHistoryResult control the sort of the tree:
 // sortingMode and sortingAnnotation.  sortingMode's value is one of the
 // nsINavHistoryQueryOptions.SORT_BY_* constants.  sortingAnnotation is the
 // annotation used to sort for SORT_BY_ANNOTATION_* mode.
 //
 // This lookup table maps the possible values of anonid's of the treecols to
@@ -98,19 +98,19 @@ let prevSortKey = null;
  *        one of the Ci.nsINavHistoryQueryOptions.SORT_BY_* constants
  * @param aSortingAnno
  *        checked only if sorting mode is one of the
  *        Ci.nsINavHistoryQueryOptions.SORT_BY_ANNOTATION_* constants
  */
 function checkSort(aTree, aSortingMode, aSortingAnno) {
   // The placeContent tree's sort is determined by the nsINavHistoryResult it
   // stores.  Get it and check that the sort is what the caller expects.
-  let res = aTree.getResult();
+  let res = aTree.result;
   isnot(res, null,
-        "sanity check: placeContent.getResult() should not return null");
+        "sanity check: placeContent.result should not return null");
 
   // Check sortingMode.
   is(res.sortingMode, aSortingMode,
      "column should now have sortingMode " + aSortingMode);
 
   // Check sortingAnnotation, but only if sortingMode is ANNOTATION.
   if ([Ci.nsINavHistoryQueryOptions.SORT_BY_ANNOTATION_ASCENDING,
        Ci.nsINavHistoryQueryOptions.SORT_BY_ANNOTATION_DESCENDING].
--- a/browser/components/places/tests/browser/browser_views_liveupdate.js
+++ b/browser/components/places/tests/browser/browser_views_liveupdate.js
@@ -292,35 +292,35 @@ function searchItemInView(aItemId, aView
 /**
  * Get places node and index for an itemId in bookmarks toolbar view.
  *
  * @param aItemId
  *        item id of the item to search.
  * @returns [node, index] or [null, null] if not found.
  */
 function getNodeForToolbarItem(aItemId) {
-  var toolbar = document.getElementById("bookmarksBarContent");
+  var toolbar = document.getElementById("PlacesToolbarItems");
 
   function findNode(aContainer) {
     var children = aContainer.childNodes;
     for (var i = 0, staticNodes = 0; i < children.length; i++) {
       var child = children[i];
 
       // Is this a Places node?
-      if (!child.node) {
+      if (!child._placesNode) {
         staticNodes++;
         continue;
       }
 
-      if (child.node.itemId == aItemId)
-        return [child.node, i - staticNodes];
+      if (child._placesNode.itemId == aItemId)
+        return [child._placesNode, i - staticNodes];
 
       // Don't search in queries, they could contain our item in a
       // different position.  Search only folders
-      if (PlacesUtils.nodeIsFolder(child.node)) {
+      if (PlacesUtils.nodeIsFolder(child._placesNode)) {
         var popup = child.lastChild;
         popup.showPopup(popup);
         var foundNode = findNode(popup);
         popup.hidePopup();
         if (foundNode[0] != null)
           return foundNode;
       }
     }
@@ -341,27 +341,27 @@ function getNodeForMenuItem(aItemId) {
   var menu = document.getElementById("bookmarksMenu");
 
   function findNode(aContainer) {
     var children = aContainer.childNodes;
     for (var i = 0, staticNodes = 0; i < children.length; i++) {
       var child = children[i];
 
       // Is this a Places node?
-      if (!child.node) {
+      if (!child._placesNode) {
         staticNodes++;
         continue;
       }
 
-      if (child.node.itemId == aItemId)
-        return [child.node, i - staticNodes];
+      if (child._placesNode.itemId == aItemId)
+        return [child._placesNode, i - staticNodes];
 
       // Don't search in queries, they could contain our item in a
       // different position.  Search only folders
-      if (PlacesUtils.nodeIsFolder(child.node)) {
+      if (PlacesUtils.nodeIsFolder(child._placesNode)) {
         var popup = child.lastChild;
         fakeOpenPopup(popup);
         var foundNode = findNode(popup);
 
         child.open = false;
         if (foundNode[0] != null)
           return foundNode;
       }
--- a/browser/components/places/tests/chrome/test_0_bug510634.xul
+++ b/browser/components/places/tests/chrome/test_0_bug510634.xul
@@ -120,17 +120,17 @@
            tree.view.getCellProperties(aRow, titleColumn, rowProperties);
            rowProperties = convertPropertiesToJSArray(rowProperties);
            ok(rowProperties.indexOf("OrganizerQuery_" + aQueryName) != -1,
              "OrganizerQuery_" + aQueryName + " is set");
          }
        );
 
       // Close the root node
-      tree.getResult().root.containerOpen = false;
+      tree.result.root.containerOpen = false;
 
       // Restore the getter for the next test.
       PlacesUIUtils.__defineGetter__("leftPaneFolderId", cachedLeftPaneFolderIdGetter);
 
       SimpleTest.finish();
     }
 
   ]]>
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -153,17 +153,17 @@ menuitem.bookmark-item {
 .menupopup-drop-indicator {
   list-style-image: none;
   height: 2px;
   -moz-margin-end: -4em;
   background-color: Highlight;
 }
 
 /* Bookmarks toolbar */
-.toolbar-drop-indicator {
+#PlacesToolbarDropIndicator {
   list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png);
 }
 
 /* Bookmark items */
 .bookmark-item:not([container])  {
   list-style-image: url("chrome://global/skin/icons/folder-item.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px)
 }
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -1784,17 +1784,17 @@ toolbarbutton.chevron > .toolbarbutton-m
   border: none;
 }
 
 .tabs-closebutton:hover:active {
   list-style-image: url("chrome://global/skin/icons/closetab-active.png");
 }
 
 /* Bookmarks toolbar */
-.toolbar-drop-indicator {
+#PlacesToolbarDropIndicator {
   list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png);
 }
 
 /* Bookmark drag and drop styles */
 
 .bookmark-item[dragover-into="true"] {
   background: Highlight !important;
   color: HighlightText !important;
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -1333,17 +1333,17 @@ toolbar[mode="text"] toolbarbutton.chevr
   visibility: collapse;
 }
 
 #checkForUpdates[loading="true"] {
   list-style-image: url("chrome://global/skin/icons/loading_16.png");
 }
 
 /* Bookmarks toolbar */
-.toolbar-drop-indicator {
+#PlacesToolbarDropIndicator {
   list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png);
 }
 
 toolbarbutton.bookmark-item[dragover="true"][open="true"] {
   -moz-appearance: none;
   background: Highlight !important;
   color: HighlightText !important;
 }