Merge mozilla-central to b2g-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 28 Apr 2015 14:05:17 +0200
changeset 241392 06aac68a8319
parent 241277 8f365dfd4fbc (current diff)
parent 241391 e0299ad29b85 (diff)
child 241393 777455c5208d
push id15318
push usercbook@mozilla.com
push date2015-04-28 12:05 +0000
treeherderb2g-inbound@06aac68a8319 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone40.0a1
Merge mozilla-central to b2g-inbound
browser/devtools/debugger/debugger-panes.js
browser/devtools/debugger/debugger-toolbar.js
browser/devtools/webide/themes/project-listing.css
toolkit/components/telemetry/TelemetryPing.jsm
toolkit/components/telemetry/tests/unit/test_TelemetryPing.js
toolkit/components/telemetry/tests/unit/test_TelemetryPingBuildID.js
toolkit/components/telemetry/tests/unit/test_TelemetryPingShutdown.js
toolkit/components/telemetry/tests/unit/test_TelemetryPing_idle.js
new file mode 100644
--- /dev/null
+++ b/.ycm_extra_conf.py
@@ -0,0 +1,27 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import imp
+import os
+from StringIO import StringIO
+import shlex
+
+path = os.path.join(os.path.dirname(__file__), 'mach')
+
+if not os.path.exists(path):
+    path = os.path.join(os.path.dirname(__file__), 'config.status')
+    config = imp.load_module('_buildconfig', open(path), path, ('', 'r', imp.PY_SOURCE))
+    path = os.path.join(config.topsrcdir, 'mach')
+mach_module = imp.load_module('_mach', open(path), path, ('', 'r', imp.PY_SOURCE))
+
+def FlagsForFile(filename):
+    mach = mach_module.get_mach()
+    out = StringIO()
+    out.encoding = None
+    mach.run(['compileflags', filename], stdout=out, stderr=out)
+
+    return {
+        'flags': shlex.split(out.getvalue()),
+        'do_cache': True
+    }
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,12 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1038068: Check add-on signatures and refuse to install unsigned or broken add-ons
-
-Not sure why this needs a clobber but tests perma-failed when they don't on
-try (2).
+Bug 1154356: escape variable name in Declaration::AppendVariableAndValueToString;
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -118,30 +118,26 @@ static const GInterfaceInfo atk_if_infos
     {(GInterfaceInitFunc)textInterfaceInitCB,
      (GInterfaceFinalizeFunc) nullptr, nullptr},
     {(GInterfaceInitFunc)documentInterfaceInitCB,
      (GInterfaceFinalizeFunc) nullptr, nullptr},
     {(GInterfaceInitFunc)imageInterfaceInitCB,
      (GInterfaceFinalizeFunc) nullptr, nullptr}
 };
 
-// This is or'd with the pointer in MaiAtkObject::accWrap if the wrap-ee is a
-// proxy.
-static const uintptr_t IS_PROXY = 1;
-
 static GQuark quark_mai_hyperlink = 0;
 
 AtkHyperlink*
 MaiAtkObject::GetAtkHyperlink()
 {
   NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized");
   MaiHyperlink* maiHyperlink =
     (MaiHyperlink*)g_object_get_qdata(G_OBJECT(this), quark_mai_hyperlink);
   if (!maiHyperlink) {
-    maiHyperlink = new MaiHyperlink(reinterpret_cast<Accessible*>(accWrap));
+    maiHyperlink = new MaiHyperlink(accWrap);
     g_object_set_qdata(G_OBJECT(this), quark_mai_hyperlink, maiHyperlink);
   }
 
   return maiHyperlink->GetAtkHyperlink();
 }
 
 void
 MaiAtkObject::Shutdown()
--- a/accessible/atk/nsMai.h
+++ b/accessible/atk/nsMai.h
@@ -46,16 +46,20 @@ extern int atkMajorVersion, atkMinorVers
  */
 static inline bool
 IsAtkVersionAtLeast(int aMajor, int aMinor)
 {
   return aMajor < atkMajorVersion ||
          (aMajor == atkMajorVersion && aMinor <= atkMinorVersion);
 }
 
+// This is or'd with the pointer in MaiAtkObject::accWrap if the wrap-ee is a
+// proxy.
+static const uintptr_t IS_PROXY = 1;
+
 /**
  * This MaiAtkObject is a thin wrapper, in the MAI namespace, for AtkObject
  */
 struct MaiAtkObject
 {
   AtkObject parent;
   /*
    * The AccessibleWrap whose properties and features are exported
--- a/accessible/atk/nsMaiHyperlink.cpp
+++ b/accessible/atk/nsMaiHyperlink.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIURI.h"
 #include "nsMaiHyperlink.h"
+#include "mozilla/a11y/ProxyAccessible.h"
 
 using namespace mozilla::a11y;
 
 /* MaiAtkHyperlink */
 
 #define MAI_TYPE_ATK_HYPERLINK      (mai_atk_hyperlink_get_type ())
 #define MAI_ATK_HYPERLINK(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
                                      MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlink))
@@ -56,18 +57,27 @@ static gchar *getUriCB(AtkHyperlink *aLi
 static AtkObject *getObjectCB(AtkHyperlink *aLink, gint aLinkIndex);
 static gint getEndIndexCB(AtkHyperlink *aLink);
 static gint getStartIndexCB(AtkHyperlink *aLink);
 static gboolean isValidCB(AtkHyperlink *aLink);
 static gint getAnchorCountCB(AtkHyperlink *aLink);
 G_END_DECLS
 
 static gpointer parent_class = nullptr;
-static Accessible*
-get_accessible_hyperlink(AtkHyperlink *aHyperlink);
+
+static MaiHyperlink*
+GetMaiHyperlink(AtkHyperlink *aHyperlink)
+{
+    NS_ENSURE_TRUE(MAI_IS_ATK_HYPERLINK(aHyperlink), nullptr);
+    MaiHyperlink * maiHyperlink =
+        MAI_ATK_HYPERLINK(aHyperlink)->maiHyperlink;
+    NS_ENSURE_TRUE(maiHyperlink != nullptr, nullptr);
+    NS_ENSURE_TRUE(maiHyperlink->GetAtkHyperlink() == aHyperlink, nullptr);
+    return maiHyperlink;
+}
 
 GType
 mai_atk_hyperlink_get_type(void)
 {
     static GType type = 0;
 
     if (!type) {
         static const GTypeInfo tinfo = {
@@ -85,23 +95,20 @@ mai_atk_hyperlink_get_type(void)
 
         type = g_type_register_static(ATK_TYPE_HYPERLINK,
                                       "MaiAtkHyperlink",
                                       &tinfo, GTypeFlags(0));
     }
     return type;
 }
 
-MaiHyperlink::MaiHyperlink(Accessible* aHyperLink) :
+MaiHyperlink::MaiHyperlink(uintptr_t aHyperLink) :
     mHyperlink(aHyperLink),
     mMaiAtkHyperlink(nullptr)
 {
-  if (!mHyperlink->IsLink())
-    return;
-
     mMaiAtkHyperlink =
         reinterpret_cast<AtkHyperlink *>
                         (g_object_new(mai_atk_hyperlink_get_type(), nullptr));
     NS_ASSERTION(mMaiAtkHyperlink, "OUT OF MEMORY");
     if (!mMaiAtkHyperlink)
       return;
 
     MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = this;
@@ -148,84 +155,107 @@ finalizeCB(GObject *aObj)
     /* call parent finalize function */
     if (G_OBJECT_CLASS (parent_class)->finalize)
         G_OBJECT_CLASS (parent_class)->finalize(aObj);
 }
 
 gchar *
 getUriCB(AtkHyperlink *aLink, gint aLinkIndex)
 {
-    Accessible* hyperlink = get_accessible_hyperlink(aLink);
-    NS_ENSURE_TRUE(hyperlink, nullptr);
+  MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
+  if (!maiLink)
+    return nullptr;
 
+  nsAutoCString cautoStr;
+  if (Accessible* hyperlink = maiLink->GetAccHyperlink()) {
     nsCOMPtr<nsIURI> uri = hyperlink->AnchorURIAt(aLinkIndex);
     if (!uri)
-        return nullptr;
+      return nullptr;
 
-    nsAutoCString cautoStr;
     nsresult rv = uri->GetSpec(cautoStr);
     NS_ENSURE_SUCCESS(rv, nullptr);
 
     return g_strdup(cautoStr.get());
+  }
+
+  bool valid;
+  maiLink->Proxy()->AnchorURIAt(aLinkIndex, cautoStr, &valid);
+  if (!valid)
+    return nullptr;
+
+  return g_strdup(cautoStr.get());
 }
 
 AtkObject *
 getObjectCB(AtkHyperlink *aLink, gint aLinkIndex)
 {
-    Accessible* hyperlink = get_accessible_hyperlink(aLink);
-    NS_ENSURE_TRUE(hyperlink, nullptr);
+  MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
+  if (!maiLink)
+    return nullptr;
 
-    Accessible* anchor = hyperlink->AnchorAt(aLinkIndex);
-    NS_ENSURE_TRUE(anchor, nullptr);
+    if (Accessible* hyperlink = maiLink->GetAccHyperlink()) {
+      Accessible* anchor = hyperlink->AnchorAt(aLinkIndex);
+      NS_ENSURE_TRUE(anchor, nullptr);
 
-    AtkObject* atkObj = AccessibleWrap::GetAtkObject(anchor);
-    //no need to add ref it, because it is "get" not "ref"
-    return atkObj;
+      return AccessibleWrap::GetAtkObject(anchor);
+    }
+
+    ProxyAccessible* anchor = maiLink->Proxy()->AnchorAt(aLinkIndex);
+    return anchor ? GetWrapperFor(anchor) : nullptr;
 }
 
 gint
 getEndIndexCB(AtkHyperlink *aLink)
 {
-    Accessible* hyperlink = get_accessible_hyperlink(aLink);
-    NS_ENSURE_TRUE(hyperlink, -1);
+  MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
+  if (!maiLink)
+    return false;
 
+  if (Accessible* hyperlink = maiLink->GetAccHyperlink())
     return static_cast<gint>(hyperlink->EndOffset());
+
+  bool valid = false;
+  uint32_t endIdx = maiLink->Proxy()->EndOffset(&valid);
+  return valid ? static_cast<gint>(endIdx) : -1;
 }
 
 gint
 getStartIndexCB(AtkHyperlink *aLink)
 {
-    Accessible* hyperlink = get_accessible_hyperlink(aLink);
-    NS_ENSURE_TRUE(hyperlink, -1);
+  MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
+  if (maiLink)
+    return -1;
 
+  if (Accessible* hyperlink = maiLink->GetAccHyperlink())
     return static_cast<gint>(hyperlink->StartOffset());
+
+  bool valid = false;
+  uint32_t startIdx = maiLink->Proxy()->StartOffset(&valid);
+  return valid ? static_cast<gint>(startIdx) : -1;
 }
 
 gboolean
 isValidCB(AtkHyperlink *aLink)
 {
-    Accessible* hyperlink = get_accessible_hyperlink(aLink);
-    NS_ENSURE_TRUE(hyperlink, FALSE);
+  MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
+  if (!maiLink)
+    return false;
 
+  if (Accessible* hyperlink = maiLink->GetAccHyperlink())
     return static_cast<gboolean>(hyperlink->IsLinkValid());
+
+  return static_cast<gboolean>(maiLink->Proxy()->IsLinkValid());
 }
 
 gint
 getAnchorCountCB(AtkHyperlink *aLink)
 {
-    Accessible* hyperlink = get_accessible_hyperlink(aLink);
-    NS_ENSURE_TRUE(hyperlink, -1);
-
-    return static_cast<gint>(hyperlink->AnchorCount());
-}
+  MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
+  if (!maiLink)
+    return -1;
 
-// Check if aHyperlink is a valid MaiHyperlink, and return the
-// HyperLinkAccessible related.
-Accessible*
-get_accessible_hyperlink(AtkHyperlink *aHyperlink)
-{
-    NS_ENSURE_TRUE(MAI_IS_ATK_HYPERLINK(aHyperlink), nullptr);
-    MaiHyperlink * maiHyperlink =
-        MAI_ATK_HYPERLINK(aHyperlink)->maiHyperlink;
-    NS_ENSURE_TRUE(maiHyperlink != nullptr, nullptr);
-    NS_ENSURE_TRUE(maiHyperlink->GetAtkHyperlink() == aHyperlink, nullptr);
-    return maiHyperlink->GetAccHyperlink();
+  if (Accessible* hyperlink = maiLink->GetAccHyperlink())
+    return static_cast<gint>(hyperlink->AnchorCount());
+
+  bool valid = false;
+  uint32_t anchorCount = maiLink->Proxy()->AnchorCount(&valid);
+  return valid ? static_cast<gint>(anchorCount) : -1;
 }
--- a/accessible/atk/nsMaiHyperlink.h
+++ b/accessible/atk/nsMaiHyperlink.h
@@ -18,25 +18,40 @@ namespace a11y {
 
 /*
  * MaiHyperlink is a auxiliary class for MaiInterfaceHyperText.
  */
 
 class MaiHyperlink
 {
 public:
-  explicit MaiHyperlink(Accessible* aHyperLink);
+  explicit MaiHyperlink(uintptr_t aHyperLink);
   ~MaiHyperlink();
 
 public:
   AtkHyperlink* GetAtkHyperlink() const { return mMaiAtkHyperlink; }
   Accessible* GetAccHyperlink()
-    { return mHyperlink && mHyperlink->IsLink() ? mHyperlink : nullptr; }
+    {
+      if (!mHyperlink || mHyperlink & IS_PROXY)
+        return nullptr;
+
+      Accessible* link = reinterpret_cast<Accessible*>(mHyperlink);
+      NS_ASSERTION(link->IsLink(), "Why isn't it a link!");
+      return link;
+    }
+
+  ProxyAccessible* Proxy() const
+  {
+    if (!(mHyperlink & IS_PROXY))
+      return nullptr;
+
+    return reinterpret_cast<ProxyAccessible*>(mHyperlink & ~IS_PROXY);
+  }
 
 protected:
-  Accessible* mHyperlink;
+  uintptr_t mHyperlink;
   AtkHyperlink* mMaiAtkHyperlink;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif /* __MAI_HYPERLINK_H__ */
--- a/accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp
+++ b/accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp
@@ -11,20 +11,21 @@
 
 using namespace mozilla::a11y;
 
 extern "C" {
 static AtkHyperlink*
 getHyperlinkCB(AtkHyperlinkImpl* aImpl)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImpl));
-  if (!accWrap)
+  if (!accWrap || !GetProxy(ATK_OBJECT(aImpl)))
     return nullptr;
 
-  NS_ENSURE_TRUE(accWrap->IsLink(), nullptr);
+  if (accWrap)
+    NS_ASSERTION(accWrap->IsLink(), "why isn't it a link!");
 
   return MAI_ATK_OBJECT(aImpl)->GetAtkHyperlink();
 }
 }
 
 void
 hyperlinkImplInterfaceInitCB(AtkHyperlinkImplIface *aIface)
 {
--- a/accessible/atk/nsMaiInterfaceHypertext.cpp
+++ b/accessible/atk/nsMaiInterfaceHypertext.cpp
@@ -17,41 +17,37 @@
 using namespace mozilla::a11y;
 
 extern "C" {
 
 static AtkHyperlink*
 getLinkCB(AtkHypertext *aText, gint aLinkIndex)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+  AtkObject* atkHyperLink = nullptr;
   if (accWrap) {
     HyperTextAccessible* hyperText = accWrap->AsHyperText();
     NS_ENSURE_TRUE(hyperText, nullptr);
 
     Accessible* hyperLink = hyperText->LinkAt(aLinkIndex);
-    if (!hyperLink) {
+    if (!hyperLink || !hyperLink->IsLink()) {
       return nullptr;
     }
 
-    AtkObject* hyperLinkAtkObj = AccessibleWrap::GetAtkObject(hyperLink);
-    NS_ENSURE_TRUE(IS_MAI_OBJECT(hyperLinkAtkObj), nullptr);
+    atkHyperLink = AccessibleWrap::GetAtkObject(hyperLink);
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+    ProxyAccessible* proxyLink = proxy->LinkAt(aLinkIndex);
+    if (!proxyLink)
+      return nullptr;
 
-    return MAI_ATK_OBJECT(hyperLinkAtkObj)->GetAtkHyperlink();
+    atkHyperLink = GetWrapperFor(proxyLink);
   }
 
-  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
-    ProxyAccessible* proxyLink = proxy->LinkAt(aLinkIndex);
-    if (proxyLink) {
-      NS_WARNING("IMPLEMENT ME! See bug 1146518.");
-      // We should somehow get from ProxyAccessible* to AtkHyperlink*.
-    }
-    return nullptr;
-  }
-
-  return nullptr;
+    NS_ENSURE_TRUE(IS_MAI_OBJECT(atkHyperLink), nullptr);
+    return MAI_ATK_OBJECT(atkHyperLink)->GetAtkHyperlink();
 }
 
 static gint
 getLinkCountCB(AtkHypertext *aText)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (accWrap) {
     HyperTextAccessible* hyperText = accWrap->AsHyperText();
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1899,11 +1899,12 @@ pref("readinglist.server", "https://read
 pref("reader.parse-node-limit", 0);
 
 // Enable Service workers for desktop on non-release builds
 #ifdef NIGHTLY_BUILD
 pref("dom.serviceWorkers.enabled", true);
 #endif
 
 pref("browser.pocket.enabled", false);
+pref("browser.pocket.hostname", "localhost");
 pref("browser.pocket.removedByUser", false);
 pref("browser.pocket.useLocaleList", true);
 pref("browser.pocket.enabledLocales", "en-US");
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -37,16 +37,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
                                   "resource:///modules/ContentSearch.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AboutHome",
                                   "resource:///modules/AboutHome.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Log",
                                   "resource://gre/modules/Log.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
                                   "resource://gre/modules/AppConstants.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
+                                  "resource://gre/modules/UpdateChannel.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "Favicons",
                                    "@mozilla.org/browser/favicon-service;1",
                                    "mozIAsyncFavicons");
 XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
                                    "@mozilla.org/network/dns-service;1",
                                    "nsIDNSService");
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
                                   "resource://gre/modules/LightweightThemeManager.jsm");
@@ -2753,17 +2755,17 @@ let BrowserOnClick = {
       port: location.port,
       timestamp: Math.round(Date.now() / 1000),
       errorCode: transportSecurityInfo.errorCode,
       failedCertChain: asciiCertChain,
       userAgent: window.navigator.userAgent,
       version: 1,
       build: gAppInfo.appBuildID,
       product: gAppInfo.name,
-      channel: Services.prefs.getCharPref("app.update.channel")
+      channel: UpdateChannel.get()
     }
 
     let reportURL = Services.prefs.getCharPref("security.ssl.errorReporting.url");
 
     let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
         .createInstance(Ci.nsIXMLHttpRequest);
     try {
       xhr.open("POST", reportURL);
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -13,22 +13,26 @@ Cu.import("resource://gre/modules/XPCOMU
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
   "resource:///modules/BrowserUITelemetry.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils",
   "resource:///modules/PlacesUIUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "RecentlyClosedTabsAndWindowsMenuUtils",
   "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Pocket",
+  "resource:///modules/Pocket.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
   "resource://gre/modules/ShortcutUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
   "resource://gre/modules/CharsetMenu.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
+  "resource://gre/modules/ReaderMode.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "CharsetBundle", function() {
   const kCharsetBundle = "chrome://global/locale/charsetMenu.properties";
   return Services.strings.createBundle(kCharsetBundle);
 });
 XPCOMUtils.defineLazyGetter(this, "BrandBundle", function() {
   const kBrandBundle = "chrome://branding/locale/brand.properties";
   return Services.strings.createBundle(kBrandBundle);
@@ -1123,31 +1127,55 @@ if (Services.prefs.getBoolPref("browser.
         addTagsField.addEventListener("input", this);
         addTagsButton.addEventListener("command", this);
       },
       onViewShowing(event) {
         let doc = event.target.ownerDocument;
 
         let loginView = doc.getElementById("pocket-login-required");
         let pageSavedView = doc.getElementById("pocket-page-saved");
-        let showPageSaved = Math.random() < 0.5;
-        loginView.hidden = !showPageSaved;
-        pageSavedView.hidden = showPageSaved;
+        let showPageSaved = Pocket.isLoggedIn;
+        loginView.hidden = showPageSaved;
+        pageSavedView.hidden = !showPageSaved;
+
+        if (!showPageSaved)
+          return;
+
+        let gBrowser = doc.defaultView.gBrowser;
+        let uri = gBrowser.currentURI;
+        if (uri.schemeIs("about"))
+          uri = ReaderMode.getOriginalUrl(uri.spec);
+        else
+          uri = uri.spec;
+        if (!uri)
+          return; //TODO should prevent the panel from showing
+
+        Pocket.save(uri, gBrowser.contentTitle).then(
+          item => {
+            doc.getElementById("pocket-remove-page").itemId = item.item_id;
+          },
+          error => {dump(error + "\n");}
+        );
+      },
+      onViewHiding(event) {
+        let doc = event.target.ownerDocument;
+        doc.getElementById("pocket-remove-page").itemId = null;
       },
 
       handleEvent: function(event) {
         let doc = event.target.ownerDocument;
         let field = doc.getElementById("pocket-page-tags-field");
         let button = doc.getElementById("pocket-page-tags-add");
         switch (event.type) {
           case "input":
             button.disabled = !field.value.trim();
             break;
           case "command":
-            //XXXjaws Send tag to the Pocket server
+            Pocket.tag(doc.getElementById("pocket-remove-page").itemId,
+                       field.value);
             field.value = "";
             break;
         }
       },
 
       USER_REMOVED_PREF: "browser.pocket.removedByUser",
       onWidgetAdded(aWidgetId, aArea, aPosition) {
         if (aWidgetId != this.id) {
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -241,17 +241,18 @@
           </description>
           <label id="pocket-account-question"/>
           <label id="pocket-login-now" class="text-link"/>
         </vbox>
         <vbox id="pocket-page-saved" hidden="true">
           <label id="pocket-page-saved-header" class="pocket-header"/>
           <hbox id="pocket-page-saved-next-steps" pack="center">
             <label id="pocket-open-pocket" class="text-link"/>
-            <label id="pocket-remove-page" class="text-link"/>
+            <label id="pocket-remove-page" class="text-link"
+                   onclick="Pocket.remove(this.itemId);"/>
           </hbox>
           <hbox id="pocket-separator">
             <box class="pocket-separator-colorstop"/>
             <box class="pocket-separator-colorstop"/>
             <box class="pocket-separator-colorstop"/>
             <box class="pocket-separator-colorstop"/>
           </hbox>
           <vbox id="pocket-page-tags">
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -1,20 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
                                   "resource:///modules/CustomizableUI.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ScrollbarSampler",
                                   "resource:///modules/ScrollbarSampler.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Pocket",
+                                  "resource:///modules/Pocket.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
                                   "resource://gre/modules/Promise.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
                                   "resource://gre/modules/ShortcutUtils.jsm");
+
 /**
  * Maintains the state and dispatches events for the main menu panel.
  */
 
 const PanelUI = {
   /** Panel events that we listen for. **/
   get kEvents() ["popupshowing", "popupshown", "popuphiding", "popuphidden"],
   /**
@@ -399,17 +402,17 @@ const PanelUI = {
     }
     if (!aIsRemoval &&
         (this.panel.state == "open" ||
          document.documentElement.hasAttribute("customizing"))) {
       this._adjustLabelsForAutoHyphens(aNode);
     }
   },
 
-  /** 
+  /**
    * Signal that we're about to make a lot of changes to the contents of the
    * panels all at once. For performance, we ignore the mutations.
    */
   beginBatchUpdate: function() {
     this._ensureEventListenersAdded();
     this.multiView.ignoreMutations = true;
   },
 
@@ -522,9 +525,8 @@ function getLocale() {
 
   try {
     return Services.prefs.getCharPref(PREF_SELECTED_LOCALE);
   }
   catch (e) { }
 
   return "en-US";
 }
-
--- a/browser/components/loop/content/js/roomViews.js
+++ b/browser/components/loop/content/js/roomViews.js
@@ -260,20 +260,23 @@ loop.roomViews = (function(mozL10n) {
                                         mozL10n.get("copy_url_button2")
               ), 
               React.createElement("button", {className: "btn btn-info btn-share", 
                       ref: "anchor", 
                       onClick: this.handleShareButtonClick}, 
                 mozL10n.get("share_button3")
               )
             ), 
-            React.createElement(SocialShareDropdown, {dispatcher: this.props.dispatcher, 
-                                 roomUrl: this.props.roomData.roomUrl, 
-                                 show: this.state.showMenu, 
-                                 ref: "menu"})
+            React.createElement(SocialShareDropdown, {
+              dispatcher: this.props.dispatcher, 
+              roomUrl: this.props.roomData.roomUrl, 
+              show: this.state.showMenu, 
+              socialShareButtonAvailable: this.props.socialShareButtonAvailable, 
+              socialShareProviders: this.props.socialShareProviders, 
+              ref: "menu"})
           ), 
           React.createElement(DesktopRoomContextView, {
             roomData: this.props.roomData, 
             show: this.props.showContext})
         )
       );
     }
   });
@@ -438,17 +441,19 @@ loop.roomViews = (function(mozL10n) {
         default: {
           return (
             React.createElement("div", {className: "room-conversation-wrapper"}, 
               React.createElement(DesktopRoomInvitationView, {
                 dispatcher: this.props.dispatcher, 
                 error: this.state.error, 
                 roomData: roomData, 
                 show: shouldRenderInvitationOverlay, 
-                showContext: shouldRenderContextView}), 
+                showContext: shouldRenderContextView, 
+                socialShareButtonAvailable: this.state.socialShareButtonAvailable, 
+                socialShareProviders: this.state.socialShareProviders}), 
               React.createElement("div", {className: "video-layout-wrapper"}, 
                 React.createElement("div", {className: "conversation room-conversation"}, 
                   React.createElement("div", {className: "media nested"}, 
                     React.createElement("div", {className: "video_wrapper remote_wrapper"}, 
                       React.createElement("div", {className: "video_inner remote focus-stream"})
                     ), 
                     React.createElement("div", {className: localStreamClasses}), 
                     React.createElement("div", {className: "screen hide"})
--- a/browser/components/loop/content/js/roomViews.jsx
+++ b/browser/components/loop/content/js/roomViews.jsx
@@ -260,20 +260,23 @@ loop.roomViews = (function(mozL10n) {
                                         mozL10n.get("copy_url_button2")}
               </button>
               <button className="btn btn-info btn-share"
                       ref="anchor"
                       onClick={this.handleShareButtonClick}>
                 {mozL10n.get("share_button3")}
               </button>
             </div>
-            <SocialShareDropdown dispatcher={this.props.dispatcher}
-                                 roomUrl={this.props.roomData.roomUrl}
-                                 show={this.state.showMenu}
-                                 ref="menu"/>
+            <SocialShareDropdown
+              dispatcher={this.props.dispatcher}
+              roomUrl={this.props.roomData.roomUrl}
+              show={this.state.showMenu}
+              socialShareButtonAvailable={this.props.socialShareButtonAvailable}
+              socialShareProviders={this.props.socialShareProviders}
+              ref="menu" />
           </div>
           <DesktopRoomContextView
             roomData={this.props.roomData}
             show={this.props.showContext} />
         </div>
       );
     }
   });
@@ -438,17 +441,19 @@ loop.roomViews = (function(mozL10n) {
         default: {
           return (
             <div className="room-conversation-wrapper">
               <DesktopRoomInvitationView
                 dispatcher={this.props.dispatcher}
                 error={this.state.error}
                 roomData={roomData}
                 show={shouldRenderInvitationOverlay}
-                showContext={shouldRenderContextView} />
+                showContext={shouldRenderContextView}
+                socialShareButtonAvailable={this.state.socialShareButtonAvailable}
+                socialShareProviders={this.state.socialShareProviders} />
               <div className="video-layout-wrapper">
                 <div className="conversation room-conversation">
                   <div className="media nested">
                     <div className="video_wrapper remote_wrapper">
                       <div className="video_inner remote focus-stream"></div>
                     </div>
                     <div className={localStreamClasses}></div>
                     <div className="screen hide"></div>
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -729,16 +729,17 @@ BrowserGlue.prototype = {
 
 #ifndef RELEASE_BUILD
     let themeName = gBrowserBundle.GetStringFromName("deveditionTheme.name");
     let vendorShortName = gBrandBundle.GetStringFromName("vendorShortName");
 
     LightweightThemeManager.addBuiltInTheme({
       id: "firefox-devedition@mozilla.org",
       name: themeName,
+      accentcolor: "transparent",
       headerURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.header.png",
       iconURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.icon.png",
       author: vendorShortName,
     });
 #endif
 
 #ifdef MOZ_CRASHREPORTER
     TabCrashReporter.init();
new file mode 100644
--- /dev/null
+++ b/browser/components/pocket/Pocket.jsm
@@ -0,0 +1,109 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+this.EXPORTED_SYMBOLS = ["Pocket"];
+
+Cu.import("resource://gre/modules/Http.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+let Pocket = {
+  get isLoggedIn() {
+    return !!this._accessToken;
+  },
+
+  prefBranch: Services.prefs.getBranch("browser.pocket.settings."),
+
+  get hostname() Services.prefs.getCharPref("browser.pocket.hostname"),
+
+  get _accessToken() {
+    let sessionId, accessToken;
+    let cookies = Services.cookies.getCookiesFromHost(this.hostname);
+    while (cookies.hasMoreElements()) {
+      let cookie = cookies.getNext().QueryInterface(Ci.nsICookie2);
+      if (cookie.name == "ftv1")
+        accessToken = cookie.value;
+      else if (cookie.name == "fsv1")
+        sessionId = cookie.value;
+    }
+
+    if (!accessToken)
+      return null;
+
+    let lastSessionId;
+    try {
+      lastSessionId = this.prefBranch.getCharPref("sessionId");
+    } catch (e) { }
+    if (sessionId != lastSessionId)
+      this.prefBranch.deleteBranch("");
+    this.prefBranch.setCharPref("sessionId", sessionId);
+
+    return accessToken;
+  },
+
+  save(url, title) {
+    let since = "0";
+    try {
+      since = this.prefBranch.getCharPref("latestSince");
+    } catch (e) { }
+
+    let data = {url: url, since: since, title: title};
+
+    return new Promise((resolve, reject) => {
+      this._send("firefox/save", data,
+        data => {
+          this.prefBranch.setCharPref("latestSince", data.since);
+          resolve(data.item);
+        },
+        error => { reject(error); }
+      );
+    });
+  },
+
+  remove(itemId) {
+    let actions = [{ action: "delete", item_id: itemId }];
+    this._send("send", {actions: JSON.stringify(actions)});
+  },
+
+  tag(itemId, tags) {
+    let actions = [{ action: "tags_add", item_id: itemId, tags: tags }];
+    this._send("send", {actions: JSON.stringify(actions)});
+  },
+
+  _send(url, data, onSuccess, onError) {
+    let token = this._accessToken;
+    if (!token)
+      throw "Attempted to send a request to Pocket while not logged in";
+
+    let browserLocale = Cc["@mozilla.org/chrome/chrome-registry;1"]
+                          .getService(Ci.nsIXULChromeRegistry)
+                          .getSelectedLocale("browser");
+
+    let postData = [
+      ["access_token", token],
+      ["consumer_key", "40249-e88c401e1b1f2242d9e441c4"],
+      ["locale_lang", browserLocale]
+    ];
+
+    for (let key in data)
+      postData.push([key, data[key]]);
+
+    httpRequest("https://" + this.hostname + "/v3/" + url, {
+      headers: [["X-Accept", "application/json"]],
+      postData: postData,
+      onLoad: (responseText) => {
+        if (onSuccess)
+          onSuccess(JSON.parse(responseText));
+      },
+      onError: function(error, responseText, xhr) {
+        if (!onError)
+          return;
+        let errorMessage = xhr.getResponseHeader("X-Error");
+        onError(new Error(error + " - " + errorMessage));
+      }
+    });
+  }
+};
--- a/browser/components/pocket/moz.build
+++ b/browser/components/pocket/moz.build
@@ -1,5 +1,7 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-JAR_MANIFESTS += ['jar.mn']
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+JAR_MANIFESTS += ['jar.mn']
+
+EXTRA_JS_MODULES += ['Pocket.jsm']
--- a/browser/components/sessionstore/SessionCookies.jsm
+++ b/browser/components/sessionstore/SessionCookies.jsm
@@ -25,16 +25,20 @@ const MAX_EXPIRY = Math.pow(2, 62);
  */
 this.SessionCookies = Object.freeze({
   update: function (windows) {
     SessionCookiesInternal.update(windows);
   },
 
   getHostsForWindow: function (window, checkPrivacy = false) {
     return SessionCookiesInternal.getHostsForWindow(window, checkPrivacy);
+  },
+
+  restore(cookies) {
+    SessionCookiesInternal.restore(cookies);
   }
 });
 
 /**
  * The internal API.
  */
 let SessionCookiesInternal = {
   /**
@@ -103,16 +107,28 @@ let SessionCookiesInternal = {
         this._extractHostsFromEntry(entry, hosts, checkPrivacy, tab.pinned);
       }
     }
 
     return hosts;
   },
 
   /**
+   * Restores a given list of session cookies.
+   */
+  restore(cookies) {
+    for (let cookie of cookies) {
+      let expiry = "expiry" in cookie ? cookie.expiry : MAX_EXPIRY;
+      Services.cookies.add(cookie.host, cookie.path || "", cookie.name || "",
+                           cookie.value, !!cookie.secure, !!cookie.httponly,
+                           /* isSession = */ true, expiry);
+    }
+  },
+
+  /**
    * Handles observers notifications that are sent whenever cookies are added,
    * changed, or removed. Ensures that the storage is updated accordingly.
    */
   observe: function (subject, topic, data) {
     switch (data) {
       case "added":
       case "changed":
         this._updateCookie(subject);
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -113,19 +113,16 @@ Cu.import("resource://gre/modules/Promis
 Cu.import("resource://gre/modules/Task.jsm", this);
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSessionStartup",
   "@mozilla.org/browser/sessionstartup;1", "nsISessionStartup");
 XPCOMUtils.defineLazyServiceGetter(this, "gScreenManager",
   "@mozilla.org/gfx/screenmanager;1", "nsIScreenManager");
 XPCOMUtils.defineLazyServiceGetter(this, "Telemetry",
   "@mozilla.org/base/telemetry;1", "nsITelemetry");
-XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
-  "@mozilla.org/parentprocessmessagemanager;1",
-  "nsIMessageListenerManager");
 XPCOMUtils.defineLazyModuleGetter(this, "console",
   "resource://gre/modules/devtools/Console.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
   "resource:///modules/RecentWindow.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
   "resource://gre/modules/AppConstants.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "GlobalState",
@@ -1516,17 +1513,17 @@ let SessionStoreInternal = {
     let state = this.getCurrentState();
 
     // Don't include the last session state in getBrowserState().
     delete state.lastSessionState;
 
     // Don't include any deferred initial state.
     delete state.deferredInitialState;
 
-    return this._toJSONString(state);
+    return JSON.stringify(state);
   },
 
   setBrowserState: function ssi_setBrowserState(aState) {
     this._handleClosedWindows();
 
     try {
       var state = JSON.parse(aState);
     }
@@ -1569,22 +1566,22 @@ let SessionStoreInternal = {
     this._globalState.setFromState(state);
 
     // restore to the given state
     this.restoreWindows(window, state, {overwriteTabs: true});
   },
 
   getWindowState: function ssi_getWindowState(aWindow) {
     if ("__SSi" in aWindow) {
-      return this._toJSONString(this._getWindowState(aWindow));
+      return JSON.stringify(this._getWindowState(aWindow));
     }
 
     if (DyingWindowCache.has(aWindow)) {
       let data = DyingWindowCache.get(aWindow);
-      return this._toJSONString({ windows: [data] });
+      return JSON.stringify({ windows: [data] });
     }
 
     throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
   },
 
   setWindowState: function ssi_setWindowState(aWindow, aState, aOverwrite) {
     if (!aWindow.__SSi) {
       throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
@@ -1595,17 +1592,17 @@ let SessionStoreInternal = {
 
   getTabState: function ssi_getTabState(aTab) {
     if (!aTab.ownerDocument.defaultView.__SSi) {
       throw Components.Exception("Default view is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
 
     let tabState = TabState.collect(aTab);
 
-    return this._toJSONString(tabState);
+    return JSON.stringify(tabState);
   },
 
   setTabState: function ssi_setTabState(aTab, aState, aOptions) {
     // Remove the tab state from the cache.
     // Note that we cannot simply replace the contents of the cache
     // as |aState| can be an incomplete state that will be completed
     // by |restoreTabs|.
     let tabState = JSON.parse(aState);
@@ -1630,18 +1627,18 @@ let SessionStoreInternal = {
 
     this.restoreTab(aTab, tabState, aOptions);
   },
 
   duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) {
     if (!aTab.ownerDocument.defaultView.__SSi) {
       throw Components.Exception("Default view is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
-    if (!aWindow.getBrowser) {
-      throw Components.Exception("Invalid window object: no getBrowser", Cr.NS_ERROR_INVALID_ARG);
+    if (!aWindow.gBrowser) {
+      throw Components.Exception("Invalid window object: no gBrowser", Cr.NS_ERROR_INVALID_ARG);
     }
 
     // Flush all data queued in the content script because we will need that
     // state to properly duplicate the given tab.
     TabState.flush(aTab.linkedBrowser);
 
     // Duplicate the tab state
     let tabState = TabState.clone(aTab);
@@ -1669,42 +1666,42 @@ let SessionStoreInternal = {
       throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
 
     return DyingWindowCache.get(aWindow)._closedTabs.length;
   },
 
   getClosedTabData: function ssi_getClosedTabDataAt(aWindow) {
     if ("__SSi" in aWindow) {
-      return this._toJSONString(this._windows[aWindow.__SSi]._closedTabs);
+      return JSON.stringify(this._windows[aWindow.__SSi]._closedTabs);
     }
 
     if (!DyingWindowCache.has(aWindow)) {
       throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
 
     let data = DyingWindowCache.get(aWindow);
-    return this._toJSONString(data._closedTabs);
+    return JSON.stringify(data._closedTabs);
   },
 
   undoCloseTab: function ssi_undoCloseTab(aWindow, aIndex) {
     if (!aWindow.__SSi) {
       throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
 
     var closedTabs = this._windows[aWindow.__SSi]._closedTabs;
 
     // default to the most-recently closed tab
     aIndex = aIndex || 0;
     if (!(aIndex in closedTabs)) {
       throw Components.Exception("Invalid index: not in the closed tabs", Cr.NS_ERROR_INVALID_ARG);
     }
 
     // fetch the data of closed tab, while removing it from the array
-    let closedTab = closedTabs.splice(aIndex, 1).shift();
+    let [closedTab] = closedTabs.splice(aIndex, 1);
     let closedTabState = closedTab.state;
 
     // create a new tab
     let tabbrowser = aWindow.gBrowser;
     let tab = tabbrowser.selectedTab = tabbrowser.addTab();
 
     // restore tab content
     this.restoreTab(tab, closedTabState);
@@ -1735,17 +1732,17 @@ let SessionStoreInternal = {
     closedTabs.splice(aIndex, 1);
   },
 
   getClosedWindowCount: function ssi_getClosedWindowCount() {
     return this._closedWindows.length;
   },
 
   getClosedWindowData: function ssi_getClosedWindowData() {
-    return this._toJSONString(this._closedWindows);
+    return JSON.stringify(this._closedWindows);
   },
 
   undoCloseWindow: function ssi_undoCloseWindow(aIndex) {
     if (!(aIndex in this._closedWindows)) {
       throw Components.Exception("Invalid index: not in the closed windows", Cr.NS_ERROR_INVALID_ARG);
     }
 
     // reopen the window
@@ -2415,17 +2412,17 @@ let SessionStoreInternal = {
            .forEach(tabbrowser.removeTab, tabbrowser);
     }
 
     if (overwriteTabs) {
       this.restoreWindowFeatures(aWindow, winData);
       delete this._windows[aWindow.__SSi].extData;
     }
     if (winData.cookies) {
-      this.restoreCookies(winData.cookies);
+      SessionCookies.restore(winData.cookies);
     }
     if (winData.extData) {
       if (!this._windows[aWindow.__SSi].extData) {
         this._windows[aWindow.__SSi].extData = {};
       }
       for (var key in winData.extData) {
         this._windows[aWindow.__SSi].extData[key] = winData.extData[key];
       }
@@ -2599,16 +2596,23 @@ let SessionStoreInternal = {
 
     // Increase the busy state counter before modifying the tab.
     this._setWindowStateBusy(window);
 
     // It's important to set the window state to dirty so that
     // we collect their data for the first time when saving state.
     DirtyWindows.add(window);
 
+    // In case we didn't collect/receive data for any tabs yet we'll have to
+    // fill the array with at least empty tabData objects until |_tPos| or
+    // we'll end up with |null| entries.
+    for (let tab of Array.slice(tabbrowser.tabs, 0, tab._tPos)) {
+      this._windows[window.__SSi].tabs.push(TabState.collect(tab));
+    }
+
     // Update the tab state in case we shut down without being notified.
     this._windows[window.__SSi].tabs[tab._tPos] = tabData;
 
     // Prepare the tab so that it can be properly restored. We'll pin/unpin
     // and show/hide tabs as necessary. We'll also attach a copy of the tab's
     // data in case we close it before it's been restored.
     if (tabData.pinned) {
       tabbrowser.pinTab(tab);
@@ -2888,35 +2892,16 @@ let SessionStoreInternal = {
     }
     // since resizing/moving a window brings it to the foreground,
     // we might want to re-focus the last focused window
     if (this.windowToFocus) {
       this.windowToFocus.focus();
     }
   },
 
-  /**
-   * Restores cookies
-   * @param aCookies
-   *        Array of cookie objects
-   */
-  restoreCookies: function ssi_restoreCookies(aCookies) {
-    // MAX_EXPIRY should be 2^63-1, but JavaScript can't handle that precision
-    var MAX_EXPIRY = Math.pow(2, 62);
-    for (let i = 0; i < aCookies.length; i++) {
-      var cookie = aCookies[i];
-      try {
-        Services.cookies.add(cookie.host, cookie.path || "", cookie.name || "",
-                             cookie.value, !!cookie.secure, !!cookie.httponly, true,
-                             "expiry" in cookie ? cookie.expiry : MAX_EXPIRY);
-      }
-      catch (ex) { console.error(ex); } // don't let a single cookie stop recovering
-    }
-  },
-
   /* ........ Disk Access .............. */
 
   /**
    * Save the current session state to disk, after a delay.
    *
    * @param aWindow (optional)
    *        Will mark the given window as dirty so that we will recollect its
    *        data before we start writing.
@@ -3102,25 +3087,16 @@ let SessionStoreInternal = {
 
     if (aWindow.windowState == aWindow.STATE_NORMAL) {
       return dimension;
     }
     return aWindow.document.documentElement.getAttribute(aAttribute) || dimension;
   },
 
   /**
-   * Get nsIURI from string
-   * @param string
-   * @returns nsIURI
-   */
-  _getURIFromString: function ssi_getURIFromString(aString) {
-    return Services.io.newURI(aString, null, null);
-  },
-
-  /**
    * @param aState is a session state
    * @param aRecentCrashes is the number of consecutive crashes
    * @returns whether a restore page will be needed for the session state
    */
   _needsRestorePage: function ssi_needsRestorePage(aState, aRecentCrashes) {
     const SIX_HOURS_IN_MS = 6 * 60 * 60 * 1000;
 
     // don't display the page when there's nothing to restore
@@ -3308,29 +3284,16 @@ let SessionStoreInternal = {
         aTargetWinState.cookies =
           aTargetWinState.cookies.concat(aWinState.cookies.splice(cIndex, 1));
         continue;
       }
       cIndex++;
     }
   },
 
-  /**
-   * Converts a JavaScript object into a JSON string
-   * (see http://www.json.org/ for more information).
-   *
-   * The inverse operation consists of JSON.parse(JSON_string).
-   *
-   * @param aJSObject is the object to be converted
-   * @returns the object's JSON representation
-   */
-  _toJSONString: function ssi_toJSONString(aJSObject) {
-    return JSON.stringify(aJSObject);
-  },
-
   _sendRestoreCompletedNotifications: function ssi_sendRestoreCompletedNotifications() {
     // not all windows restored, yet
     if (this._restoreCount > 1) {
       this._restoreCount--;
       return;
     }
 
     // observers were already notified
--- a/browser/devtools/animationinspector/test/head.js
+++ b/browser/devtools/animationinspector/test/head.js
@@ -357,17 +357,19 @@ function waitForPlayState(player, playSt
  * When done, check its currentTime.
  * @param {PlayerWidget} widget.
  * @param {Numer} time.
  * @return {Promise} Resolves when the animation is paused and tests have ran.
  */
 let checkPausedAt = Task.async(function*(widget, time) {
   info("Wait for the next auto-refresh");
 
-  yield waitForPlayState(widget.player, "paused");
+  yield waitForStateCondition(widget.player, state => {
+    return state.playState === "paused" && state.currentTime === time;
+  }, "Waiting for animation to pause at " + time + "ms");
 
   ok(widget.el.classList.contains("paused"), "The widget is in paused mode");
   is(widget.player.state.currentTime, time,
     "The player front's currentTime was set to " + time);
   is(widget.currentTimeEl.value, time, "The input's value was set to " + time);
 });
 
 /**
deleted file mode 100644
--- a/browser/devtools/debugger/debugger-panes.js
+++ /dev/null
@@ -1,3526 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-// Used to detect minification for automatic pretty printing
-const SAMPLE_SIZE = 50; // no of lines
-const INDENT_COUNT_THRESHOLD = 5; // percentage
-const CHARACTER_LIMIT = 250; // line character limit
-
-// Maps known URLs to friendly source group names and put them at the
-// bottom of source list.
-const KNOWN_SOURCE_GROUPS = {
-  "Add-on SDK": "resource://gre/modules/commonjs/",
-};
-
-KNOWN_SOURCE_GROUPS[L10N.getStr("evalGroupLabel")] = "eval";
-
-/**
- * Functions handling the sources UI.
- */
-function SourcesView() {
-  dumpn("SourcesView was instantiated");
-
-  this.togglePrettyPrint = this.togglePrettyPrint.bind(this);
-  this.toggleBlackBoxing = this.toggleBlackBoxing.bind(this);
-  this.toggleBreakpoints = this.toggleBreakpoints.bind(this);
-
-  this._onEditorLoad = this._onEditorLoad.bind(this);
-  this._onEditorUnload = this._onEditorUnload.bind(this);
-  this._onEditorCursorActivity = this._onEditorCursorActivity.bind(this);
-  this._onSourceSelect = this._onSourceSelect.bind(this);
-  this._onStopBlackBoxing = this._onStopBlackBoxing.bind(this);
-  this._onBreakpointRemoved = this._onBreakpointRemoved.bind(this);
-  this._onBreakpointClick = this._onBreakpointClick.bind(this);
-  this._onBreakpointCheckboxClick = this._onBreakpointCheckboxClick.bind(this);
-  this._onConditionalPopupShowing = this._onConditionalPopupShowing.bind(this);
-  this._onConditionalPopupShown = this._onConditionalPopupShown.bind(this);
-  this._onConditionalPopupHiding = this._onConditionalPopupHiding.bind(this);
-  this._onConditionalTextboxKeyPress = this._onConditionalTextboxKeyPress.bind(this);
-  this._onCopyUrlCommand = this._onCopyUrlCommand.bind(this);
-  this._onNewTabCommand = this._onNewTabCommand.bind(this);
-}
-
-SourcesView.prototype = Heritage.extend(WidgetMethods, {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the SourcesView");
-
-    this.widget = new SideMenuWidget(document.getElementById("sources"), {
-      contextMenu: document.getElementById("debuggerSourcesContextMenu"),
-      showArrows: true
-    });
-
-    this.emptyText = L10N.getStr("noSourcesText");
-    this._blackBoxCheckboxTooltip = L10N.getStr("blackBoxCheckboxTooltip");
-
-    this._commandset = document.getElementById("debuggerCommands");
-    this._popupset = document.getElementById("debuggerPopupset");
-    this._cmPopup = document.getElementById("sourceEditorContextMenu");
-    this._cbPanel = document.getElementById("conditional-breakpoint-panel");
-    this._cbTextbox = document.getElementById("conditional-breakpoint-panel-textbox");
-    this._blackBoxButton = document.getElementById("black-box");
-    this._stopBlackBoxButton = document.getElementById("black-boxed-message-button");
-    this._prettyPrintButton = document.getElementById("pretty-print");
-    this._toggleBreakpointsButton = document.getElementById("toggle-breakpoints");
-    this._newTabMenuItem = document.getElementById("debugger-sources-context-newtab");
-    this._copyUrlMenuItem = document.getElementById("debugger-sources-context-copyurl");
-
-    if (Prefs.prettyPrintEnabled) {
-      this._prettyPrintButton.removeAttribute("hidden");
-    }
-
-    window.on(EVENTS.EDITOR_LOADED, this._onEditorLoad, false);
-    window.on(EVENTS.EDITOR_UNLOADED, this._onEditorUnload, false);
-    this.widget.addEventListener("select", this._onSourceSelect, false);
-    this._stopBlackBoxButton.addEventListener("click", this._onStopBlackBoxing, false);
-    this._cbPanel.addEventListener("popupshowing", this._onConditionalPopupShowing, false);
-    this._cbPanel.addEventListener("popupshown", this._onConditionalPopupShown, false);
-    this._cbPanel.addEventListener("popuphiding", this._onConditionalPopupHiding, false);
-    this._cbTextbox.addEventListener("keypress", this._onConditionalTextboxKeyPress, false);
-    this._copyUrlMenuItem.addEventListener("command", this._onCopyUrlCommand, false);
-    this._newTabMenuItem.addEventListener("command", this._onNewTabCommand, false);
-
-    this.allowFocusOnRightClick = true;
-    this.autoFocusOnSelection = false;
-
-    // Sort the contents by the displayed label.
-    this.sortContents((aFirst, aSecond) => {
-      return +(aFirst.attachment.label.toLowerCase() >
-               aSecond.attachment.label.toLowerCase());
-    });
-
-    // Sort known source groups towards the end of the list
-    this.widget.groupSortPredicate = function(a, b) {
-      if ((a in KNOWN_SOURCE_GROUPS) == (b in KNOWN_SOURCE_GROUPS)) {
-        return a.localeCompare(b);
-      }
-      return (a in KNOWN_SOURCE_GROUPS) ? 1 : -1;
-    };
-
-    this._addCommands();
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the SourcesView");
-
-    window.off(EVENTS.EDITOR_LOADED, this._onEditorLoad, false);
-    window.off(EVENTS.EDITOR_UNLOADED, this._onEditorUnload, false);
-    this.widget.removeEventListener("select", this._onSourceSelect, false);
-    this._stopBlackBoxButton.removeEventListener("click", this._onStopBlackBoxing, false);
-    this._cbPanel.removeEventListener("popupshowing", this._onConditionalPopupShowing, false);
-    this._cbPanel.removeEventListener("popupshowing", this._onConditionalPopupShown, false);
-    this._cbPanel.removeEventListener("popuphiding", this._onConditionalPopupHiding, false);
-    this._cbTextbox.removeEventListener("keypress", this._onConditionalTextboxKeyPress, false);
-    this._copyUrlMenuItem.removeEventListener("command", this._onCopyUrlCommand, false);
-    this._newTabMenuItem.removeEventListener("command", this._onNewTabCommand, false);
-  },
-
-  /**
-   * Add commands that XUL can fire.
-   */
-  _addCommands: function() {
-    utils.addCommands(this._commandset, {
-      addBreakpointCommand: e => this._onCmdAddBreakpoint(e),
-      addConditionalBreakpointCommand: e => this._onCmdAddConditionalBreakpoint(e),
-      blackBoxCommand: () => this.toggleBlackBoxing(),
-      unBlackBoxButton: () => this._onStopBlackBoxing(),
-      prettyPrintCommand: () => this.togglePrettyPrint(),
-      toggleBreakpointsCommand: () =>this.toggleBreakpoints(),
-      nextSourceCommand: () => this.selectNextItem(),
-      prevSourceCommand: () => this.selectPrevItem()
-    });
-  },
-
-  /**
-   * Sets the preferred location to be selected in this sources container.
-   * @param string aUrl
-   */
-  set preferredSource(aUrl) {
-    this._preferredValue = aUrl;
-
-    // Selects the element with the specified value in this sources container,
-    // if already inserted.
-    if (this.containsValue(aUrl)) {
-      this.selectedValue = aUrl;
-    }
-  },
-
-  /**
-   * Adds a source to this sources container.
-   *
-   * @param object aSource
-   *        The source object coming from the active thread.
-   * @param object aOptions [optional]
-   *        Additional options for adding the source. Supported options:
-   *        - staged: true to stage the item to be appended later
-   */
-  addSource: function(aSource, aOptions = {}) {
-    if (!aSource.url) {
-      // We don't show any unnamed eval scripts yet (see bug 1124106)
-      return;
-    }
-
-    let { label, group, unicodeUrl } = this._parseUrl(aSource);
-
-    let contents = document.createElement("label");
-    contents.className = "plain dbg-source-item";
-    contents.setAttribute("value", label);
-    contents.setAttribute("crop", "start");
-    contents.setAttribute("flex", "1");
-    contents.setAttribute("tooltiptext", unicodeUrl);
-
-    // If the source is blackboxed, apply the appropriate style.
-    if (gThreadClient.source(aSource).isBlackBoxed) {
-      contents.classList.add("black-boxed");
-    }
-
-    // Append a source item to this container.
-    this.push([contents, aSource.actor], {
-      staged: aOptions.staged, /* stage the item to be appended later? */
-      attachment: {
-        label: label,
-        group: group,
-        checkboxState: !aSource.isBlackBoxed,
-        checkboxTooltip: this._blackBoxCheckboxTooltip,
-        source: aSource
-      }
-    });
-  },
-
-  _parseUrl: function(aSource) {
-    let fullUrl = aSource.url;
-    let url = fullUrl.split(" -> ").pop();
-    let label = aSource.addonPath ? aSource.addonPath : SourceUtils.getSourceLabel(url);
-    let group = aSource.addonID ? aSource.addonID : SourceUtils.getSourceGroup(url);
-
-    return {
-      label: label,
-      group: group,
-      unicodeUrl: NetworkHelper.convertToUnicode(unescape(fullUrl))
-    };
-  },
-
-  /**
-   * Adds a breakpoint to this sources container.
-   *
-   * @param object aBreakpointClient
-   *               See Breakpoints.prototype._showBreakpoint
-   * @param object aOptions [optional]
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   */
-  addBreakpoint: function(aBreakpointClient, aOptions = {}) {
-    let { location, disabled } = aBreakpointClient;
-
-    // Make sure we're not duplicating anything. If a breakpoint at the
-    // specified source url and line already exists, just toggle it.
-    if (this.getBreakpoint(location)) {
-      this[disabled ? "disableBreakpoint" : "enableBreakpoint"](location);
-      return;
-    }
-
-    // Get the source item to which the breakpoint should be attached.
-    let sourceItem = this.getItemByValue(this.getActorForLocation(location));
-
-    // Create the element node and menu popup for the breakpoint item.
-    let breakpointArgs = Heritage.extend(aBreakpointClient, aOptions);
-    let breakpointView = this._createBreakpointView.call(this, breakpointArgs);
-    let contextMenu = this._createContextMenu.call(this, breakpointArgs);
-
-    // Append a breakpoint child item to the corresponding source item.
-    sourceItem.append(breakpointView.container, {
-      attachment: Heritage.extend(breakpointArgs, {
-        actor: location.actor,
-        line: location.line,
-        view: breakpointView,
-        popup: contextMenu
-      }),
-      attributes: [
-        ["contextmenu", contextMenu.menupopupId]
-      ],
-      // Make sure that when the breakpoint item is removed, the corresponding
-      // menupopup and commandset are also destroyed.
-      finalize: this._onBreakpointRemoved
-    });
-
-    // Highlight the newly appended breakpoint child item if
-    // necessary.
-    if (aOptions.openPopup || !aOptions.noEditorUpdate) {
-      this.highlightBreakpoint(location, aOptions);
-    }
-
-    window.emit(EVENTS.BREAKPOINT_SHOWN_IN_PANE);
-  },
-
-  /**
-   * Removes a breakpoint from this sources container.
-   * It does not also remove the breakpoint from the controller. Be careful.
-   *
-   * @param object aLocation
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   */
-  removeBreakpoint: function(aLocation) {
-    // When a parent source item is removed, all the child breakpoint items are
-    // also automagically removed.
-    let sourceItem = this.getItemByValue(aLocation.actor);
-    if (!sourceItem) {
-      return;
-    }
-    let breakpointItem = this.getBreakpoint(aLocation);
-    if (!breakpointItem) {
-      return;
-    }
-
-    // Clear the breakpoint view.
-    sourceItem.remove(breakpointItem);
-
-    window.emit(EVENTS.BREAKPOINT_HIDDEN_IN_PANE);
-  },
-
-  /**
-   * Returns the breakpoint at the specified source url and line.
-   *
-   * @param object aLocation
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   * @return object
-   *         The corresponding breakpoint item if found, null otherwise.
-   */
-  getBreakpoint: function(aLocation) {
-    return this.getItemForPredicate(aItem =>
-      aItem.attachment.actor == aLocation.actor &&
-      aItem.attachment.line == aLocation.line);
-  },
-
-  /**
-   * Returns all breakpoints for all sources.
-   *
-   * @return array
-   *         The breakpoints for all sources if any, an empty array otherwise.
-   */
-  getAllBreakpoints: function(aStore = []) {
-    return this.getOtherBreakpoints(undefined, aStore);
-  },
-
-  /**
-   * Returns all breakpoints which are not at the specified source url and line.
-   *
-   * @param object aLocation [optional]
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   * @param array aStore [optional]
-   *        A list in which to store the corresponding breakpoints.
-   * @return array
-   *         The corresponding breakpoints if found, an empty array otherwise.
-   */
-  getOtherBreakpoints: function(aLocation = {}, aStore = []) {
-    for (let source of this) {
-      for (let breakpointItem of source) {
-        let { actor, line } = breakpointItem.attachment;
-        if (actor != aLocation.actor || line != aLocation.line) {
-          aStore.push(breakpointItem);
-        }
-      }
-    }
-    return aStore;
-  },
-
-  /**
-   * Enables a breakpoint.
-   *
-   * @param object aLocation
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   * @param object aOptions [optional]
-   *        Additional options or flags supported by this operation:
-   *          - silent: pass true to not update the checkbox checked state;
-   *                    this is usually necessary when the checked state will
-   *                    be updated automatically (e.g: on a checkbox click).
-   * @return object
-   *         A promise that is resolved after the breakpoint is enabled, or
-   *         rejected if no breakpoint was found at the specified location.
-   */
-  enableBreakpoint: function(aLocation, aOptions = {}) {
-    let breakpointItem = this.getBreakpoint(aLocation);
-    if (!breakpointItem) {
-      return promise.reject(new Error("No breakpoint found."));
-    }
-
-    // Breakpoint will now be enabled.
-    let attachment = breakpointItem.attachment;
-    attachment.disabled = false;
-
-    // Update the corresponding menu items to reflect the enabled state.
-    let prefix = "bp-cMenu-"; // "breakpoints context menu"
-    let identifier = DebuggerController.Breakpoints.getIdentifier(attachment);
-    let enableSelfId = prefix + "enableSelf-" + identifier + "-menuitem";
-    let disableSelfId = prefix + "disableSelf-" + identifier + "-menuitem";
-    document.getElementById(enableSelfId).setAttribute("hidden", "true");
-    document.getElementById(disableSelfId).removeAttribute("hidden");
-
-    // Update the breakpoint toggle button checked state.
-    this._toggleBreakpointsButton.removeAttribute("checked");
-
-    // Update the checkbox state if necessary.
-    if (!aOptions.silent) {
-      attachment.view.checkbox.setAttribute("checked", "true");
-    }
-
-    return DebuggerController.Breakpoints.addBreakpoint(aLocation, {
-      // No need to update the pane, since this method is invoked because
-      // a breakpoint's view was interacted with.
-      noPaneUpdate: true
-    });
-  },
-
-  /**
-   * Disables a breakpoint.
-   *
-   * @param object aLocation
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   * @param object aOptions [optional]
-   *        Additional options or flags supported by this operation:
-   *          - silent: pass true to not update the checkbox checked state;
-   *                    this is usually necessary when the checked state will
-   *                    be updated automatically (e.g: on a checkbox click).
-   * @return object
-   *         A promise that is resolved after the breakpoint is disabled, or
-   *         rejected if no breakpoint was found at the specified location.
-   */
-  disableBreakpoint: function(aLocation, aOptions = {}) {
-    let breakpointItem = this.getBreakpoint(aLocation);
-    if (!breakpointItem) {
-      return promise.reject(new Error("No breakpoint found."));
-    }
-
-    // Breakpoint will now be disabled.
-    let attachment = breakpointItem.attachment;
-    attachment.disabled = true;
-
-    // Update the corresponding menu items to reflect the disabled state.
-    let prefix = "bp-cMenu-"; // "breakpoints context menu"
-    let identifier = DebuggerController.Breakpoints.getIdentifier(attachment);
-    let enableSelfId = prefix + "enableSelf-" + identifier + "-menuitem";
-    let disableSelfId = prefix + "disableSelf-" + identifier + "-menuitem";
-    document.getElementById(enableSelfId).removeAttribute("hidden");
-    document.getElementById(disableSelfId).setAttribute("hidden", "true");
-
-    // Update the checkbox state if necessary.
-    if (!aOptions.silent) {
-      attachment.view.checkbox.removeAttribute("checked");
-    }
-
-    return DebuggerController.Breakpoints.removeBreakpoint(aLocation, {
-      // No need to update this pane, since this method is invoked because
-      // a breakpoint's view was interacted with.
-      noPaneUpdate: true,
-      // Mark this breakpoint as being "disabled", not completely removed.
-      // This makes sure it will not be forgotten across target navigations.
-      rememberDisabled: true
-    });
-  },
-
-  /**
-   * Highlights a breakpoint in this sources container.
-   *
-   * @param object aLocation
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   * @param object aOptions [optional]
-   *        An object containing some of the following boolean properties:
-   *          - openPopup: tells if the expression popup should be shown.
-   *          - noEditorUpdate: tells if you want to skip editor updates.
-   */
-  highlightBreakpoint: function(aLocation, aOptions = {}) {
-    let breakpointItem = this.getBreakpoint(aLocation);
-    if (!breakpointItem) {
-      return;
-    }
-
-    // Breakpoint will now be selected.
-    this._selectBreakpoint(breakpointItem);
-
-    // Update the editor location if necessary.
-    if (!aOptions.noEditorUpdate) {
-      DebuggerView.setEditorLocation(aLocation.actor, aLocation.line, { noDebug: true });
-    }
-
-    // If the breakpoint requires a new conditional expression, display
-    // the panel to input the corresponding expression.
-    if (aOptions.openPopup) {
-      this._openConditionalPopup();
-    } else {
-      this._hideConditionalPopup();
-    }
-  },
-
-  /**
-   * Highlight the breakpoint on the current currently focused line/column
-   * if it exists.
-   */
-  highlightBreakpointAtCursor: function() {
-    let actor = DebuggerView.Sources.selectedValue;
-    let line = DebuggerView.editor.getCursor().line + 1;
-
-    let location = { actor: actor, line: line };
-    this.highlightBreakpoint(location, { noEditorUpdate: true });
-  },
-
-  /**
-   * Unhighlights the current breakpoint in this sources container.
-   */
-  unhighlightBreakpoint: function() {
-    this._hideConditionalPopup();
-    this._unselectBreakpoint();
-  },
-
-  /**
-   * Display the message thrown on breakpoint condition
-   */
-  showBreakpointConditionThrownMessage: function(aLocation, aMessage = "") {
-    let breakpointItem = this.getBreakpoint(aLocation);
-    if (!breakpointItem) {
-      return;
-    }
-    let attachment = breakpointItem.attachment;
-    attachment.view.container.classList.add("dbg-breakpoint-condition-thrown");
-    attachment.view.message.setAttribute("value", aMessage);
-  },
-
-  /**
-   * Update the checked/unchecked and enabled/disabled states of the buttons in
-   * the sources toolbar based on the currently selected source's state.
-   */
-  updateToolbarButtonsState: function() {
-    const { source } = this.selectedItem.attachment;
-    const sourceClient = gThreadClient.source(source);
-
-    if (sourceClient.isBlackBoxed) {
-      this._prettyPrintButton.setAttribute("disabled", true);
-      this._blackBoxButton.setAttribute("checked", true);
-    } else {
-      this._prettyPrintButton.removeAttribute("disabled");
-      this._blackBoxButton.removeAttribute("checked");
-    }
-
-    if (sourceClient.isPrettyPrinted) {
-      this._prettyPrintButton.setAttribute("checked", true);
-    } else {
-      this._prettyPrintButton.removeAttribute("checked");
-    }
-  },
-
-  /**
-   * Toggle the pretty printing of the selected source.
-   */
-  togglePrettyPrint: Task.async(function*() {
-    if (this._prettyPrintButton.hasAttribute("disabled")) {
-      return;
-    }
-
-    const resetEditor = ([{ actor }]) => {
-      // Only set the text when the source is still selected.
-      if (actor == this.selectedValue) {
-        DebuggerView.setEditorLocation(actor, 0, { force: true });
-      }
-    };
-
-    const printError = ([{ url }, error]) => {
-      DevToolsUtils.reportException("togglePrettyPrint", error);
-    };
-
-    DebuggerView.showProgressBar();
-    const { source } = this.selectedItem.attachment;
-    const sourceClient = gThreadClient.source(source);
-    const shouldPrettyPrint = !sourceClient.isPrettyPrinted;
-
-    if (shouldPrettyPrint) {
-      this._prettyPrintButton.setAttribute("checked", true);
-    } else {
-      this._prettyPrintButton.removeAttribute("checked");
-    }
-
-    try {
-      let resolution = yield DebuggerController.SourceScripts.togglePrettyPrint(source);
-      resetEditor(resolution);
-    } catch (rejection) {
-      printError(rejection);
-    }
-
-    DebuggerView.showEditor();
-    this.updateToolbarButtonsState();
-  }),
-
-  /**
-   * Toggle the black boxed state of the selected source.
-   */
-  toggleBlackBoxing: Task.async(function*() {
-    const { source } = this.selectedItem.attachment;
-    const sourceClient = gThreadClient.source(source);
-    const shouldBlackBox = !sourceClient.isBlackBoxed;
-
-    // Be optimistic that the (un-)black boxing will succeed, so enable/disable
-    // the pretty print button and check/uncheck the black box button immediately.
-    // Then, once we actually get the results from the server, make sure that
-    // it is in the correct state again by calling `updateToolbarButtonsState`.
-
-    if (shouldBlackBox) {
-      this._prettyPrintButton.setAttribute("disabled", true);
-      this._blackBoxButton.setAttribute("checked", true);
-    } else {
-      this._prettyPrintButton.removeAttribute("disabled");
-      this._blackBoxButton.removeAttribute("checked");
-    }
-
-    try {
-      yield DebuggerController.SourceScripts.setBlackBoxing(source, shouldBlackBox);
-    } catch (e) {
-      // Continue execution in this task even if blackboxing failed.
-    }
-
-    this.updateToolbarButtonsState();
-  }),
-
-  /**
-   * Toggles all breakpoints enabled/disabled.
-   */
-  toggleBreakpoints: function() {
-    let breakpoints = this.getAllBreakpoints();
-    let hasBreakpoints = breakpoints.length > 0;
-    let hasEnabledBreakpoints = breakpoints.some(e => !e.attachment.disabled);
-
-    if (hasBreakpoints && hasEnabledBreakpoints) {
-      this._toggleBreakpointsButton.setAttribute("checked", true);
-      this._onDisableAll();
-    } else {
-      this._toggleBreakpointsButton.removeAttribute("checked");
-      this._onEnableAll();
-    }
-  },
-
-  hidePrettyPrinting: function() {
-    this._prettyPrintButton.style.display = 'none';
-
-    if (this._blackBoxButton.style.display === 'none') {
-      let sep = document.querySelector('#sources-toolbar .devtools-separator');
-      sep.style.display = 'none';
-    }
-  },
-
-  hideBlackBoxing: function() {
-    this._blackBoxButton.style.display = 'none';
-
-    if (this._prettyPrintButton.style.display === 'none') {
-      let sep = document.querySelector('#sources-toolbar .devtools-separator');
-      sep.style.display = 'none';
-    }
-  },
-
-  /**
-   * Look up a source actor id for a location. This is necessary for
-   * backwards compatibility; otherwise we could just use the `actor`
-   * property. Older servers don't use the same actor ids for sources
-   * across reloads, so we resolve a url to the current actor if a url
-   * exists.
-   *
-   * @param object aLocation
-   *        An object with the following properties:
-   *        - actor: the source actor id
-   *        - url: a url (might be null)
-   */
-  getActorForLocation: function(aLocation) {
-    if (aLocation.url) {
-      for (var item of this) {
-        let source = item.attachment.source;
-
-        if (aLocation.url === source.url) {
-          return source.actor;
-        }
-      }
-    }
-    return aLocation.actor;
-  },
-
-  /**
-   * Marks a breakpoint as selected in this sources container.
-   *
-   * @param object aItem
-   *        The breakpoint item to select.
-   */
-  _selectBreakpoint: function(aItem) {
-    if (this._selectedBreakpointItem == aItem) {
-      return;
-    }
-    this._unselectBreakpoint();
-
-    this._selectedBreakpointItem = aItem;
-    this._selectedBreakpointItem.target.classList.add("selected");
-
-    // Ensure the currently selected breakpoint is visible.
-    this.widget.ensureElementIsVisible(aItem.target);
-  },
-
-  /**
-   * Marks the current breakpoint as unselected in this sources container.
-   */
-  _unselectBreakpoint: function() {
-    if (!this._selectedBreakpointItem) {
-      return;
-    }
-    this._selectedBreakpointItem.target.classList.remove("selected");
-    this._selectedBreakpointItem = null;
-  },
-
-  /**
-   * Opens a conditional breakpoint's expression input popup.
-   */
-  _openConditionalPopup: function() {
-    let breakpointItem = this._selectedBreakpointItem;
-    let attachment = breakpointItem.attachment;
-    // Check if this is an enabled conditional breakpoint, and if so,
-    // retrieve the current conditional epression.
-    let breakpointPromise = DebuggerController.Breakpoints._getAdded(attachment);
-    if (breakpointPromise) {
-      breakpointPromise.then(aBreakpointClient => {
-        let isConditionalBreakpoint = aBreakpointClient.hasCondition();
-        let condition = aBreakpointClient.getCondition();
-        doOpen.call(this, isConditionalBreakpoint ? condition : "")
-      });
-    } else {
-      doOpen.call(this, "")
-    }
-
-    function doOpen(aConditionalExpression) {
-      // Update the conditional expression textbox. If no expression was
-      // previously set, revert to using an empty string by default.
-      this._cbTextbox.value = aConditionalExpression;
-
-      // Show the conditional expression panel. The popup arrow should be pointing
-      // at the line number node in the breakpoint item view.
-      this._cbPanel.hidden = false;
-      this._cbPanel.openPopup(breakpointItem.attachment.view.lineNumber,
-        BREAKPOINT_CONDITIONAL_POPUP_POSITION,
-        BREAKPOINT_CONDITIONAL_POPUP_OFFSET_X,
-        BREAKPOINT_CONDITIONAL_POPUP_OFFSET_Y);
-    }
-  },
-
-  /**
-   * Hides a conditional breakpoint's expression input popup.
-   */
-  _hideConditionalPopup: function() {
-    this._cbPanel.hidden = true;
-
-    // Sometimes this._cbPanel doesn't have hidePopup method which doesn't
-    // break anything but simply outputs an exception to the console.
-    if (this._cbPanel.hidePopup) {
-      this._cbPanel.hidePopup();
-    }
-  },
-
-  /**
-   * Customization function for creating a breakpoint item's UI.
-   *
-   * @param object aOptions
-   *        A couple of options or flags supported by this operation:
-   *          - location: the breakpoint's source location and line number
-   *          - disabled: the breakpoint's disabled state, boolean
-   *          - text: the breakpoint's line text to be displayed
-   *          - message: thrown string when the breakpoint condition throws,
-   * @return object
-   *         An object containing the breakpoint container, checkbox,
-   *         line number and line text nodes.
-   */
-  _createBreakpointView: function(aOptions) {
-    let { location, disabled, text, message } = aOptions;
-    let identifier = DebuggerController.Breakpoints.getIdentifier(location);
-
-    let checkbox = document.createElement("checkbox");
-    checkbox.setAttribute("checked", !disabled);
-    checkbox.className = "dbg-breakpoint-checkbox";
-
-    let lineNumberNode = document.createElement("label");
-    lineNumberNode.className = "plain dbg-breakpoint-line";
-    lineNumberNode.setAttribute("value", location.line);
-
-    let lineTextNode = document.createElement("label");
-    lineTextNode.className = "plain dbg-breakpoint-text";
-    lineTextNode.setAttribute("value", text);
-    lineTextNode.setAttribute("crop", "end");
-    lineTextNode.setAttribute("flex", "1");
-
-    let tooltip = text ? text.substr(0, BREAKPOINT_LINE_TOOLTIP_MAX_LENGTH) : "";
-    lineTextNode.setAttribute("tooltiptext", tooltip);
-
-    let thrownNode = document.createElement("label");
-    thrownNode.className = "plain dbg-breakpoint-condition-thrown-message dbg-breakpoint-text";
-    thrownNode.setAttribute("value", message);
-    thrownNode.setAttribute("crop", "end");
-    thrownNode.setAttribute("flex", "1");
-
-    let bpLineContainer = document.createElement("hbox");
-    bpLineContainer.className = "plain dbg-breakpoint-line-container";
-    bpLineContainer.setAttribute("flex", "1");
-
-    bpLineContainer.appendChild(lineNumberNode);
-    bpLineContainer.appendChild(lineTextNode);
-
-    let bpDetailContainer = document.createElement("vbox");
-    bpDetailContainer.className = "plain dbg-breakpoint-detail-container";
-    bpDetailContainer.setAttribute("flex", "1");
-
-    bpDetailContainer.appendChild(bpLineContainer);
-    bpDetailContainer.appendChild(thrownNode);
-
-    let container = document.createElement("hbox");
-    container.id = "breakpoint-" + identifier;
-    container.className = "dbg-breakpoint side-menu-widget-item-other";
-    container.classList.add("devtools-monospace");
-    container.setAttribute("align", "center");
-    container.setAttribute("flex", "1");
-
-    container.addEventListener("click", this._onBreakpointClick, false);
-    checkbox.addEventListener("click", this._onBreakpointCheckboxClick, false);
-
-    container.appendChild(checkbox);
-    container.appendChild(bpDetailContainer);
-
-    return {
-      container: container,
-      checkbox: checkbox,
-      lineNumber: lineNumberNode,
-      lineText: lineTextNode,
-      message: thrownNode
-    };
-  },
-
-  /**
-   * Creates a context menu for a breakpoint element.
-   *
-   * @param object aOptions
-   *        A couple of options or flags supported by this operation:
-   *          - location: the breakpoint's source location and line number
-   *          - disabled: the breakpoint's disabled state, boolean
-   * @return object
-   *         An object containing the breakpoint commandset and menu popup ids.
-   */
-  _createContextMenu: function(aOptions) {
-    let { location, disabled } = aOptions;
-    let identifier = DebuggerController.Breakpoints.getIdentifier(location);
-
-    let commandset = document.createElement("commandset");
-    let menupopup = document.createElement("menupopup");
-    commandset.id = "bp-cSet-" + identifier;
-    menupopup.id = "bp-mPop-" + identifier;
-
-    createMenuItem.call(this, "enableSelf", !disabled);
-    createMenuItem.call(this, "disableSelf", disabled);
-    createMenuItem.call(this, "deleteSelf");
-    createMenuSeparator();
-    createMenuItem.call(this, "setConditional");
-    createMenuSeparator();
-    createMenuItem.call(this, "enableOthers");
-    createMenuItem.call(this, "disableOthers");
-    createMenuItem.call(this, "deleteOthers");
-    createMenuSeparator();
-    createMenuItem.call(this, "enableAll");
-    createMenuItem.call(this, "disableAll");
-    createMenuSeparator();
-    createMenuItem.call(this, "deleteAll");
-
-    this._popupset.appendChild(menupopup);
-    this._commandset.appendChild(commandset);
-
-    return {
-      commandsetId: commandset.id,
-      menupopupId: menupopup.id
-    };
-
-    /**
-     * Creates a menu item specified by a name with the appropriate attributes
-     * (label and handler).
-     *
-     * @param string aName
-     *        A global identifier for the menu item.
-     * @param boolean aHiddenFlag
-     *        True if this menuitem should be hidden.
-     */
-    function createMenuItem(aName, aHiddenFlag) {
-      let menuitem = document.createElement("menuitem");
-      let command = document.createElement("command");
-
-      let prefix = "bp-cMenu-"; // "breakpoints context menu"
-      let commandId = prefix + aName + "-" + identifier + "-command";
-      let menuitemId = prefix + aName + "-" + identifier + "-menuitem";
-
-      let label = L10N.getStr("breakpointMenuItem." + aName);
-      let func = "_on" + aName.charAt(0).toUpperCase() + aName.slice(1);
-
-      command.id = commandId;
-      command.setAttribute("label", label);
-      command.addEventListener("command", () => this[func](location), false);
-
-      menuitem.id = menuitemId;
-      menuitem.setAttribute("command", commandId);
-      aHiddenFlag && menuitem.setAttribute("hidden", "true");
-
-      commandset.appendChild(command);
-      menupopup.appendChild(menuitem);
-    }
-
-    /**
-     * Creates a simple menu separator element and appends it to the current
-     * menupopup hierarchy.
-     */
-    function createMenuSeparator() {
-      let menuseparator = document.createElement("menuseparator");
-      menupopup.appendChild(menuseparator);
-    }
-  },
-
-  /**
-   * Copy the source url from the currently selected item.
-   */
-  _onCopyUrlCommand: function() {
-    let selected = this.selectedItem && this.selectedItem.attachment;
-    if (!selected) {
-      return;
-    }
-    clipboardHelper.copyString(selected.source.url, document);
-  },
-
-  /**
-   * Opens selected item source in a new tab.
-   */
-  _onNewTabCommand: function() {
-    let win = Services.wm.getMostRecentWindow("navigator:browser");
-    let selected = this.selectedItem.attachment;
-    win.openUILinkIn(selected.source.url, "tab", { relatedToCurrent: true });
-  },
-
-  /**
-   * Function called each time a breakpoint item is removed.
-   *
-   * @param object aItem
-   *        The corresponding item.
-   */
-  _onBreakpointRemoved: function(aItem) {
-    dumpn("Finalizing breakpoint item: " + aItem.stringify());
-
-    // Destroy the context menu for the breakpoint.
-    let contextMenu = aItem.attachment.popup;
-    document.getElementById(contextMenu.commandsetId).remove();
-    document.getElementById(contextMenu.menupopupId).remove();
-
-    // Clear the breakpoint selection.
-    if (this._selectedBreakpointItem == aItem) {
-      this._selectedBreakpointItem = null;
-    }
-  },
-
-  /**
-   * The load listener for the source editor.
-   */
-  _onEditorLoad: function(aName, aEditor) {
-    aEditor.on("cursorActivity", this._onEditorCursorActivity);
-  },
-
-  /**
-   * The unload listener for the source editor.
-   */
-  _onEditorUnload: function(aName, aEditor) {
-    aEditor.off("cursorActivity", this._onEditorCursorActivity);
-  },
-
-  /**
-   * The selection listener for the source editor.
-   */
-  _onEditorCursorActivity: function(e) {
-    let editor = DebuggerView.editor;
-    let start  = editor.getCursor("start").line + 1;
-    let end    = editor.getCursor().line + 1;
-    let actor    = this.selectedValue;
-
-    let location = { actor: actor, line: start };
-
-    if (this.getBreakpoint(location) && start == end) {
-      this.highlightBreakpoint(location, { noEditorUpdate: true });
-    } else {
-      this.unhighlightBreakpoint();
-    }
-  },
-
-  /**
-   * The select listener for the sources container.
-   */
-  _onSourceSelect: Task.async(function*({ detail: sourceItem }) {
-    if (!sourceItem) {
-      return;
-    }
-    const { source } = sourceItem.attachment;
-    const sourceClient = gThreadClient.source(source);
-
-    // The container is not empty and an actual item was selected.
-    DebuggerView.setEditorLocation(sourceItem.value);
-
-    // Attempt to automatically pretty print minified source code.
-    if (Prefs.autoPrettyPrint && !sourceClient.isPrettyPrinted) {
-      let isMinified = yield SourceUtils.isMinified(sourceClient);
-      if (isMinified) {
-        this.togglePrettyPrint();
-      }
-    }
-
-    // Set window title. No need to split the url by " -> " here, because it was
-    // already sanitized when the source was added.
-    document.title = L10N.getFormatStr("DebuggerWindowScriptTitle",
-                                       sourceItem.attachment.source.url);
-
-    DebuggerView.maybeShowBlackBoxMessage();
-    this.updateToolbarButtonsState();
-  }),
-
-  /**
-   * The click listener for the "stop black boxing" button.
-   */
-  _onStopBlackBoxing: Task.async(function*() {
-    const { source } = this.selectedItem.attachment;
-
-    try {
-      yield DebuggerController.SourceScripts.setBlackBoxing(source, false);
-    } catch (e) {
-      // Continue execution in this task even if blackboxing failed.
-    }
-
-    this.updateToolbarButtonsState();
-  }),
-
-  /**
-   * The click listener for a breakpoint container.
-   */
-  _onBreakpointClick: function(e) {
-    let sourceItem = this.getItemForElement(e.target);
-    let breakpointItem = this.getItemForElement.call(sourceItem, e.target);
-    let attachment = breakpointItem.attachment;
-
-    // Check if this is an enabled conditional breakpoint.
-    let breakpointPromise = DebuggerController.Breakpoints._getAdded(attachment);
-    if (breakpointPromise) {
-      breakpointPromise.then(aBreakpointClient => {
-        doHighlight.call(this, aBreakpointClient.hasCondition());
-      });
-    } else {
-      doHighlight.call(this, false);
-    }
-
-    function doHighlight(aConditionalBreakpointFlag) {
-      // Highlight the breakpoint in this pane and in the editor.
-      this.highlightBreakpoint(attachment, {
-        // Don't show the conditional expression popup if this is not a
-        // conditional breakpoint, or the right mouse button was pressed (to
-        // avoid clashing the popup with the context menu).
-        openPopup: aConditionalBreakpointFlag && e.button == 0
-      });
-    }
-  },
-
-  /**
-   * The click listener for a breakpoint checkbox.
-   */
-  _onBreakpointCheckboxClick: function(e) {
-    let sourceItem = this.getItemForElement(e.target);
-    let breakpointItem = this.getItemForElement.call(sourceItem, e.target);
-    let attachment = breakpointItem.attachment;
-
-    // Toggle the breakpoint enabled or disabled.
-    this[attachment.disabled ? "enableBreakpoint" : "disableBreakpoint"](attachment, {
-      // Do this silently (don't update the checkbox checked state), since
-      // this listener is triggered because a checkbox was already clicked.
-      silent: true
-    });
-
-    // Don't update the editor location (avoid propagating into _onBreakpointClick).
-    e.preventDefault();
-    e.stopPropagation();
-  },
-
-  /**
-   * The popup showing listener for the breakpoints conditional expression panel.
-   */
-  _onConditionalPopupShowing: function() {
-    this._conditionalPopupVisible = true; // Used in tests.
-    window.emit(EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWING);
-  },
-
-  /**
-   * The popup shown listener for the breakpoints conditional expression panel.
-   */
-  _onConditionalPopupShown: function() {
-    this._cbTextbox.focus();
-    this._cbTextbox.select();
-  },
-
-  /**
-   * The popup hiding listener for the breakpoints conditional expression panel.
-   */
-  _onConditionalPopupHiding: Task.async(function*() {
-    this._conditionalPopupVisible = false; // Used in tests.
-
-    let breakpointItem = this._selectedBreakpointItem;
-    let attachment = breakpointItem.attachment;
-
-    // Check if this is an enabled conditional breakpoint, and if so,
-    // save the current conditional expression.
-    let breakpointPromise = DebuggerController.Breakpoints._getAdded(attachment);
-    if (breakpointPromise) {
-      let { location } = yield breakpointPromise;
-      let condition = this._cbTextbox.value;
-      yield DebuggerController.Breakpoints.updateCondition(location, condition);
-    }
-
-    window.emit(EVENTS.CONDITIONAL_BREAKPOINT_POPUP_HIDING);
-  }),
-
-  /**
-   * The keypress listener for the breakpoints conditional expression textbox.
-   */
-  _onConditionalTextboxKeyPress: function(e) {
-    if (e.keyCode == e.DOM_VK_RETURN) {
-      this._hideConditionalPopup();
-    }
-  },
-
-  /**
-   * Called when the add breakpoint key sequence was pressed.
-   */
-  _onCmdAddBreakpoint: function(e) {
-    let actor = DebuggerView.Sources.selectedValue;
-    let line = (e && e.sourceEvent.target.tagName == 'menuitem' ?
-                DebuggerView.clickedLine + 1 :
-                DebuggerView.editor.getCursor().line + 1);
-    let location = { actor, line };
-    let breakpointItem = this.getBreakpoint(location);
-
-    // If a breakpoint already existed, remove it now.
-    if (breakpointItem) {
-      DebuggerController.Breakpoints.removeBreakpoint(location);
-    }
-    // No breakpoint existed at the required location, add one now.
-    else {
-      DebuggerController.Breakpoints.addBreakpoint(location);
-    }
-  },
-
-  /**
-   * Called when the add conditional breakpoint key sequence was pressed.
-   */
-  _onCmdAddConditionalBreakpoint: function(e) {
-    let actor = DebuggerView.Sources.selectedValue;
-    let line = (e && e.sourceEvent.target.tagName == 'menuitem' ?
-                DebuggerView.clickedLine + 1 :
-                DebuggerView.editor.getCursor().line + 1);
-    let location = { actor, line };
-    let breakpointItem = this.getBreakpoint(location);
-
-    // If a breakpoint already existed or wasn't a conditional, morph it now.
-    if (breakpointItem) {
-      this.highlightBreakpoint(location, { openPopup: true });
-    }
-    // No breakpoint existed at the required location, add one now.
-    else {
-      DebuggerController.Breakpoints.addBreakpoint(location, { openPopup: true });
-    }
-  },
-
-  /**
-   * Function invoked on the "setConditional" menuitem command.
-   *
-   * @param object aLocation
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   */
-  _onSetConditional: function(aLocation) {
-    // Highlight the breakpoint and show a conditional expression popup.
-    this.highlightBreakpoint(aLocation, { openPopup: true });
-  },
-
-  /**
-   * Function invoked on the "enableSelf" menuitem command.
-   *
-   * @param object aLocation
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   */
-  _onEnableSelf: function(aLocation) {
-    // Enable the breakpoint, in this container and the controller store.
-    this.enableBreakpoint(aLocation);
-  },
-
-  /**
-   * Function invoked on the "disableSelf" menuitem command.
-   *
-   * @param object aLocation
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   */
-  _onDisableSelf: function(aLocation) {
-    // Disable the breakpoint, in this container and the controller store.
-    this.disableBreakpoint(aLocation);
-  },
-
-  /**
-   * Function invoked on the "deleteSelf" menuitem command.
-   *
-   * @param object aLocation
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   */
-  _onDeleteSelf: function(aLocation) {
-    // Remove the breakpoint, from this container and the controller store.
-    this.removeBreakpoint(aLocation);
-    DebuggerController.Breakpoints.removeBreakpoint(aLocation);
-  },
-
-  /**
-   * Function invoked on the "enableOthers" menuitem command.
-   *
-   * @param object aLocation
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   */
-  _onEnableOthers: function(aLocation) {
-    let enableOthers = aCallback => {
-      let other = this.getOtherBreakpoints(aLocation);
-      let outstanding = other.map(e => this.enableBreakpoint(e.attachment));
-      promise.all(outstanding).then(aCallback);
-    }
-
-    // Breakpoints can only be set while the debuggee is paused. To avoid
-    // an avalanche of pause/resume interrupts of the main thread, simply
-    // pause it beforehand if it's not already.
-    if (gThreadClient.state != "paused") {
-      gThreadClient.interrupt(() => enableOthers(() => gThreadClient.resume()));
-    } else {
-      enableOthers();
-    }
-  },
-
-  /**
-   * Function invoked on the "disableOthers" menuitem command.
-   *
-   * @param object aLocation
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   */
-  _onDisableOthers: function(aLocation) {
-    let other = this.getOtherBreakpoints(aLocation);
-    other.forEach(e => this._onDisableSelf(e.attachment));
-  },
-
-  /**
-   * Function invoked on the "deleteOthers" menuitem command.
-   *
-   * @param object aLocation
-   *        @see DebuggerController.Breakpoints.addBreakpoint
-   */
-  _onDeleteOthers: function(aLocation) {
-    let other = this.getOtherBreakpoints(aLocation);
-    other.forEach(e => this._onDeleteSelf(e.attachment));
-  },
-
-  /**
-   * Function invoked on the "enableAll" menuitem command.
-   */
-  _onEnableAll: function() {
-    this._onEnableOthers(undefined);
-  },
-
-  /**
-   * Function invoked on the "disableAll" menuitem command.
-   */
-  _onDisableAll: function() {
-    this._onDisableOthers(undefined);
-  },
-
-  /**
-   * Function invoked on the "deleteAll" menuitem command.
-   */
-  _onDeleteAll: function() {
-    this._onDeleteOthers(undefined);
-  },
-
-  _commandset: null,
-  _popupset: null,
-  _cmPopup: null,
-  _cbPanel: null,
-  _cbTextbox: null,
-  _selectedBreakpointItem: null,
-  _conditionalPopupVisible: false
-});
-
-/**
- * Functions handling the traces UI.
- */
-function TracerView() {
-  this._selectedItem = null;
-  this._matchingItems = null;
-  this.widget = null;
-
-  this._highlightItem = this._highlightItem.bind(this);
-  this._isNotSelectedItem = this._isNotSelectedItem.bind(this);
-
-  this._unhighlightMatchingItems =
-    DevToolsUtils.makeInfallible(this._unhighlightMatchingItems.bind(this));
-  this._onToggleTracing =
-    DevToolsUtils.makeInfallible(this._onToggleTracing.bind(this));
-  this._onStartTracing =
-    DevToolsUtils.makeInfallible(this._onStartTracing.bind(this));
-  this._onClear =
-    DevToolsUtils.makeInfallible(this._onClear.bind(this));
-  this._onSelect =
-    DevToolsUtils.makeInfallible(this._onSelect.bind(this));
-  this._onMouseOver =
-    DevToolsUtils.makeInfallible(this._onMouseOver.bind(this));
-  this._onSearch =
-    DevToolsUtils.makeInfallible(this._onSearch.bind(this));
-}
-
-TracerView.MAX_TRACES = 200;
-
-TracerView.prototype = Heritage.extend(WidgetMethods, {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the TracerView");
-
-    this._traceButton = document.getElementById("trace");
-    this._tracerTab = document.getElementById("tracer-tab");
-
-    // Remove tracer related elements from the dom and tear everything down if
-    // the tracer isn't enabled.
-    if (!Prefs.tracerEnabled) {
-      this._traceButton.remove();
-      this._traceButton = null;
-      this._tracerTab.remove();
-      this._tracerTab = null;
-      return;
-    }
-
-    this.widget = new FastListWidget(document.getElementById("tracer-traces"));
-    this._traceButton.removeAttribute("hidden");
-    this._tracerTab.removeAttribute("hidden");
-
-    this._search = document.getElementById("tracer-search");
-    this._template = document.getElementsByClassName("trace-item-template")[0];
-    this._templateItem = this._template.getElementsByClassName("trace-item")[0];
-    this._templateTypeIcon = this._template.getElementsByClassName("trace-type")[0];
-    this._templateNameNode = this._template.getElementsByClassName("trace-name")[0];
-
-    this.widget.addEventListener("select", this._onSelect, false);
-    this.widget.addEventListener("mouseover", this._onMouseOver, false);
-    this.widget.addEventListener("mouseout", this._unhighlightMatchingItems, false);
-    this._search.addEventListener("input", this._onSearch, false);
-
-    this._startTooltip = L10N.getStr("startTracingTooltip");
-    this._stopTooltip = L10N.getStr("stopTracingTooltip");
-    this._tracingNotStartedString = L10N.getStr("tracingNotStartedText");
-    this._noFunctionCallsString = L10N.getStr("noFunctionCallsText");
-
-    this._traceButton.setAttribute("tooltiptext", this._startTooltip);
-    this.emptyText = this._tracingNotStartedString;
-
-    this._addCommands();
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the TracerView");
-
-    if (!this.widget) {
-      return;
-    }
-
-    this.widget.removeEventListener("select", this._onSelect, false);
-    this.widget.removeEventListener("mouseover", this._onMouseOver, false);
-    this.widget.removeEventListener("mouseout", this._unhighlightMatchingItems, false);
-    this._search.removeEventListener("input", this._onSearch, false);
-  },
-
-  /**
-   * Add commands that XUL can fire.
-   */
-  _addCommands: function() {
-    utils.addCommands(document.getElementById('debuggerCommands'), {
-      toggleTracing: () => this._onToggleTracing(),
-      startTracing: () => this._onStartTracing(),
-      clearTraces: () => this._onClear()
-    });
-  },
-
-  /**
-   * Function invoked by the "toggleTracing" command to switch the tracer state.
-   */
-  _onToggleTracing: function() {
-    if (DebuggerController.Tracer.tracing) {
-      this._onStopTracing();
-    } else {
-      this._onStartTracing();
-    }
-  },
-
-  /**
-   * Function invoked either by the "startTracing" command or by
-   * _onToggleTracing to start execution tracing in the backend.
-   *
-   * @return object
-   *         A promise resolved once the tracing has successfully started.
-   */
-  _onStartTracing: function() {
-    this._traceButton.setAttribute("checked", true);
-    this._traceButton.setAttribute("tooltiptext", this._stopTooltip);
-
-    this.empty();
-    this.emptyText = this._noFunctionCallsString;
-
-    let deferred = promise.defer();
-    DebuggerController.Tracer.startTracing(deferred.resolve);
-    return deferred.promise;
-  },
-
-  /**
-   * Function invoked by _onToggleTracing to stop execution tracing in the
-   * backend.
-   *
-   * @return object
-   *         A promise resolved once the tracing has successfully stopped.
-   */
-  _onStopTracing: function() {
-    this._traceButton.removeAttribute("checked");
-    this._traceButton.setAttribute("tooltiptext", this._startTooltip);
-
-    this.emptyText = this._tracingNotStartedString;
-
-    let deferred = promise.defer();
-    DebuggerController.Tracer.stopTracing(deferred.resolve);
-    return deferred.promise;
-  },
-
-  /**
-   * Function invoked by the "clearTraces" command to empty the traces pane.
-   */
-  _onClear: function() {
-    this.empty();
-  },
-
-  /**
-   * Populate the given parent scope with the variable with the provided name
-   * and value.
-   *
-   * @param String aName
-   *        The name of the variable.
-   * @param Object aParent
-   *        The parent scope.
-   * @param Object aValue
-   *        The value of the variable.
-   */
-  _populateVariable: function(aName, aParent, aValue) {
-    let item = aParent.addItem(aName, { value: aValue });
-
-    if (aValue) {
-      let wrappedValue = new DebuggerController.Tracer.WrappedObject(aValue);
-      DebuggerView.Variables.controller.populate(item, wrappedValue);
-      item.expand();
-      item.twisty = false;
-    }
-  },
-
-  /**
-   * Handler for the widget's "select" event. Displays parameters, exception, or
-   * return value depending on whether the selected trace is a call, throw, or
-   * return respectively.
-   *
-   * @param Object traceItem
-   *        The selected trace item.
-   */
-  _onSelect: function _onSelect({ detail: traceItem }) {
-    if (!traceItem) {
-      return;
-    }
-
-    const data = traceItem.attachment.trace;
-    const { location: { url, line } } = data;
-    DebuggerView.setEditorLocation(
-      DebuggerView.Sources.getActorForLocation({ url }),
-      line,
-      { noDebug: true }
-    );
-
-    DebuggerView.Variables.empty();
-    const scope = DebuggerView.Variables.addScope();
-
-    if (data.type == "call") {
-      const params = DevToolsUtils.zip(data.parameterNames, data.arguments);
-      for (let [name, val] of params) {
-        if (val === undefined) {
-          scope.addItem(name, { value: "<value not available>" });
-        } else {
-          this._populateVariable(name, scope, val);
-        }
-      }
-    } else {
-      const varName = "<" + (data.type == "throw" ? "exception" : data.type) + ">";
-      this._populateVariable(varName, scope, data.returnVal);
-    }
-
-    scope.expand();
-    DebuggerView.showInstrumentsPane();
-  },
-
-  /**
-   * Add the hover frame enter/exit highlighting to a given item.
-   */
-  _highlightItem: function(aItem) {
-    if (!aItem || !aItem.target) {
-      return;
-    }
-    const trace = aItem.target.querySelector(".trace-item");
-    trace.classList.add("selected-matching");
-  },
-
-  /**
-   * Remove the hover frame enter/exit highlighting to a given item.
-   */
-  _unhighlightItem: function(aItem) {
-    if (!aItem || !aItem.target) {
-      return;
-    }
-    const match = aItem.target.querySelector(".selected-matching");
-    if (match) {
-      match.classList.remove("selected-matching");
-    }
-  },
-
-  /**
-   * Remove the frame enter/exit pair highlighting we do when hovering.
-   */
-  _unhighlightMatchingItems: function() {
-    if (this._matchingItems) {
-      this._matchingItems.forEach(this._unhighlightItem);
-      this._matchingItems = null;
-    }
-  },
-
-  /**
-   * Returns true if the given item is not the selected item.
-   */
-  _isNotSelectedItem: function(aItem) {
-    return aItem !== this.selectedItem;
-  },
-
-  /**
-   * Highlight the frame enter/exit pair of items for the given item.
-   */
-  _highlightMatchingItems: function(aItem) {
-    const frameId = aItem.attachment.trace.frameId;
-    const predicate = e => e.attachment.trace.frameId == frameId;
-
-    this._unhighlightMatchingItems();
-    this._matchingItems = this.items.filter(predicate);
-    this._matchingItems
-      .filter(this._isNotSelectedItem)
-      .forEach(this._highlightItem);
-  },
-
-  /**
-   * Listener for the mouseover event.
-   */
-  _onMouseOver: function({ target }) {
-    const traceItem = this.getItemForElement(target);
-    if (traceItem) {
-      this._highlightMatchingItems(traceItem);
-    }
-  },
-
-  /**
-   * Listener for typing in the search box.
-   */
-  _onSearch: function() {
-    const query = this._search.value.trim().toLowerCase();
-    const predicate = name => name.toLowerCase().contains(query);
-    this.filterContents(item => predicate(item.attachment.trace.name));
-  },
-
-  /**
-   * Select the traces tab in the sidebar.
-   */
-  selectTab: function() {
-    const tabs = this._tracerTab.parentElement;
-    tabs.selectedIndex = Array.indexOf(tabs.children, this._tracerTab);
-  },
-
-  /**
-   * Commit all staged items to the widget. Overridden so that we can call
-   * |FastListWidget.prototype.flush|.
-   */
-  commit: function() {
-    WidgetMethods.commit.call(this);
-    // TODO: Accessing non-standard widget properties. Figure out what's the
-    // best way to expose such things. Bug 895514.
-    this.widget.flush();
-  },
-
-  /**
-   * Adds the trace record provided as an argument to the view.
-   *
-   * @param object aTrace
-   *        The trace record coming from the tracer actor.
-   */
-  addTrace: function(aTrace) {
-    // Create the element node for the trace item.
-    let view = this._createView(aTrace);
-
-    // Append a source item to this container.
-    this.push([view], {
-      staged: true,
-      attachment: {
-        trace: aTrace
-      }
-    });
-  },
-
-  /**
-   * Customization function for creating an item's UI.
-   *
-   * @return nsIDOMNode
-   *         The network request view.
-   */
-  _createView: function(aTrace) {
-    let { type, name, location, blackBoxed, depth, frameId } = aTrace;
-    let { parameterNames, returnVal, arguments: args } = aTrace;
-    let fragment = document.createDocumentFragment();
-
-    this._templateItem.classList.toggle("black-boxed", blackBoxed);
-    this._templateItem.setAttribute("tooltiptext", SourceUtils.trimUrl(location.url));
-    this._templateItem.style.MozPaddingStart = depth + "em";
-
-    const TYPES = ["call", "yield", "return", "throw"];
-    for (let t of TYPES) {
-      this._templateTypeIcon.classList.toggle("trace-" + t, t == type);
-    }
-    this._templateTypeIcon.setAttribute("value", {
-      call: "\u2192",
-      yield: "Y",
-      return: "\u2190",
-      throw: "E",
-      terminated: "TERMINATED"
-    }[type]);
-
-    this._templateNameNode.setAttribute("value", name);
-
-    // All extra syntax and parameter nodes added.
-    const addedNodes = [];
-
-    if (parameterNames) {
-      const syntax = (p) => {
-        const el = document.createElement("label");
-        el.setAttribute("value", p);
-        el.classList.add("trace-syntax");
-        el.classList.add("plain");
-        addedNodes.push(el);
-        return el;
-      };
-
-      this._templateItem.appendChild(syntax("("));
-
-      for (let i = 0, n = parameterNames.length; i < n; i++) {
-        let param = document.createElement("label");
-        param.setAttribute("value", parameterNames[i]);
-        param.classList.add("trace-param");
-        param.classList.add("plain");
-        addedNodes.push(param);
-        this._templateItem.appendChild(param);
-
-        if (i + 1 !== n) {
-          this._templateItem.appendChild(syntax(", "));
-        }
-      }
-
-      this._templateItem.appendChild(syntax(")"));
-    }
-
-    // Flatten the DOM by removing one redundant box (the template container).
-    for (let node of this._template.childNodes) {
-      fragment.appendChild(node.cloneNode(true));
-    }
-
-    // Remove any added nodes from the template.
-    for (let node of addedNodes) {
-      this._templateItem.removeChild(node);
-    }
-
-    return fragment;
-  }
-});
-
-/**
- * Utility functions for handling sources.
- */
-let SourceUtils = {
-  _labelsCache: new Map(), // Can't use WeakMaps because keys are strings.
-  _groupsCache: new Map(),
-  _minifiedCache: new WeakMap(),
-
-  /**
-   * Returns true if the specified url and/or content type are specific to
-   * javascript files.
-   *
-   * @return boolean
-   *         True if the source is likely javascript.
-   */
-  isJavaScript: function(aUrl, aContentType = "") {
-    return (aUrl && /\.jsm?$/.test(this.trimUrlQuery(aUrl))) ||
-           aContentType.contains("javascript");
-  },
-
-  /**
-   * Determines if the source text is minified by using
-   * the percentage indented of a subset of lines
-   *
-   * @return object
-   *         A promise that resolves to true if source text is minified.
-   */
-  isMinified: Task.async(function*(sourceClient) {
-    if (this._minifiedCache.has(sourceClient)) {
-      return this._minifiedCache.get(sourceClient);
-    }
-
-    let [, text] = yield DebuggerController.SourceScripts.getText(sourceClient);
-    let isMinified;
-    let lineEndIndex = 0;
-    let lineStartIndex = 0;
-    let lines = 0;
-    let indentCount = 0;
-    let overCharLimit = false;
-
-    // Strip comments.
-    text = text.replace(/\/\*[\S\s]*?\*\/|\/\/(.+|\n)/g, "");
-
-    while (lines++ < SAMPLE_SIZE) {
-      lineEndIndex = text.indexOf("\n", lineStartIndex);
-      if (lineEndIndex == -1) {
-         break;
-      }
-      if (/^\s+/.test(text.slice(lineStartIndex, lineEndIndex))) {
-        indentCount++;
-      }
-      // For files with no indents but are not minified.
-      if ((lineEndIndex - lineStartIndex) > CHARACTER_LIMIT) {
-        overCharLimit = true;
-        break;
-      }
-      lineStartIndex = lineEndIndex + 1;
-    }
-
-    isMinified =
-      ((indentCount / lines) * 100) < INDENT_COUNT_THRESHOLD || overCharLimit;
-
-    this._minifiedCache.set(sourceClient, isMinified);
-    return isMinified;
-  }),
-
-  /**
-   * Clears the labels, groups and minify cache, populated by methods like
-   * SourceUtils.getSourceLabel or Source Utils.getSourceGroup.
-   * This should be done every time the content location changes.
-   */
-  clearCache: function() {
-    this._labelsCache.clear();
-    this._groupsCache.clear();
-    this._minifiedCache.clear();
-  },
-
-  /**
-   * Gets a unique, simplified label from a source url.
-   *
-   * @param string aUrl
-   *        The source url.
-   * @return string
-   *         The simplified label.
-   */
-  getSourceLabel: function(aUrl) {
-    let cachedLabel = this._labelsCache.get(aUrl);
-    if (cachedLabel) {
-      return cachedLabel;
-    }
-
-    let sourceLabel = null;
-
-    for (let name of Object.keys(KNOWN_SOURCE_GROUPS)) {
-      if (aUrl.startsWith(KNOWN_SOURCE_GROUPS[name])) {
-        sourceLabel = aUrl.substring(KNOWN_SOURCE_GROUPS[name].length);
-      }
-    }
-
-    if (!sourceLabel) {
-      sourceLabel = this.trimUrl(aUrl);
-    }
-
-    let unicodeLabel = NetworkHelper.convertToUnicode(unescape(sourceLabel));
-    this._labelsCache.set(aUrl, unicodeLabel);
-    return unicodeLabel;
-  },
-
-  /**
-   * Gets as much information as possible about the hostname and directory paths
-   * of an url to create a short url group identifier.
-   *
-   * @param string aUrl
-   *        The source url.
-   * @return string
-   *         The simplified group.
-   */
-  getSourceGroup: function(aUrl) {
-    let cachedGroup = this._groupsCache.get(aUrl);
-    if (cachedGroup) {
-      return cachedGroup;
-    }
-
-    try {
-      // Use an nsIURL to parse all the url path parts.
-      var uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
-    } catch (e) {
-      // This doesn't look like a url, or nsIURL can't handle it.
-      return "";
-    }
-
-    let groupLabel = uri.prePath;
-
-    for (let name of Object.keys(KNOWN_SOURCE_GROUPS)) {
-      if (aUrl.startsWith(KNOWN_SOURCE_GROUPS[name])) {
-        groupLabel = name;
-      }
-    }
-
-    let unicodeLabel = NetworkHelper.convertToUnicode(unescape(groupLabel));
-    this._groupsCache.set(aUrl, unicodeLabel)
-    return unicodeLabel;
-  },
-
-  /**
-   * Trims the url by shortening it if it exceeds a certain length, adding an
-   * ellipsis at the end.
-   *
-   * @param string aUrl
-   *        The source url.
-   * @param number aLength [optional]
-   *        The expected source url length.
-   * @param number aSection [optional]
-   *        The section to trim. Supported values: "start", "center", "end"
-   * @return string
-   *         The shortened url.
-   */
-  trimUrlLength: function(aUrl, aLength, aSection) {
-    aLength = aLength || SOURCE_URL_DEFAULT_MAX_LENGTH;
-    aSection = aSection || "end";
-
-    if (aUrl.length > aLength) {
-      switch (aSection) {
-        case "start":
-          return L10N.ellipsis + aUrl.slice(-aLength);
-          break;
-        case "center":
-          return aUrl.substr(0, aLength / 2 - 1) + L10N.ellipsis + aUrl.slice(-aLength / 2 + 1);
-          break;
-        case "end":
-          return aUrl.substr(0, aLength) + L10N.ellipsis;
-          break;
-      }
-    }
-    return aUrl;
-  },
-
-  /**
-   * Trims the query part or reference identifier of a url string, if necessary.
-   *
-   * @param string aUrl
-   *        The source url.
-   * @return string
-   *         The shortened url.
-   */
-  trimUrlQuery: function(aUrl) {
-    let length = aUrl.length;
-    let q1 = aUrl.indexOf('?');
-    let q2 = aUrl.indexOf('&');
-    let q3 = aUrl.indexOf('#');
-    let q = Math.min(q1 != -1 ? q1 : length,
-                     q2 != -1 ? q2 : length,
-                     q3 != -1 ? q3 : length);
-
-    return aUrl.slice(0, q);
-  },
-
-  /**
-   * Trims as much as possible from a url, while keeping the label unique
-   * in the sources container.
-   *
-   * @param string | nsIURL aUrl
-   *        The source url.
-   * @param string aLabel [optional]
-   *        The resulting label at each step.
-   * @param number aSeq [optional]
-   *        The current iteration step.
-   * @return string
-   *         The resulting label at the final step.
-   */
-  trimUrl: function(aUrl, aLabel, aSeq) {
-    if (!(aUrl instanceof Ci.nsIURL)) {
-      try {
-        // Use an nsIURL to parse all the url path parts.
-        aUrl = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
-      } catch (e) {
-        // This doesn't look like a url, or nsIURL can't handle it.
-        return aUrl;
-      }
-    }
-    if (!aSeq) {
-      let name = aUrl.fileName;
-      if (name) {
-        // This is a regular file url, get only the file name (contains the
-        // base name and extension if available).
-
-        // If this url contains an invalid query, unfortunately nsIURL thinks
-        // it's part of the file extension. It must be removed.
-        aLabel = aUrl.fileName.replace(/\&.*/, "");
-      } else {
-        // This is not a file url, hence there is no base name, nor extension.
-        // Proceed using other available information.
-        aLabel = "";
-      }
-      aSeq = 1;
-    }
-
-    // If we have a label and it doesn't only contain a query...
-    if (aLabel && aLabel.indexOf("?") != 0) {
-      // A page may contain multiple requests to the same url but with different
-      // queries. It is *not* redundant to show each one.
-      if (!DebuggerView.Sources.getItemForAttachment(e => e.label == aLabel)) {
-        return aLabel;
-      }
-    }
-
-    // Append the url query.
-    if (aSeq == 1) {
-      let query = aUrl.query;
-      if (query) {
-        return this.trimUrl(aUrl, aLabel + "?" + query, aSeq + 1);
-      }
-      aSeq++;
-    }
-    // Append the url reference.
-    if (aSeq == 2) {
-      let ref = aUrl.ref;
-      if (ref) {
-        return this.trimUrl(aUrl, aLabel + "#" + aUrl.ref, aSeq + 1);
-      }
-      aSeq++;
-    }
-    // Prepend the url directory.
-    if (aSeq == 3) {
-      let dir = aUrl.directory;
-      if (dir) {
-        return this.trimUrl(aUrl, dir.replace(/^\//, "") + aLabel, aSeq + 1);
-      }
-      aSeq++;
-    }
-    // Prepend the hostname and port number.
-    if (aSeq == 4) {
-      let host = aUrl.hostPort;
-      if (host) {
-        return this.trimUrl(aUrl, host + "/" + aLabel, aSeq + 1);
-      }
-      aSeq++;
-    }
-    // Use the whole url spec but ignoring the reference.
-    if (aSeq == 5) {
-      return this.trimUrl(aUrl, aUrl.specIgnoringRef, aSeq + 1);
-    }
-    // Give up.
-    return aUrl.spec;
-  }
-};
-
-/**
- * Functions handling the variables bubble UI.
- */
-function VariableBubbleView() {
-  dumpn("VariableBubbleView was instantiated");
-
-  this._onMouseMove = this._onMouseMove.bind(this);
-  this._onMouseOut = this._onMouseOut.bind(this);
-  this._onPopupHiding = this._onPopupHiding.bind(this);
-}
-
-VariableBubbleView.prototype = {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the VariableBubbleView");
-
-    this._editorContainer = document.getElementById("editor");
-    this._editorContainer.addEventListener("mousemove", this._onMouseMove, false);
-    this._editorContainer.addEventListener("mouseout", this._onMouseOut, false);
-
-    this._tooltip = new Tooltip(document, {
-      closeOnEvents: [{
-        emitter: DebuggerController._toolbox,
-        event: "select"
-      }, {
-        emitter: this._editorContainer,
-        event: "scroll",
-        useCapture: true
-      }]
-    });
-    this._tooltip.defaultPosition = EDITOR_VARIABLE_POPUP_POSITION;
-    this._tooltip.defaultShowDelay = EDITOR_VARIABLE_HOVER_DELAY;
-    this._tooltip.panel.addEventListener("popuphiding", this._onPopupHiding);
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the VariableBubbleView");
-
-    this._tooltip.panel.removeEventListener("popuphiding", this._onPopupHiding);
-    this._editorContainer.removeEventListener("mousemove", this._onMouseMove, false);
-    this._editorContainer.removeEventListener("mouseout", this._onMouseOut, false);
-  },
-
-  /**
-   * Specifies whether literals can be (redundantly) inspected in a popup.
-   * This behavior is deprecated, but still tested in a few places.
-   */
-  _ignoreLiterals: true,
-
-  /**
-   * Searches for an identifier underneath the specified position in the
-   * source editor, and if found, opens a VariablesView inspection popup.
-   *
-   * @param number x, y
-   *        The left/top coordinates where to look for an identifier.
-   */
-  _findIdentifier: function(x, y) {
-    let editor = DebuggerView.editor;
-
-    // Calculate the editor's line and column at the current x and y coords.
-    let hoveredPos = editor.getPositionFromCoords({ left: x, top: y });
-    let hoveredOffset = editor.getOffset(hoveredPos);
-    let hoveredLine = hoveredPos.line;
-    let hoveredColumn = hoveredPos.ch;
-
-    // A source contains multiple scripts. Find the start index of the script
-    // containing the specified offset relative to its parent source.
-    let contents = editor.getText();
-    let location = DebuggerView.Sources.selectedValue;
-    let parsedSource = DebuggerController.Parser.get(contents, location);
-    let scriptInfo = parsedSource.getScriptInfo(hoveredOffset);
-
-    // If the script length is negative, we're not hovering JS source code.
-    if (scriptInfo.length == -1) {
-      return;
-    }
-
-    // Using the script offset, determine the actual line and column inside the
-    // script, to use when finding identifiers.
-    let scriptStart = editor.getPosition(scriptInfo.start);
-    let scriptLineOffset = scriptStart.line;
-    let scriptColumnOffset = (hoveredLine == scriptStart.line ? scriptStart.ch : 0);
-
-    let scriptLine = hoveredLine - scriptLineOffset;
-    let scriptColumn = hoveredColumn - scriptColumnOffset;
-    let identifierInfo = parsedSource.getIdentifierAt({
-      line: scriptLine + 1,
-      column: scriptColumn,
-      scriptIndex: scriptInfo.index,
-      ignoreLiterals: this._ignoreLiterals
-    });
-
-    // If the info is null, we're not hovering any identifier.
-    if (!identifierInfo) {
-      return;
-    }
-
-    // Transform the line and column relative to the parsed script back
-    // to the context of the parent source.
-    let { start: identifierStart, end: identifierEnd } = identifierInfo.location;
-    let identifierCoords = {
-      line: identifierStart.line + scriptLineOffset,
-      column: identifierStart.column + scriptColumnOffset,
-      length: identifierEnd.column - identifierStart.column
-    };
-
-    // Evaluate the identifier in the current stack frame and show the
-    // results in a VariablesView inspection popup.
-    DebuggerController.StackFrames.evaluate(identifierInfo.evalString)
-      .then(frameFinished => {
-        if ("return" in frameFinished) {
-          this.showContents({
-            coords: identifierCoords,
-            evalPrefix: identifierInfo.evalString,
-            objectActor: frameFinished.return
-          });
-        } else {
-          let msg = "Evaluation has thrown for: " + identifierInfo.evalString;
-          console.warn(msg);
-          dumpn(msg);
-        }
-      })
-      .then(null, err => {
-        let msg = "Couldn't evaluate: " + err.message;
-        console.error(msg);
-        dumpn(msg);
-      });
-  },
-
-  /**
-   * Shows an inspection popup for a specified object actor grip.
-   *
-   * @param string object
-   *        An object containing the following properties:
-   *          - coords: the inspected identifier coordinates in the editor,
-   *                    containing the { line, column, length } properties.
-   *          - evalPrefix: a prefix for the variables view evaluation macros.
-   *          - objectActor: the value grip for the object actor.
-   */
-  showContents: function({ coords, evalPrefix, objectActor }) {
-    let editor = DebuggerView.editor;
-    let { line, column, length } = coords;
-
-    // Highlight the function found at the mouse position.
-    this._markedText = editor.markText(
-      { line: line - 1, ch: column },
-      { line: line - 1, ch: column + length });
-
-    // If the grip represents a primitive value, use a more lightweight
-    // machinery to display it.
-    if (VariablesView.isPrimitive({ value: objectActor })) {
-      let className = VariablesView.getClass(objectActor);
-      let textContent = VariablesView.getString(objectActor);
-      this._tooltip.setTextContent({
-        messages: [textContent],
-        messagesClass: className,
-        containerClass: "plain"
-      }, [{
-        label: L10N.getStr('addWatchExpressionButton'),
-        className: "dbg-expression-button",
-        command: () => {
-          DebuggerView.VariableBubble.hideContents();
-          DebuggerView.WatchExpressions.addExpression(evalPrefix, true);
-        }
-      }]);
-    } else {
-      this._tooltip.setVariableContent(objectActor, {
-        searchPlaceholder: L10N.getStr("emptyPropertiesFilterText"),
-        searchEnabled: Prefs.variablesSearchboxVisible,
-        eval: (variable, value) => {
-          let string = variable.evaluationMacro(variable, value);
-          DebuggerController.StackFrames.evaluate(string);
-          DebuggerView.VariableBubble.hideContents();
-        }
-      }, {
-        getEnvironmentClient: aObject => gThreadClient.environment(aObject),
-        getObjectClient: aObject => gThreadClient.pauseGrip(aObject),
-        simpleValueEvalMacro: this._getSimpleValueEvalMacro(evalPrefix),
-        getterOrSetterEvalMacro: this._getGetterOrSetterEvalMacro(evalPrefix),
-        overrideValueEvalMacro: this._getOverrideValueEvalMacro(evalPrefix)
-      }, {
-        fetched: (aEvent, aType) => {
-          if (aType == "properties") {
-            window.emit(EVENTS.FETCHED_BUBBLE_PROPERTIES);
-          }
-        }
-      }, [{
-        label: L10N.getStr("addWatchExpressionButton"),
-        className: "dbg-expression-button",
-        command: () => {
-          DebuggerView.VariableBubble.hideContents();
-          DebuggerView.WatchExpressions.addExpression(evalPrefix, true);
-        }
-      }], DebuggerController._toolbox);
-    }
-
-    this._tooltip.show(this._markedText.anchor);
-  },
-
-  /**
-   * Hides the inspection popup.
-   */
-  hideContents: function() {
-    clearNamedTimeout("editor-mouse-move");
-    this._tooltip.hide();
-  },
-
-  /**
-   * Checks whether the inspection popup is shown.
-   *
-   * @return boolean
-   *         True if the panel is shown or showing, false otherwise.
-   */
-  contentsShown: function() {
-    return this._tooltip.isShown();
-  },
-
-  /**
-   * Functions for getting customized variables view evaluation macros.
-   *
-   * @param string aPrefix
-   *        See the corresponding VariablesView.* functions.
-   */
-  _getSimpleValueEvalMacro: function(aPrefix) {
-    return (item, string) =>
-      VariablesView.simpleValueEvalMacro(item, string, aPrefix);
-  },
-  _getGetterOrSetterEvalMacro: function(aPrefix) {
-    return (item, string) =>
-      VariablesView.getterOrSetterEvalMacro(item, string, aPrefix);
-  },
-  _getOverrideValueEvalMacro: function(aPrefix) {
-    return (item, string) =>
-      VariablesView.overrideValueEvalMacro(item, string, aPrefix);
-  },
-
-  /**
-   * The mousemove listener for the source editor.
-   */
-  _onMouseMove: function(e) {
-    // Prevent the variable inspection popup from showing when the thread client
-    // is not paused, or while a popup is already visible, or when the user tries
-    // to select text in the editor.
-    let isResumed = gThreadClient && gThreadClient.state != "paused";
-    let isSelecting = DebuggerView.editor.somethingSelected() && e.buttons > 0;
-    let isPopupVisible = !this._tooltip.isHidden();
-    if (isResumed || isSelecting || isPopupVisible) {
-      clearNamedTimeout("editor-mouse-move");
-      return;
-    }
-    // Allow events to settle down first. If the mouse hovers over
-    // a certain point in the editor long enough, try showing a variable bubble.
-    setNamedTimeout("editor-mouse-move",
-      EDITOR_VARIABLE_HOVER_DELAY, () => this._findIdentifier(e.clientX, e.clientY));
-  },
-
-  /**
-   * The mouseout listener for the source editor container node.
-   */
-  _onMouseOut: function() {
-    clearNamedTimeout("editor-mouse-move");
-  },
-
-  /**
-   * Listener handling the popup hiding event.
-   */
-  _onPopupHiding: function({ target }) {
-    if (this._tooltip.panel != target) {
-      return;
-    }
-    if (this._markedText) {
-      this._markedText.clear();
-      this._markedText = null;
-    }
-    if (!this._tooltip.isEmpty()) {
-      this._tooltip.empty();
-    }
-  },
-
-  _editorContainer: null,
-  _markedText: null,
-  _tooltip: null
-};
-
-/**
- * Functions handling the watch expressions UI.
- */
-function WatchExpressionsView() {
-  dumpn("WatchExpressionsView was instantiated");
-
-  this.switchExpression = this.switchExpression.bind(this);
-  this.deleteExpression = this.deleteExpression.bind(this);
-  this._createItemView = this._createItemView.bind(this);
-  this._onClick = this._onClick.bind(this);
-  this._onClose = this._onClose.bind(this);
-  this._onBlur = this._onBlur.bind(this);
-  this._onKeyPress = this._onKeyPress.bind(this);
-}
-
-WatchExpressionsView.prototype = Heritage.extend(WidgetMethods, {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the WatchExpressionsView");
-
-    this.widget = new SimpleListWidget(document.getElementById("expressions"));
-    this.widget.setAttribute("context", "debuggerWatchExpressionsContextMenu");
-    this.widget.addEventListener("click", this._onClick, false);
-
-    this.headerText = L10N.getStr("addWatchExpressionText");
-    this._addCommands();
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the WatchExpressionsView");
-
-    this.widget.removeEventListener("click", this._onClick, false);
-  },
-
-  /**
-   * Add commands that XUL can fire.
-   */
-  _addCommands: function() {
-    utils.addCommands(document.getElementById('debuggerCommands'), {
-      addWatchExpressionCommand: () => this._onCmdAddExpression(),
-      removeAllWatchExpressionsCommand: () => this._onCmdRemoveAllExpressions()
-    });
-  },
-
-  /**
-   * Adds a watch expression in this container.
-   *
-   * @param string aExpression [optional]
-   *        An optional initial watch expression text.
-   * @param boolean aSkipUserInput [optional]
-   *        Pass true to avoid waiting for additional user input
-   *        on the watch expression.
-   */
-  addExpression: function(aExpression = "", aSkipUserInput = false) {
-    // Watch expressions are UI elements which benefit from visible panes.
-    DebuggerView.showInstrumentsPane();
-
-    // Create the element node for the watch expression item.
-    let itemView = this._createItemView(aExpression);
-
-    // Append a watch expression item to this container.
-    let expressionItem = this.push([itemView.container], {
-      index: 0, /* specifies on which position should the item be appended */
-      attachment: {
-        view: itemView,
-        initialExpression: aExpression,
-        currentExpression: "",
-      }
-    });
-
-    // Automatically focus the new watch expression input
-    // if additional user input is desired.
-    if (!aSkipUserInput) {
-      expressionItem.attachment.view.inputNode.select();
-      expressionItem.attachment.view.inputNode.focus();
-      DebuggerView.Variables.parentNode.scrollTop = 0;
-    }
-    // Otherwise, add and evaluate the new watch expression immediately.
-    else {
-      this.toggleContents(false);
-      this._onBlur({ target: expressionItem.attachment.view.inputNode });
-    }
-  },
-
-  /**
-   * Changes the watch expression corresponding to the specified variable item.
-   * This function is called whenever a watch expression's code is edited in
-   * the variables view container.
-   *
-   * @param Variable aVar
-   *        The variable representing the watch expression evaluation.
-   * @param string aExpression
-   *        The new watch expression text.
-   */
-  switchExpression: function(aVar, aExpression) {
-    let expressionItem =
-      [i for (i of this) if (i.attachment.currentExpression == aVar.name)][0];
-
-    // Remove the watch expression if it's going to be empty or a duplicate.
-    if (!aExpression || this.getAllStrings().indexOf(aExpression) != -1) {
-      this.deleteExpression(aVar);
-      return;
-    }
-
-    // Save the watch expression code string.
-    expressionItem.attachment.currentExpression = aExpression;
-    expressionItem.attachment.view.inputNode.value = aExpression;
-
-    // Synchronize with the controller's watch expressions store.
-    DebuggerController.StackFrames.syncWatchExpressions();
-  },
-
-  /**
-   * Removes the watch expression corresponding to the specified variable item.
-   * This function is called whenever a watch expression's value is edited in
-   * the variables view container.
-   *
-   * @param Variable aVar
-   *        The variable representing the watch expression evaluation.
-   */
-  deleteExpression: function(aVar) {
-    let expressionItem =
-      [i for (i of this) if (i.attachment.currentExpression == aVar.name)][0];
-
-    // Remove the watch expression.
-    this.remove(expressionItem);
-
-    // Synchronize with the controller's watch expressions store.
-    DebuggerController.StackFrames.syncWatchExpressions();
-  },
-
-  /**
-   * Gets the watch expression code string for an item in this container.
-   *
-   * @param number aIndex
-   *        The index used to identify the watch expression.
-   * @return string
-   *         The watch expression code string.
-   */
-  getString: function(aIndex) {
-    return this.getItemAtIndex(aIndex).attachment.currentExpression;
-  },
-
-  /**
-   * Gets the watch expressions code strings for all items in this container.
-   *
-   * @return array
-   *         The watch expressions code strings.
-   */
-  getAllStrings: function() {
-    return this.items.map(e => e.attachment.currentExpression);
-  },
-
-  /**
-   * Customization function for creating an item's UI.
-   *
-   * @param string aExpression
-   *        The watch expression string.
-   */
-  _createItemView: function(aExpression) {
-    let container = document.createElement("hbox");
-    container.className = "list-widget-item dbg-expression";
-    container.setAttribute("align", "center");
-
-    let arrowNode = document.createElement("hbox");
-    arrowNode.className = "dbg-expression-arrow";
-
-    let inputNode = document.createElement("textbox");
-    inputNode.className = "plain dbg-expression-input devtools-monospace";
-    inputNode.setAttribute("value", aExpression);
-    inputNode.setAttribute("flex", "1");
-
-    let closeNode = document.createElement("toolbarbutton");
-    closeNode.className = "plain variables-view-delete";
-
-    closeNode.addEventListener("click", this._onClose, false);
-    inputNode.addEventListener("blur", this._onBlur, false);
-    inputNode.addEventListener("keypress", this._onKeyPress, false);
-
-    container.appendChild(arrowNode);
-    container.appendChild(inputNode);
-    container.appendChild(closeNode);
-
-    return {
-      container: container,
-      arrowNode: arrowNode,
-      inputNode: inputNode,
-      closeNode: closeNode
-    };
-  },
-
-  /**
-   * Called when the add watch expression key sequence was pressed.
-   */
-  _onCmdAddExpression: function(aText) {
-    // Only add a new expression if there's no pending input.
-    if (this.getAllStrings().indexOf("") == -1) {
-      this.addExpression(aText || DebuggerView.editor.getSelection());
-    }
-  },
-
-  /**
-   * Called when the remove all watch expressions key sequence was pressed.
-   */
-  _onCmdRemoveAllExpressions: function() {
-    // Empty the view of all the watch expressions and clear the cache.
-    this.empty();
-
-    // Synchronize with the controller's watch expressions store.
-    DebuggerController.StackFrames.syncWatchExpressions();
-  },
-
-  /**
-   * The click listener for this container.
-   */
-  _onClick: function(e) {
-    if (e.button != 0) {
-      // Only allow left-click to trigger this event.
-      return;
-    }
-    let expressionItem = this.getItemForElement(e.target);
-    if (!expressionItem) {
-      // The container is empty or we didn't click on an actual item.
-      this.addExpression();
-    }
-  },
-
-  /**
-   * The click listener for a watch expression's close button.
-   */
-  _onClose: function(e) {
-    // Remove the watch expression.
-    this.remove(this.getItemForElement(e.target));
-
-    // Synchronize with the controller's watch expressions store.
-    DebuggerController.StackFrames.syncWatchExpressions();
-
-    // Prevent clicking the expression element itself.
-    e.preventDefault();
-    e.stopPropagation();
-  },
-
-  /**
-   * The blur listener for a watch expression's textbox.
-   */
-  _onBlur: function({ target: textbox }) {
-    let expressionItem = this.getItemForElement(textbox);
-    let oldExpression = expressionItem.attachment.currentExpression;
-    let newExpression = textbox.value.trim();
-
-    // Remove the watch expression if it's empty.
-    if (!newExpression) {
-      this.remove(expressionItem);
-    }
-    // Remove the watch expression if it's a duplicate.
-    else if (!oldExpression && this.getAllStrings().indexOf(newExpression) != -1) {
-      this.remove(expressionItem);
-    }
-    // Expression is eligible.
-    else {
-      expressionItem.attachment.currentExpression = newExpression;
-    }
-
-    // Synchronize with the controller's watch expressions store.
-    DebuggerController.StackFrames.syncWatchExpressions();
-  },
-
-  /**
-   * The keypress listener for a watch expression's textbox.
-   */
-  _onKeyPress: function(e) {
-    switch (e.keyCode) {
-      case e.DOM_VK_RETURN:
-      case e.DOM_VK_ESCAPE:
-        e.stopPropagation();
-        DebuggerView.editor.focus();
-    }
-  }
-});
-
-/**
- * Functions handling the event listeners UI.
- */
-function EventListenersView() {
-  dumpn("EventListenersView was instantiated");
-
-  this._onCheck = this._onCheck.bind(this);
-  this._onClick = this._onClick.bind(this);
-}
-
-EventListenersView.prototype = Heritage.extend(WidgetMethods, {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the EventListenersView");
-
-    this.widget = new SideMenuWidget(document.getElementById("event-listeners"), {
-      showItemCheckboxes: true,
-      showGroupCheckboxes: true
-    });
-
-    this.emptyText = L10N.getStr("noEventListenersText");
-    this._eventCheckboxTooltip = L10N.getStr("eventCheckboxTooltip");
-    this._onSelectorString = " " + L10N.getStr("eventOnSelector") + " ";
-    this._inSourceString = " " + L10N.getStr("eventInSource") + " ";
-    this._inNativeCodeString = L10N.getStr("eventNative");
-
-    this.widget.addEventListener("check", this._onCheck, false);
-    this.widget.addEventListener("click", this._onClick, false);
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the EventListenersView");
-
-    this.widget.removeEventListener("check", this._onCheck, false);
-    this.widget.removeEventListener("click", this._onClick, false);
-  },
-
-  /**
-   * Adds an event to this event listeners container.
-   *
-   * @param object aListener
-   *        The listener object coming from the active thread.
-   * @param object aOptions [optional]
-   *        Additional options for adding the source. Supported options:
-   *        - staged: true to stage the item to be appended later
-   */
-  addListener: function(aListener, aOptions = {}) {
-    let { node: { selector }, function: { url }, type } = aListener;
-    if (!type) return;
-
-    // Some listener objects may be added from plugins, thus getting
-    // translated to native code.
-    if (!url) {
-      url = this._inNativeCodeString;
-    }
-
-    // If an event item for this listener's url and type was already added,
-    // avoid polluting the view and simply increase the "targets" count.
-    let eventItem = this.getItemForPredicate(aItem =>
-      aItem.attachment.url == url &&
-      aItem.attachment.type == type);
-
-    if (eventItem) {
-      let { selectors, view: { targets } } = eventItem.attachment;
-      if (selectors.indexOf(selector) == -1) {
-        selectors.push(selector);
-        targets.setAttribute("value", L10N.getFormatStr("eventNodes", selectors.length));
-      }
-      return;
-    }
-
-    // There's no easy way of grouping event types into higher-level groups,
-    // so we need to do this by hand.
-    let is = (...args) => args.indexOf(type) != -1;
-    let has = str => type.contains(str);
-    let starts = str => type.startsWith(str);
-    let group;
-
-    if (starts("animation")) {
-      group = L10N.getStr("animationEvents");
-    } else if (starts("audio")) {
-      group = L10N.getStr("audioEvents");
-    } else if (is("levelchange")) {
-      group = L10N.getStr("batteryEvents");
-    } else if (is("cut", "copy", "paste")) {
-      group = L10N.getStr("clipboardEvents");
-    } else if (starts("composition")) {
-      group = L10N.getStr("compositionEvents");
-    } else if (starts("device")) {
-      group = L10N.getStr("deviceEvents");
-    } else if (is("fullscreenchange", "fullscreenerror", "orientationchange",
-      "overflow", "resize", "scroll", "underflow", "zoom")) {
-      group = L10N.getStr("displayEvents");
-    } else if (starts("drag") || starts("drop")) {
-      group = L10N.getStr("dragAndDropEvents");
-    } else if (starts("gamepad")) {
-      group = L10N.getStr("gamepadEvents");
-    } else if (is("canplay", "canplaythrough", "durationchange", "emptied",
-      "ended", "loadeddata", "loadedmetadata", "pause", "play", "playing",
-      "ratechange", "seeked", "seeking", "stalled", "suspend", "timeupdate",
-      "volumechange", "waiting")) {
-      group = L10N.getStr("mediaEvents");
-    } else if (is("blocked", "complete", "success", "upgradeneeded", "versionchange")) {
-      group = L10N.getStr("indexedDBEvents");
-    } else if (is("blur", "change", "focus", "focusin", "focusout", "invalid",
-      "reset", "select", "submit")) {
-      group = L10N.getStr("interactionEvents");
-    } else if (starts("key") || is("input")) {
-      group = L10N.getStr("keyboardEvents");
-    } else if (starts("mouse") || has("click") || is("contextmenu", "show", "wheel")) {
-      group = L10N.getStr("mouseEvents");
-    } else if (starts("DOM")) {
-      group = L10N.getStr("mutationEvents");
-    } else if (is("abort", "error", "hashchange", "load", "loadend", "loadstart",
-      "pagehide", "pageshow", "progress", "timeout", "unload", "uploadprogress",
-      "visibilitychange")) {
-      group = L10N.getStr("navigationEvents");
-    } else if (is("pointerlockchange", "pointerlockerror")) {
-      group = L10N.getStr("pointerLockEvents");
-    } else if (is("compassneedscalibration", "userproximity")) {
-      group = L10N.getStr("sensorEvents");
-    } else if (starts("storage")) {
-      group = L10N.getStr("storageEvents");
-    } else if (is("beginEvent", "endEvent", "repeatEvent")) {
-      group = L10N.getStr("timeEvents");
-    } else if (starts("touch")) {
-      group = L10N.getStr("touchEvents");
-    } else {
-      group = L10N.getStr("otherEvents");
-    }
-
-    // Create the element node for the event listener item.
-    let itemView = this._createItemView(type, selector, url);
-
-    // Event breakpoints survive target navigations. Make sure the newly
-    // inserted event item is correctly checked.
-    let checkboxState =
-      DebuggerController.Breakpoints.DOM.activeEventNames.indexOf(type) != -1;
-
-    // Append an event listener item to this container.
-    this.push([itemView.container], {
-      staged: aOptions.staged, /* stage the item to be appended later? */
-      attachment: {
-        url: url,
-        type: type,
-        view: itemView,
-        selectors: [selector],
-        group: group,
-        checkboxState: checkboxState,
-        checkboxTooltip: this._eventCheckboxTooltip
-      }
-    });
-  },
-
-  /**
-   * Gets all the event types known to this container.
-   *
-   * @return array
-   *         List of event types, for example ["load", "click"...]
-   */
-  getAllEvents: function() {
-    return this.attachments.map(e => e.type);
-  },
-
-  /**
-   * Gets the checked event types in this container.
-   *
-   * @return array
-   *         List of event types, for example ["load", "click"...]
-   */
-  getCheckedEvents: function() {
-    return this.attachments.filter(e => e.checkboxState).map(e => e.type);
-  },
-
-  /**
-   * Customization function for creating an item's UI.
-   *
-   * @param string aType
-   *        The event type, for example "click".
-   * @param string aSelector
-   *        The target element's selector.
-   * @param string url
-   *        The source url in which the event listener is located.
-   * @return object
-   *         An object containing the event listener view nodes.
-   */
-  _createItemView: function(aType, aSelector, aUrl) {
-    let container = document.createElement("hbox");
-    container.className = "dbg-event-listener";
-
-    let eventType = document.createElement("label");
-    eventType.className = "plain dbg-event-listener-type";
-    eventType.setAttribute("value", aType);
-    container.appendChild(eventType);
-
-    let typeSeparator = document.createElement("label");
-    typeSeparator.className = "plain dbg-event-listener-separator";
-    typeSeparator.setAttribute("value", this._onSelectorString);
-    container.appendChild(typeSeparator);
-
-    let eventTargets = document.createElement("label");
-    eventTargets.className = "plain dbg-event-listener-targets";
-    eventTargets.setAttribute("value", aSelector);
-    container.appendChild(eventTargets);
-
-    let selectorSeparator = document.createElement("label");
-    selectorSeparator.className = "plain dbg-event-listener-separator";
-    selectorSeparator.setAttribute("value", this._inSourceString);
-    container.appendChild(selectorSeparator);
-
-    let eventLocation = document.createElement("label");
-    eventLocation.className = "plain dbg-event-listener-location";
-    eventLocation.setAttribute("value", SourceUtils.getSourceLabel(aUrl));
-    eventLocation.setAttribute("flex", "1");
-    eventLocation.setAttribute("crop", "center");
-    container.appendChild(eventLocation);
-
-    return {
-      container: container,
-      type: eventType,
-      targets: eventTargets,
-      location: eventLocation
-    };
-  },
-
-  /**
-   * The check listener for the event listeners container.
-   */
-  _onCheck: function({ detail: { description, checked }, target }) {
-    if (description == "item") {
-      this.getItemForElement(target).attachment.checkboxState = checked;
-      DebuggerController.Breakpoints.DOM.scheduleEventBreakpointsUpdate();
-      return;
-    }
-
-    // Check all the event items in this group.
-    this.items
-      .filter(e => e.attachment.group == description)
-      .forEach(e => this.callMethod("checkItem", e.target, checked));
-  },
-
-  /**
-   * The select listener for the event listeners container.
-   */
-  _onClick: function({ target }) {
-    // Changing the checkbox state is handled by the _onCheck event. Avoid
-    // handling that again in this click event, so pass in "noSiblings"
-    // when retrieving the target's item, to ignore the checkbox.
-    let eventItem = this.getItemForElement(target, { noSiblings: true });
-    if (eventItem) {
-      let newState = eventItem.attachment.checkboxState ^= 1;
-      this.callMethod("checkItem", eventItem.target, newState);
-    }
-  },
-
-  _eventCheckboxTooltip: "",
-  _onSelectorString: "",
-  _inSourceString: "",
-  _inNativeCodeString: ""
-});
-
-/**
- * Functions handling the global search UI.
- */
-function GlobalSearchView() {
-  dumpn("GlobalSearchView was instantiated");
-
-  this._onHeaderClick = this._onHeaderClick.bind(this);
-  this._onLineClick = this._onLineClick.bind(this);
-  this._onMatchClick = this._onMatchClick.bind(this);
-}
-
-GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the GlobalSearchView");
-
-    this.widget = new SimpleListWidget(document.getElementById("globalsearch"));
-    this._splitter = document.querySelector("#globalsearch + .devtools-horizontal-splitter");
-
-    this.emptyText = L10N.getStr("noMatchingStringsText");
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the GlobalSearchView");
-  },
-
-  /**
-   * Sets the results container hidden or visible. It's hidden by default.
-   * @param boolean aFlag
-   */
-  set hidden(aFlag) {
-    this.widget.setAttribute("hidden", aFlag);
-    this._splitter.setAttribute("hidden", aFlag);
-  },
-
-  /**
-   * Gets the visibility state of the global search container.
-   * @return boolean
-   */
-  get hidden()
-    this.widget.getAttribute("hidden") == "true" ||
-    this._splitter.getAttribute("hidden") == "true",
-
-  /**
-   * Hides and removes all items from this search container.
-   */
-  clearView: function() {
-    this.hidden = true;
-    this.empty();
-  },
-
-  /**
-   * Selects the next found item in this container.
-   * Does not change the currently focused node.
-   */
-  selectNext: function() {
-    let totalLineResults = LineResults.size();
-    if (!totalLineResults) {
-      return;
-    }
-    if (++this._currentlyFocusedMatch >= totalLineResults) {
-      this._currentlyFocusedMatch = 0;
-    }
-    this._onMatchClick({
-      target: LineResults.getElementAtIndex(this._currentlyFocusedMatch)
-    });
-  },
-
-  /**
-   * Selects the previously found item in this container.
-   * Does not change the currently focused node.
-   */
-  selectPrev: function() {
-    let totalLineResults = LineResults.size();
-    if (!totalLineResults) {
-      return;
-    }
-    if (--this._currentlyFocusedMatch < 0) {
-      this._currentlyFocusedMatch = totalLineResults - 1;
-    }
-    this._onMatchClick({
-      target: LineResults.getElementAtIndex(this._currentlyFocusedMatch)
-    });
-  },
-
-  /**
-   * Schedules searching for a string in all of the sources.
-   *
-   * @param string aToken
-   *        The string to search for.
-   * @param number aWait
-   *        The amount of milliseconds to wait until draining.
-   */
-  scheduleSearch: function(aToken, aWait) {
-    // The amount of time to wait for the requests to settle.
-    let maxDelay = GLOBAL_SEARCH_ACTION_MAX_DELAY;
-    let delay = aWait === undefined ? maxDelay / aToken.length : aWait;
-
-    // Allow requests to settle down first.
-    setNamedTimeout("global-search", delay, () => {
-      // Start fetching as many sources as possible, then perform the search.
-      let actors = DebuggerView.Sources.values;
-      let sourcesFetched = DebuggerController.SourceScripts.getTextForSources(actors);
-      sourcesFetched.then(aSources => this._doSearch(aToken, aSources));
-    });
-  },
-
-  /**
-   * Finds string matches in all the sources stored in the controller's cache,
-   * and groups them by url and line number.
-   *
-   * @param string aToken
-   *        The string to search for.
-   * @param array aSources
-   *        An array of [url, text] tuples for each source.
-   */
-  _doSearch: function(aToken, aSources) {
-    // Don't continue filtering if the searched token is an empty string.
-    if (!aToken) {
-      this.clearView();
-      return;
-    }
-
-    // Search is not case sensitive, prepare the actual searched token.
-    let lowerCaseToken = aToken.toLowerCase();
-    let tokenLength = aToken.length;
-
-    // Create a Map containing search details for each source.
-    let globalResults = new GlobalResults();
-
-    // Search for the specified token in each source's text.
-    for (let [actor, text] of aSources) {
-      let item = DebuggerView.Sources.getItemByValue(actor);
-      let url = item.attachment.source.url;
-      if (!url) {
-        continue;
-      }
-
-      // Verify that the search token is found anywhere in the source.
-      if (!text.toLowerCase().contains(lowerCaseToken)) {
-        continue;
-      }
-      // ...and if so, create a Map containing search details for each line.
-      let sourceResults = new SourceResults(actor, globalResults);
-
-      // Search for the specified token in each line's text.
-      text.split("\n").forEach((aString, aLine) => {
-        // Search is not case sensitive, prepare the actual searched line.
-        let lowerCaseLine = aString.toLowerCase();
-
-        // Verify that the search token is found anywhere in this line.
-        if (!lowerCaseLine.contains(lowerCaseToken)) {
-          return;
-        }
-        // ...and if so, create a Map containing search details for each word.
-        let lineResults = new LineResults(aLine, sourceResults);
-
-        // Search for the specified token this line's text.
-        lowerCaseLine.split(lowerCaseToken).reduce((aPrev, aCurr, aIndex, aArray) => {
-          let prevLength = aPrev.length;
-          let currLength = aCurr.length;
-
-          // Everything before the token is unmatched.
-          let unmatched = aString.substr(prevLength, currLength);
-          lineResults.add(unmatched);
-
-          // The lowered-case line was split by the lowered-case token. So,
-          // get the actual matched text from the original line's text.
-          if (aIndex != aArray.length - 1) {
-            let matched = aString.substr(prevLength + currLength, tokenLength);
-            let range = { start: prevLength + currLength, length: matched.length };
-            lineResults.add(matched, range, true);
-          }
-
-          // Continue with the next sub-region in this line's text.
-          return aPrev + aToken + aCurr;
-        }, "");
-
-        if (lineResults.matchCount) {
-          sourceResults.add(lineResults);
-        }
-      });
-
-      if (sourceResults.matchCount) {
-        globalResults.add(sourceResults);
-      }
-    }
-
-    // Rebuild the results, then signal if there are any matches.
-    if (globalResults.matchCount) {
-      this.hidden = false;
-      this._currentlyFocusedMatch = -1;
-      this._createGlobalResultsUI(globalResults);
-      window.emit(EVENTS.GLOBAL_SEARCH_MATCH_FOUND);
-    } else {
-      window.emit(EVENTS.GLOBAL_SEARCH_MATCH_NOT_FOUND);
-    }
-  },
-
-  /**
-   * Creates global search results entries and adds them to this container.
-   *
-   * @param GlobalResults aGlobalResults
-   *        An object containing all source results, grouped by source location.
-   */
-  _createGlobalResultsUI: function(aGlobalResults) {
-    let i = 0;
-
-    for (let sourceResults of aGlobalResults) {
-      if (i++ == 0) {
-        this._createSourceResultsUI(sourceResults);
-      } else {
-        // Dispatch subsequent document manipulation operations, to avoid
-        // blocking the main thread when a large number of search results
-        // is found, thus giving the impression of faster searching.
-        Services.tm.currentThread.dispatch({ run:
-          this._createSourceResultsUI.bind(this, sourceResults)
-        }, 0);
-      }
-    }
-  },
-
-  /**
-   * Creates source search results entries and adds them to this container.
-   *
-   * @param SourceResults aSourceResults
-   *        An object containing all the matched lines for a specific source.
-   */
-  _createSourceResultsUI: function(aSourceResults) {
-    // Create the element node for the source results item.
-    let container = document.createElement("hbox");
-    aSourceResults.createView(container, {
-      onHeaderClick: this._onHeaderClick,
-      onLineClick: this._onLineClick,
-      onMatchClick: this._onMatchClick
-    });
-
-    // Append a source results item to this container.
-    let item = this.push([container], {
-      index: -1, /* specifies on which position should the item be appended */
-      attachment: {
-        sourceResults: aSourceResults
-      }
-    });
-  },
-
-  /**
-   * The click listener for a results header.
-   */
-  _onHeaderClick: function(e) {
-    let sourceResultsItem = SourceResults.getItemForElement(e.target);
-    sourceResultsItem.instance.toggle(e);
-  },
-
-  /**
-   * The click listener for a results line.
-   */
-  _onLineClick: function(e) {
-    let lineResultsItem = LineResults.getItemForElement(e.target);
-    this._onMatchClick({ target: lineResultsItem.firstMatch });
-  },
-
-  /**
-   * The click listener for a result match.
-   */
-  _onMatchClick: function(e) {
-    if (e instanceof Event) {
-      e.preventDefault();
-      e.stopPropagation();
-    }
-
-    let target = e.target;
-    let sourceResultsItem = SourceResults.getItemForElement(target);
-    let lineResultsItem = LineResults.getItemForElement(target);
-
-    sourceResultsItem.instance.expand();
-    this._currentlyFocusedMatch = LineResults.indexOfElement(target);
-    this._scrollMatchIntoViewIfNeeded(target);
-    this._bounceMatch(target);
-
-    let actor = sourceResultsItem.instance.actor;
-    let line = lineResultsItem.instance.line;
-
-    DebuggerView.setEditorLocation(actor, line + 1, { noDebug: true });
-
-    let range = lineResultsItem.lineData.range;
-    let cursor = DebuggerView.editor.getOffset({ line: line, ch: 0 });
-    let [ anchor, head ] = DebuggerView.editor.getPosition(
-      cursor + range.start,
-      cursor + range.start + range.length
-    );
-
-    DebuggerView.editor.setSelection(anchor, head);
-  },
-
-  /**
-   * Scrolls a match into view if not already visible.
-   *
-   * @param nsIDOMNode aMatch
-   *        The match to scroll into view.
-   */
-  _scrollMatchIntoViewIfNeeded: function(aMatch) {
-    this.widget.ensureElementIsVisible(aMatch);
-  },
-
-  /**
-   * Starts a bounce animation for a match.
-   *
-   * @param nsIDOMNode aMatch
-   *        The match to start a bounce animation for.
-   */
-  _bounceMatch: function(aMatch) {
-    Services.tm.currentThread.dispatch({ run: () => {
-      aMatch.addEventListener("transitionend", function onEvent() {
-        aMatch.removeEventListener("transitionend", onEvent);
-        aMatch.removeAttribute("focused");
-      });
-      aMatch.setAttribute("focused", "");
-    }}, 0);
-    aMatch.setAttribute("focusing", "");
-  },
-
-  _splitter: null,
-  _currentlyFocusedMatch: -1,
-  _forceExpandResults: false
-});
-
-/**
- * An object containing all source results, grouped by source location.
- * Iterable via "for (let [location, sourceResults] of globalResults) { }".
- */
-function GlobalResults() {
-  this._store = [];
-  SourceResults._itemsByElement = new Map();
-  LineResults._itemsByElement = new Map();
-}
-
-GlobalResults.prototype = {
-  /**
-   * Adds source results to this store.
-   *
-   * @param SourceResults aSourceResults
-   *        An object containing search results for a specific source.
-   */
-  add: function(aSourceResults) {
-    this._store.push(aSourceResults);
-  },
-
-  /**
-   * Gets the number of source results in this store.
-   */
-  get matchCount() this._store.length
-};
-
-/**
- * An object containing all the matched lines for a specific source.
- * Iterable via "for (let [lineNumber, lineResults] of sourceResults) { }".
- *
- * @param string aActor
- *        The target source actor id.
- * @param GlobalResults aGlobalResults
- *        An object containing all source results, grouped by source location.
- */
-function SourceResults(aActor, aGlobalResults) {
-  let item = DebuggerView.Sources.getItemByValue(aActor);
-  this.actor = aActor;
-  this.label = item.attachment.source.url;
-  this._globalResults = aGlobalResults;
-  this._store = [];
-}
-
-SourceResults.prototype = {
-  /**
-   * Adds line results to this store.
-   *
-   * @param LineResults aLineResults
-   *        An object containing search results for a specific line.
-   */
-  add: function(aLineResults) {
-    this._store.push(aLineResults);
-  },
-
-  /**
-   * Gets the number of line results in this store.
-   */
-  get matchCount() this._store.length,
-
-  /**
-   * Expands the element, showing all the added details.
-   */
-  expand: function() {
-    this._resultsContainer.removeAttribute("hidden");
-    this._arrow.setAttribute("open", "");
-  },
-
-  /**
-   * Collapses the element, hiding all the added details.
-   */
-  collapse: function() {
-    this._resultsContainer.setAttribute("hidden", "true");
-    this._arrow.removeAttribute("open");
-  },
-
-  /**
-   * Toggles between the element collapse/expand state.
-   */
-  toggle: function(e) {
-    this.expanded ^= 1;
-  },
-
-  /**
-   * Gets this element's expanded state.
-   * @return boolean
-   */
-  get expanded()
-    this._resultsContainer.getAttribute("hidden") != "true" &&
-    this._arrow.hasAttribute("open"),
-
-  /**
-   * Sets this element's expanded state.
-   * @param boolean aFlag
-   */
-  set expanded(aFlag) this[aFlag ? "expand" : "collapse"](),
-
-  /**
-   * Gets the element associated with this item.
-   * @return nsIDOMNode
-   */
-  get target() this._target,
-
-  /**
-   * Customization function for creating this item's UI.
-   *
-   * @param nsIDOMNode aElementNode
-   *        The element associated with the displayed item.
-   * @param object aCallbacks
-   *        An object containing all the necessary callback functions:
-   *          - onHeaderClick
-   *          - onMatchClick
-   */
-  createView: function(aElementNode, aCallbacks) {
-    this._target = aElementNode;
-
-    let arrow = this._arrow = document.createElement("box");
-    arrow.className = "arrow";
-
-    let locationNode = document.createElement("label");
-    locationNode.className = "plain dbg-results-header-location";
-    locationNode.setAttribute("value", this.label);
-
-    let matchCountNode = document.createElement("label");
-    matchCountNode.className = "plain dbg-results-header-match-count";
-    matchCountNode.setAttribute("value", "(" + this.matchCount + ")");
-
-    let resultsHeader = this._resultsHeader = document.createElement("hbox");
-    resultsHeader.className = "dbg-results-header";
-    resultsHeader.setAttribute("align", "center")
-    resultsHeader.appendChild(arrow);
-    resultsHeader.appendChild(locationNode);
-    resultsHeader.appendChild(matchCountNode);
-    resultsHeader.addEventListener("click", aCallbacks.onHeaderClick, false);
-
-    let resultsContainer = this._resultsContainer = document.createElement("vbox");
-    resultsContainer.className = "dbg-results-container";
-    resultsContainer.setAttribute("hidden", "true");
-
-    // Create lines search results entries and add them to this container.
-    // Afterwards, if the number of matches is reasonable, expand this
-    // container automatically.
-    for (let lineResults of this._store) {
-      lineResults.createView(resultsContainer, aCallbacks);
-    }
-    if (this.matchCount < GLOBAL_SEARCH_EXPAND_MAX_RESULTS) {
-      this.expand();
-    }
-
-    let resultsBox = document.createElement("vbox");
-    resultsBox.setAttribute("flex", "1");
-    resultsBox.appendChild(resultsHeader);
-    resultsBox.appendChild(resultsContainer);
-
-    aElementNode.id = "source-results-" + this.actor;
-    aElementNode.className = "dbg-source-results";
-    aElementNode.appendChild(resultsBox);
-
-    SourceResults._itemsByElement.set(aElementNode, { instance: this });
-  },
-
-  actor: "",
-  _globalResults: null,
-  _store: null,
-  _target: null,
-  _arrow: null,
-  _resultsHeader: null,
-  _resultsContainer: null
-};
-
-/**
- * An object containing all the matches for a specific line.
- * Iterable via "for (let chunk of lineResults) { }".
- *
- * @param number aLine
- *        The target line in the source.
- * @param SourceResults aSourceResults
- *        An object containing all the matched lines for a specific source.
- */
-function LineResults(aLine, aSourceResults) {
-  this.line = aLine;
-  this._sourceResults = aSourceResults;
-  this._store = [];
-  this._matchCount = 0;
-}
-
-LineResults.prototype = {
-  /**
-   * Adds string details to this store.
-   *
-   * @param string aString
-   *        The text contents chunk in the line.
-   * @param object aRange
-   *        An object containing the { start, length } of the chunk.
-   * @param boolean aMatchFlag
-   *        True if the chunk is a matched string, false if just text content.
-   */
-  add: function(aString, aRange, aMatchFlag) {
-    this._store.push({ string: aString, range: aRange, match: !!aMatchFlag });
-    this._matchCount += aMatchFlag ? 1 : 0;
-  },
-
-  /**
-   * Gets the number of word results in this store.
-   */
-  get matchCount() this._matchCount,
-
-  /**
-   * Gets the element associated with this item.
-   * @return nsIDOMNode
-   */
-  get target() this._target,
-
-  /**
-   * Customization function for creating this item's UI.
-   *
-   * @param nsIDOMNode aElementNode
-   *        The element associated with the displayed item.
-   * @param object aCallbacks
-   *        An object containing all the necessary callback functions:
-   *          - onMatchClick
-   *          - onLineClick
-   */
-  createView: function(aElementNode, aCallbacks) {
-    this._target = aElementNode;
-
-    let lineNumberNode = document.createElement("label");
-    lineNumberNode.className = "plain dbg-results-line-number";
-    lineNumberNode.classList.add("devtools-monospace");
-    lineNumberNode.setAttribute("value", this.line + 1);
-
-    let lineContentsNode = document.createElement("hbox");
-    lineContentsNode.className = "dbg-results-line-contents";
-    lineContentsNode.classList.add("devtools-monospace");
-    lineContentsNode.setAttribute("flex", "1");
-
-    let lineString = "";
-    let lineLength = 0;
-    let firstMatch = null;
-
-    for (let lineChunk of this._store) {
-      let { string, range, match } = lineChunk;
-      lineString = string.substr(0, GLOBAL_SEARCH_LINE_MAX_LENGTH - lineLength);
-      lineLength += string.length;
-
-      let lineChunkNode = document.createElement("label");
-      lineChunkNode.className = "plain dbg-results-line-contents-string";
-      lineChunkNode.setAttribute("value", lineString);
-      lineChunkNode.setAttribute("match", match);
-      lineContentsNode.appendChild(lineChunkNode);
-
-      if (match) {
-        this._entangleMatch(lineChunkNode, lineChunk);
-        lineChunkNode.addEventListener("click", aCallbacks.onMatchClick, false);
-        firstMatch = firstMatch || lineChunkNode;
-      }
-      if (lineLength >= GLOBAL_SEARCH_LINE_MAX_LENGTH) {
-        lineContentsNode.appendChild(this._ellipsis.cloneNode(true));
-        break;
-      }
-    }
-
-    this._entangleLine(lineContentsNode, firstMatch);
-    lineContentsNode.addEventListener("click", aCallbacks.onLineClick, false);
-
-    let searchResult = document.createElement("hbox");
-    searchResult.className = "dbg-search-result";
-    searchResult.appendChild(lineNumberNode);
-    searchResult.appendChild(lineContentsNode);
-
-    aElementNode.appendChild(searchResult);
-  },
-
-  /**
-   * Handles a match while creating the view.
-   * @param nsIDOMNode aNode
-   * @param object aMatchChunk
-   */
-  _entangleMatch: function(aNode, aMatchChunk) {
-    LineResults._itemsByElement.set(aNode, {
-      instance: this,
-      lineData: aMatchChunk
-    });
-  },
-
-  /**
-   * Handles a line while creating the view.
-   * @param nsIDOMNode aNode
-   * @param nsIDOMNode aFirstMatch
-   */
-  _entangleLine: function(aNode, aFirstMatch) {
-    LineResults._itemsByElement.set(aNode, {
-      instance: this,
-      firstMatch: aFirstMatch,
-      ignored: true
-    });
-  },
-
-  /**
-   * An nsIDOMNode label with an ellipsis value.
-   */
-  _ellipsis: (function() {
-    let label = document.createElement("label");
-    label.className = "plain dbg-results-line-contents-string";
-    label.setAttribute("value", L10N.ellipsis);
-    return label;
-  })(),
-
-  line: 0,
-  _sourceResults: null,
-  _store: null,
-  _target: null
-};
-
-/**
- * A generator-iterator over the global, source or line results.
- */
-GlobalResults.prototype[Symbol.iterator] =
-SourceResults.prototype[Symbol.iterator] =
-LineResults.prototype[Symbol.iterator] = function*() {
-  yield* this._store;
-};
-
-/**
- * Gets the item associated with the specified element.
- *
- * @param nsIDOMNode aElement
- *        The element used to identify the item.
- * @return object
- *         The matched item, or null if nothing is found.
- */
-SourceResults.getItemForElement =
-LineResults.getItemForElement = function(aElement) {
-  return WidgetMethods.getItemForElement.call(this, aElement, { noSiblings: true });
-};
-
-/**
- * Gets the element associated with a particular item at a specified index.
- *
- * @param number aIndex
- *        The index used to identify the item.
- * @return nsIDOMNode
- *         The matched element, or null if nothing is found.
- */
-SourceResults.getElementAtIndex =
-LineResults.getElementAtIndex = function(aIndex) {
-  for (let [element, item] of this._itemsByElement) {
-    if (!item.ignored && !aIndex--) {
-      return element;
-    }
-  }
-  return null;
-};
-
-/**
- * Gets the index of an item associated with the specified element.
- *
- * @param nsIDOMNode aElement
- *        The element to get the index for.
- * @return number
- *         The index of the matched element, or -1 if nothing is found.
- */
-SourceResults.indexOfElement =
-LineResults.indexOfElement = function(aElement) {
-  let count = 0;
-  for (let [element, item] of this._itemsByElement) {
-    if (element == aElement) {
-      return count;
-    }
-    if (!item.ignored) {
-      count++;
-    }
-  }
-  return -1;
-};
-
-/**
- * Gets the number of cached items associated with a specified element.
- *
- * @return number
- *         The number of key/value pairs in the corresponding map.
- */
-SourceResults.size =
-LineResults.size = function() {
-  let count = 0;
-  for (let [, item] of this._itemsByElement) {
-    if (!item.ignored) {
-      count++;
-    }
-  }
-  return count;
-};
-
-/**
- * Preliminary setup for the DebuggerView object.
- */
-DebuggerView.Sources = new SourcesView();
-DebuggerView.VariableBubble = new VariableBubbleView();
-DebuggerView.Tracer = new TracerView();
-DebuggerView.WatchExpressions = new WatchExpressionsView();
-DebuggerView.EventListeners = new EventListenersView();
-DebuggerView.GlobalSearch = new GlobalSearchView();
deleted file mode 100644
--- a/browser/devtools/debugger/debugger-toolbar.js
+++ /dev/null
@@ -1,1641 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-// A time interval sufficient for the options popup panel to finish hiding
-// itself.
-const POPUP_HIDDEN_DELAY = 100; // ms
-
-/**
- * Functions handling the toolbar view: close button, expand/collapse button,
- * pause/resume and stepping buttons etc.
- */
-function ToolbarView() {
-  dumpn("ToolbarView was instantiated");
-
-  this._onTogglePanesPressed = this._onTogglePanesPressed.bind(this);
-  this._onResumePressed = this._onResumePressed.bind(this);
-  this._onStepOverPressed = this._onStepOverPressed.bind(this);
-  this._onStepInPressed = this._onStepInPressed.bind(this);
-  this._onStepOutPressed = this._onStepOutPressed.bind(this);
-}
-
-ToolbarView.prototype = {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the ToolbarView");
-
-    this._instrumentsPaneToggleButton = document.getElementById("instruments-pane-toggle");
-    this._resumeButton = document.getElementById("resume");
-    this._stepOverButton = document.getElementById("step-over");
-    this._stepInButton = document.getElementById("step-in");
-    this._stepOutButton = document.getElementById("step-out");
-    this._resumeOrderTooltip = new Tooltip(document);
-    this._resumeOrderTooltip.defaultPosition = TOOLBAR_ORDER_POPUP_POSITION;
-
-    let resumeKey = ShortcutUtils.prettifyShortcut(document.getElementById("resumeKey"));
-    let stepOverKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepOverKey"));
-    let stepInKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepInKey"));
-    let stepOutKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepOutKey"));
-    this._resumeTooltip = L10N.getFormatStr("resumeButtonTooltip", resumeKey);
-    this._pauseTooltip = L10N.getFormatStr("pauseButtonTooltip", resumeKey);
-    this._stepOverTooltip = L10N.getFormatStr("stepOverTooltip", stepOverKey);
-    this._stepInTooltip = L10N.getFormatStr("stepInTooltip", stepInKey);
-    this._stepOutTooltip = L10N.getFormatStr("stepOutTooltip", stepOutKey);
-
-    this._instrumentsPaneToggleButton.addEventListener("mousedown", this._onTogglePanesPressed, false);
-    this._resumeButton.addEventListener("mousedown", this._onResumePressed, false);
-    this._stepOverButton.addEventListener("mousedown", this._onStepOverPressed, false);
-    this._stepInButton.addEventListener("mousedown", this._onStepInPressed, false);
-    this._stepOutButton.addEventListener("mousedown", this._onStepOutPressed, false);
-
-    this._stepOverButton.setAttribute("tooltiptext", this._stepOverTooltip);
-    this._stepInButton.setAttribute("tooltiptext", this._stepInTooltip);
-    this._stepOutButton.setAttribute("tooltiptext", this._stepOutTooltip);
-    this._addCommands();
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the ToolbarView");
-
-    this._instrumentsPaneToggleButton.removeEventListener("mousedown", this._onTogglePanesPressed, false);
-    this._resumeButton.removeEventListener("mousedown", this._onResumePressed, false);
-    this._stepOverButton.removeEventListener("mousedown", this._onStepOverPressed, false);
-    this._stepInButton.removeEventListener("mousedown", this._onStepInPressed, false);
-    this._stepOutButton.removeEventListener("mousedown", this._onStepOutPressed, false);
-  },
-
-  /**
-   * Add commands that XUL can fire.
-   */
-  _addCommands: function() {
-    utils.addCommands(document.getElementById('debuggerCommands'), {
-      resumeCommand: () => this._onResumePressed(),
-      stepOverCommand: () => this._onStepOverPressed(),
-      stepInCommand: () => this._onStepInPressed(),
-      stepOutCommand: () => this._onStepOutPressed()
-    });
-  },
-
-  /**
-   * Display a warning when trying to resume a debuggee while another is paused.
-   * Debuggees must be unpaused in a Last-In-First-Out order.
-   *
-   * @param string aPausedUrl
-   *        The URL of the last paused debuggee.
-   */
-  showResumeWarning: function(aPausedUrl) {
-    let label = L10N.getFormatStr("resumptionOrderPanelTitle", aPausedUrl);
-    let defaultStyle = "default-tooltip-simple-text-colors";
-    this._resumeOrderTooltip.setTextContent({ messages: [label], isAlertTooltip: true });
-    this._resumeOrderTooltip.show(this._resumeButton);
-  },
-
-  /**
-   * Sets the resume button state based on the debugger active thread.
-   *
-   * @param string aState
-   *        Either "paused" or "attached".
-   */
-  toggleResumeButtonState: function(aState) {
-    // If we're paused, check and show a resume label on the button.
-    if (aState == "paused") {
-      this._resumeButton.setAttribute("checked", "true");
-      this._resumeButton.setAttribute("tooltiptext", this._resumeTooltip);
-    }
-    // If we're attached, do the opposite.
-    else if (aState == "attached") {
-      this._resumeButton.removeAttribute("checked");
-      this._resumeButton.setAttribute("tooltiptext", this._pauseTooltip);
-    }
-  },
-
-  /**
-   * Listener handling the toggle button click event.
-   */
-  _onTogglePanesPressed: function() {
-    DebuggerView.toggleInstrumentsPane({
-      visible: DebuggerView.instrumentsPaneHidden,
-      animated: true,
-      delayed: true
-    });
-  },
-
-  /**
-   * Listener handling the pause/resume button click event.
-   */
-  _onResumePressed: function() {
-    if (DebuggerController.StackFrames._currentFrameDescription != FRAME_TYPE.NORMAL) {
-      return;
-    }
-
-    if (DebuggerController.activeThread.paused) {
-      let warn = DebuggerController._ensureResumptionOrder;
-      DebuggerController.StackFrames.currentFrameDepth = -1;
-      DebuggerController.activeThread.resume(warn);
-    } else {
-      DebuggerController.ThreadState.interruptedByResumeButton = true;
-      DebuggerController.activeThread.interrupt();
-    }
-  },
-
-  /**
-   * Listener handling the step over button click event.
-   */
-  _onStepOverPressed: function() {
-    if (DebuggerController.activeThread.paused) {
-      DebuggerController.StackFrames.currentFrameDepth = -1;
-      let warn = DebuggerController._ensureResumptionOrder;
-      DebuggerController.activeThread.stepOver(warn);
-    }
-  },
-
-  /**
-   * Listener handling the step in button click event.
-   */
-  _onStepInPressed: function() {
-    if (DebuggerController.StackFrames._currentFrameDescription != FRAME_TYPE.NORMAL) {
-      return;
-    }
-
-    if (DebuggerController.activeThread.paused) {
-      DebuggerController.StackFrames.currentFrameDepth = -1;
-      let warn = DebuggerController._ensureResumptionOrder;
-      DebuggerController.activeThread.stepIn(warn);
-    }
-  },
-
-  /**
-   * Listener handling the step out button click event.
-   */
-  _onStepOutPressed: function() {
-    if (DebuggerController.activeThread.paused) {
-      DebuggerController.StackFrames.currentFrameDepth = -1;
-      let warn = DebuggerController._ensureResumptionOrder;
-      DebuggerController.activeThread.stepOut(warn);
-    }
-  },
-
-  _instrumentsPaneToggleButton: null,
-  _resumeButton: null,
-  _stepOverButton: null,
-  _stepInButton: null,
-  _stepOutButton: null,
-  _resumeOrderTooltip: null,
-  _resumeTooltip: "",
-  _pauseTooltip: "",
-  _stepOverTooltip: "",
-  _stepInTooltip: "",
-  _stepOutTooltip: ""
-};
-
-/**
- * Functions handling the options UI.
- */
-function OptionsView() {
-  dumpn("OptionsView was instantiated");
-
-  this._toggleAutoPrettyPrint = this._toggleAutoPrettyPrint.bind(this);
-  this._togglePauseOnExceptions = this._togglePauseOnExceptions.bind(this);
-  this._toggleIgnoreCaughtExceptions = this._toggleIgnoreCaughtExceptions.bind(this);
-  this._toggleShowPanesOnStartup = this._toggleShowPanesOnStartup.bind(this);
-  this._toggleShowVariablesOnlyEnum = this._toggleShowVariablesOnlyEnum.bind(this);
-  this._toggleShowVariablesFilterBox = this._toggleShowVariablesFilterBox.bind(this);
-  this._toggleShowOriginalSource = this._toggleShowOriginalSource.bind(this);
-  this._toggleAutoBlackBox = this._toggleAutoBlackBox.bind(this);
-}
-
-OptionsView.prototype = {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the OptionsView");
-
-    this._button = document.getElementById("debugger-options");
-    this._autoPrettyPrint = document.getElementById("auto-pretty-print");
-    this._pauseOnExceptionsItem = document.getElementById("pause-on-exceptions");
-    this._ignoreCaughtExceptionsItem = document.getElementById("ignore-caught-exceptions");
-    this._showPanesOnStartupItem = document.getElementById("show-panes-on-startup");
-    this._showVariablesOnlyEnumItem = document.getElementById("show-vars-only-enum");
-    this._showVariablesFilterBoxItem = document.getElementById("show-vars-filter-box");
-    this._showOriginalSourceItem = document.getElementById("show-original-source");
-    this._autoBlackBoxItem = document.getElementById("auto-black-box");
-
-    this._autoPrettyPrint.setAttribute("checked", Prefs.autoPrettyPrint);
-    this._pauseOnExceptionsItem.setAttribute("checked", Prefs.pauseOnExceptions);
-    this._ignoreCaughtExceptionsItem.setAttribute("checked", Prefs.ignoreCaughtExceptions);
-    this._showPanesOnStartupItem.setAttribute("checked", Prefs.panesVisibleOnStartup);
-    this._showVariablesOnlyEnumItem.setAttribute("checked", Prefs.variablesOnlyEnumVisible);
-    this._showVariablesFilterBoxItem.setAttribute("checked", Prefs.variablesSearchboxVisible);
-    this._showOriginalSourceItem.setAttribute("checked", Prefs.sourceMapsEnabled);
-    this._autoBlackBoxItem.setAttribute("checked", Prefs.autoBlackBox);
-
-    this._addCommands();
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the OptionsView");
-    // Nothing to do here yet.
-  },
-
-  /**
-   * Add commands that XUL can fire.
-   */
-  _addCommands: function() {
-    utils.addCommands(document.getElementById('debuggerCommands'), {
-      toggleAutoPrettyPrint: () => this._toggleAutoPrettyPrint(),
-      togglePauseOnExceptions: () => this._togglePauseOnExceptions(),
-      toggleIgnoreCaughtExceptions: () => this._toggleIgnoreCaughtExceptions(),
-      toggleShowPanesOnStartup: () => this._toggleShowPanesOnStartup(),
-      toggleShowOnlyEnum: () => this._toggleShowVariablesOnlyEnum(),
-      toggleShowVariablesFilterBox: () => this._toggleShowVariablesFilterBox(),
-      toggleShowOriginalSource: () => this._toggleShowOriginalSource(),
-      toggleAutoBlackBox: () =>  this._toggleAutoBlackBox()
-    });
-  },
-
-  /**
-   * Listener handling the 'gear menu' popup showing event.
-   */
-  _onPopupShowing: function() {
-    this._button.setAttribute("open", "true");
-    window.emit(EVENTS.OPTIONS_POPUP_SHOWING);
-  },
-
-  /**
-   * Listener handling the 'gear menu' popup hiding event.
-   */
-  _onPopupHiding: function() {
-    this._button.removeAttribute("open");
-  },
-
-  /**
-   * Listener handling the 'gear menu' popup hidden event.
-   */
-  _onPopupHidden: function() {
-    window.emit(EVENTS.OPTIONS_POPUP_HIDDEN);
-  },
-
-  /**
-   * Listener handling the 'auto pretty print' menuitem command.
-   */
-  _toggleAutoPrettyPrint: function(){
-    Prefs.autoPrettyPrint =
-      this._autoPrettyPrint.getAttribute("checked") == "true";
-  },
-
-  /**
-   * Listener handling the 'pause on exceptions' menuitem command.
-   */
-  _togglePauseOnExceptions: function() {
-    Prefs.pauseOnExceptions =
-      this._pauseOnExceptionsItem.getAttribute("checked") == "true";
-
-    DebuggerController.activeThread.pauseOnExceptions(
-      Prefs.pauseOnExceptions,
-      Prefs.ignoreCaughtExceptions);
-  },
-
-  _toggleIgnoreCaughtExceptions: function() {
-    Prefs.ignoreCaughtExceptions =
-      this._ignoreCaughtExceptionsItem.getAttribute("checked") == "true";
-
-    DebuggerController.activeThread.pauseOnExceptions(
-      Prefs.pauseOnExceptions,
-      Prefs.ignoreCaughtExceptions);
-  },
-
-  /**
-   * Listener handling the 'show panes on startup' menuitem command.
-   */
-  _toggleShowPanesOnStartup: function() {
-    Prefs.panesVisibleOnStartup =
-      this._showPanesOnStartupItem.getAttribute("checked") == "true";
-  },
-
-  /**
-   * Listener handling the 'show non-enumerables' menuitem command.
-   */
-  _toggleShowVariablesOnlyEnum: function() {
-    let pref = Prefs.variablesOnlyEnumVisible =
-      this._showVariablesOnlyEnumItem.getAttribute("checked") == "true";
-
-    DebuggerView.Variables.onlyEnumVisible = pref;
-  },
-
-  /**
-   * Listener handling the 'show variables searchbox' menuitem command.
-   */
-  _toggleShowVariablesFilterBox: function() {
-    let pref = Prefs.variablesSearchboxVisible =
-      this._showVariablesFilterBoxItem.getAttribute("checked") == "true";
-
-    DebuggerView.Variables.searchEnabled = pref;
-  },
-
-  /**
-   * Listener handling the 'show original source' menuitem command.
-   */
-  _toggleShowOriginalSource: function() {
-    let pref = Prefs.sourceMapsEnabled =
-      this._showOriginalSourceItem.getAttribute("checked") == "true";
-
-    // Don't block the UI while reconfiguring the server.
-    window.once(EVENTS.OPTIONS_POPUP_HIDDEN, () => {
-      // The popup panel needs more time to hide after triggering onpopuphidden.
-      window.setTimeout(() => {
-        DebuggerController.reconfigureThread({
-          useSourceMaps: pref,
-          autoBlackBox: Prefs.autoBlackBox
-        });
-      }, POPUP_HIDDEN_DELAY);
-    });
-  },
-
-  /**
-   * Listener handling the 'automatically black box minified sources' menuitem
-   * command.
-   */
-  _toggleAutoBlackBox: function() {
-    let pref = Prefs.autoBlackBox =
-      this._autoBlackBoxItem.getAttribute("checked") == "true";
-
-    // Don't block the UI while reconfiguring the server.
-    window.once(EVENTS.OPTIONS_POPUP_HIDDEN, () => {
-      // The popup panel needs more time to hide after triggering onpopuphidden.
-      window.setTimeout(() => {
-        DebuggerController.reconfigureThread({
-          useSourceMaps: Prefs.sourceMapsEnabled,
-          autoBlackBox: pref
-        });
-      }, POPUP_HIDDEN_DELAY);
-    });
-  },
-
-  _button: null,
-  _pauseOnExceptionsItem: null,
-  _showPanesOnStartupItem: null,
-  _showVariablesOnlyEnumItem: null,
-  _showVariablesFilterBoxItem: null,
-  _showOriginalSourceItem: null,
-  _autoBlackBoxItem: null
-};
-
-/**
- * Functions handling the stackframes UI.
- */
-function StackFramesView() {
-  dumpn("StackFramesView was instantiated");
-
-  this._onStackframeRemoved = this._onStackframeRemoved.bind(this);
-  this._onSelect = this._onSelect.bind(this);
-  this._onScroll = this._onScroll.bind(this);
-  this._afterScroll = this._afterScroll.bind(this);
-}
-
-StackFramesView.prototype = Heritage.extend(WidgetMethods, {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the StackFramesView");
-
-    this.widget = new BreadcrumbsWidget(document.getElementById("stackframes"));
-    this.widget.addEventListener("select", this._onSelect, false);
-    this.widget.addEventListener("scroll", this._onScroll, true);
-    window.addEventListener("resize", this._onScroll, true);
-
-    this.autoFocusOnFirstItem = false;
-    this.autoFocusOnSelection = false;
-
-    // This view's contents are also mirrored in a different container.
-    this._mirror = DebuggerView.StackFramesClassicList;
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the StackFramesView");
-
-    this.widget.removeEventListener("select", this._onSelect, false);
-    this.widget.removeEventListener("scroll", this._onScroll, true);
-    window.removeEventListener("resize", this._onScroll, true);
-  },
-
-  /**
-   * Adds a frame in this stackframes container.
-   *
-   * @param string aTitle
-   *        The frame title (function name).
-   * @param string aUrl
-   *        The frame source url.
-   * @param string aLine
-   *        The frame line number.
-   * @param number aDepth
-   *        The frame depth in the stack.
-   * @param boolean aIsBlackBoxed
-   *        Whether or not the frame is black boxed.
-   */
-  addFrame: function(aTitle, aUrl, aLine, aDepth, aIsBlackBoxed) {
-    // Blackboxed stack frames are collapsed into a single entry in
-    // the view. By convention, only the first frame is displayed.
-    if (aIsBlackBoxed) {
-      if (this._prevBlackBoxedUrl == aUrl) {
-        return;
-      }
-      this._prevBlackBoxedUrl = aUrl;
-    } else {
-      this._prevBlackBoxedUrl = null;
-    }
-
-    // Create the element node for the stack frame item.
-    let frameView = this._createFrameView.apply(this, arguments);
-
-    // Append a stack frame item to this container.
-    this.push([frameView], {
-      index: 0, /* specifies on which position should the item be appended */
-      attachment: {
-        title: aTitle,
-        url: aUrl,
-        line: aLine,
-        depth: aDepth
-      },
-      // Make sure that when the stack frame item is removed, the corresponding
-      // mirrored item in the classic list is also removed.
-      finalize: this._onStackframeRemoved
-    });
-
-    // Mirror this newly inserted item inside the "Call Stack" tab.
-    this._mirror.addFrame(aTitle, aUrl, aLine, aDepth);
-  },
-
-  /**
-   * Selects the frame at the specified depth in this container.
-   * @param number aDepth
-   */
-  set selectedDepth(aDepth) {
-    this.selectedItem = aItem => aItem.attachment.depth == aDepth;
-  },
-
-  /**
-   * Gets the currently selected stack frame's depth in this container.
-   * This will essentially be the opposite of |selectedIndex|, which deals
-   * with the position in the view, where the last item added is actually
-   * the bottommost, not topmost.
-   * @return number
-   */
-  get selectedDepth() {
-    return this.selectedItem.attachment.depth;
-  },
-
-  /**
-   * Specifies if the active thread has more frames that need to be loaded.
-   */
-  dirty: false,
-
-  /**
-   * Customization function for creating an item's UI.
-   *
-   * @param string aTitle
-   *        The frame title to be displayed in the list.
-   * @param string aUrl
-   *        The frame source url.
-   * @param string aLine
-   *        The frame line number.
-   * @param number aDepth
-   *        The frame depth in the stack.
-   * @param boolean aIsBlackBoxed
-   *        Whether or not the frame is black boxed.
-   * @return nsIDOMNode
-   *         The stack frame view.
-   */
-  _createFrameView: function(aTitle, aUrl, aLine, aDepth, aIsBlackBoxed) {
-    let container = document.createElement("hbox");
-    container.id = "stackframe-" + aDepth;
-    container.className = "dbg-stackframe";
-
-    let frameDetails = SourceUtils.trimUrlLength(
-      SourceUtils.getSourceLabel(aUrl),
-      STACK_FRAMES_SOURCE_URL_MAX_LENGTH,
-      STACK_FRAMES_SOURCE_URL_TRIM_SECTION);
-
-    if (aIsBlackBoxed) {
-      container.classList.add("dbg-stackframe-black-boxed");
-    } else {
-      let frameTitleNode = document.createElement("label");
-      frameTitleNode.className = "plain dbg-stackframe-title breadcrumbs-widget-item-tag";
-      frameTitleNode.setAttribute("value", aTitle);
-      container.appendChild(frameTitleNode);
-
-      frameDetails += SEARCH_LINE_FLAG + aLine;
-    }
-
-    let frameDetailsNode = document.createElement("label");
-    frameDetailsNode.className = "plain dbg-stackframe-details breadcrumbs-widget-item-id";
-    frameDetailsNode.setAttribute("value", frameDetails);
-    container.appendChild(frameDetailsNode);
-
-    return container;
-  },
-
-  /**
-   * Function called each time a stack frame item is removed.
-   *
-   * @param object aItem
-   *        The corresponding item.
-   */
-  _onStackframeRemoved: function(aItem) {
-    dumpn("Finalizing stackframe item: " + aItem.stringify());
-
-    // Remove the mirrored item in the classic list.
-    let depth = aItem.attachment.depth;
-    this._mirror.remove(this._mirror.getItemForAttachment(e => e.depth == depth));
-
-    // Forget the previously blackboxed stack frame url.
-    this._prevBlackBoxedUrl = null;
-  },
-
-  /**
-   * The select listener for the stackframes container.
-   */
-  _onSelect: function(e) {
-    let stackframeItem = this.selectedItem;
-    if (stackframeItem) {
-      // The container is not empty and an actual item was selected.
-      let depth = stackframeItem.attachment.depth;
-
-      // Mirror the selected item in the classic list.
-      this.suppressSelectionEvents = true;
-      this._mirror.selectedItem = e => e.attachment.depth == depth;
-      this.suppressSelectionEvents = false;
-
-      DebuggerController.StackFrames.selectFrame(depth);
-    }
-  },
-
-  /**
-   * The scroll listener for the stackframes container.
-   */
-  _onScroll: function() {
-    // Update the stackframes container only if we have to.
-    if (!this.dirty) {
-      return;
-    }
-    // Allow requests to settle down first.
-    setNamedTimeout("stack-scroll", STACK_FRAMES_SCROLL_DELAY, this._afterScroll);
-  },
-
-  /**
-   * Requests the addition of more frames from the controller.
-   */
-  _afterScroll: function() {
-    let scrollPosition = this.widget.getAttribute("scrollPosition");
-    let scrollWidth = this.widget.getAttribute("scrollWidth");
-
-    // If the stackframes container scrolled almost to the end, with only
-    // 1/10 of a breadcrumb remaining, load more content.
-    if (scrollPosition - scrollWidth / 10 < 1) {
-      this.ensureIndexIsVisible(CALL_STACK_PAGE_SIZE - 1);
-      this.dirty = false;
-
-      // Loads more stack frames from the debugger server cache.
-      DebuggerController.StackFrames.addMoreFrames();
-    }
-  },
-
-  _mirror: null,
-  _prevBlackBoxedUrl: null
-});
-
-/*
- * Functions handling the stackframes classic list UI.
- * Controlled by the DebuggerView.StackFrames isntance.
- */
-function StackFramesClassicListView() {
-  dumpn("StackFramesClassicListView was instantiated");
-
-  this._onSelect = this._onSelect.bind(this);
-}
-
-StackFramesClassicListView.prototype = Heritage.extend(WidgetMethods, {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the StackFramesClassicListView");
-
-    this.widget = new SideMenuWidget(document.getElementById("callstack-list"));
-    this.widget.addEventListener("select", this._onSelect, false);
-
-    this.emptyText = L10N.getStr("noStackFramesText");
-    this.autoFocusOnFirstItem = false;
-    this.autoFocusOnSelection = false;
-
-    // This view's contents are also mirrored in a different container.
-    this._mirror = DebuggerView.StackFrames;
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the StackFramesClassicListView");
-
-    this.widget.removeEventListener("select", this._onSelect, false);
-  },
-
-  /**
-   * Adds a frame in this stackframes container.
-   *
-   * @param string aTitle
-   *        The frame title (function name).
-   * @param string aUrl
-   *        The frame source url.
-   * @param string aLine
-   *        The frame line number.
-   * @param number aDepth
-   *        The frame depth in the stack.
-   */
-  addFrame: function(aTitle, aUrl, aLine, aDepth) {
-    // Create the element node for the stack frame item.
-    let frameView = this._createFrameView.apply(this, arguments);
-
-    // Append a stack frame item to this container.
-    this.push([frameView], {
-      attachment: {
-        depth: aDepth
-      }
-    });
-  },
-
-  /**
-   * Customization function for creating an item's UI.
-   *
-   * @param string aTitle
-   *        The frame title to be displayed in the list.
-   * @param string aUrl
-   *        The frame source url.
-   * @param string aLine
-   *        The frame line number.
-   * @param number aDepth
-   *        The frame depth in the stack.
-   * @return nsIDOMNode
-   *         The stack frame view.
-   */
-  _createFrameView: function(aTitle, aUrl, aLine, aDepth) {
-    let container = document.createElement("hbox");
-    container.id = "classic-stackframe-" + aDepth;
-    container.className = "dbg-classic-stackframe";
-    container.setAttribute("flex", "1");
-
-    let frameTitleNode = document.createElement("label");
-    frameTitleNode.className = "plain dbg-classic-stackframe-title";
-    frameTitleNode.setAttribute("value", aTitle);
-    frameTitleNode.setAttribute("crop", "center");
-
-    let frameDetailsNode = document.createElement("hbox");
-    frameDetailsNode.className = "plain dbg-classic-stackframe-details";
-
-    let frameUrlNode = document.createElement("label");
-    frameUrlNode.className = "plain dbg-classic-stackframe-details-url";
-    frameUrlNode.setAttribute("value", SourceUtils.getSourceLabel(aUrl));
-    frameUrlNode.setAttribute("crop", "center");
-    frameDetailsNode.appendChild(frameUrlNode);
-
-    let frameDetailsSeparator = document.createElement("label");
-    frameDetailsSeparator.className = "plain dbg-classic-stackframe-details-sep";
-    frameDetailsSeparator.setAttribute("value", SEARCH_LINE_FLAG);
-    frameDetailsNode.appendChild(frameDetailsSeparator);
-
-    let frameLineNode = document.createElement("label");
-    frameLineNode.className = "plain dbg-classic-stackframe-details-line";
-    frameLineNode.setAttribute("value", aLine);
-    frameDetailsNode.appendChild(frameLineNode);
-
-    container.appendChild(frameTitleNode);
-    container.appendChild(frameDetailsNode);
-
-    return container;
-  },
-
-  /**
-   * The select listener for the stackframes container.
-   */
-  _onSelect: function(e) {
-    let stackframeItem = this.selectedItem;
-    if (stackframeItem) {
-      // The container is not empty and an actual item was selected.
-      // Mirror the selected item in the breadcrumbs list.
-      let depth = stackframeItem.attachment.depth;
-      this._mirror.selectedItem = e => e.attachment.depth == depth;
-    }
-  },
-
-  _mirror: null
-});
-
-/**
- * Functions handling the filtering UI.
- */
-function FilterView() {
-  dumpn("FilterView was instantiated");
-
-  this._onClick = this._onClick.bind(this);
-  this._onInput = this._onInput.bind(this);
-  this._onKeyPress = this._onKeyPress.bind(this);
-  this._onBlur = this._onBlur.bind(this);
-}
-
-FilterView.prototype = {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the FilterView");
-
-    this._searchbox = document.getElementById("searchbox");
-    this._searchboxHelpPanel = document.getElementById("searchbox-help-panel");
-    this._filterLabel = document.getElementById("filter-label");
-    this._globalOperatorButton = document.getElementById("global-operator-button");
-    this._globalOperatorLabel = document.getElementById("global-operator-label");
-    this._functionOperatorButton = document.getElementById("function-operator-button");
-    this._functionOperatorLabel = document.getElementById("function-operator-label");
-    this._tokenOperatorButton = document.getElementById("token-operator-button");
-    this._tokenOperatorLabel = document.getElementById("token-operator-label");
-    this._lineOperatorButton = document.getElementById("line-operator-button");
-    this._lineOperatorLabel = document.getElementById("line-operator-label");
-    this._variableOperatorButton = document.getElementById("variable-operator-button");
-    this._variableOperatorLabel = document.getElementById("variable-operator-label");
-
-    this._fileSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("fileSearchKey"));
-    this._globalSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("globalSearchKey"));
-    this._filteredFunctionsKey = ShortcutUtils.prettifyShortcut(document.getElementById("functionSearchKey"));
-    this._tokenSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("tokenSearchKey"));
-    this._lineSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("lineSearchKey"));
-    this._variableSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("variableSearchKey"));
-
-    this._searchbox.addEventListener("click", this._onClick, false);
-    this._searchbox.addEventListener("select", this._onInput, false);
-    this._searchbox.addEventListener("input", this._onInput, false);
-    this._searchbox.addEventListener("keypress", this._onKeyPress, false);
-    this._searchbox.addEventListener("blur", this._onBlur, false);
-
-    let placeholder = L10N.getFormatStr("emptySearchText", this._fileSearchKey);
-    this._searchbox.setAttribute("placeholder", placeholder);
-
-    this._globalOperatorButton.setAttribute("label", SEARCH_GLOBAL_FLAG);
-    this._functionOperatorButton.setAttribute("label", SEARCH_FUNCTION_FLAG);
-    this._tokenOperatorButton.setAttribute("label", SEARCH_TOKEN_FLAG);
-    this._lineOperatorButton.setAttribute("label", SEARCH_LINE_FLAG);
-    this._variableOperatorButton.setAttribute("label", SEARCH_VARIABLE_FLAG);
-
-    this._filterLabel.setAttribute("value",
-      L10N.getFormatStr("searchPanelFilter", this._fileSearchKey));
-    this._globalOperatorLabel.setAttribute("value",
-      L10N.getFormatStr("searchPanelGlobal", this._globalSearchKey));
-    this._functionOperatorLabel.setAttribute("value",
-      L10N.getFormatStr("searchPanelFunction", this._filteredFunctionsKey));
-    this._tokenOperatorLabel.setAttribute("value",
-      L10N.getFormatStr("searchPanelToken", this._tokenSearchKey));
-    this._lineOperatorLabel.setAttribute("value",
-      L10N.getFormatStr("searchPanelGoToLine", this._lineSearchKey));
-    this._variableOperatorLabel.setAttribute("value",
-      L10N.getFormatStr("searchPanelVariable", this._variableSearchKey));
-
-    this._addCommands();
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the FilterView");
-
-    this._searchbox.removeEventListener("click", this._onClick, false);
-    this._searchbox.removeEventListener("select", this._onInput, false);
-    this._searchbox.removeEventListener("input", this._onInput, false);
-    this._searchbox.removeEventListener("keypress", this._onKeyPress, false);
-    this._searchbox.removeEventListener("blur", this._onBlur, false);
-  },
-
-  /**
-   * Add commands that XUL can fire.
-   */
-  _addCommands: function() {
-    utils.addCommands(document.getElementById('debuggerCommands'), {
-      fileSearchCommand: () => this._doFileSearch(),
-      globalSearchCommand: () => this._doGlobalSearch(),
-      functionSearchCommand: () => this._doFunctionSearch(),
-      tokenSearchCommand: () => this._doTokenSearch(),
-      lineSearchCommand: () => this._doLineSearch(),
-      variableSearchCommand: () => this._doVariableSearch(),
-      variablesFocusCommand: () => this._doVariablesFocus()
-    });
-  },
-
-  /**
-   * Gets the entered operator and arguments in the searchbox.
-   * @return array
-   */
-  get searchData() {
-    let operator = "", args = [];
-
-    let rawValue = this._searchbox.value;
-    let rawLength = rawValue.length;
-    let globalFlagIndex = rawValue.indexOf(SEARCH_GLOBAL_FLAG);
-    let functionFlagIndex = rawValue.indexOf(SEARCH_FUNCTION_FLAG);
-    let variableFlagIndex = rawValue.indexOf(SEARCH_VARIABLE_FLAG);
-    let tokenFlagIndex = rawValue.lastIndexOf(SEARCH_TOKEN_FLAG);
-    let lineFlagIndex = rawValue.lastIndexOf(SEARCH_LINE_FLAG);
-
-    // This is not a global, function or variable search, allow file/line flags.
-    if (globalFlagIndex != 0 && functionFlagIndex != 0 && variableFlagIndex != 0) {
-      // Token search has precedence over line search.
-      if (tokenFlagIndex != -1) {
-        operator = SEARCH_TOKEN_FLAG;
-        args.push(rawValue.slice(0, tokenFlagIndex)); // file
-        args.push(rawValue.substr(tokenFlagIndex + 1, rawLength)); // token
-      } else if (lineFlagIndex != -1) {
-        operator = SEARCH_LINE_FLAG;
-        args.push(rawValue.slice(0, lineFlagIndex)); // file
-        args.push(+rawValue.substr(lineFlagIndex + 1, rawLength) || 0); // line
-      } else {
-        args.push(rawValue);
-      }
-    }
-    // Global searches dissalow the use of file or line flags.
-    else if (globalFlagIndex == 0) {
-      operator = SEARCH_GLOBAL_FLAG;
-      args.push(rawValue.slice(1));
-    }
-    // Function searches dissalow the use of file or line flags.
-    else if (functionFlagIndex == 0) {
-      operator = SEARCH_FUNCTION_FLAG;
-      args.push(rawValue.slice(1));
-    }
-    // Variable searches dissalow the use of file or line flags.
-    else if (variableFlagIndex == 0) {
-      operator = SEARCH_VARIABLE_FLAG;
-      args.push(rawValue.slice(1));
-    }
-
-    return [operator, args];
-  },
-
-  /**
-   * Returns the current search operator.
-   * @return string
-   */
-  get searchOperator() this.searchData[0],
-
-  /**
-   * Returns the current search arguments.
-   * @return array
-   */
-  get searchArguments() this.searchData[1],
-
-  /**
-   * Clears the text from the searchbox and any changed views.
-   */
-  clearSearch: function() {
-    this._searchbox.value = "";
-    this.clearViews();
-  },
-
-  /**
-   * Clears all the views that may pop up when searching.
-   */
-  clearViews: function() {
-    DebuggerView.GlobalSearch.clearView();
-    DebuggerView.FilteredSources.clearView();
-    DebuggerView.FilteredFunctions.clearView();
-    this._searchboxHelpPanel.hidePopup();
-  },
-
-  /**
-   * Performs a line search if necessary.
-   * (Jump to lines in the currently visible source).
-   *
-   * @param number aLine
-   *        The source line number to jump to.
-   */
-  _performLineSearch: function(aLine) {
-    // Make sure we're actually searching for a valid line.
-    if (aLine) {
-      DebuggerView.editor.setCursor({ line: aLine - 1, ch: 0 }, "center");
-    }
-  },
-
-  /**
-   * Performs a token search if necessary.
-   * (Search for tokens in the currently visible source).
-   *
-   * @param string aToken
-   *        The source token to find.
-   */
-  _performTokenSearch: function(aToken) {
-    // Make sure we're actually searching for a valid token.
-    if (!aToken) {
-      return;
-    }
-    DebuggerView.editor.find(aToken);
-  },
-
-  /**
-   * The click listener for the search container.
-   */
-  _onClick: function() {
-    // If there's some text in the searchbox, displaying a panel would
-    // interfere with double/triple click default behaviors.
-    if (!this._searchbox.value) {
-      this._searchboxHelpPanel.openPopup(this._searchbox);
-    }
-  },
-
-  /**
-   * The input listener for the search container.
-   */
-  _onInput: function() {
-    this.clearViews();
-
-    // Make sure we're actually searching for something.
-    if (!this._searchbox.value) {
-      return;
-    }
-
-    // Perform the required search based on the specified operator.
-    switch (this.searchOperator) {
-      case SEARCH_GLOBAL_FLAG:
-        // Schedule a global search for when the user stops typing.
-        DebuggerView.GlobalSearch.scheduleSearch(this.searchArguments[0]);
-        break;
-      case SEARCH_FUNCTION_FLAG:
-      // Schedule a function search for when the user stops typing.
-        DebuggerView.FilteredFunctions.scheduleSearch(this.searchArguments[0]);
-        break;
-      case SEARCH_VARIABLE_FLAG:
-        // Schedule a variable search for when the user stops typing.
-        DebuggerView.Variables.scheduleSearch(this.searchArguments[0]);
-        break;
-      case SEARCH_TOKEN_FLAG:
-        // Schedule a file+token search for when the user stops typing.
-        DebuggerView.FilteredSources.scheduleSearch(this.searchArguments[0]);
-        this._performTokenSearch(this.searchArguments[1]);
-        break;
-      case SEARCH_LINE_FLAG:
-        // Schedule a file+line search for when the user stops typing.
-        DebuggerView.FilteredSources.scheduleSearch(this.searchArguments[0]);
-        this._performLineSearch(this.searchArguments[1]);
-        break;
-      default:
-        // Schedule a file only search for when the user stops typing.
-        DebuggerView.FilteredSources.scheduleSearch(this.searchArguments[0]);
-        break;
-    }
-  },
-
-  /**
-   * The key press listener for the search container.
-   */
-  _onKeyPress: function(e) {
-    // This attribute is not implemented in Gecko at this time, see bug 680830.
-    e.char = String.fromCharCode(e.charCode);
-
-    // Perform the required action based on the specified operator.
-    let [operator, args] = this.searchData;
-    let isGlobalSearch = operator == SEARCH_GLOBAL_FLAG;
-    let isFunctionSearch = operator == SEARCH_FUNCTION_FLAG;
-    let isVariableSearch = operator == SEARCH_VARIABLE_FLAG;
-    let isTokenSearch = operator == SEARCH_TOKEN_FLAG;
-    let isLineSearch = operator == SEARCH_LINE_FLAG;
-    let isFileOnlySearch = !operator && args.length == 1;
-
-    // Depending on the pressed keys, determine to correct action to perform.
-    let actionToPerform;
-
-    // Meta+G and Ctrl+N focus next matches.
-    if ((e.char == "g" && e.metaKey) || e.char == "n" && e.ctrlKey) {
-      actionToPerform = "selectNext";
-    }
-    // Meta+Shift+G and Ctrl+P focus previous matches.
-    else if ((e.char == "G" && e.metaKey) || e.char == "p" && e.ctrlKey) {
-      actionToPerform = "selectPrev";
-    }
-    // Return, enter, down and up keys focus next or previous matches, while
-    // the escape key switches focus from the search container.
-    else switch (e.keyCode) {
-      case e.DOM_VK_RETURN:
-        var isReturnKey = true;
-        // If the shift key is pressed, focus on the previous result
-        actionToPerform = e.shiftKey ? "selectPrev" : "selectNext";
-        break;
-      case e.DOM_VK_DOWN:
-        actionToPerform = "selectNext";
-        break;
-      case e.DOM_VK_UP:
-        actionToPerform = "selectPrev";
-        break;
-    }
-
-    // If there's no action to perform, or no operator, file line or token
-    // were specified, then this is either a broken or empty search.
-    if (!actionToPerform || (!operator && !args.length)) {
-      DebuggerView.editor.dropSelection();
-      return;
-    }
-
-    e.preventDefault();
-    e.stopPropagation();
-
-    // Jump to the next/previous entry in the global search, or perform
-    // a new global search immediately
-    if (isGlobalSearch) {
-      let targetView = DebuggerView.GlobalSearch;
-      if (!isReturnKey) {
-        targetView[actionToPerform]();
-      } else if (targetView.hidden) {
-        targetView.scheduleSearch(args[0], 0);
-      }
-      return;
-    }
-
-    // Jump to the next/previous entry in the function search, perform
-    // a new function search immediately, or clear it.
-    if (isFunctionSearch) {
-      let targetView = DebuggerView.FilteredFunctions;
-      if (!isReturnKey) {
-        targetView[actionToPerform]();
-      } else if (targetView.hidden) {
-        targetView.scheduleSearch(args[0], 0);
-      } else {
-        if (!targetView.selectedItem) {
-          targetView.selectedIndex = 0;
-        }
-        this.clearSearch();
-      }
-      return;
-    }
-
-    // Perform a new variable search immediately.
-    if (isVariableSearch) {
-      let targetView = DebuggerView.Variables;
-      if (isReturnKey) {
-        targetView.scheduleSearch(args[0], 0);
-      }
-      return;
-    }
-
-    // Jump to the next/previous entry in the file search, perform
-    // a new file search immediately, or clear it.
-    if (isFileOnlySearch) {
-      let targetView = DebuggerView.FilteredSources;
-      if (!isReturnKey) {
-        targetView[actionToPerform]();
-      } else if (targetView.hidden) {
-        targetView.scheduleSearch(args[0], 0);
-      } else {
-        if (!targetView.selectedItem) {
-          targetView.selectedIndex = 0;
-        }
-        this.clearSearch();
-      }
-      return;
-    }
-
-    // Jump to the next/previous instance of the currently searched token.
-    if (isTokenSearch) {
-      let methods = { selectNext: "findNext", selectPrev: "findPrev" };
-      DebuggerView.editor[methods[actionToPerform]]();
-      return;
-    }
-
-    // Increment/decrement the currently searched caret line.
-    if (isLineSearch) {
-      let [, line] = args;
-      let amounts = { selectNext: 1, selectPrev: -1 };
-
-      // Modify the line number and jump to it.
-      line += !isReturnKey ? amounts[actionToPerform] : 0;
-      let lineCount = DebuggerView.editor.lineCount();
-      let lineTarget = line < 1 ? 1 : line > lineCount ? lineCount : line;
-      this._doSearch(SEARCH_LINE_FLAG, lineTarget);
-      return;
-    }
-  },
-
-  /**
-   * The blur listener for the search container.
-   */
-  _onBlur: function() {
-    this.clearViews();
-  },
-
-  /**
-   * Called when a filtering key sequence was pressed.
-   *
-   * @param string aOperator
-   *        The operator to use for filtering.
-   */
-  _doSearch: function(aOperator = "", aText = "") {
-    this._searchbox.focus();
-    this._searchbox.value = ""; // Need to clear value beforehand. Bug 779738.
-
-    if (aText) {
-      this._searchbox.value = aOperator + aText;
-      return;
-    }
-    if (DebuggerView.editor.somethingSelected()) {
-      this._searchbox.value = aOperator + DebuggerView.editor.getSelection();
-      return;
-    }
-    if (SEARCH_AUTOFILL.indexOf(aOperator) != -1) {
-      let cursor = DebuggerView.editor.getCursor();
-      let content = DebuggerView.editor.getText();
-      let location = DebuggerView.Sources.selectedItem.attachment.source.url;
-      let source = DebuggerController.Parser.get(content, location);
-      let identifier = source.getIdentifierAt({ line: cursor.line+1, column: cursor.ch });
-
-      if (identifier && identifier.name) {
-        this._searchbox.value = aOperator + identifier.name;
-        this._searchbox.select();
-        this._searchbox.selectionStart += aOperator.length;
-        return;
-      }
-    }
-    this._searchbox.value = aOperator;
-  },
-
-  /**
-   * Called when the source location filter key sequence was pressed.
-   */
-  _doFileSearch: function() {
-    this._doSearch();
-    this._searchboxHelpPanel.openPopup(this._searchbox);
-  },
-
-  /**
-   * Called when the global search filter key sequence was pressed.
-   */
-  _doGlobalSearch: function() {
-    this._doSearch(SEARCH_GLOBAL_FLAG);
-    this._searchboxHelpPanel.hidePopup();
-  },
-
-  /**
-   * Called when the source function filter key sequence was pressed.
-   */
-  _doFunctionSearch: function() {
-    this._doSearch(SEARCH_FUNCTION_FLAG);
-    this._searchboxHelpPanel.hidePopup();
-  },
-
-  /**
-   * Called when the source token filter key sequence was pressed.
-   */
-  _doTokenSearch: function() {
-    this._doSearch(SEARCH_TOKEN_FLAG);
-    this._searchboxHelpPanel.hidePopup();
-  },
-
-  /**
-   * Called when the source line filter key sequence was pressed.
-   */
-  _doLineSearch: function() {
-    this._doSearch(SEARCH_LINE_FLAG);
-    this._searchboxHelpPanel.hidePopup();
-  },
-
-  /**
-   * Called when the variable search filter key sequence was pressed.
-   */
-  _doVariableSearch: function() {
-    this._doSearch(SEARCH_VARIABLE_FLAG);
-    this._searchboxHelpPanel.hidePopup();
-  },
-
-  /**
-   * Called when the variables focus key sequence was pressed.
-   */
-  _doVariablesFocus: function() {
-    DebuggerView.showInstrumentsPane();
-    DebuggerView.Variables.focusFirstVisibleItem();
-  },
-
-  _searchbox: null,
-  _searchboxHelpPanel: null,
-  _globalOperatorButton: null,
-  _globalOperatorLabel: null,
-  _functionOperatorButton: null,
-  _functionOperatorLabel: null,
-  _tokenOperatorButton: null,
-  _tokenOperatorLabel: null,
-  _lineOperatorButton: null,
-  _lineOperatorLabel: null,
-  _variableOperatorButton: null,
-  _variableOperatorLabel: null,
-  _fileSearchKey: "",
-  _globalSearchKey: "",
-  _filteredFunctionsKey: "",
-  _tokenSearchKey: "",
-  _lineSearchKey: "",
-  _variableSearchKey: "",
-};
-
-/**
- * Functions handling the filtered sources UI.
- */
-function FilteredSourcesView() {
-  dumpn("FilteredSourcesView was instantiated");
-
-  this._onClick = this._onClick.bind(this);
-  this._onSelect = this._onSelect.bind(this);
-}
-
-FilteredSourcesView.prototype = Heritage.extend(ResultsPanelContainer.prototype, {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the FilteredSourcesView");
-
-    this.anchor = document.getElementById("searchbox");
-    this.widget.addEventListener("select", this._onSelect, false);
-    this.widget.addEventListener("click", this._onClick, false);
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the FilteredSourcesView");
-
-    this.widget.removeEventListener("select", this._onSelect, false);
-    this.widget.removeEventListener("click", this._onClick, false);
-    this.anchor = null;
-  },
-
-  /**
-   * Schedules searching for a source.
-   *
-   * @param string aToken
-   *        The function to search for.
-   * @param number aWait
-   *        The amount of milliseconds to wait until draining.
-   */
-  scheduleSearch: function(aToken, aWait) {
-    // The amount of time to wait for the requests to settle.
-    let maxDelay = FILE_SEARCH_ACTION_MAX_DELAY;
-    let delay = aWait === undefined ? maxDelay / aToken.length : aWait;
-
-    // Allow requests to settle down first.
-    setNamedTimeout("sources-search", delay, () => this._doSearch(aToken));
-  },
-
-  /**
-   * Finds file matches in all the displayed sources.
-   *
-   * @param string aToken
-   *        The string to search for.
-   */
-  _doSearch: function(aToken, aStore = []) {
-    // Don't continue filtering if the searched token is an empty string.
-    // In contrast with function searching, in this case we don't want to
-    // show a list of all the files when no search token was supplied.
-    if (!aToken) {
-      return;
-    }
-
-    for (let item of DebuggerView.Sources.items) {
-      let lowerCaseLabel = item.attachment.label.toLowerCase();
-      let lowerCaseToken = aToken.toLowerCase();
-      if (lowerCaseLabel.match(lowerCaseToken)) {
-        aStore.push(item);
-      }
-
-      // Once the maximum allowed number of results is reached, proceed
-      // with building the UI immediately.
-      if (aStore.length >= RESULTS_PANEL_MAX_RESULTS) {
-        this._syncView(aStore);
-        return;
-      }
-    }
-
-    // Couldn't reach the maximum allowed number of results, but that's ok,
-    // continue building the UI.
-    this._syncView(aStore);
-  },
-
-  /**
-   * Updates the list of sources displayed in this container.
-   *
-   * @param array aSearchResults
-   *        The results array, containing search details for each source.
-   */
-  _syncView: function(aSearchResults) {
-    // If there are no matches found, keep the popup hidden and avoid
-    // creating the view.
-    if (!aSearchResults.length) {
-      window.emit(EVENTS.FILE_SEARCH_MATCH_NOT_FOUND);
-      return;
-    }
-
-    for (let item of aSearchResults) {
-      let url = item.attachment.source.url;
-
-      if (url) {
-        // Create the element node for the location item.
-        let itemView = this._createItemView(
-          SourceUtils.trimUrlLength(item.attachment.label),
-          SourceUtils.trimUrlLength(url, 0, "start")
-        );
-
-        // Append a location item to this container for each match.
-        this.push([itemView], {
-          index: -1, /* specifies on which position should the item be appended */
-          attachment: {
-            url: url
-          }
-        });
-      }
-    }
-
-    // There's at least one item displayed in this container. Don't select it
-    // automatically if not forced (by tests) or in tandem with an operator.
-    if (this._autoSelectFirstItem || DebuggerView.Filtering.searchOperator) {
-      this.selectedIndex = 0;
-    }
-    this.hidden = false;
-
-    // Signal that file search matches were found and displayed.
-    window.emit(EVENTS.FILE_SEARCH_MATCH_FOUND);
-  },
-
-  /**
-   * The click listener for this container.
-   */
-  _onClick: function(e) {
-    let locationItem = this.getItemForElement(e.target);
-    if (locationItem) {
-      this.selectedItem = locationItem;
-      DebuggerView.Filtering.clearSearch();
-    }
-  },
-
-  /**
-   * The select listener for this container.
-   *
-   * @param object aItem
-   *        The item associated with the element to select.
-   */
-  _onSelect: function({ detail: locationItem }) {
-    if (locationItem) {
-      let actor = DebuggerView.Sources.getActorForLocation({ url: locationItem.attachment.url });
-      DebuggerView.setEditorLocation(actor, undefined, {
-        noCaret: true,
-        noDebug: true
-      });
-    }
-  }
-});
-
-/**
- * Functions handling the function search UI.
- */
-function FilteredFunctionsView() {
-  dumpn("FilteredFunctionsView was instantiated");
-
-  this._onClick = this._onClick.bind(this);
-  this._onSelect = this._onSelect.bind(this);
-}
-
-FilteredFunctionsView.prototype = Heritage.extend(ResultsPanelContainer.prototype, {
-  /**
-   * Initialization function, called when the debugger is started.
-   */
-  initialize: function() {
-    dumpn("Initializing the FilteredFunctionsView");
-
-    this.anchor = document.getElementById("searchbox");
-    this.widget.addEventListener("select", this._onSelect, false);
-    this.widget.addEventListener("click", this._onClick, false);
-  },
-
-  /**
-   * Destruction function, called when the debugger is closed.
-   */
-  destroy: function() {
-    dumpn("Destroying the FilteredFunctionsView");
-
-    this.widget.removeEventListener("select", this._onSelect, false);
-    this.widget.removeEventListener("click", this._onClick, false);
-    this.anchor = null;
-  },
-
-  /**
-   * Schedules searching for a function in all of the sources.
-   *
-   * @param string aToken
-   *        The function to search for.
-   * @param number aWait
-   *        The amount of milliseconds to wait until draining.
-   */
-  scheduleSearch: function(aToken, aWait) {
-    // The amount of time to wait for the requests to settle.
-    let maxDelay = FUNCTION_SEARCH_ACTION_MAX_DELAY;
-    let delay = aWait === undefined ? maxDelay / aToken.length : aWait;
-
-    // Allow requests to settle down first.
-    setNamedTimeout("function-search", delay, () => {
-      // Start fetching as many sources as possible, then perform the search.
-      let actors = DebuggerView.Sources.values;
-      let sourcesFetched = DebuggerController.SourceScripts.getTextForSources(actors);
-      sourcesFetched.then(aSources => this._doSearch(aToken, aSources));
-    });
-  },
-
-  /**
-   * Finds function matches in all the sources stored in the cache, and groups
-   * them by location and line number.
-   *
-   * @param string aToken
-   *        The string to search for.
-   * @param array aSources
-   *        An array of [url, text] tuples for each source.
-   */
-  _doSearch: function(aToken, aSources, aStore = []) {
-    // Continue parsing even if the searched token is an empty string, to
-    // cache the syntax tree nodes generated by the reflection API.
-
-    // Make sure the currently displayed source is parsed first. Once the
-    // maximum allowed number of results are found, parsing will be halted.
-    let currentActor = DebuggerView.Sources.selectedValue;
-    let currentSource = aSources.filter(([actor]) => actor == currentActor)[0];
-    aSources.splice(aSources.indexOf(currentSource), 1);
-    aSources.unshift(currentSource);
-
-    // If not searching for a specific function, only parse the displayed source,
-    // which is now the first item in the sources array.
-    if (!aToken) {
-      aSources.splice(1);
-    }
-
-    for (let [actor, contents] of aSources) {
-      let item = DebuggerView.Sources.getItemByValue(actor);
-      let url = item.attachment.source.url;
-      if (!url) {
-        continue;
-      }
-
-      let parsedSource = DebuggerController.Parser.get(contents, url);
-      let sourceResults = parsedSource.getNamedFunctionDefinitions(aToken);
-
-      for (let scriptResult of sourceResults) {
-        for (let parseResult of scriptResult) {
-          aStore.push({
-            sourceUrl: scriptResult.sourceUrl,
-            scriptOffset: scriptResult.scriptOffset,
-            functionName: parseResult.functionName,
-            functionLocation: parseResult.functionLocation,
-            inferredName: parseResult.inferredName,
-            inferredChain: parseResult.inferredChain,
-            inferredLocation: parseResult.inferredLocation
-          });
-
-          // Once the maximum allowed number of results is reached, proceed
-          // with building the UI immediately.
-          if (aStore.length >= RESULTS_PANEL_MAX_RESULTS) {
-            this._syncView(aStore);
-            return;
-          }
-        }
-      }
-    }
-
-    // Couldn't reach the maximum allowed number of results, but that's ok,
-    // continue building the UI.
-    this._syncView(aStore);
-  },
-
-  /**
-   * Updates the list of functions displayed in this container.
-   *
-   * @param array aSearchResults
-   *        The results array, containing search details for each source.
-   */
-  _syncView: function(aSearchResults) {
-    // If there are no matches found, keep the popup hidden and avoid
-    // creating the view.
-    if (!aSearchResults.length) {
-      window.emit(EVENTS.FUNCTION_SEARCH_MATCH_NOT_FOUND);
-      return;
-    }
-
-    for (let item of aSearchResults) {
-      // Some function expressions don't necessarily have a name, but the
-      // parser provides us with an inferred name from an enclosing
-      // VariableDeclarator, AssignmentExpression, ObjectExpression node.
-      if (item.functionName && item.inferredName &&
-          item.functionName != item.inferredName) {
-        let s = " " + L10N.getStr("functionSearchSeparatorLabel") + " ";
-        item.displayedName = item.inferredName + s + item.functionName;
-      }
-      // The function doesn't have an explicit name, but it could be inferred.
-      else if (item.inferredName) {
-        item.displayedName = item.inferredName;
-      }
-      // The function only has an explicit name.
-      else {
-        item.displayedName = item.functionName;
-      }
-
-      // Some function expressions have unexpected bounds, since they may not
-      // necessarily have an associated name defining them.
-      if (item.inferredLocation) {
-        item.actualLocation = item.inferredLocation;
-      } else {
-        item.actualLocation = item.functionLocation;
-      }
-
-      // Create the element node for the function item.
-      let itemView = this._createItemView(
-        SourceUtils.trimUrlLength(item.displayedName + "()"),
-        SourceUtils.trimUrlLength(item.sourceUrl, 0, "start"),
-        (item.inferredChain || []).join(".")
-      );
-
-      // Append a function item to this container for each match.
-      this.push([itemView], {
-        index: -1, /* specifies on which position should the item be appended */
-        attachment: item
-      });
-    }
-
-    // There's at least one item displayed in this container. Don't select it
-    // automatically if not forced (by tests).
-    if (this._autoSelectFirstItem) {
-      this.selectedIndex = 0;
-    }
-    this.hidden = false;
-
-    // Signal that function search matches were found and displayed.
-    window.emit(EVENTS.FUNCTION_SEARCH_MATCH_FOUND);
-  },
-
-  /**
-   * The click listener for this container.
-   */
-  _onClick: function(e) {
-    let functionItem = this.getItemForElement(e.target);
-    if (functionItem) {
-      this.selectedItem = functionItem;
-      DebuggerView.Filtering.clearSearch();
-    }
-  },
-
-  /**
-   * The select listener for this container.
-   */
-  _onSelect: function({ detail: functionItem }) {
-    if (functionItem) {
-      let sourceUrl = functionItem.attachment.sourceUrl;
-      let actor = DebuggerView.Sources.getActorForLocation({ url: sourceUrl });
-      let scriptOffset = functionItem.attachment.scriptOffset;
-      let actualLocation = functionItem.attachment.actualLocation;
-
-      DebuggerView.setEditorLocation(actor, actualLocation.start.line, {
-        charOffset: scriptOffset,
-        columnOffset: actualLocation.start.column,
-        align: "center",
-        noDebug: true
-      });
-    }
-  },
-
-  _searchTimeout: null,
-  _searchFunction: null,
-  _searchedToken: ""
-});
-
-/**
- * Preliminary setup for the DebuggerView object.
- */
-DebuggerView.Toolbar = new ToolbarView();
-DebuggerView.Options = new OptionsView();
-DebuggerView.Filtering = new FilterView();
-DebuggerView.FilteredSources = new FilteredSourcesView();
-DebuggerView.FilteredFunctions = new FilteredFunctionsView();
-DebuggerView.StackFrames = new StackFramesView();
-DebuggerView.StackFramesClassicList = new StackFramesClassicListView();
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -48,18 +48,16 @@ let DebuggerView = {
 
     let deferred = promise.defer();
     this._startup = deferred.promise;
 
     this._initializePanes();
     this.Toolbar.initialize();
     this.Options.initialize();
     this.Filtering.initialize();
-    this.FilteredSources.initialize();
-    this.FilteredFunctions.initialize();
     this.StackFrames.initialize();
     this.StackFramesClassicList.initialize();
     this.Sources.initialize();
     this.VariableBubble.initialize();
     this.Tracer.initialize();
     this.WatchExpressions.initialize();
     this.EventListeners.initialize();
     this.GlobalSearch.initialize();
@@ -83,18 +81,16 @@ let DebuggerView = {
     }
 
     let deferred = promise.defer();
     this._shutdown = deferred.promise;
 
     this.Toolbar.destroy();
     this.Options.destroy();
     this.Filtering.destroy();
-    this.FilteredSources.destroy();
-    this.FilteredFunctions.destroy();
     this.StackFrames.destroy();
     this.StackFramesClassicList.destroy();
     this.Sources.destroy();
     this.VariableBubble.destroy();
     this.Tracer.destroy();
     this.WatchExpressions.destroy();
     this.EventListeners.destroy();
     this.GlobalSearch.destroy();
@@ -644,18 +640,16 @@ let DebuggerView = {
 
   /**
    * Handles any initialization on a tab navigation event issued by the client.
    */
   handleTabNavigation: function() {
     dumpn("Handling tab navigation in the DebuggerView");
 
     this.Filtering.clearSearch();
-    this.FilteredSources.clearView();
-    this.FilteredFunctions.clearView();
     this.GlobalSearch.clearView();
     this.StackFrames.empty();
     this.Sources.empty();
     this.Variables.empty();
     this.EventListeners.empty();
 
     if (this.editor) {
       this.editor.setMode(Editor.modes.text);
@@ -667,18 +661,16 @@ let DebuggerView = {
     this.Sources.emptyText = L10N.getStr("loadingSourcesText");
   },
 
   _startup: null,
   _shutdown: null,
   Toolbar: null,
   Options: null,
   Filtering: null,
-  FilteredSources: null,
-  FilteredFunctions: null,
   GlobalSearch: null,
   StackFrames: null,
   Sources: null,
   Tracer: null,
   Variables: null,
   VariableBubble: null,
   WatchExpressions: null,
   EventListeners: null,
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -20,22 +20,31 @@
         fullscreenbutton="true"
         screenX="4" screenY="4"
         width="960" height="480"
         persist="screenX screenY width height sizemode">
 
   <script type="application/javascript;version=1.8"
           src="chrome://browser/content/devtools/theme-switching.js"/>
   <script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
-  <script type="text/javascript" src="debugger/utils.js"/>
   <script type="text/javascript" src="debugger-controller.js"/>
   <script type="text/javascript" src="debugger-view.js"/>
-  <script type="text/javascript" src="debugger-toolbar.js"/>
-  <script type="text/javascript" src="debugger-panes.js"/>
-
+  <script type="text/javascript" src="debugger/utils.js"/>
+  <script type="text/javascript" src="debugger/sources-view.js"/>
+  <script type="text/javascript" src="debugger/variable-bubble-view.js"/>
+  <script type="text/javascript" src="debugger/tracer-view.js"/>
+  <script type="text/javascript" src="debugger/watch-expressions-view.js"/>
+  <script type="text/javascript" src="debugger/event-listeners-view.js"/>
+  <script type="text/javascript" src="debugger/global-search-view.js"/>
+  <script type="text/javascript" src="debugger/toolbar-view.js"/>
+  <script type="text/javascript" src="debugger/options-view.js"/>
+  <script type="text/javascript" src="debugger/stack-frames-view.js"/>
+  <script type="text/javascript" src="debugger/stack-frames-classic-view.js"/>
+  <script type="text/javascript" src="debugger/filter-view.js"/>
+  
   <commandset id="editMenuCommands"/>
 
   <commandset id="debuggerCommands"></commandset>
 
   <popupset id="debuggerPopupset">
     <menupopup id="sourceEditorContextMenu"
                onpopupshowing="goUpdateGlobalEditMenuItems()">
       <menuitem id="se-dbg-cMenu-addBreakpoint"
--- a/browser/devtools/debugger/test/browser_dbg_search-popup-jank.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-popup-jank.js
@@ -12,18 +12,18 @@ let gSearchBox;
 
 function test() {
   initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
-    gDebugger.DebuggerView.FilteredSources._autoSelectFirstItem = false;
-    gDebugger.DebuggerView.FilteredFunctions._autoSelectFirstItem = false;
+    gDebugger.DebuggerView.Filtering.FilteredSources._autoSelectFirstItem = false;
+    gDebugger.DebuggerView.Filtering.FilteredFunctions._autoSelectFirstItem = false;
 
     waitForSourceShown(gPanel, "-01.js")
       .then(superGenericFileSearch)
       .then(() => ensureSourceIs(aPanel, "-01.js"))
       .then(() => ensureCaretAt(aPanel, 1))
 
       .then(superAccurateFileSearch)
       .then(() => ensureSourceIs(aPanel, "-01.js"))
--- a/browser/devtools/debugger/test/browser_dbg_search-sources-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-sources-01.js
@@ -14,17 +14,17 @@ function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(3);
 
   initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
-    gSearchView = gDebugger.DebuggerView.FilteredSources;
+    gSearchView = gDebugger.DebuggerView.Filtering.FilteredSources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceShown(gPanel, "-01.js")
       .then(bogusSearch)
       .then(firstSearch)
       .then(secondSearch)
       .then(thirdSearch)
       .then(fourthSearch)
--- a/browser/devtools/debugger/test/browser_dbg_search-sources-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-sources-02.js
@@ -15,17 +15,17 @@ function test() {
   requestLongerTimeout(3);
 
   initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gSourceUtils = gDebugger.SourceUtils;
-    gSearchView = gDebugger.DebuggerView.FilteredSources;
+    gSearchView = gDebugger.DebuggerView.Filtering.FilteredSources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceShown(gPanel, "-01.js")
       .then(firstSearch)
       .then(secondSearch)
       .then(thirdSearch)
       .then(fourthSearch)
       .then(fifthSearch)
--- a/browser/devtools/debugger/test/browser_dbg_search-symbols.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-symbols.js
@@ -13,17 +13,17 @@ let gEditor, gSources, gSearchBox, gFilt
 function test() {
   initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
-    gFilteredFunctions = gDebugger.DebuggerView.FilteredFunctions;
+    gFilteredFunctions = gDebugger.DebuggerView.Filtering.FilteredFunctions;
 
     waitForSourceShown(gPanel, "-01.js")
       .then(() => showSource("doc_function-search.html"))
       .then(htmlSearch)
       .then(() => showSource("code_function-search-01.js"))
       .then(firstJsSearch)
       .then(() => showSource("code_function-search-02.js"))
       .then(secondJsSearch)
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -722,18 +722,18 @@ function initChromeDebugger(aOnClose) {
   return deferred.promise;
 }
 
 function prepareDebugger(aDebugger) {
   if ("target" in aDebugger) {
     let view = aDebugger.panelWin.DebuggerView;
     view.Variables.lazyEmpty = false;
     view.Variables.lazySearch = false;
-    view.FilteredSources._autoSelectFirstItem = true;
-    view.FilteredFunctions._autoSelectFirstItem = true;
+    view.Filtering.FilteredSources._autoSelectFirstItem = true;
+    view.Filtering.FilteredFunctions._autoSelectFirstItem = true;
   } else {
     // Nothing to do here yet.
   }
 }
 
 function teardown(aPanel, aFlags = {}) {
   info("Destroying the specified debugger.");
 
--- a/browser/devtools/debugger/utils.js
+++ b/browser/devtools/debugger/utils.js
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const utils = {
+const XULUtils = {
   /**
    * Create <command> elements within `commandset` with event handlers
    * bound to the `command` event
    *
    * @param commandset HTML Element
    *        A <commandset> element
    * @param commands Object
    *        An object where keys specify <command> ids and values
@@ -21,8 +21,301 @@ const utils = {
       // XXX bug 371900: the command element must have an oncommand
       // attribute as a string set by `setAttribute` for keys to use it
       node.setAttribute('oncommand', ' ');
       node.addEventListener('command', commands[name]);
       commandset.appendChild(node);
     });
   }
 };
+
+// Used to detect minification for automatic pretty printing
+const SAMPLE_SIZE = 50; // no of lines
+const INDENT_COUNT_THRESHOLD = 5; // percentage
+const CHARACTER_LIMIT = 250; // line character limit
+
+/**
+ * Utility functions for handling sources.
+ */
+const SourceUtils = {
+  _labelsCache: new Map(), // Can't use WeakMaps because keys are strings.
+  _groupsCache: new Map(),
+  _minifiedCache: new WeakMap(),
+
+  /**
+   * Returns true if the specified url and/or content type are specific to
+   * javascript files.
+   *
+   * @return boolean
+   *         True if the source is likely javascript.
+   */
+  isJavaScript: function(aUrl, aContentType = "") {
+    return (aUrl && /\.jsm?$/.test(this.trimUrlQuery(aUrl))) ||
+           aContentType.contains("javascript");
+  },
+
+  /**
+   * Determines if the source text is minified by using
+   * the percentage indented of a subset of lines
+   *
+   * @return object
+   *         A promise that resolves to true if source text is minified.
+   */
+  isMinified: Task.async(function*(sourceClient) {
+    if (this._minifiedCache.has(sourceClient)) {
+      return this._minifiedCache.get(sourceClient);
+    }
+
+    let [, text] = yield DebuggerController.SourceScripts.getText(sourceClient);
+    let isMinified;
+    let lineEndIndex = 0;
+    let lineStartIndex = 0;
+    let lines = 0;
+    let indentCount = 0;
+    let overCharLimit = false;
+
+    // Strip comments.
+    text = text.replace(/\/\*[\S\s]*?\*\/|\/\/(.+|\n)/g, "");
+
+    while (lines++ < SAMPLE_SIZE) {
+      lineEndIndex = text.indexOf("\n", lineStartIndex);
+      if (lineEndIndex == -1) {
+         break;
+      }
+      if (/^\s+/.test(text.slice(lineStartIndex, lineEndIndex))) {
+        indentCount++;
+      }
+      // For files with no indents but are not minified.
+      if ((lineEndIndex - lineStartIndex) > CHARACTER_LIMIT) {
+        overCharLimit = true;
+        break;
+      }
+      lineStartIndex = lineEndIndex + 1;
+    }
+
+    isMinified =
+      ((indentCount / lines) * 100) < INDENT_COUNT_THRESHOLD || overCharLimit;
+
+    this._minifiedCache.set(sourceClient, isMinified);
+    return isMinified;
+  }),
+
+  /**
+   * Clears the labels, groups and minify cache, populated by methods like
+   * SourceUtils.getSourceLabel or Source Utils.getSourceGroup.
+   * This should be done every time the content location changes.
+   */
+  clearCache: function() {
+    this._labelsCache.clear();
+    this._groupsCache.clear();
+    this._minifiedCache.clear();
+  },
+
+  /**
+   * Gets a unique, simplified label from a source url.
+   *
+   * @param string aUrl
+   *        The source url.
+   * @return string
+   *         The simplified label.
+   */
+  getSourceLabel: function(aUrl) {
+    let cachedLabel = this._labelsCache.get(aUrl);
+    if (cachedLabel) {
+      return cachedLabel;
+    }
+
+    let sourceLabel = null;
+
+    for (let name of Object.keys(KNOWN_SOURCE_GROUPS)) {
+      if (aUrl.startsWith(KNOWN_SOURCE_GROUPS[name])) {
+        sourceLabel = aUrl.substring(KNOWN_SOURCE_GROUPS[name].length);
+      }
+    }
+
+    if (!sourceLabel) {
+      sourceLabel = this.trimUrl(aUrl);
+    }
+
+    let unicodeLabel = NetworkHelper.convertToUnicode(unescape(sourceLabel));
+    this._labelsCache.set(aUrl, unicodeLabel);
+    return unicodeLabel;
+  },
+
+  /**
+   * Gets as much information as possible about the hostname and directory paths
+   * of an url to create a short url group identifier.
+   *
+   * @param string aUrl
+   *        The source url.
+   * @return string
+   *         The simplified group.
+   */
+  getSourceGroup: function(aUrl) {
+    let cachedGroup = this._groupsCache.get(aUrl);
+    if (cachedGroup) {
+      return cachedGroup;
+    }
+
+    try {
+      // Use an nsIURL to parse all the url path parts.
+      var uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
+    } catch (e) {
+      // This doesn't look like a url, or nsIURL can't handle it.
+      return "";
+    }
+
+    let groupLabel = uri.prePath;
+
+    for (let name of Object.keys(KNOWN_SOURCE_GROUPS)) {
+      if (aUrl.startsWith(KNOWN_SOURCE_GROUPS[name])) {
+        groupLabel = name;
+      }
+    }
+
+    let unicodeLabel = NetworkHelper.convertToUnicode(unescape(groupLabel));
+    this._groupsCache.set(aUrl, unicodeLabel)
+    return unicodeLabel;
+  },
+
+  /**
+   * Trims the url by shortening it if it exceeds a certain length, adding an
+   * ellipsis at the end.
+   *
+   * @param string aUrl
+   *        The source url.
+   * @param number aLength [optional]
+   *        The expected source url length.
+   * @param number aSection [optional]
+   *        The section to trim. Supported values: "start", "center", "end"
+   * @return string
+   *         The shortened url.
+   */
+  trimUrlLength: function(aUrl, aLength, aSection) {
+    aLength = aLength || SOURCE_URL_DEFAULT_MAX_LENGTH;
+    aSection = aSection || "end";
+
+    if (aUrl.length > aLength) {
+      switch (aSection) {
+        case "start":
+          return L10N.ellipsis + aUrl.slice(-aLength);
+          break;
+        case "center":
+          return aUrl.substr(0, aLength / 2 - 1) + L10N.ellipsis + aUrl.slice(-aLength / 2 + 1);
+          break;
+        case "end":
+          return aUrl.substr(0, aLength) + L10N.ellipsis;
+          break;
+      }
+    }
+    return aUrl;
+  },
+
+  /**
+   * Trims the query part or reference identifier of a url string, if necessary.
+   *
+   * @param string aUrl
+   *        The source url.
+   * @return string
+   *         The shortened url.
+   */
+  trimUrlQuery: function(aUrl) {
+    let length = aUrl.length;
+    let q1 = aUrl.indexOf('?');
+    let q2 = aUrl.indexOf('&');
+    let q3 = aUrl.indexOf('#');
+    let q = Math.min(q1 != -1 ? q1 : length,
+                     q2 != -1 ? q2 : length,
+                     q3 != -1 ? q3 : length);
+
+    return aUrl.slice(0, q);
+  },
+
+  /**
+   * Trims as much as possible from a url, while keeping the label unique
+   * in the sources container.
+   *
+   * @param string | nsIURL aUrl
+   *        The source url.
+   * @param string aLabel [optional]
+   *        The resulting label at each step.
+   * @param number aSeq [optional]
+   *        The current iteration step.
+   * @return string
+   *         The resulting label at the final step.
+   */
+  trimUrl: function(aUrl, aLabel, aSeq) {
+    if (!(aUrl instanceof Ci.nsIURL)) {
+      try {
+        // Use an nsIURL to parse all the url path parts.
+        aUrl = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
+      } catch (e) {
+        // This doesn't look like a url, or nsIURL can't handle it.
+        return aUrl;
+      }
+    }
+    if (!aSeq) {
+      let name = aUrl.fileName;
+      if (name) {
+        // This is a regular file url, get only the file name (contains the
+        // base name and extension if available).
+
+        // If this url contains an invalid query, unfortunately nsIURL thinks
+        // it's part of the file extension. It must be removed.
+        aLabel = aUrl.fileName.replace(/\&.*/, "");
+      } else {
+        // This is not a file url, hence there is no base name, nor extension.
+        // Proceed using other available information.
+        aLabel = "";
+      }
+      aSeq = 1;
+    }
+
+    // If we have a label and it doesn't only contain a query...
+    if (aLabel && aLabel.indexOf("?") != 0) {
+      // A page may contain multiple requests to the same url but with different
+      // queries. It is *not* redundant to show each one.
+      if (!DebuggerView.Sources.getItemForAttachment(e => e.label == aLabel)) {
+        return aLabel;
+      }
+    }
+
+    // Append the url query.
+    if (aSeq == 1) {
+      let query = aUrl.query;
+      if (query) {
+        return this.trimUrl(aUrl, aLabel + "?" + query, aSeq + 1);
+      }
+      aSeq++;
+    }
+    // Append the url reference.
+    if (aSeq == 2) {
+      let ref = aUrl.ref;
+      if (ref) {
+        return this.trimUrl(aUrl, aLabel + "#" + aUrl.ref, aSeq + 1);
+      }
+      aSeq++;
+    }
+    // Prepend the url directory.
+    if (aSeq == 3) {
+      let dir = aUrl.directory;
+      if (dir) {
+        return this.trimUrl(aUrl, dir.replace(/^\//, "") + aLabel, aSeq + 1);
+      }
+      aSeq++;
+    }
+    // Prepend the hostname and port number.
+    if (aSeq == 4) {
+      let host = aUrl.hostPort;
+      if (host) {
+        return this.trimUrl(aUrl, host + "/" + aLabel, aSeq + 1);
+      }
+      aSeq++;
+    }
+    // Use the whole url spec but ignoring the reference.
+    if (aSeq == 5) {
+      return this.trimUrl(aUrl, aUrl.specIgnoringRef, aSeq + 1);
+    }
+    // Give up.
+    return aUrl.spec;
+  }
+};
+
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/views/event-listeners-view.js
@@ -0,0 +1,274 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+/**
+ * Functions handling the event listeners UI.
+ */
+function EventListenersView(DebuggerController) {
+  dumpn("EventListenersView was instantiated");
+
+  this.Breakpoints = DebuggerController.Breakpoints;
+
+  this._onCheck = this._onCheck.bind(this);
+  this._onClick = this._onClick.bind(this);
+}
+
+EventListenersView.prototype = Heritage.extend(WidgetMethods, {
+  /**
+   * Initialization function, called when the debugger is started.
+   */
+  initialize: function() {
+    dumpn("Initializing the EventListenersView");
+
+    this.widget = new SideMenuWidget(document.getElementById("event-listeners"), {
+      showItemCheckboxes: true,
+      showGroupCheckboxes: true
+    });
+
+    this.emptyText = L10N.getStr("noEventListenersText");
+    this._eventCheckboxTooltip = L10N.getStr("eventCheckboxTooltip");
+    this._onSelectorString = " " + L10N.getStr("eventOnSelector") + " ";
+    this._inSourceString = " " + L10N.getStr("eventInSource") + " ";
+    this._inNativeCodeString = L10N.getStr("eventNative");
+
+    this.widget.addEventListener("check", this._onCheck, false);
+    this.widget.addEventListener("click", this._onClick, false);
+  },
+
+  /**
+   * Destruction function, called when the debugger is closed.
+   */
+  destroy: function() {
+    dumpn("Destroying the EventListenersView");
+
+    this.widget.removeEventListener("check", this._onCheck, false);
+    this.widget.removeEventListener("click", this._onClick, false);
+  },
+
+  /**
+   * Adds an event to this event listeners container.
+   *
+   * @param object aListener
+   *        The listener object coming from the active thread.
+   * @param object aOptions [optional]
+   *        Additional options for adding the source. Supported options:
+   *        - staged: true to stage the item to be appended later
+   */
+  addListener: function(aListener, aOptions = {}) {
+    let { node: { selector }, function: { url }, type } = aListener;
+    if (!type) return;
+
+    // Some listener objects may be added from plugins, thus getting
+    // translated to native code.
+    if (!url) {
+      url = this._inNativeCodeString;
+    }
+
+    // If an event item for this listener's url and type was already added,
+    // avoid polluting the view and simply increase the "targets" count.
+    let eventItem = this.getItemForPredicate(aItem =>
+      aItem.attachment.url == url &&
+      aItem.attachment.type == type);
+
+    if (eventItem) {
+      let { selectors, view: { targets } } = eventItem.attachment;
+      if (selectors.indexOf(selector) == -1) {
+        selectors.push(selector);
+        targets.setAttribute("value", L10N.getFormatStr("eventNodes", selectors.length));
+      }
+      return;
+    }
+
+    // There's no easy way of grouping event types into higher-level groups,
+    // so we need to do this by hand.
+    let is = (...args) => args.indexOf(type) != -1;
+    let has = str => type.contains(str);
+    let starts = str => type.startsWith(str);
+    let group;
+
+    if (starts("animation")) {
+      group = L10N.getStr("animationEvents");
+    } else if (starts("audio")) {
+      group = L10N.getStr("audioEvents");
+    } else if (is("levelchange")) {
+      group = L10N.getStr("batteryEvents");
+    } else if (is("cut", "copy", "paste")) {
+      group = L10N.getStr("clipboardEvents");
+    } else if (starts("composition")) {
+      group = L10N.getStr("compositionEvents");
+    } else if (starts("device")) {
+      group = L10N.getStr("deviceEvents");
+    } else if (is("fullscreenchange", "fullscreenerror", "orientationchange",
+      "overflow", "resize", "scroll", "underflow", "zoom")) {
+      group = L10N.getStr("displayEvents");
+    } else if (starts("drag") || starts("drop")) {
+      group = L10N.getStr("dragAndDropEvents");
+    } else if (starts("gamepad")) {
+      group = L10N.getStr("gamepadEvents");
+    } else if (is("canplay", "canplaythrough", "durationchange", "emptied",
+      "ended", "loadeddata", "loadedmetadata", "pause", "play", "playing",
+      "ratechange", "seeked", "seeking", "stalled", "suspend", "timeupdate",
+      "volumechange", "waiting")) {
+      group = L10N.getStr("mediaEvents");
+    } else if (is("blocked", "complete", "success", "upgradeneeded", "versionchange")) {
+      group = L10N.getStr("indexedDBEvents");
+    } else if (is("blur", "change", "focus", "focusin", "focusout", "invalid",
+      "reset", "select", "submit")) {
+      group = L10N.getStr("interactionEvents");
+    } else if (starts("key") || is("input")) {
+      group = L10N.getStr("keyboardEvents");
+    } else if (starts("mouse") || has("click") || is("contextmenu", "show", "wheel")) {
+      group = L10N.getStr("mouseEvents");
+    } else if (starts("DOM")) {
+      group = L10N.getStr("mutationEvents");
+    } else if (is("abort", "error", "hashchange", "load", "loadend", "loadstart",
+      "pagehide", "pageshow", "progress", "timeout", "unload", "uploadprogress",
+      "visibilitychange")) {
+      group = L10N.getStr("navigationEvents");
+    } else if (is("pointerlockchange", "pointerlockerror")) {
+      group = L10N.getStr("pointerLockEvents");
+    } else if (is("compassneedscalibration", "userproximity")) {
+      group = L10N.getStr("sensorEvents");
+    } else if (starts("storage")) {
+      group = L10N.getStr("storageEvents");
+    } else if (is("beginEvent", "endEvent", "repeatEvent")) {
+      group = L10N.getStr("timeEvents");
+    } else if (starts("touch")) {
+      group = L10N.getStr("touchEvents");
+    } else {
+      group = L10N.getStr("otherEvents");
+    }
+
+    // Create the element node for the event listener item.
+    let itemView = this._createItemView(type, selector, url);
+
+    // Event breakpoints survive target navigations. Make sure the newly
+    // inserted event item is correctly checked.
+    let checkboxState =
+      this.Breakpoints.DOM.activeEventNames.indexOf(type) != -1;
+
+    // Append an event listener item to this container.
+    this.push([itemView.container], {
+      staged: aOptions.staged, /* stage the item to be appended later? */
+      attachment: {
+        url: url,
+        type: type,
+        view: itemView,
+        selectors: [selector],
+        group: group,
+        checkboxState: checkboxState,
+        checkboxTooltip: this._eventCheckboxTooltip
+      }
+    });
+  },
+
+  /**
+   * Gets all the event types known to this container.
+   *
+   * @return array
+   *         List of event types, for example ["load", "click"...]
+   */
+  getAllEvents: function() {
+    return this.attachments.map(e => e.type);
+  },
+
+  /**
+   * Gets the checked event types in this container.
+   *
+   * @return array
+   *         List of event types, for example ["load", "click"...]
+   */
+  getCheckedEvents: function() {
+    return this.attachments.filter(e => e.checkboxState).map(e => e.type);
+  },
+
+  /**
+   * Customization function for creating an item's UI.
+   *
+   * @param string aType
+   *        The event type, for example "click".
+   * @param string aSelector
+   *        The target element's selector.
+   * @param string url
+   *        The source url in which the event listener is located.
+   * @return object
+   *         An object containing the event listener view nodes.
+   */
+  _createItemView: function(aType, aSelector, aUrl) {
+    let container = document.createElement("hbox");
+    container.className = "dbg-event-listener";
+
+    let eventType = document.createElement("label");
+    eventType.className = "plain dbg-event-listener-type";
+    eventType.setAttribute("value", aType);
+    container.appendChild(eventType);
+
+    let typeSeparator = document.createElement("label");
+    typeSeparator.className = "plain dbg-event-listener-separator";
+    typeSeparator.setAttribute("value", this._onSelectorString);
+    container.appendChild(typeSeparator);
+
+    let eventTargets = document.createElement("label");
+    eventTargets.className = "plain dbg-event-listener-targets";
+    eventTargets.setAttribute("value", aSelector);
+    container.appendChild(eventTargets);
+
+    let selectorSeparator = document.createElement("label");
+    selectorSeparator.className = "plain dbg-event-listener-separator";
+    selectorSeparator.setAttribute("value", this._inSourceString);
+    container.appendChild(selectorSeparator);
+
+    let eventLocation = document.createElement("label");
+    eventLocation.className = "plain dbg-event-listener-location";
+    eventLocation.setAttribute("value", SourceUtils.getSourceLabel(aUrl));
+    eventLocation.setAttribute("flex", "1");
+    eventLocation.setAttribute("crop", "center");
+    container.appendChild(eventLocation);
+
+    return {
+      container: container,
+      type: eventType,
+      targets: eventTargets,
+      location: eventLocation
+    };
+  },
+
+  /**
+   * The check listener for the event listeners container.
+   */
+  _onCheck: function({ detail: { description, checked }, target }) {
+    if (description == "item") {
+      this.getItemForElement(target).attachment.checkboxState = checked;
+      this.Breakpoints.DOM.scheduleEventBreakpointsUpdate();
+      return;
+    }
+
+    // Check all the event items in this group.
+    this.items
+      .filter(e => e.attachment.group == description)
+      .forEach(e => this.callMethod("checkItem", e.target, checked));
+  },
+
+  /**
+   * The select listener for the event listeners container.
+   */
+  _onClick: function({ target }) {
+    // Changing the checkbox state is handled by the _onCheck event. Avoid
+    // handling that again in this click event, so pass in "noSiblings"
+    // when retrieving the target's item, to ignore the checkbox.
+    let eventItem = this.getItemForElement(target, { noSiblings: true });
+    if (eventItem) {
+      let newState = eventItem.attachment.checkboxState ^= 1;
+      this.callMethod("checkItem", eventItem.target, newState);
+    }
+  },
+
+  _eventCheckboxTooltip: "",
+  _onSelectorString: "",
+  _inSourceString: "",
+  _inNativeCodeString: ""
+});
+
+DebuggerView.EventListeners = new EventListenersView(DebuggerController);
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/views/filter-view.js
@@ -0,0 +1,912 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+
+/**
+ * Functions handling the filtering UI.
+ */
+function FilterView(DebuggerController, DebuggerView) {
+  dumpn("FilterView was instantiated");
+
+  this.Parser = DebuggerController.Parser;
+
+  this.DebuggerView = DebuggerView;
+  this.FilteredSources = new FilteredSourcesView(DebuggerView);
+  this.FilteredFunctions = new FilteredFunctionsView(DebuggerController.SourceScripts,
+                                                     DebuggerController.Parser,
+                                                     DebuggerView);
+
+  this._onClick = this._onClick.bind(this);
+  this._onInput = this._onInput.bind(this);
+  this._onKeyPress = this._onKeyPress.bind(this);
+  this._onBlur = this._onBlur.bind(this);
+}
+
+FilterView.prototype = {
+  /**
+   * Initialization function, called when the debugger is started.
+   */
+  initialize: function() {
+    dumpn("Initializing the FilterView");
+
+    this._searchbox = document.getElementById("searchbox");
+    this._searchboxHelpPanel = document.getElementById("searchbox-help-panel");
+    this._filterLabel = document.getElementById("filter-label");
+    this._globalOperatorButton = document.getElementById("global-operator-button");
+    this._globalOperatorLabel = document.getElementById("global-operator-label");
+    this._functionOperatorButton = document.getElementById("function-operator-button");
+    this._functionOperatorLabel = document.getElementById("function-operator-label");
+    this._tokenOperatorButton = document.getElementById("token-operator-button");
+    this._tokenOperatorLabel = document.getElementById("token-operator-label");
+    this._lineOperatorButton = document.getElementById("line-operator-button");
+    this._lineOperatorLabel = document.getElementById("line-operator-label");
+    this._variableOperatorButton = document.getElementById("variable-operator-button");
+    this._variableOperatorLabel = document.getElementById("variable-operator-label");
+
+    this._fileSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("fileSearchKey"));
+    this._globalSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("globalSearchKey"));
+    this._filteredFunctionsKey = ShortcutUtils.prettifyShortcut(document.getElementById("functionSearchKey"));
+    this._tokenSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("tokenSearchKey"));
+    this._lineSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("lineSearchKey"));
+    this._variableSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("variableSearchKey"));
+
+    this._searchbox.addEventListener("click", this._onClick, false);
+    this._searchbox.addEventListener("select", this._onInput, false);
+    this._searchbox.addEventListener("input", this._onInput, false);
+    this._searchbox.addEventListener("keypress", this._onKeyPress, false);
+    this._searchbox.addEventListener("blur", this._onBlur, false);
+
+    let placeholder = L10N.getFormatStr("emptySearchText", this._fileSearchKey);
+    this._searchbox.setAttribute("placeholder", placeholder);
+
+    this._globalOperatorButton.setAttribute("label", SEARCH_GLOBAL_FLAG);
+    this._functionOperatorButton.setAttribute("label", SEARCH_FUNCTION_FLAG);
+    this._tokenOperatorButton.setAttribute("label", SEARCH_TOKEN_FLAG);
+    this._lineOperatorButton.setAttribute("label", SEARCH_LINE_FLAG);
+    this._variableOperatorButton.setAttribute("label", SEARCH_VARIABLE_FLAG);
+
+    this._filterLabel.setAttribute("value",
+      L10N.getFormatStr("searchPanelFilter", this._fileSearchKey));
+    this._globalOperatorLabel.setAttribute("value",
+      L10N.getFormatStr("searchPanelGlobal", this._globalSearchKey));
+    this._functionOperatorLabel.setAttribute("value",
+      L10N.getFormatStr("searchPanelFunction", this._filteredFunctionsKey));
+    this._tokenOperatorLabel.setAttribute("value",
+      L10N.getFormatStr("searchPanelToken", this._tokenSearchKey));
+    this._lineOperatorLabel.setAttribute("value",
+      L10N.getFormatStr("searchPanelGoToLine", this._lineSearchKey));
+    this._variableOperatorLabel.setAttribute("value",
+      L10N.getFormatStr("searchPanelVariable", this._variableSearchKey));
+
+    this.FilteredSources.initialize();
+    this.FilteredFunctions.initialize();
+
+    this._addCommands();
+  },
+
+  /**
+   * Destruction function, called when the debugger is closed.
+   */
+  destroy: function() {
+    dumpn("Destroying the FilterView");
+
+    this._searchbox.removeEventListener("click", this._onClick, false);
+    this._searchbox.removeEventListener("select", this._onInput, false);
+    this._searchbox.removeEventListener("input", this._onInput, false);
+    this._searchbox.removeEventListener("keypress", this._onKeyPress, false);
+    this._searchbox.removeEventListener("blur", this._onBlur, false);
+
+    this.FilteredSources.destroy();
+    this.FilteredFunctions.destroy();
+  },
+
+  /**
+   * Add commands that XUL can fire.
+   */
+  _addCommands: function() {
+    XULUtils.addCommands(document.getElementById('debuggerCommands'), {
+      fileSearchCommand: () => this._doFileSearch(),
+      globalSearchCommand: () => this._doGlobalSearch(),
+      functionSearchCommand: () => this._doFunctionSearch(),
+      tokenSearchCommand: () => this._doTokenSearch(),
+      lineSearchCommand: () => this._doLineSearch(),
+      variableSearchCommand: () => this._doVariableSearch(),
+      variablesFocusCommand: () => this._doVariablesFocus()
+    });
+  },
+
+  /**
+   * Gets the entered operator and arguments in the searchbox.
+   * @return array
+   */
+  get searchData() {
+    let operator = "", args = [];
+
+    let rawValue = this._searchbox.value;
+    let rawLength = rawValue.length;
+    let globalFlagIndex = rawValue.indexOf(SEARCH_GLOBAL_FLAG);
+    let functionFlagIndex = rawValue.indexOf(SEARCH_FUNCTION_FLAG);
+    let variableFlagIndex = rawValue.indexOf(SEARCH_VARIABLE_FLAG);
+    let tokenFlagIndex = rawValue.lastIndexOf(SEARCH_TOKEN_FLAG);
+    let lineFlagIndex = rawValue.lastIndexOf(SEARCH_LINE_FLAG);
+
+    // This is not a global, function or variable search, allow file/line flags.
+    if (globalFlagIndex != 0 && functionFlagIndex != 0 && variableFlagIndex != 0) {
+      // Token search has precedence over line search.
+      if (tokenFlagIndex != -1) {
+        operator = SEARCH_TOKEN_FLAG;
+        args.push(rawValue.slice(0, tokenFlagIndex)); // file
+        args.push(rawValue.substr(tokenFlagIndex + 1, rawLength)); // token
+      } else if (lineFlagIndex != -1) {
+        operator = SEARCH_LINE_FLAG;
+        args.push(rawValue.slice(0, lineFlagIndex)); // file
+        args.push(+rawValue.substr(lineFlagIndex + 1, rawLength) || 0); // line
+      } else {
+        args.push(rawValue);
+      }
+    }
+    // Global searches dissalow the use of file or line flags.
+    else if (globalFlagIndex == 0) {
+      operator = SEARCH_GLOBAL_FLAG;
+      args.push(rawValue.slice(1));
+    }
+    // Function searches dissalow the use of file or line flags.
+    else if (functionFlagIndex == 0) {
+      operator = SEARCH_FUNCTION_FLAG;
+      args.push(rawValue.slice(1));
+    }
+    // Variable searches dissalow the use of file or line flags.
+    else if (variableFlagIndex == 0) {
+      operator = SEARCH_VARIABLE_FLAG;
+      args.push(rawValue.slice(1));
+    }
+
+    return [operator, args];
+  },
+
+  /**
+   * Returns the current search operator.
+   * @return string
+   */
+  get searchOperator() this.searchData[0],
+
+  /**
+   * Returns the current search arguments.
+   * @return array
+   */
+  get searchArguments() this.searchData[1],
+
+  /**
+   * Clears the text from the searchbox and any changed views.
+   */
+  clearSearch: function() {
+    this._searchbox.value = "";
+    this.clearViews();
+
+    this.FilteredSources.clearView();
+    this.FilteredFunctions.clearView();
+  },
+
+  /**
+   * Clears all the views that may pop up when searching.
+   */
+  clearViews: function() {
+    this.DebuggerView.GlobalSearch.clearView();
+    this.FilteredSources.clearView();
+    this.FilteredFunctions.clearView();
+    this._searchboxHelpPanel.hidePopup();
+  },
+
+  /**
+   * Performs a line search if necessary.
+   * (Jump to lines in the currently visible source).
+   *
+   * @param number aLine
+   *        The source line number to jump to.
+   */
+  _performLineSearch: function(aLine) {
+    // Make sure we're actually searching for a valid line.
+    if (aLine) {
+      this.DebuggerView.editor.setCursor({ line: aLine - 1, ch: 0 }, "center");
+    }
+  },
+
+  /**
+   * Performs a token search if necessary.
+   * (Search for tokens in the currently visible source).
+   *
+   * @param string aToken
+   *        The source token to find.
+   */
+  _performTokenSearch: function(aToken) {
+    // Make sure we're actually searching for a valid token.
+    if (!aToken) {
+      return;
+    }
+    this.DebuggerView.editor.find(aToken);
+  },
+
+  /**
+   * The click listener for the search container.
+   */
+  _onClick: function() {
+    // If there's some text in the searchbox, displaying a panel would
+    // interfere with double/triple click default behaviors.
+    if (!this._searchbox.value) {
+      this._searchboxHelpPanel.openPopup(this._searchbox);
+    }
+  },
+
+  /**
+   * The input listener for the search container.
+   */
+  _onInput: function() {
+    this.clearViews();
+
+    // Make sure we're actually searching for something.
+    if (!this._searchbox.value) {
+      return;
+    }
+
+    // Perform the required search based on the specified operator.
+    switch (this.searchOperator) {
+      case SEARCH_GLOBAL_FLAG:
+        // Schedule a global search for when the user stops typing.
+        this.DebuggerView.GlobalSearch.scheduleSearch(this.searchArguments[0]);
+        break;
+      case SEARCH_FUNCTION_FLAG:
+      // Schedule a function search for when the user stops typing.
+        this.FilteredFunctions.scheduleSearch(this.searchArguments[0]);
+        break;
+      case SEARCH_VARIABLE_FLAG:
+        // Schedule a variable search for when the user stops typing.
+        this.DebuggerView.Variables.scheduleSearch(this.searchArguments[0]);
+        break;
+      case SEARCH_TOKEN_FLAG:
+        // Schedule a file+token search for when the user stops typing.
+        this.FilteredSources.scheduleSearch(this.searchArguments[0]);
+        this._performTokenSearch(this.searchArguments[1]);
+        break;
+      case SEARCH_LINE_FLAG:
+        // Schedule a file+line search for when the user stops typing.
+        this.FilteredSources.scheduleSearch(this.searchArguments[0]);
+        this._performLineSearch(this.searchArguments[1]);
+        break;
+      default:
+        // Schedule a file only search for when the user stops typing.
+        this.FilteredSources.scheduleSearch(this.searchArguments[0]);
+        break;
+    }
+  },
+
+  /**
+   * The key press listener for the search container.
+   */
+  _onKeyPress: function(e) {
+    // This attribute is not implemented in Gecko at this time, see bug 680830.
+    e.char = String.fromCharCode(e.charCode);
+
+    // Perform the required action based on the specified operator.
+    let [operator, args] = this.searchData;
+    let isGlobalSearch = operator == SEARCH_GLOBAL_FLAG;
+    let isFunctionSearch = operator == SEARCH_FUNCTION_FLAG;
+    let isVariableSearch = operator == SEARCH_VARIABLE_FLAG;
+    let isTokenSearch = operator == SEARCH_TOKEN_FLAG;
+    let isLineSearch = operator == SEARCH_LINE_FLAG;
+    let isFileOnlySearch = !operator && args.length == 1;
+
+    // Depending on the pressed keys, determine to correct action to perform.
+    let actionToPerform;
+
+    // Meta+G and Ctrl+N focus next matches.
+    if ((e.char == "g" && e.metaKey) || e.char == "n" && e.ctrlKey) {
+      actionToPerform = "selectNext";
+    }
+    // Meta+Shift+G and Ctrl+P focus previous matches.
+    else if ((e.char == "G" && e.metaKey) || e.char == "p" && e.ctrlKey) {
+      actionToPerform = "selectPrev";
+    }
+    // Return, enter, down and up keys focus next or previous matches, while
+    // the escape key switches focus from the search container.
+    else switch (e.keyCode) {
+      case e.DOM_VK_RETURN:
+        var isReturnKey = true;
+        // If the shift key is pressed, focus on the previous result
+        actionToPerform = e.shiftKey ? "selectPrev" : "selectNext";
+        break;
+      case e.DOM_VK_DOWN:
+        actionToPerform = "selectNext";
+        break;
+      case e.DOM_VK_UP:
+        actionToPerform = "selectPrev";
+        break;
+    }
+
+    // If there's no action to perform, or no operator, file line or token
+    // were specified, then this is either a broken or empty search.
+    if (!actionToPerform || (!operator && !args.length)) {
+      this.DebuggerView.editor.dropSelection();
+      return;
+    }
+
+    e.preventDefault();
+    e.stopPropagation();
+
+    // Jump to the next/previous entry in the global search, or perform
+    // a new global search immediately
+    if (isGlobalSearch) {
+      let targetView = this.DebuggerView.GlobalSearch;
+      if (!isReturnKey) {
+        targetView[actionToPerform]();
+      } else if (targetView.hidden) {
+        targetView.scheduleSearch(args[0], 0);
+      }
+      return;
+    }
+
+    // Jump to the next/previous entry in the function search, perform
+    // a new function search immediately, or clear it.
+    if (isFunctionSearch) {
+      let targetView = this.FilteredFunctions;
+      if (!isReturnKey) {
+        targetView[actionToPerform]();
+      } else if (targetView.hidden) {
+        targetView.scheduleSearch(args[0], 0);
+      } else {
+        if (!targetView.selectedItem) {
+          targetView.selectedIndex = 0;
+        }
+        this.clearSearch();
+      }
+      return;
+    }
+
+    // Perform a new variable search immediately.
+    if (isVariableSearch) {
+      let targetView = this.DebuggerView.Variables;
+      if (isReturnKey) {
+        targetView.scheduleSearch(args[0], 0);
+      }
+      return;
+    }
+
+    // Jump to the next/previous entry in the file search, perform
+    // a new file search immediately, or clear it.
+    if (isFileOnlySearch) {
+      let targetView = this.FilteredSources;
+      if (!isReturnKey) {
+        targetView[actionToPerform]();
+      } else if (targetView.hidden) {
+        targetView.scheduleSearch(args[0], 0);
+      } else {
+        if (!targetView.selectedItem) {
+          targetView.selectedIndex = 0;
+        }
+        this.clearSearch();
+      }
+      return;
+    }
+
+    // Jump to the next/previous instance of the currently searched token.
+    if (isTokenSearch) {
+      let methods = { selectNext: "findNext", selectPrev: "findPrev" };
+      this.DebuggerView.editor[methods[actionToPerform]]();
+      return;
+    }
+
+    // Increment/decrement the currently searched caret line.
+    if (isLineSearch) {
+      let [, line] = args;
+      let amounts = { selectNext: 1, selectPrev: -1 };
+
+      // Modify the line number and jump to it.
+      line += !isReturnKey ? amounts[actionToPerform] : 0;
+      let lineCount = this.DebuggerView.editor.lineCount();
+      let lineTarget = line < 1 ? 1 : line > lineCount ? lineCount : line;
+      this._doSearch(SEARCH_LINE_FLAG, lineTarget);
+      return;
+    }
+  },
+
+  /**
+   * The blur listener for the search container.
+   */
+  _onBlur: function() {
+    this.clearViews();
+  },
+
+  /**
+   * Called when a filtering key sequence was pressed.
+   *
+   * @param string aOperator
+   *        The operator to use for filtering.
+   */
+  _doSearch: function(aOperator = "", aText = "") {
+    this._searchbox.focus();
+    this._searchbox.value = ""; // Need to clear value beforehand. Bug 779738.
+
+    if (aText) {
+      this._searchbox.value = aOperator + aText;
+      return;
+    }
+    if (this.DebuggerView.editor.somethingSelected()) {
+      this._searchbox.value = aOperator + this.DebuggerView.editor.getSelection();
+      return;
+    }
+    if (SEARCH_AUTOFILL.indexOf(aOperator) != -1) {
+      let cursor = this.DebuggerView.editor.getCursor();
+      let content = this.DebuggerView.editor.getText();
+      let location = this.DebuggerView.Sources.selectedItem.attachment.source.url;
+      let source = this.Parser.get(content, location);
+      let identifier = source.getIdentifierAt({ line: cursor.line+1, column: cursor.ch });
+
+      if (identifier && identifier.name) {
+        this._searchbox.value = aOperator + identifier.name;
+        this._searchbox.select();
+        this._searchbox.selectionStart += aOperator.length;
+        return;
+      }
+    }
+    this._searchbox.value = aOperator;
+  },
+
+  /**
+   * Called when the source location filter key sequence was pressed.
+   */
+  _doFileSearch: function() {
+    this._doSearch();
+    this._searchboxHelpPanel.openPopup(this._searchbox);
+  },
+
+  /**
+   * Called when the global search filter key sequence was pressed.
+   */
+  _doGlobalSearch: function() {
+    this._doSearch(SEARCH_GLOBAL_FLAG);
+    this._searchboxHelpPanel.hidePopup();
+  },
+
+  /**
+   * Called when the source function filter key sequence was pressed.
+   */
+  _doFunctionSearch: function() {
+    this._doSearch(SEARCH_FUNCTION_FLAG);
+    this._searchboxHelpPanel.hidePopup();
+  },
+
+  /**
+   * Called when the source token filter key sequence was pressed.
+   */
+  _doTokenSearch: function() {
+    this._doSearch(SEARCH_TOKEN_FLAG);
+    this._searchboxHelpPanel.hidePopup();
+  },
+
+  /**
+   * Called when the source line filter key sequence was pressed.
+   */
+  _doLineSearch: function() {
+    this._doSearch(SEARCH_LINE_FLAG);
+    this._searchboxHelpPanel.hidePopup();
+  },
+
+  /**
+   * Called when the variable search filter key sequence was pressed.
+   */
+  _doVariableSearch: function() {
+    this._doSearch(SEARCH_VARIABLE_FLAG);
+    this._searchboxHelpPanel.hidePopup();
+  },
+
+  /**
+   * Called when the variables focus key sequence was pressed.
+   */
+  _doVariablesFocus: function() {
+    this.DebuggerView.showInstrumentsPane();
+    this.DebuggerView.Variables.focusFirstVisibleItem();
+  },
+
+  _searchbox: null,
+  _searchboxHelpPanel: null,
+  _globalOperatorButton: null,
+  _globalOperatorLabel: null,
+  _functionOperatorButton: null,
+  _functionOperatorLabel: null,
+  _tokenOperatorButton: null,
+  _tokenOperatorLabel: null,
+  _lineOperatorButton: null,
+  _lineOperatorLabel: null,
+  _variableOperatorButton: null,
+  _variableOperatorLabel: null,
+  _fileSearchKey: "",
+  _globalSearchKey: "",
+  _filteredFunctionsKey: "",
+  _tokenSearchKey: "",
+  _lineSearchKey: "",
+  _variableSearchKey: "",
+};
+
+/**
+ * Functions handling the filtered sources UI.
+ */
+function FilteredSourcesView(DebuggerView) {
+  dumpn("FilteredSourcesView was instantiated");
+
+  this.DebuggerView = DebuggerView;
+
+  this._onClick = this._onClick.bind(this);
+  this._onSelect = this._onSelect.bind(this);
+}
+
+FilteredSourcesView.prototype = Heritage.extend(ResultsPanelContainer.prototype, {
+  /**
+   * Initialization function, called when the debugger is started.
+   */
+  initialize: function() {
+    dumpn("Initializing the FilteredSourcesView");
+
+    this.anchor = document.getElementById("searchbox");
+    this.widget.addEventListener("select", this._onSelect, false);
+    this.widget.addEventListener("click", this._onClick, false);
+  },
+
+  /**
+   * Destruction function, called when the debugger is closed.
+   */
+  destroy: function() {
+    dumpn("Destroying the FilteredSourcesView");
+
+    this.widget.removeEventListener("select", this._onSelect, false);
+    this.widget.removeEventListener("click", this._onClick, false);
+    this.anchor = null;
+  },
+
+  /**
+   * Schedules searching for a source.
+   *
+   * @param string aToken
+   *        The function to search for.
+   * @param number aWait
+   *        The amount of milliseconds to wait until draining.
+   */
+  scheduleSearch: function(aToken, aWait) {
+    // The amount of time to wait for the requests to settle.
+    let maxDelay = FILE_SEARCH_ACTION_MAX_DELAY;
+    let delay = aWait === undefined ? maxDelay / aToken.length : aWait;
+
+    // Allow requests to settle down first.
+    setNamedTimeout("sources-search", delay, () => this._doSearch(aToken));
+  },
+
+  /**
+   * Finds file matches in all the displayed sources.
+   *
+   * @param string aToken
+   *        The string to search for.
+   */
+  _doSearch: function(aToken, aStore = []) {
+    // Don't continue filtering if the searched token is an empty string.
+    // In contrast with function searching, in this case we don't want to
+    // show a list of all the files when no search token was supplied.
+    if (!aToken) {
+      return;
+    }
+
+    for (let item of this.DebuggerView.Sources.items) {
+      let lowerCaseLabel = item.attachment.label.toLowerCase();
+      let lowerCaseToken = aToken.toLowerCase();
+      if (lowerCaseLabel.match(lowerCaseToken)) {
+        aStore.push(item);
+      }
+
+      // Once the maximum allowed number of results is reached, proceed
+      // with building the UI immediately.
+      if (aStore.length >= RESULTS_PANEL_MAX_RESULTS) {
+        this._syncView(aStore);
+        return;
+      }
+    }
+
+    // Couldn't reach the maximum allowed number of results, but that's ok,
+    // continue building the UI.
+    this._syncView(aStore);
+  },
+
+  /**
+   * Updates the list of sources displayed in this container.
+   *
+   * @param array aSearchResults
+   *        The results array, containing search details for each source.
+   */
+  _syncView: function(aSearchResults) {
+    // If there are no matches found, keep the popup hidden and avoid
+    // creating the view.
+    if (!aSearchResults.length) {
+      window.emit(EVENTS.FILE_SEARCH_MATCH_NOT_FOUND);
+      return;
+    }
+
+    for (let item of aSearchResults) {
+      let url = item.attachment.source.url;
+
+      if (url) {
+        // Create the element node for the location item.
+        let itemView = this._createItemView(
+          SourceUtils.trimUrlLength(item.attachment.label),
+          SourceUtils.trimUrlLength(url, 0, "start")
+        );
+
+        // Append a location item to this container for each match.
+        this.push([itemView], {
+          index: -1, /* specifies on which position should the item be appended */
+          attachment: {
+            url: url
+          }
+        });
+      }
+    }
+
+    // There's at least one item displayed in this container. Don't select it
+    // automatically if not forced (by tests) or in tandem with an operator.
+    if (this._autoSelectFirstItem || this.DebuggerView.Filtering.searchOperator) {
+      this.selectedIndex = 0;
+    }
+    this.hidden = false;
+
+    // Signal that file search matches were found and displayed.
+    window.emit(EVENTS.FILE_SEARCH_MATCH_FOUND);
+  },
+
+  /**
+   * The click listener for this container.
+   */
+  _onClick: function(e) {
+    let locationItem = this.getItemForElement(e.target);
+    if (locationItem) {
+      this.selectedItem = locationItem;
+      this.DebuggerView.Filtering.clearSearch();
+    }
+  },
+
+  /**
+   * The select listener for this container.
+   *
+   * @param object aItem
+   *        The item associated with the element to select.
+   */
+  _onSelect: function({ detail: locationItem }) {
+    if (locationItem) {
+      let actor = this.DebuggerView.Sources.getActorForLocation({ url: locationItem.attachment.url });
+      this.DebuggerView.setEditorLocation(actor, undefined, {
+        noCaret: true,
+        noDebug: true
+      });
+    }
+  }
+});
+
+/**
+ * Functions handling the function search UI.
+ */
+function FilteredFunctionsView(SourceScripts, Parser, DebuggerView) {
+  dumpn("FilteredFunctionsView was instantiated");
+
+  this.SourceScripts = SourceScripts;
+  this.Parser = Parser;
+  this.DebuggerView = DebuggerView;
+
+  this._onClick = this._onClick.bind(this);
+  this._onSelect = this._onSelect.bind(this);
+}
+
+FilteredFunctionsView.prototype = Heritage.extend(ResultsPanelContainer.prototype, {
+  /**
+   * Initialization function, called when the debugger is started.
+   */
+  initialize: function() {
+    dumpn("Initializing the FilteredFunctionsView");
+
+    this.anchor = document.getElementById("searchbox");
+    this.widget.addEventListener("select", this._onSelect, false);
+    this.widget.addEventListener("click", this._onClick, false);
+  },
+
+  /**
+   * Destruction function, called when the debugger is closed.
+   */
+  destroy: function() {
+    dumpn("Destroying the FilteredFunctionsView");
+
+    this.widget.removeEventListener("select", this._onSelect, false);
+    this.widget.removeEventListener("click", this._onClick, false);
+    this.anchor = null;
+  },
+
+  /**
+   * Schedules searching for a function in all of the sources.
+   *
+   * @param string aToken
+   *        The function to search for.
+   * @param number aWait
+   *        The amount of milliseconds to wait until draining.
+   */
+  scheduleSearch: function(aToken, aWait) {
+    // The amount of time to wait for the requests to settle.
+    let maxDelay = FUNCTION_SEARCH_ACTION_MAX_DELAY;
+    let delay = aWait === undefined ? maxDelay / aToken.length : aWait;
+
+    // Allow requests to settle down first.
+    setNamedTimeout("function-search", delay, () => {
+      // Start fetching as many sources as possible, then perform the search.
+      let actors = this.DebuggerView.Sources.values;
+      let sourcesFetched = this.SourceScripts.getTextForSources(actors);
+      sourcesFetched.then(aSources => this._doSearch(aToken, aSources));
+    });
+  },
+
+  /**
+   * Finds function matches in all the sources stored in the cache, and groups
+   * them by location and line number.
+   *
+   * @param string aToken
+   *        The string to search for.
+   * @param array aSources
+   *        An array of [url, text] tuples for each source.
+   */
+  _doSearch: function(aToken, aSources, aStore = []) {
+    // Continue parsing even if the searched token is an empty string, to
+    // cache the syntax tree nodes generated by the reflection API.
+
+    // Make sure the currently displayed source is parsed first. Once the
+    // maximum allowed number of results are found, parsing will be halted.
+    let currentActor = this.DebuggerView.Sources.selectedValue;
+    let currentSource = aSources.filter(([actor]) => actor == currentActor)[0];
+    aSources.splice(aSources.indexOf(currentSource), 1);
+    aSources.unshift(currentSource);
+
+    // If not searching for a specific function, only parse the displayed source,
+    // which is now the first item in the sources array.
+    if (!aToken) {
+      aSources.splice(1);
+    }
+
+    for (let [actor, contents] of aSources) {
+      let item = this.DebuggerView.Sources.getItemByValue(actor);
+      let url = item.attachment.source.url;
+      if (!url) {
+        continue;
+      }
+
+      let parsedSource = this.Parser.get(contents, url);
+      let sourceResults = parsedSource.getNamedFunctionDefinitions(aToken);
+
+      for (let scriptResult of sourceResults) {
+        for (let parseResult of scriptResult) {
+          aStore.push({
+            sourceUrl: scriptResult.sourceUrl,
+            scriptOffset: scriptResult.scriptOffset,
+            functionName: parseResult.functionName,
+            functionLocation: parseResult.functionLocation,
+            inferredName: parseResult.inferredName,
+            inferredChain: parseResult.inferredChain,
+            inferredLocation: parseResult.inferredLocation
+          });
+
+          // Once the maximum allowed number of results is reached, proceed
+          // with building the UI immediately.
+          if (aStore.length >= RESULTS_PANEL_MAX_RESULTS) {
+            this._syncView(aStore);
+            return;
+          }
+        }
+      }
+    }
+
+    // Couldn't reach the maximum allowed number of results, but that's ok,
+    // continue building the UI.
+    this._syncView(aStore);
+  },
+
+  /**
+   * Updates the list of functions displayed in this container.
+   *
+   * @param array aSearchResults
+   *        The results array, containing search details for each source.
+   */
+  _syncView: function(aSearchResults) {
+    // If there are no matches found, keep the popup hidden and avoid
+    // creating the view.
+    if (!aSearchResults.length) {
+      window.emit(EVENTS.FUNCTION_SEARCH_MATCH_NOT_FOUND);
+      return;
+    }
+
+    for (let item of aSearchResults) {
+      // Some function expressions don't necessarily have a name, but the
+      // parser provides us with an inferred name from an enclosing
+      // VariableDeclarator, AssignmentExpression, ObjectExpression node.
+      if (item.functionName && item.inferredName &&
+          item.functionName != item.inferredName) {
+        let s = " " + L10N.getStr("functionSearchSeparatorLabel") + " ";
+        item.displayedName = item.inferredName + s + item.functionName;
+      }
+      // The function doesn't have an explicit name, but it could be inferred.
+      else if (item.inferredName) {
+        item.displayedName = item.inferredName;
+      }
+      // The function only has an explicit name.
+      else {
+        item.displayedName = item.functionName;
+      }
+
+      // Some function expressions have unexpected bounds, since they may not
+      // necessarily have an associated name defining them.
+      if (item.inferredLocation) {
+        item.actualLocation = item.inferredLocation;
+      } else {
+        item.actualLocation = item.functionLocation;
+      }
+
+      // Create the element node for the function item.
+      let itemView = this._createItemView(
+        SourceUtils.trimUrlLength(item.displayedName + "()"),
+        SourceUtils.trimUrlLength(item.sourceUrl, 0, "start"),
+        (item.inferredChain || []).join(".")
+      );
+
+      // Append a function item to this container for each match.
+      this.push([itemView], {
+        index: -1, /* specifies on which position should the item be appended */
+        attachment: item
+      });
+    }
+
+    // There's at least one item displayed in this container. Don't select it
+    // automatically if not forced (by tests).
+    if (this._autoSelectFirstItem) {
+      this.selectedIndex = 0;
+    }
+    this.hidden = false;
+
+    // Signal that function search matches were found and displayed.
+    window.emit(EVENTS.FUNCTION_SEARCH_MATCH_FOUND);
+  },
+
+  /**
+   * The click listener for this container.
+   */
+  _onClick: function(e) {
+    let functionItem = this.getItemForElement(e.target);
+    if (functionItem) {
+      this.selectedItem = functionItem;
+      this.DebuggerView.Filtering.clearSearch();
+    }
+  },
+
+  /**
+   * The select listener for this container.
+   */
+  _onSelect: function({ detail: functionItem }) {
+    if (functionItem) {
+      let sourceUrl = functionItem.attachment.sourceUrl;
+      let actor = this.DebuggerView.Sources.getActorForLocation({ url: sourceUrl });
+      let scriptOffset = functionItem.attachment.scriptOffset;
+      let actualLocation = functionItem.attachment.actualLocation;
+
+      this.DebuggerView.setEditorLocation(actor, actualLocation.start.line, {
+        charOffset: scriptOffset,
+        columnOffset: actualLocation.start.column,
+        align: "center",
+        noDebug: true
+      });
+    }
+  },
+
+  _searchTimeout: null,
+  _searchFunction: null,
+  _searchedToken: ""
+});
+
+DebuggerView.Filtering = new FilterView(DebuggerController, DebuggerView);
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/views/global-search-view.js
@@ -0,0 +1,736 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+/**
+ * Functions handling the global search UI.
+ */
+function GlobalSearchView(DebuggerController, DebuggerView) {
+  dumpn("GlobalSearchView was instantiated");
+
+  this.SourceScripts = DebuggerController.SourceScripts;
+  this.DebuggerView = DebuggerView;
+
+  this._onHeaderClick = this._onHeaderClick.bind(this);
+  this._onLineClick = this._onLineClick.bind(this);
+  this._onMatchClick = this._onMatchClick.bind(this);
+}
+
+GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
+  /**
+   * Initialization function, called when the debugger is started.
+   */
+  initialize: function() {
+    dumpn("Initializing the GlobalSearchView");
+
+    this.widget = new SimpleListWidget(document.getElementById("globalsearch"));
+    this._splitter = document.querySelector("#globalsearch + .devtools-horizontal-splitter");
+
+    this.emptyText = L10N.getStr("noMatchingStringsText");
+  },
+
+  /**
+   * Destruction function, called when the debugger is closed.
+   */
+  destroy: function() {
+    dumpn("Destroying the GlobalSearchView");
+  },
+
+  /**
+   * Sets the results container hidden or visible. It's hidden by default.
+   * @param boolean aFlag
+   */
+  set hidden(aFlag) {
+    this.widget.setAttribute("hidden", aFlag);
+    this._splitter.setAttribute("hidden", aFlag);
+  },
+
+  /**
+   * Gets the visibility state of the global search container.
+   * @return boolean
+   */
+  get hidden()
+    this.widget.getAttribute("hidden") == "true" ||
+    this._splitter.getAttribute("hidden") == "true",
+
+  /**
+   * Hides and removes all items from this search container.
+   */
+  clearView: function() {
+    this.hidden = true;
+    this.empty();
+  },
+
+  /**
+   * Selects the next found item in this container.
+   * Does not change the currently focused node.
+   */
+  selectNext: function() {
+    let totalLineResults = LineResults.size();
+    if (!totalLineResults) {
+      return;
+    }
+    if (++this._currentlyFocusedMatch >= totalLineResults) {
+      this._currentlyFocusedMatch = 0;
+    }
+    this._onMatchClick({
+      target: LineResults.getElementAtIndex(this._currentlyFocusedMatch)
+    });
+  },
+
+  /**
+   * Selects the previously found item in this container.
+   * Does not change the currently focused node.
+   */
+  selectPrev: function() {
+    let totalLineResults = LineResults.size();
+    if (!totalLineResults) {
+      return;
+    }
+    if (--this._currentlyFocusedMatch < 0) {
+      this._currentlyFocusedMatch = totalLineResults - 1;
+    }
+    this._onMatchClick({
+      target: LineResults.getElementAtIndex(this._currentlyFocusedMatch)
+    });
+  },
+
+  /**
+   * Schedules searching for a string in all of the sources.
+   *
+   * @param string aToken
+   *        The string to search for.
+   * @param number aWait
+   *        The amount of milliseconds to wait until draining.
+   */
+  scheduleSearch: function(aToken, aWait) {
+    // The amount of time to wait for the requests to settle.
+    let maxDelay = GLOBAL_SEARCH_ACTION_MAX_DELAY;
+    let delay = aWait === undefined ? maxDelay / aToken.length : aWait;
+
+    // Allow requests to settle down first.
+    setNamedTimeout("global-search", delay, () => {
+      // Start fetching as many sources as possible, then perform the search.
+      let actors = this.DebuggerView.Sources.values;
+      let sourcesFetched = this.SourceScripts.getTextForSources(actors);
+      sourcesFetched.then(aSources => this._doSearch(aToken, aSources));
+    });
+  },
+
+  /**
+   * Finds string matches in all the sources stored in the controller's cache,
+   * and groups them by url and line number.
+   *
+   * @param string aToken
+   *        The string to search for.
+   * @param array aSources
+   *        An array of [url, text] tuples for each source.
+   */
+  _doSearch: function(aToken, aSources) {
+    // Don't continue filtering if the searched token is an empty string.
+    if (!aToken) {
+      this.clearView();
+      return;
+    }
+
+    // Search is not case sensitive, prepare the actual searched token.
+    let lowerCaseToken = aToken.toLowerCase();
+    let tokenLength = aToken.length;
+
+    // Create a Map containing search details for each source.
+    let globalResults = new GlobalResults();
+
+    // Search for the specified token in each source's text.
+    for (let [actor, text] of aSources) {
+      let item = this.DebuggerView.Sources.getItemByValue(actor);
+      let url = item.attachment.source.url;
+      if (!url) {
+        continue;
+      }
+
+      // Verify that the search token is found anywhere in the source.
+      if (!text.toLowerCase().contains(lowerCaseToken)) {
+        continue;
+      }
+      // ...and if so, create a Map containing search details for each line.
+      let sourceResults = new SourceResults(actor,
+                                            globalResults,
+                                            this.DebuggerView.Sources);
+
+      // Search for the specified token in each line's text.
+      text.split("\n").forEach((aString, aLine) => {
+        // Search is not case sensitive, prepare the actual searched line.
+        let lowerCaseLine = aString.toLowerCase();
+
+        // Verify that the search token is found anywhere in this line.
+        if (!lowerCaseLine.contains(lowerCaseToken)) {
+          return;
+        }
+        // ...and if so, create a Map containing search details for each word.
+        let lineResults = new LineResults(aLine, sourceResults);
+
+        // Search for the specified token this line's text.
+        lowerCaseLine.split(lowerCaseToken).reduce((aPrev, aCurr, aIndex, aArray) => {
+          let prevLength = aPrev.length;
+          let currLength = aCurr.length;
+
+          // Everything before the token is unmatched.
+          let unmatched = aString.substr(prevLength, currLength);
+          lineResults.add(unmatched);
+
+          // The lowered-case line was split by the lowered-case token. So,
+          // get the actual matched text from the original line's text.
+          if (aIndex != aArray.length - 1) {
+            let matched = aString.substr(prevLength + currLength, tokenLength);
+            let range = { start: prevLength + currLength, length: matched.length };
+            lineResults.add(matched, range, true);
+          }
+
+          // Continue with the next sub-region in this line's text.
+          return aPrev + aToken + aCurr;
+        }, "");
+
+        if (lineResults.matchCount) {
+          sourceResults.add(lineResults);
+        }
+      });
+
+      if (sourceResults.matchCount) {
+        globalResults.add(sourceResults);
+      }
+    }
+
+    // Rebuild the results, then signal if there are any matches.
+    if (globalResults.matchCount) {
+      this.hidden = false;
+      this._currentlyFocusedMatch = -1;
+      this._createGlobalResultsUI(globalResults);
+      window.emit(EVENTS.GLOBAL_SEARCH_MATCH_FOUND);
+    } else {
+      window.emit(EVENTS.GLOBAL_SEARCH_MATCH_NOT_FOUND);
+    }
+  },
+
+  /**
+   * Creates global search results entries and adds them to this container.
+   *
+   * @param GlobalResults aGlobalResults
+   *        An object containing all source results, grouped by source location.
+   */
+  _createGlobalResultsUI: function(aGlobalResults) {
+    let i = 0;
+
+    for (let sourceResults of aGlobalResults) {
+      if (i++ == 0) {
+        this._createSourceResultsUI(sourceResults);
+      } else {
+        // Dispatch subsequent document manipulation operations, to avoid
+        // blocking the main thread when a large number of search results
+        // is found, thus giving the impression of faster searching.
+        Services.tm.currentThread.dispatch({ run:
+          this._createSourceResultsUI.bind(this, sourceResults)
+        }, 0);
+      }
+    }
+  },
+
+  /**
+   * Creates source search results entries and adds them to this container.
+   *
+   * @param SourceResults aSourceResults
+   *        An object containing all the matched lines for a specific source.
+   */
+  _createSourceResultsUI: function(aSourceResults) {
+    // Create the element node for the source results item.
+    let container = document.createElement("hbox");
+    aSourceResults.createView(container, {
+      onHeaderClick: this._onHeaderClick,
+      onLineClick: this._onLineClick,
+      onMatchClick: this._onMatchClick
+    });
+
+    // Append a source results item to this container.
+    let item = this.push([container], {
+      index: -1, /* specifies on which position should the item be appended */
+      attachment: {
+        sourceResults: aSourceResults
+      }
+    });
+  },
+
+  /**
+   * The click listener for a results header.
+   */
+  _onHeaderClick: function(e) {
+    let sourceResultsItem = SourceResults.getItemForElement(e.target);
+    sourceResultsItem.instance.toggle(e);
+  },
+
+  /**
+   * The click listener for a results line.
+   */
+  _onLineClick: function(e) {
+    let lineResultsItem = LineResults.getItemForElement(e.target);
+    this._onMatchClick({ target: lineResultsItem.firstMatch });
+  },
+
+  /**
+   * The click listener for a result match.
+   */
+  _onMatchClick: function(e) {
+    if (e instanceof Event) {
+      e.preventDefault();
+      e.stopPropagation();
+    }
+
+    let target = e.target;
+    let sourceResultsItem = SourceResults.getItemForElement(target);
+    let lineResultsItem = LineResults.getItemForElement(target);
+
+    sourceResultsItem.instance.expand();
+    this._currentlyFocusedMatch = LineResults.indexOfElement(target);
+    this._scrollMatchIntoViewIfNeeded(target);
+    this._bounceMatch(target);
+
+    let actor = sourceResultsItem.instance.actor;
+    let line = lineResultsItem.instance.line;
+
+    this.DebuggerView.setEditorLocation(actor, line + 1, { noDebug: true });
+
+    let range = lineResultsItem.lineData.range;
+    let cursor = this.DebuggerView.editor.getOffset({ line: line, ch: 0 });
+    let [ anchor, head ] = this.DebuggerView.editor.getPosition(
+      cursor + range.start,
+      cursor + range.start + range.length
+    );
+
+    this.DebuggerView.editor.setSelection(anchor, head);
+  },
+
+  /**
+   * Scrolls a match into view if not already visible.
+   *
+   * @param nsIDOMNode aMatch
+   *        The match to scroll into view.
+   */
+  _scrollMatchIntoViewIfNeeded: function(aMatch) {
+    this.widget.ensureElementIsVisible(aMatch);
+  },
+
+  /**
+   * Starts a bounce animation for a match.
+   *
+   * @param nsIDOMNode aMatch
+   *        The match to start a bounce animation for.
+   */
+  _bounceMatch: function(aMatch) {
+    Services.tm.currentThread.dispatch({ run: () => {
+      aMatch.addEventListener("transitionend", function onEvent() {
+        aMatch.removeEventListener("transitionend", onEvent);
+        aMatch.removeAttribute("focused");
+      });
+      aMatch.setAttribute("focused", "");
+    }}, 0);
+    aMatch.setAttribute("focusing", "");
+  },
+
+  _splitter: null,
+  _currentlyFocusedMatch: -1,
+  _forceExpandResults: false
+});
+
+DebuggerView.GlobalSearch = new GlobalSearchView(DebuggerController, DebuggerView);
+
+/**
+ * An object containing all source results, grouped by source location.
+ * Iterable via "for (let [location, sourceResults] of globalResults) { }".
+ */
+function GlobalResults() {
+  this._store = [];
+  SourceResults._itemsByElement = new Map();
+  LineResults._itemsByElement = new Map();
+}
+
+GlobalResults.prototype = {
+  /**
+   * Adds source results to this store.
+   *
+   * @param SourceResults aSourceResults
+   *        An object containing search results for a specific source.
+   */
+  add: function(aSourceResults) {
+    this._store.push(aSourceResults);
+  },
+
+  /**
+   * Gets the number of source results in this store.
+   */
+  get matchCount() this._store.length
+};
+
+/**
+ * An object containing all the matched lines for a specific source.
+ * Iterable via "for (let [lineNumber, lineResults] of sourceResults) { }".
+ *
+ * @param string aActor
+ *        The target source actor id.
+ * @param GlobalResults aGlobalResults
+ *        An object containing all source results, grouped by source location.
+ */
+function SourceResults(aActor, aGlobalResults, sourcesView) {
+  let item = sourcesView.getItemByValue(aActor);
+  this.actor = aActor;
+  this.label = item.attachment.source.url;
+  this._globalResults = aGlobalResults;
+  this._store = [];
+}
+
+SourceResults.prototype = {
+  /**
+   * Adds line results to this store.
+   *
+   * @param LineResults aLineResults
+   *        An object containing search results for a specific line.
+   */
+  add: function(aLineResults) {
+    this._store.push(aLineResults);
+  },
+
+  /**
+   * Gets the number of line results in this store.
+   */
+  get matchCount() this._store.length,
+
+  /**
+   * Expands the element, showing all the added details.
+   */
+  expand: function() {
+    this._resultsContainer.removeAttribute("hidden");
+    this._arrow.setAttribute("open", "");
+  },
+
+  /**
+   * Collapses the element, hiding all the added details.
+   */
+  collapse: function() {
+    this._resultsContainer.setAttribute("hidden", "true");
+    this._arrow.removeAttribute("open");
+  },
+
+  /**
+   * Toggles between the element collapse/expand state.
+   */
+  toggle: function(e) {
+    this.expanded ^= 1;
+  },
+
+  /**
+   * Gets this element's expanded state.
+   * @return boolean
+   */
+  get expanded()
+    this._resultsContainer.getAttribute("hidden") != "true" &&
+    this._arrow.hasAttribute("open"),
+
+  /**
+   * Sets this element's expanded state.
+   * @param boolean aFlag
+   */
+  set expanded(aFlag) this[aFlag ? "expand" : "collapse"](),
+
+  /**
+   * Gets the element associated with this item.
+   * @return nsIDOMNode
+   */
+  get target() this._target,
+
+  /**
+   * Customization function for creating this item's UI.
+   *
+   * @param nsIDOMNode aElementNode
+   *        The element associated with the displayed item.
+   * @param object aCallbacks
+   *        An object containing all the necessary callback functions:
+   *          - onHeaderClick
+   *          - onMatchClick
+   */
+  createView: function(aElementNode, aCallbacks) {
+    this._target = aElementNode;
+
+    let arrow = this._arrow = document.createElement("box");
+    arrow.className = "arrow";
+
+    let locationNode = document.createElement("label");
+    locationNode.className = "plain dbg-results-header-location";
+    locationNode.setAttribute("value", this.label);
+
+    let matchCountNode = document.createElement("label");
+    matchCountNode.className = "plain dbg-results-header-match-count";
+    matchCountNode.setAttribute("value", "(" + this.matchCount + ")");
+
+    let resultsHeader = this._resultsHeader = document.createElement("hbox");
+    resultsHeader.className = "dbg-results-header";
+    resultsHeader.setAttribute("align", "center")
+    resultsHeader.appendChild(arrow);
+    resultsHeader.appendChild(locationNode);
+    resultsHeader.appendChild(matchCountNode);
+    resultsHeader.addEventListener("click", aCallbacks.onHeaderClick, false);
+
+    let resultsContainer = this._resultsContainer = document.createElement("vbox");
+    resultsContainer.className = "dbg-results-container";
+    resultsContainer.setAttribute("hidden", "true");
+
+    // Create lines search results entries and add them to this container.
+    // Afterwards, if the number of matches is reasonable, expand this
+    // container automatically.
+    for (let lineResults of this._store) {
+      lineResults.createView(resultsContainer, aCallbacks);
+    }
+    if (this.matchCount < GLOBAL_SEARCH_EXPAND_MAX_RESULTS) {
+      this.expand();
+    }
+
+    let resultsBox = document.createElement("vbox");
+    resultsBox.setAttribute("flex", "1");
+    resultsBox.appendChild(resultsHeader);
+    resultsBox.appendChild(resultsContainer);
+
+    aElementNode.id = "source-results-" + this.actor;
+    aElementNode.className = "dbg-source-results";
+    aElementNode.appendChild(resultsBox);
+
+    SourceResults._itemsByElement.set(aElementNode, { instance: this });
+  },
+
+  actor: "",
+  _globalResults: null,
+  _store: null,
+  _target: null,
+  _arrow: null,
+  _resultsHeader: null,
+  _resultsContainer: null
+};
+
+/**
+ * An object containing all the matches for a specific line.
+ * Iterable via "for (let chunk of lineResults) { }".
+ *
+ * @param number aLine
+ *        The target line in the source.
+ * @param SourceResults aSourceResults
+ *        An object containing all the matched lines for a specific source.
+ */
+function LineResults(aLine, aSourceResults) {
+  this.line = aLine;
+  this._sourceResults = aSourceResults;
+  this._store = [];
+  this._matchCount = 0;
+}
+
+LineResults.prototype = {
+  /**
+   * Adds string details to this store.
+   *
+   * @param string aString
+   *        The text contents chunk in the line.
+   * @param object aRange
+   *        An object containing the { start, length } of the chunk.
+   * @param boolean aMatchFlag
+   *        True if the chunk is a matched string, false if just text content.
+   */
+  add: function(aString, aRange, aMatchFlag) {
+    this._store.push({ string: aString, range: aRange, match: !!aMatchFlag });
+    this._matchCount += aMatchFlag ? 1 : 0;
+  },
+
+  /**
+   * Gets the number of word results in this store.
+   */
+  get matchCount() this._matchCount,
+
+  /**
+   * Gets the element associated with this item.
+   * @return nsIDOMNode
+   */
+  get target() this._target,
+
+  /**
+   * Customization function for creating this item's UI.
+   *
+   * @param nsIDOMNode aElementNode
+   *        The element associated with the displayed item.
+   * @param object aCallbacks
+   *        An object containing all the necessary callback functions:
+   *          - onMatchClick
+   *          - onLineClick
+   */
+  createView: function(aElementNode, aCallbacks) {
+    this._target = aElementNode;
+
+    let lineNumberNode = document.createElement("label");
+    lineNumberNode.className = "plain dbg-results-line-number";
+    lineNumberNode.classList.add("devtools-monospace");
+    lineNumberNode.setAttribute("value", this.line + 1);
+
+    let lineContentsNode = document.createElement("hbox");
+    lineContentsNode.className = "dbg-results-line-contents";
+    lineContentsNode.classList.add("devtools-monospace");
+    lineContentsNode.setAttribute("flex", "1");
+
+    let lineString = "";
+    let lineLength = 0;
+    let firstMatch = null;
+
+    for (let lineChunk of this._store) {
+      let { string, range, match } = lineChunk;
+      lineString = string.substr(0, GLOBAL_SEARCH_LINE_MAX_LENGTH - lineLength);
+      lineLength += string.length;
+
+      let lineChunkNode = document.createElement("label");
+      lineChunkNode.className = "plain dbg-results-line-contents-string";
+      lineChunkNode.setAttribute("value", lineString);
+      lineChunkNode.setAttribute("match", match);
+      lineContentsNode.appendChild(lineChunkNode);
+
+      if (match) {
+        this._entangleMatch(lineChunkNode, lineChunk);
+        lineChunkNode.addEventListener("click", aCallbacks.onMatchClick, false);
+        firstMatch = firstMatch || lineChunkNode;
+      }
+      if (lineLength >= GLOBAL_SEARCH_LINE_MAX_LENGTH) {
+        lineContentsNode.appendChild(this._ellipsis.cloneNode(true));
+        break;
+      }
+    }
+
+    this._entangleLine(lineContentsNode, firstMatch);
+    lineContentsNode.addEventListener("click", aCallbacks.onLineClick, false);
+
+    let searchResult = document.createElement("hbox");
+    searchResult.className = "dbg-search-result";
+    searchResult.appendChild(lineNumberNode);
+    searchResult.appendChild(lineContentsNode);
+
+    aElementNode.appendChild(searchResult);
+  },
+
+  /**
+   * Handles a match while creating the view.
+   * @param nsIDOMNode aNode
+   * @param object aMatchChunk
+   */
+  _entangleMatch: function(aNode, aMatchChunk) {
+    LineResults._itemsByElement.set(aNode, {
+      instance: this,
+      lineData: aMatchChunk
+    });
+  },
+
+  /**
+   * Handles a line while creating the view.
+   * @param nsIDOMNode aNode
+   * @param nsIDOMNode aFirstMatch
+   */
+  _entangleLine: function(aNode, aFirstMatch) {
+    LineResults._itemsByElement.set(aNode, {
+      instance: this,
+      firstMatch: aFirstMatch,
+      ignored: true
+    });
+  },
+
+  /**
+   * An nsIDOMNode label with an ellipsis value.
+   */
+  _ellipsis: (function() {
+    let label = document.createElement("label");
+    label.className = "plain dbg-results-line-contents-string";
+    label.setAttribute("value", L10N.ellipsis);
+    return label;
+  })(),
+
+  line: 0,
+  _sourceResults: null,
+  _store: null,
+  _target: null
+};
+
+/**
+ * A generator-iterator over the global, source or line results.
+ */
+GlobalResults.prototype[Symbol.iterator] =
+SourceResults.prototype[Symbol.iterator] =
+LineResults.prototype[Symbol.iterator] = function*() {
+  yield* this._store;
+};
+
+/**
+ * Gets the item associated with the specified element.
+ *
+ * @param nsIDOMNode aElement
+ *        The element used to identify the item.
+ * @return object
+ *         The matched item, or null if nothing is found.
+ */
+SourceResults.getItemForElement =
+LineResults.getItemForElement = function(aElement) {
+  return WidgetMethods.getItemForElement.call(this, aElement, { noSiblings: true });
+};
+
+/**
+ * Gets the element associated with a particular item at a specified index.
+ *
+ * @param number aIndex
+ *        The index used to identify the item.
+ * @return nsIDOMNode
+ *         The matched element, or null if nothing is found.
+ */
+SourceResults.getElementAtIndex =
+LineResults.getElementAtIndex = function(aIndex) {
+  for (let [element, item] of this._itemsByElement) {
+    if (!item.ignored && !aIndex--) {
+      return element;
+    }
+  }
+  return null;
+};
+
+/**
+ * Gets the index of an item associated with the specified element.
+ *
+ * @param nsIDOMNode aElement
+ *        The element to get the index for.
+ * @return number
+ *         The index of the matched element, or -1 if nothing is found.
+ */
+SourceResults.indexOfElement =
+LineResults.indexOfElement = function(aElement) {
+  let count = 0;
+  for (let [element, item] of this._itemsByElement) {
+    if (element == aElement) {
+      return count;
+    }
+    if (!item.ignored) {
+      count++;
+    }
+  }
+  return -1;
+};
+
+/**
+ * Gets the number of cached items associated with a specified element.
+ *
+ * @return number
+ *         The number of key/value pairs in the corresponding map.
+ */
+SourceResults.size =
+LineResults.size = function() {
+  let count = 0;
+  for (let [, item] of this._itemsByElement) {
+    if (!item.ignored) {
+      count++;
+    }
+  }
+  return count;
+};
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/views/options-view.js
@@ -0,0 +1,209 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// A time interval sufficient for the options popup panel to finish hiding
+// itself.
+const POPUP_HIDDEN_DELAY = 100; // ms
+
+/**
+ * Functions handling the options UI.
+ */
+function OptionsView(DebuggerController, DebuggerView) {
+  dumpn("OptionsView was instantiated");
+
+  this.DebuggerController = DebuggerController;
+  this.DebuggerView = DebuggerView;
+
+  this._toggleAutoPrettyPrint = this._toggleAutoPrettyPrint.bind(this);
+  this._togglePauseOnExceptions = this._togglePauseOnExceptions.bind(this);
+  this._toggleIgnoreCaughtExceptions = this._toggleIgnoreCaughtExceptions.bind(this);
+  this._toggleShowPanesOnStartup = this._toggleShowPanesOnStartup.bind(this);
+  this._toggleShowVariablesOnlyEnum = this._toggleShowVariablesOnlyEnum.bind(this);
+  this._toggleShowVariablesFilterBox = this._toggleShowVariablesFilterBox.bind(this);
+  this._toggleShowOriginalSource = this._toggleShowOriginalSource.bind(this);
+  this._toggleAutoBlackBox = this._toggleAutoBlackBox.bind(this);
+}
+
+OptionsView.prototype = {
+  /**
+   * Initialization function, called when the debugger is started.
+   */
+  initialize: function() {
+    dumpn("Initializing the OptionsView");
+
+    this._button = document.getElementById("debugger-options");
+    this._autoPrettyPrint = document.getElementById("auto-pretty-print");
+    this._pauseOnExceptionsItem = document.getElementById("pause-on-exceptions");
+    this._ignoreCaughtExceptionsItem = document.getElementById("ignore-caught-exceptions");
+    this._showPanesOnStartupItem = document.getElementById("show-panes-on-startup");
+    this._showVariablesOnlyEnumItem = document.getElementById("show-vars-only-enum");
+    this._showVariablesFilterBoxItem = document.getElementById("show-vars-filter-box");
+    this._showOriginalSourceItem = document.getElementById("show-original-source");
+    this._autoBlackBoxItem = document.getElementById("auto-black-box");
+
+    this._autoPrettyPrint.setAttribute("checked", Prefs.autoPrettyPrint);
+    this._pauseOnExceptionsItem.setAttribute("checked", Prefs.pauseOnExceptions);
+    this._ignoreCaughtExceptionsItem.setAttribute("checked", Prefs.ignoreCaughtExceptions);
+    this._showPanesOnStartupItem.setAttribute("checked", Prefs.panesVisibleOnStartup);
+    this._showVariablesOnlyEnumItem.setAttribute("checked", Prefs.variablesOnlyEnumVisible);
+    this._showVariablesFilterBoxItem.setAttribute("checked", Prefs.variablesSearchboxVisible);
+    this._showOriginalSourceItem.setAttribute("checked", Prefs.sourceMapsEnabled);
+    this._autoBlackBoxItem.setAttribute("checked", Prefs.autoBlackBox);
+
+    this._addCommands();
+  },
+
+  /**
+   * Destruction function, called when the debugger is closed.
+   */
+  destroy: function() {
+    dumpn("Destroying the OptionsView");
+    // Nothing to do here yet.
+  },
+
+  /**
+   * Add commands that XUL can fire.
+   */
+  _addCommands: function() {
+    XULUtils.addCommands(document.getElementById('debuggerCommands'), {
+      toggleAutoPrettyPrint: () => this._toggleAutoPrettyPrint(),
+      togglePauseOnExceptions: () => this._togglePauseOnExceptions(),
+      toggleIgnoreCaughtExceptions: () => this._toggleIgnoreCaughtExceptions(),
+      toggleShowPanesOnStartup: () => this._toggleShowPanesOnStartup(),
+      toggleShowOnlyEnum: () => this._toggleShowVariablesOnlyEnum(),
+      toggleShowVariablesFilterBox: () => this._toggleShowVariablesFilterBox(),
+      toggleShowOriginalSource: () => this._toggleShowOriginalSource(),
+      toggleAutoBlackBox: () =>  this._toggleAutoBlackBox()
+    });
+  },
+
+  /**
+   * Listener handling the 'gear menu' popup showing event.
+   */
+  _onPopupShowing: function() {
+    this._button.setAttribute("open", "true");
+    window.emit(EVENTS.OPTIONS_POPUP_SHOWING);
+  },
+
+  /**
+   * Listener handling the 'gear menu' popup hiding event.
+   */
+  _onPopupHiding: function() {
+    this._button.removeAttribute("open");
+  },
+
+  /**
+   * Listener handling the 'gear menu' popup hidden event.
+   */
+  _onPopupHidden: function() {
+    window.emit(EVENTS.OPTIONS_POPUP_HIDDEN);
+  },
+
+  /**
+   * Listener handling the 'auto pretty print' menuitem command.
+   */
+  _toggleAutoPrettyPrint: function(){
+    Prefs.autoPrettyPrint =
+      this._autoPrettyPrint.getAttribute("checked") == "true";
+  },
+
+  /**
+   * Listener handling the 'pause on exceptions' menuitem command.
+   */
+  _togglePauseOnExceptions: function() {
+    Prefs.pauseOnExceptions =
+      this._pauseOnExceptionsItem.getAttribute("checked") == "true";
+
+    this.DebuggerController.activeThread.pauseOnExceptions(
+      Prefs.pauseOnExceptions,
+      Prefs.ignoreCaughtExceptions);
+  },
+
+  _toggleIgnoreCaughtExceptions: function() {
+    Prefs.ignoreCaughtExceptions =
+      this._ignoreCaughtExceptionsItem.getAttribute("checked") == "true";
+
+    this.DebuggerController.activeThread.pauseOnExceptions(
+      Prefs.pauseOnExceptions,
+      Prefs.ignoreCaughtExceptions);
+  },
+
+  /**
+   * Listener handling the 'show panes on startup' menuitem command.
+   */
+  _toggleShowPanesOnStartup: function() {
+    Prefs.panesVisibleOnStartup =
+      this._showPanesOnStartupItem.getAttribute("checked") == "true";
+  },
+
+  /**
+   * Listener handling the 'show non-enumerables' menuitem command.
+   */
+  _toggleShowVariablesOnlyEnum: function() {
+    let pref = Prefs.variablesOnlyEnumVisible =
+      this._showVariablesOnlyEnumItem.getAttribute("checked") == "true";
+
+    this.DebuggerView.Variables.onlyEnumVisible = pref;
+  },
+
+  /**
+   * Listener handling the 'show variables searchbox' menuitem command.
+   */
+  _toggleShowVariablesFilterBox: function() {
+    let pref = Prefs.variablesSearchboxVisible =
+      this._showVariablesFilterBoxItem.getAttribute("checked") == "true";
+
+    this.DebuggerView.Variables.searchEnabled = pref;
+  },
+
+  /**
+   * Listener handling the 'show original source' menuitem command.
+   */
+  _toggleShowOriginalSource: function() {
+    let pref = Prefs.sourceMapsEnabled =
+      this._showOriginalSourceItem.getAttribute("checked") == "true";
+
+    // Don't block the UI while reconfiguring the server.
+    window.once(EVENTS.OPTIONS_POPUP_HIDDEN, () => {
+      // The popup panel needs more time to hide after triggering onpopuphidden.
+      window.setTimeout(() => {
+        this.DebuggerController.reconfigureThread({
+          useSourceMaps: pref,
+          autoBlackBox: Prefs.autoBlackBox
+        });
+      }, POPUP_HIDDEN_DELAY);
+    });
+  },
+
+  /**
+   * Listener handling the 'automatically black box minified sources' menuitem
+   * command.
+   */
+  _toggleAutoBlackBox: function() {
+    let pref = Prefs.autoBlackBox =
+      this._autoBlackBoxItem.getAttribute("checked") == "true";
+
+    // Don't block the UI while reconfiguring the server.
+    window.once(EVENTS.OPTIONS_POPUP_HIDDEN, () => {
+      // The popup panel needs more time to hide after triggering onpopuphidden.
+      window.setTimeout(() => {
+        this.DebuggerController.reconfigureThread({
+          useSourceMaps: Prefs.sourceMapsEnabled,
+          autoBlackBox: pref
+        });
+      }, POPUP_HIDDEN_DELAY);
+    });
+  },
+
+  _button: null,
+  _pauseOnExceptionsItem: null,
+  _showPanesOnStartupItem: null,
+  _showVariablesOnlyEnumItem: null,
+  _showVariablesFilterBoxItem: null,
+  _showOriginalSourceItem: null,
+  _autoBlackBoxItem: null
+};
+
+DebuggerView.Options = new OptionsView(DebuggerController, DebuggerView);
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/views/sources-view.js
@@ -0,0 +1,1256 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// Maps known URLs to friendly source group names and put them at the
+// bottom of source list.
+const KNOWN_SOURCE_GROUPS = {
+  "Add-on SDK": "resource://gre/modules/commonjs/",
+};
+
+KNOWN_SOURCE_GROUPS[L10N.getStr("evalGroupLabel")] = "eval";
+
+/**
+ * Functions handling the sources UI.
+ */
+function SourcesView(DebuggerController, DebuggerView) {
+  dumpn("SourcesView was instantiated");
+
+  this.Breakpoints = DebuggerController.Breakpoints;
+  this.SourceScripts = DebuggerController.SourceScripts;
+  this.DebuggerView = DebuggerView;
+
+  this.togglePrettyPrint = this.togglePrettyPrint.bind(this);
+  this.toggleBlackBoxing = this.toggleBlackBoxing.bind(this);
+  this.toggleBreakpoints = this.toggleBreakpoints.bind(this);
+
+  this._onEditorLoad = this._onEditorLoad.bind(this);
+  this._onEditorUnload = this._onEditorUnload.bind(this);
+  this._onEditorCursorActivity = this._onEditorCursorActivity.bind(this);
+  this._onSourceSelect = this._onSourceSelect.bind(this);
+  this._onStopBlackBoxing = this._onStopBlackBoxing.bind(this);
+  this._onBreakpointRemoved = this._onBreakpointRemoved.bind(this);
+  this._onBreakpointClick = this._onBreakpointClick.bind(this);
+  this._onBreakpointCheckboxClick = this._onBreakpointCheckboxClick.bind(this);
+  this._onConditionalPopupShowing = this._onConditionalPopupShowing.bind(this);
+  this._onConditionalPopupShown = this._onConditionalPopupShown.bind(this);
+  this._onConditionalPopupHiding = this._onConditionalPopupHiding.bind(this);
+  this._onConditionalTextboxKeyPress = this._onConditionalTextboxKeyPress.bind(this);
+  this._onCopyUrlCommand = this._onCopyUrlCommand.bind(this);
+  this._onNewTabCommand = this._onNewTabCommand.bind(this);
+}
+
+SourcesView.prototype = Heritage.extend(WidgetMethods, {
+  /**
+   * Initialization function, called when the debugger is started.
+   */
+  initialize: function() {
+    dumpn("Initializing the SourcesView");
+
+    this.widget = new SideMenuWidget(document.getElementById("sources"), {
+      contextMenu: document.getElementById("debuggerSourcesContextMenu"),
+      showArrows: true
+    });
+
+    this.emptyText = L10N.getStr("noSourcesText");
+    this._blackBoxCheckboxTooltip = L10N.getStr("blackBoxCheckboxTooltip");
+
+    this._commandset = document.getElementById("debuggerCommands");
+    this._popupset = document.getElementById("debuggerPopupset");
+    this._cmPopup = document.getElementById("sourceEditorContextMenu");
+    this._cbPanel = document.getElementById("conditional-breakpoint-panel");
+    this._cbTextbox = document.getElementById("conditional-breakpoint-panel-textbox");
+    this._blackBoxButton = document.getElementById("black-box");
+    this._stopBlackBoxButton = document.getElementById("black-boxed-message-button");
+    this._prettyPrintButton = document.getElementById("pretty-print");
+    this._toggleBreakpointsButton = document.getElementById("toggle-breakpoints");
+    this._newTabMenuItem = document.getElementById("debugger-sources-context-newtab");
+    this._copyUrlMenuItem = document.getElementById("debugger-sources-context-copyurl");
+
+    if (Prefs.prettyPrintEnabled) {
+      this._prettyPrintButton.removeAttribute("hidden");
+    }
+
+    window.on(EVENTS.EDITOR_LOADED, this._onEditorLoad, false);
+    window.on(EVENTS.EDITOR_UNLOADED, this._onEditorUnload, false);
+    this.widget.addEventListener("select", this._onSourceSelect, false);
+    this._stopBlackBoxButton.addEventListener("click", this._onStopBlackBoxing, false);
+    this._cbPanel.addEventListener("popupshowing", this._onConditionalPopupShowing, false);
+    this._cbPanel.addEventListener("popupshown", this._onConditionalPopupShown, false);
+    this._cbPanel.addEventListener("popuphiding", this._onConditionalPopupHiding, false);
+    this._cbTextbox.addEventListener("keypress", this._onConditionalTextboxKeyPress, false);
+    this._copyUrlMenuItem.addEventListener("command", this._onCopyUrlCommand, false);
+    this._newTabMenuItem.addEventListener("command", this._onNewTabCommand, false);
+
+    this.allowFocusOnRightClick = true;
+    this.autoFocusOnSelection = false;
+
+    // Sort the contents by the displayed label.
+    this.sortContents((aFirst, aSecond) => {
+      return +(aFirst.attachment.label.toLowerCase() >
+               aSecond.attachment.label.toLowerCase());
+    });
+
+    // Sort known source groups towards the end of the list
+    this.widget.groupSortPredicate = function(a, b) {
+      if ((a in KNOWN_SOURCE_GROUPS) == (b in KNOWN_SOURCE_GROUPS)) {
+        return a.localeCompare(b);
+      }
+      return (a in KNOWN_SOURCE_GROUPS) ? 1 : -1;
+    };
+
+    this._addCommands();
+  },
+
+  /**
+   * Destruction function, called when the debugger is closed.
+   */
+  destroy: function() {
+    dumpn("Destroying the SourcesView");
+
+    window.off(EVENTS.EDITOR_LOADED, this._onEditorLoad, false);
+    window.off(EVENTS.EDITOR_UNLOADED, this._onEditorUnload, false);
+    this.widget.removeEventListener("select", this._onSourceSelect, false);
+    this._stopBlackBoxButton.removeEventListener("click", this._onStopBlackBoxing, false);
+    this._cbPanel.removeEventListener("popupshowing", this._onConditionalPopupShowing, false);
+    this._cbPanel.removeEventListener("popupshowing", this._onConditionalPopupShown, false);
+    this._cbPanel.removeEventListener("popuphiding", this._onConditionalPopupHiding, false);
+    this._cbTextbox.removeEventListener("keypress", this._onConditionalTextboxKeyPress, false);
+    this._copyUrlMenuItem.removeEventListener("command", this._onCopyUrlCommand, false);
+    this._newTabMenuItem.removeEventListener("command", this._onNewTabCommand, false);
+  },
+
+  /**
+   * Add commands that XUL can fire.
+   */
+  _addCommands: function() {
+    XULUtils.addCommands(this._commandset, {
+      addBreakpointCommand: e => this._onCmdAddBreakpoint(e),
+      addConditionalBreakpointCommand: e => this._onCmdAddConditionalBreakpoint(e),
+      blackBoxCommand: () => this.toggleBlackBoxing(),
+      unBlackBoxButton: () => this._onStopBlackBoxing(),
+      prettyPrintCommand: () => this.togglePrettyPrint(),
+      toggleBreakpointsCommand: () =>this.toggleBreakpoints(),
+      nextSourceCommand: () => this.selectNextItem(),
+      prevSourceCommand: () => this.selectPrevItem()
+    });
+  },
+
+  /**
+   * Sets the preferred location to be selected in this sources container.
+   * @param string aUrl
+   */
+  set preferredSource(aUrl) {
+    this._preferredValue = aUrl;
+
+    // Selects the element with the specified value in this sources container,
+    // if already inserted.
+    if (this.containsValue(aUrl)) {
+      this.selectedValue = aUrl;
+    }
+  },
+
+  /**
+   * Adds a source to this sources container.
+   *
+   * @param object aSource
+   *        The source object coming from the active thread.
+   * @param object aOptions [optional]
+   *        Additional options for adding the source. Supported options:
+   *        - staged: true to stage the item to be appended later
+   */
+  addSource: function(aSource, aOptions = {}) {
+    if (!aSource.url) {
+      // We don't show any unnamed eval scripts yet (see bug 1124106)
+      return;
+    }
+
+    let { label, group, unicodeUrl } = this._parseUrl(aSource);
+
+    let contents = document.createElement("label");
+    contents.className = "plain dbg-source-item";
+    contents.setAttribute("value", label);
+    contents.setAttribute("crop", "start");
+    contents.setAttribute("flex", "1");
+    contents.setAttribute("tooltiptext", unicodeUrl);
+
+    // If the source is blackboxed, apply the appropriate style.
+    if (gThreadClient.source(aSource).isBlackBoxed) {
+      contents.classList.add("black-boxed");
+    }
+
+    // Append a source item to this container.
+    this.push([contents, aSource.actor], {
+      staged: aOptions.staged, /* stage the item to be appended later? */
+      attachment: {
+        label: label,
+        group: group,
+        checkboxState: !aSource.isBlackBoxed,
+        checkboxTooltip: this._blackBoxCheckboxTooltip,
+        source: aSource
+      }
+    });
+  },
+
+  _parseUrl: function(aSource) {
+    let fullUrl = aSource.url;
+    let url = fullUrl.split(" -> ").pop();
+    let label = aSource.addonPath ? aSource.addonPath : SourceUtils.getSourceLabel(url);
+    let group = aSource.addonID ? aSource.addonID : SourceUtils.getSourceGroup(url);
+
+    return {
+      label: label,
+      group: group,
+      unicodeUrl: NetworkHelper.convertToUnicode(unescape(fullUrl))
+    };
+  },
+
+  /**
+   * Adds a breakpoint to this sources container.
+   *
+   * @param object aBreakpointClient
+   *               See Breakpoints.prototype._showBreakpoint
+   * @param object aOptions [optional]
+   *        @see DebuggerController.Breakpoints.addBreakpoint
+   */
+  addBreakpoint: function(aBreakpointClient, aOptions = {}) {
+    let { location, disabled } = aBreakpointClient;
+
+    // Make sure we're not duplicating anything. If a breakpoint at the
+    // specified source url and line already exists, just toggle it.
+    if (this.getBreakpoint(location)) {
+      this[disabled ? "disableBreakpoint" : "enableBreakpoint"](location);
+      return;
+    }
+
+    // Get the source item to which the breakpoint should be attached.
+    let sourceItem = this.getItemByValue(this.getActorForLocation(location));
+
+    // Create the element node and menu popup for the breakpoint item.
+    let breakpointArgs = Heritage.extend(aBreakpointClient, aOptions);
+    let breakpointView = this._createBreakpointView.call(this, breakpointArgs);
+    let contextMenu = this._createContextMenu.call(this, breakpointArgs);
+
+    // Append a breakpoint child item to the corresponding source item.
+    sourceItem.append(breakpointView.container, {
+      attachment: Heritage.extend(breakpointArgs, {
+        actor: location.actor,
+        line: location.line,
+        view: breakpointView,
+        popup: contextMenu
+      }),
+      attributes: [
+        ["contextmenu", contextMenu.menupopupId]
+      ],
+      // Make sure that when the breakpoint item is removed, the corresponding
+      // menupopup and commandset are also destroyed.
+      finalize: this._onBreakpointRemoved
+    });
+
+    // Highlight the newly appended breakpoint child item if
+    // necessary.
+    if (aOptions.openPopup || !aOptions.noEditorUpdate) {
+      this.highlightBreakpoint(location, aOptions);
+    }
+
+    window.emit(EVENTS.BREAKPOINT_SHOWN_IN_PANE);
+  },
+
+  /**
+   * Removes a breakpoint from this sources container.
+   * It does not also remove the breakpoint from the controller. Be careful.
+   *
+   * @param object aLocation
+   *        @see DebuggerController.Breakpoints.addBreakpoint
+   */
+  removeBreakpoint: function(aLocation) {
+    // When a parent source item is removed, all the child breakpoint items are
+    // also automagically removed.
+    let sourceItem = this.getItemByValue(aLocation.actor);
+    if (!sourceItem) {
+      return;
+    }
+    let breakpointItem = this.getBreakpoint(aLocation);
+    if (!breakpointItem) {
+      return;
+    }
+
+    // Clear the breakpoint view.
+    sourceItem.remove(breakpointItem);
+
+    window.emit(EVENTS.BREAKPOINT_HIDDEN_IN_PANE);
+  },
+
+  /**
+   * Returns the breakpoint at the specified source url and line.
+   *
+   * @param object aLocation
+   *        @see DebuggerController.Breakpoints.addBreakpoint
+   * @return object
+   *         The corresponding breakpoint item if found, null otherwise.
+   */
+  getBreakpoint: function(aLocation) {
+    return this.getItemForPredicate(aItem =>
+      aItem.attachment.actor == aLocation.actor &&
+      aItem.attachment.line == aLocation.line);
+  },
+
+  /**
+   * Returns all breakpoints for all sources.
+   *
+   * @return array
+   *         The breakpoints for all sources if any, an empty array otherwise.
+   */
+  getAllBreakpoints: function(aStore = []) {
+    return this.getOtherBreakpoints(undefined, aStore);
+  },
+
+  /**
+   * Returns all breakpoints which are not at the specified source url and line.
+   *
+   * @param object aLocation [optional]
+   *        @see DebuggerController.Breakpoints.addBreakpoint
+   * @param array aStore [optional]
+   *        A list in which to store the corresponding breakpoints.
+   * @return array
+   *         The corresponding breakpoints if found, an empty array otherwise.
+   */
+  getOtherBreakpoints: function(aLocation = {}, aStore = []) {
+    for (let source of this) {
+      for (let breakpointItem of source) {
+        let { actor, line } = breakpointItem.attachment;
+        if (actor != aLocation.actor || line != aLocation.line) {
+          aStore.push(breakpointItem);
+        }
+      }
+    }
+    return aStore;
+  },
+
+  /**
+   * Enables a breakpoint.
+   *
+   * @param object aLocation
+   *        @see DebuggerController.Breakpoints.addBreakpoint
+   * @param object aOptions [optional]
+   *        Additional options or flags supported by this operation:
+   *          - silent: pass true to not update the checkbox checked state;
+   *                    this is usually necessary when the checked state will
+   *                    be updated automatically (e.g: on a checkbox click).
+   * @return object
+   *         A promise that is resolved after the breakpoint is enabled, or
+   *         rejected if no breakpoint was found at the specified location.
+   */
+  enableBreakpoint: function(aLocation, aOptions = {}) {
+    let breakpointItem = this.getBreakpoint(aLocation);
+    if (!breakpointItem) {
+      return promise.reject(new Error("No breakpoint found."));
+    }
+
+    // Breakpoint will now be enabled.
+    let attachment = breakpointItem.attachment;
+    attachment.disabled = false;
+
+    // Update the corresponding menu items to reflect the enabled state.
+    let prefix = "bp-cMenu-"; // "breakpoints context menu"
+    let identifier = this.Breakpoints.getIdentifier(attachment);
+    let enableSelfId = prefix + "enableSelf-" + identifier + "-menuitem";
+    let disableSelfId = prefix + "disableSelf-" + identifier + "-menuitem";
+    document.getElementById(enableSelfId).setAttribute("hidden", "true");
+    document.getElementById(disableSelfId).removeAttribute("hidden");
+
+    // Update the breakpoint toggle button checked state.
+    this._toggleBreakpointsButton.removeAttribute("checked");
+
+    // Update the checkbox state if necessary.
+    if (!aOptions.silent) {
+      attachment.view.checkbox.setAttribute("checked", "true");
+    }
+
+    return this.Breakpoints.addBreakpoint(aLocation, {
+      // No need to update the pane, since this method is invoked because
+      // a breakpoint's view was interacted with.
+      noPaneUpdate: true
+    });
+  },
+
+  /**
+   * Disables a breakpoint.
+   *
+   * @param object aLocation
+   *        @see DebuggerController.Breakpoints.addBreakpoint
+   * @param object aOptions [optional]
+   *        Additional options or flags supported by this operation:
+   *          - silent: pass true to not update the checkbox checked state;
+   *                    this is usually necessary when the checked state will
+   *                    be updated automatically (e.g: on a checkbox click).
+   * @return object
+   *         A promise that is resolved after the breakpoint is disabled, or
+   *         rejected if no breakpoint was found at the specified location.
+   */
+  disableBreakpoint: function(aLocation, aOptions = {}) {
+    let breakpointItem = this.getBreakpoint(aLocation);
+    if (!breakpointItem) {
+      return promise.reject(new Error("No breakpoint found."));
+    }
+
+    // Breakpoint will now be disabled.
+    let attachment = breakpointItem.attachment;
+    attachment.disabled = true;
+
+    // Update the corresponding menu items to reflect the disabled state.
+    let prefix = "bp-cMenu-"; // "breakpoints context menu"
+    let identifier = this.Breakpoints.getIdentifier(attachment);
+    let enableSelfId = prefix + "enableSelf-" + identifier + "-menuitem";
+    let disableSelfId = prefix + "disableSelf-" + identifier + "-menuitem";
+    document.getElementById(enableSelfId).removeAttribute("hidden");
+    document.getElementById(disableSelfId).setAttribute("hidden", "true");
+
+    // Update the checkbox state if necessary.
+    if (!aOptions.silent) {
+      attachment.view.checkbox.removeAttribute("checked");
+    }
+
+    return this.Breakpoints.removeBreakpoint(aLocation, {
+      // No need to update this pane, since this method is invoked because
+      // a breakpoint's view was interacted with.
+      noPaneUpdate: true,
+      // Mark this breakpoint as being "disabled", not completely removed.
+      // This makes sure it will not be forgotten across target navigations.
+      rememberDisabled: true
+    });
+  },
+
+  /**
+   * Highlights a breakpoint in this sources container.
+   *
+   * @param object aLocation
+   *        @see DebuggerController.Breakpoints.addBreakpoint
+   * @param object aOptions [optional]
+   *        An object containing some of the following boolean properties:
+   *          - openPopup: tells if the expression popup should be shown.
+   *          - noEditorUpdate: tells if you want to skip editor updates.
+   */
+  highlightBreakpoint: function(aLocation, aOptions = {}) {
+    let breakpointItem = this.getBreakpoint(aLocation);
+    if (!breakpointItem) {
+      return;
+    }
+
+    // Breakpoint will now be selected.
+    this._selectBreakpoint(breakpointItem);
+
+    // Update the editor location if necessary.
+    if (!aOptions.noEditorUpdate) {
+      this.DebuggerView.setEditorLocation(aLocation.actor, aLocation.line, { noDebug: true });
+    }
+
+    // If the breakpoint requires a new conditional expression, display
+    // the panel to input the corresponding expression.
+    if (aOptions.openPopup) {
+      this._openConditionalPopup();
+    } else {
+      this._hideConditionalPopup();
+    }
+  },
+
+  /**
+   * Highlight the breakpoint on the current currently focused line/column
+   * if it exists.
+   */
+  highlightBreakpointAtCursor: function() {
+    let actor = this.selectedValue;
+    let line = this.DebuggerView.editor.getCursor().line + 1;
+
+    let location = { actor: actor, line: line };
+    this.highlightBreakpoint(location, { noEditorUpdate: true });
+  },
+
+  /**
+   * Unhighlights the current breakpoint in this sources container.
+   */
+  unhighlightBreakpoint: function() {
+    this._hideConditionalPopup();
+    this._unselectBreakpoint();
+  },
+
+   /**
+    * Display the message thrown on breakpoint condition
+    */
+  showBreakpointConditionThrownMessage: function(aLocation, aMessage = "") {
+    let breakpointItem = this.getBreakpoint(aLocation);
+    if (!breakpointItem) {
+      return;
+    }
+    let attachment = breakpointItem.attachment;
+    attachment.view.container.classList.add("dbg-breakpoint-condition-thrown");
+    attachment.view.message.setAttribute("value", aMessage);
+  },
+
+  /**
+   * Update the checked/unchecked and enabled/disabled states of the buttons in
+   * the sources toolbar based on the currently selected source's state.
+   */
+  updateToolbarButtonsState: function() {
+    const { source } = this.selectedItem.attachment;
+    const sourceClient = gThreadClient.source(source);
+
+    if (sourceClient.isBlackBoxed) {
+      this._prettyPrintButton.setAttribute("disabled", true);
+      this._blackBoxButton.setAttribute("checked", true);
+    } else {
+      this._prettyPrintButton.removeAttribute("disabled");
+      this._blackBoxButton.removeAttribute("checked");
+    }
+
+    if (sourceClient.isPrettyPrinted) {
+      this._prettyPrintButton.setAttribute("checked", true);
+    } else {
+      this._prettyPrintButton.removeAttribute("checked");
+    }
+  },
+
+  /**
+   * Toggle the pretty printing of the selected source.
+   */
+  togglePrettyPrint: Task.async(function*() {
+    if (this._prettyPrintButton.hasAttribute("disabled")) {
+      return;
+    }
+
+    const resetEditor = ([{ actor }]) => {
+      // Only set the text when the source is still selected.
+      if (actor == this.selectedValue) {
+        this.DebuggerView.setEditorLocation(actor, 0, { force: true });
+      }
+    };
+
+    const printError = ([{ url }, error]) => {
+      DevToolsUtils.reportException("togglePrettyPrint", error);
+    };
+
+    this.DebuggerView.showProgressBar();
+    const { source } = this.selectedItem.attachment;
+    const sourceClient = gThreadClient.source(source);
+    const shouldPrettyPrint = !sourceClient.isPrettyPrinted;
+
+    if (shouldPrettyPrint) {
+      this._prettyPrintButton.setAttribute("checked", true);
+    } else {
+      this._prettyPrintButton.removeAttribute("checked");
+    }
+
+    try {
+      let resolution = yield this.SourceScripts.togglePrettyPrint(source);
+      resetEditor(resolution);
+    } catch (rejection) {
+      printError(rejection);
+    }
+
+    this.DebuggerView.showEditor();
+    this.updateToolbarButtonsState();
+  }),
+
+  /**
+   * Toggle the black boxed state of the selected source.
+   */
+  toggleBlackBoxing: Task.async(function*() {
+    const { source } = this.selectedItem.attachment;
+    const sourceClient = gThreadClient.source(source);
+    const shouldBlackBox = !sourceClient.isBlackBoxed;
+
+    // Be optimistic that the (un-)black boxing will succeed, so enable/disable
+    // the pretty print button and check/uncheck the black box button immediately.
+    // Then, once we actually get the results from the server, make sure that
+    // it is in the correct state again by calling `updateToolbarButtonsState`.
+
+    if (shouldBlackBox) {
+      this._prettyPrintButton.setAttribute("disabled", true);
+      this._blackBoxButton.setAttribute("checked", true);
+    } else {
+      this._prettyPrintButton.removeAttribute("disabled");
+      this._blackBoxButton.removeAttribute("checked");
+    }
+
+    try {
+      yield this.SourceScripts.setBlackBoxing(source, shouldBlackBox);
+    } catch (e) {
+      // Continue execution in this task even if blackboxing failed.
+    }
+
+    this.updateToolbarButtonsState();
+  }),
+
+  /**
+   * Toggles all breakpoints enabled/disabled.
+   */
+  toggleBreakpoints: function() {
+    let breakpoints = this.getAllBreakpoints();
+    let hasBreakpoints = breakpoints.length > 0;
+    let hasEnabledBreakpoints = breakpoints.some(e => !e.attachment.disabled);
+
+    if (hasBreakpoints && hasEnabledBreakpoints) {
+      this._toggleBreakpointsButton.setAttribute("checked", true);
+      this._onDisableAll();
+    } else {
+      this._toggleBreakpointsButton.removeAttribute("checked");
+      this._onEnableAll();
+    }
+  },
+
+  hidePrettyPrinting: function() {
+    this._prettyPrintButton.style.display = 'none';
+
+    if (this._blackBoxButton.style.display === 'none') {
+      let sep = document.querySelector('#sources-toolbar .devtools-separator');
+      sep.style.display = 'none';
+    }
+  },
+
+  hideBlackBoxing: function() {
+    this._blackBoxButton.style.display = 'none';
+
+    if (this._prettyPrintButton.style.display === 'none') {
+      let sep = document.querySelector('#sources-toolbar .devtools-separator');
+      sep.style.display = 'none';
+    }
+  },
+
+  /**
+   * Look up a source actor id for a location. This is necessary for
+   * backwards compatibility; otherwise we could just use the `actor`
+   * property. Older servers don't use the same actor ids for sources
+   * across reloads, so we resolve a url to the current actor if a url
+   * exists.
+   *
+   * @param object aLocation
+   *        An object with the following properties:
+   *        - actor: the source actor id
+   *        - url: a url (might be null)
+   */
+  getActorForLocation: function(aLocation) {
+    if (aLocation.url) {
+      for (var item of this) {
+        let source = item.attachment.source;
+
+        if (aLocation.url === source.url) {
+          return source.actor;
+        }
+      }
+    }
+    return aLocation.actor;
+  },
+
+  /**
+   * Marks a breakpoint as selected in this sources container.
+   *
+   * @param object aItem
+   *        The breakpoint item to select.
+   */
+  _selectBreakpoint: function(aItem) {
+    if (this._selectedBreakpointItem == aItem) {
+      return;
+    }
+    this._unselectBreakpoint();
+
+    this._selectedBreakpointItem = aItem;
+    this._selectedBreakpointItem.target.classList.add("selected");
+
+    // Ensure the currently selected breakpoint is visible.
+    this.widget.ensureElementIsVisible(aItem.target);
+  },
+
+  /**
+   * Marks the current breakpoint as unselected in this sources container.
+   */
+  _unselectBreakpoint: function() {
+    if (!this._selectedBreakpointItem) {
+      return;
+    }
+    this._selectedBreakpointItem.target.classList.remove("selected");
+    this._selectedBreakpointItem